1*d9c61bb3SMichael Grzeschik // SPDX-License-Identifier: GPL-2.0
2*d9c61bb3SMichael Grzeschik /*
3*d9c61bb3SMichael Grzeschik * func_utils.h
4*d9c61bb3SMichael Grzeschik *
5*d9c61bb3SMichael Grzeschik * Utility definitions for USB functions
6*d9c61bb3SMichael Grzeschik *
7*d9c61bb3SMichael Grzeschik * Copyright (c) 2013 Samsung Electronics Co., Ltd.
8*d9c61bb3SMichael Grzeschik * http://www.samsung.com
9*d9c61bb3SMichael Grzeschik *
10*d9c61bb3SMichael Grzeschik * Author: Andrzej Pietrasiewicz <[email protected]>
11*d9c61bb3SMichael Grzeschik */
12*d9c61bb3SMichael Grzeschik
13*d9c61bb3SMichael Grzeschik #ifndef _FUNC_UTILS_H_
14*d9c61bb3SMichael Grzeschik #define _FUNC_UTILS_H_
15*d9c61bb3SMichael Grzeschik
16*d9c61bb3SMichael Grzeschik #include <linux/usb/gadget.h>
17*d9c61bb3SMichael Grzeschik #include <linux/overflow.h>
18*d9c61bb3SMichael Grzeschik
19*d9c61bb3SMichael Grzeschik /* Variable Length Array Macros **********************************************/
20*d9c61bb3SMichael Grzeschik #define vla_group(groupname) size_t groupname##__next = 0
21*d9c61bb3SMichael Grzeschik #define vla_group_size(groupname) groupname##__next
22*d9c61bb3SMichael Grzeschik
23*d9c61bb3SMichael Grzeschik #define vla_item(groupname, type, name, n) \
24*d9c61bb3SMichael Grzeschik size_t groupname##_##name##__offset = ({ \
25*d9c61bb3SMichael Grzeschik size_t offset = 0; \
26*d9c61bb3SMichael Grzeschik if (groupname##__next != SIZE_MAX) { \
27*d9c61bb3SMichael Grzeschik size_t align_mask = __alignof__(type) - 1; \
28*d9c61bb3SMichael Grzeschik size_t size = array_size(n, sizeof(type)); \
29*d9c61bb3SMichael Grzeschik offset = (groupname##__next + align_mask) & \
30*d9c61bb3SMichael Grzeschik ~align_mask; \
31*d9c61bb3SMichael Grzeschik if (check_add_overflow(offset, size, \
32*d9c61bb3SMichael Grzeschik &groupname##__next)) { \
33*d9c61bb3SMichael Grzeschik groupname##__next = SIZE_MAX; \
34*d9c61bb3SMichael Grzeschik offset = 0; \
35*d9c61bb3SMichael Grzeschik } \
36*d9c61bb3SMichael Grzeschik } \
37*d9c61bb3SMichael Grzeschik offset; \
38*d9c61bb3SMichael Grzeschik })
39*d9c61bb3SMichael Grzeschik
40*d9c61bb3SMichael Grzeschik #define vla_item_with_sz(groupname, type, name, n) \
41*d9c61bb3SMichael Grzeschik size_t groupname##_##name##__sz = array_size(n, sizeof(type)); \
42*d9c61bb3SMichael Grzeschik size_t groupname##_##name##__offset = ({ \
43*d9c61bb3SMichael Grzeschik size_t offset = 0; \
44*d9c61bb3SMichael Grzeschik if (groupname##__next != SIZE_MAX) { \
45*d9c61bb3SMichael Grzeschik size_t align_mask = __alignof__(type) - 1; \
46*d9c61bb3SMichael Grzeschik offset = (groupname##__next + align_mask) & \
47*d9c61bb3SMichael Grzeschik ~align_mask; \
48*d9c61bb3SMichael Grzeschik if (check_add_overflow(offset, groupname##_##name##__sz,\
49*d9c61bb3SMichael Grzeschik &groupname##__next)) { \
50*d9c61bb3SMichael Grzeschik groupname##__next = SIZE_MAX; \
51*d9c61bb3SMichael Grzeschik offset = 0; \
52*d9c61bb3SMichael Grzeschik } \
53*d9c61bb3SMichael Grzeschik } \
54*d9c61bb3SMichael Grzeschik offset; \
55*d9c61bb3SMichael Grzeschik })
56*d9c61bb3SMichael Grzeschik
57*d9c61bb3SMichael Grzeschik #define vla_ptr(ptr, groupname, name) \
58*d9c61bb3SMichael Grzeschik ((void *) ((char *)ptr + groupname##_##name##__offset))
59*d9c61bb3SMichael Grzeschik
60*d9c61bb3SMichael Grzeschik struct usb_ep;
61*d9c61bb3SMichael Grzeschik struct usb_request;
62*d9c61bb3SMichael Grzeschik
63*d9c61bb3SMichael Grzeschik /**
64*d9c61bb3SMichael Grzeschik * alloc_ep_req - returns a usb_request allocated by the gadget driver and
65*d9c61bb3SMichael Grzeschik * allocates the request's buffer.
66*d9c61bb3SMichael Grzeschik *
67*d9c61bb3SMichael Grzeschik * @ep: the endpoint to allocate a usb_request
68*d9c61bb3SMichael Grzeschik * @len: usb_requests's buffer suggested size
69*d9c61bb3SMichael Grzeschik *
70*d9c61bb3SMichael Grzeschik * In case @ep direction is OUT, the @len will be aligned to ep's
71*d9c61bb3SMichael Grzeschik * wMaxPacketSize. In order to avoid memory leaks or drops, *always* use
72*d9c61bb3SMichael Grzeschik * usb_requests's length (req->length) to refer to the allocated buffer size.
73*d9c61bb3SMichael Grzeschik * Requests allocated via alloc_ep_req() *must* be freed by free_ep_req().
74*d9c61bb3SMichael Grzeschik */
75*d9c61bb3SMichael Grzeschik struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len);
76*d9c61bb3SMichael Grzeschik
77*d9c61bb3SMichael Grzeschik /* Frees a usb_request previously allocated by alloc_ep_req() */
free_ep_req(struct usb_ep * ep,struct usb_request * req)78*d9c61bb3SMichael Grzeschik static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req)
79*d9c61bb3SMichael Grzeschik {
80*d9c61bb3SMichael Grzeschik WARN_ON(req->buf == NULL);
81*d9c61bb3SMichael Grzeschik kfree(req->buf);
82*d9c61bb3SMichael Grzeschik req->buf = NULL;
83*d9c61bb3SMichael Grzeschik usb_ep_free_request(ep, req);
84*d9c61bb3SMichael Grzeschik }
85*d9c61bb3SMichael Grzeschik
86*d9c61bb3SMichael Grzeschik #endif /* _FUNC_UTILS_H_ */
87