15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21efd54eaSAndrzej Pietrasiewicz /*
31efd54eaSAndrzej Pietrasiewicz * u_f.h
41efd54eaSAndrzej Pietrasiewicz *
51efd54eaSAndrzej Pietrasiewicz * Utility definitions for USB functions
61efd54eaSAndrzej Pietrasiewicz *
71efd54eaSAndrzej Pietrasiewicz * Copyright (c) 2013 Samsung Electronics Co., Ltd.
81efd54eaSAndrzej Pietrasiewicz * http://www.samsung.com
91efd54eaSAndrzej Pietrasiewicz *
101b4a3b51SAndrzej Pietrasiewicz * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
111efd54eaSAndrzej Pietrasiewicz */
121efd54eaSAndrzej Pietrasiewicz
131efd54eaSAndrzej Pietrasiewicz #ifndef __U_F_H__
141efd54eaSAndrzej Pietrasiewicz #define __U_F_H__
151efd54eaSAndrzej Pietrasiewicz
16079fe5a6SFelipe F. Tonello #include <linux/usb/gadget.h>
17b1cd1b65SBrooke Basile #include <linux/overflow.h>
18079fe5a6SFelipe F. Tonello
1974d48466SAndrzej Pietrasiewicz /* Variable Length Array Macros **********************************************/
2074d48466SAndrzej Pietrasiewicz #define vla_group(groupname) size_t groupname##__next = 0
2174d48466SAndrzej Pietrasiewicz #define vla_group_size(groupname) groupname##__next
2274d48466SAndrzej Pietrasiewicz
2374d48466SAndrzej Pietrasiewicz #define vla_item(groupname, type, name, n) \
2474d48466SAndrzej Pietrasiewicz size_t groupname##_##name##__offset = ({ \
25b1cd1b65SBrooke Basile size_t offset = 0; \
26b1cd1b65SBrooke Basile if (groupname##__next != SIZE_MAX) { \
2774d48466SAndrzej Pietrasiewicz size_t align_mask = __alignof__(type) - 1; \
28b1cd1b65SBrooke Basile size_t size = array_size(n, sizeof(type)); \
29*bfd08d06SAndy Shevchenko offset = (groupname##__next + align_mask) & \
30*bfd08d06SAndy Shevchenko ~align_mask; \
31b1cd1b65SBrooke Basile if (check_add_overflow(offset, size, \
32b1cd1b65SBrooke Basile &groupname##__next)) { \
33b1cd1b65SBrooke Basile groupname##__next = SIZE_MAX; \
34b1cd1b65SBrooke Basile offset = 0; \
35b1cd1b65SBrooke Basile } \
36b1cd1b65SBrooke Basile } \
3774d48466SAndrzej Pietrasiewicz offset; \
3874d48466SAndrzej Pietrasiewicz })
3974d48466SAndrzej Pietrasiewicz
4074d48466SAndrzej Pietrasiewicz #define vla_item_with_sz(groupname, type, name, n) \
41b1cd1b65SBrooke Basile size_t groupname##_##name##__sz = array_size(n, sizeof(type)); \
4274d48466SAndrzej Pietrasiewicz size_t groupname##_##name##__offset = ({ \
43b1cd1b65SBrooke Basile size_t offset = 0; \
44b1cd1b65SBrooke Basile if (groupname##__next != SIZE_MAX) { \
4574d48466SAndrzej Pietrasiewicz size_t align_mask = __alignof__(type) - 1; \
46*bfd08d06SAndy Shevchenko offset = (groupname##__next + align_mask) & \
47*bfd08d06SAndy Shevchenko ~align_mask; \
48b1cd1b65SBrooke Basile if (check_add_overflow(offset, groupname##_##name##__sz,\
49b1cd1b65SBrooke Basile &groupname##__next)) { \
50b1cd1b65SBrooke Basile groupname##__next = SIZE_MAX; \
51b1cd1b65SBrooke Basile offset = 0; \
52b1cd1b65SBrooke Basile } \
53b1cd1b65SBrooke Basile } \
5474d48466SAndrzej Pietrasiewicz offset; \
5574d48466SAndrzej Pietrasiewicz })
5674d48466SAndrzej Pietrasiewicz
5774d48466SAndrzej Pietrasiewicz #define vla_ptr(ptr, groupname, name) \
5874d48466SAndrzej Pietrasiewicz ((void *) ((char *)ptr + groupname##_##name##__offset))
5974d48466SAndrzej Pietrasiewicz
601efd54eaSAndrzej Pietrasiewicz struct usb_ep;
611efd54eaSAndrzej Pietrasiewicz struct usb_request;
621efd54eaSAndrzej Pietrasiewicz
63e0466156SFelipe F. Tonello /**
64e0466156SFelipe F. Tonello * alloc_ep_req - returns a usb_request allocated by the gadget driver and
65e0466156SFelipe F. Tonello * allocates the request's buffer.
66e0466156SFelipe F. Tonello *
67e0466156SFelipe F. Tonello * @ep: the endpoint to allocate a usb_request
68e0466156SFelipe F. Tonello * @len: usb_requests's buffer suggested size
69e0466156SFelipe F. Tonello *
70e0466156SFelipe F. Tonello * In case @ep direction is OUT, the @len will be aligned to ep's
71e0466156SFelipe F. Tonello * wMaxPacketSize. In order to avoid memory leaks or drops, *always* use
72e0466156SFelipe F. Tonello * usb_requests's length (req->length) to refer to the allocated buffer size.
73e0466156SFelipe F. Tonello * Requests allocated via alloc_ep_req() *must* be freed by free_ep_req().
74e0466156SFelipe F. Tonello */
75aadbe812SFelipe F. Tonello struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len);
76e0466156SFelipe F. Tonello
77e0466156SFelipe F. Tonello /* Frees a usb_request previously allocated by alloc_ep_req() */
free_ep_req(struct usb_ep * ep,struct usb_request * req)78079fe5a6SFelipe F. Tonello static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req)
79079fe5a6SFelipe F. Tonello {
807fafcfdfSYavuz, Tuba WARN_ON(req->buf == NULL);
81079fe5a6SFelipe F. Tonello kfree(req->buf);
827fafcfdfSYavuz, Tuba req->buf = NULL;
83079fe5a6SFelipe F. Tonello usb_ep_free_request(ep, req);
84079fe5a6SFelipe F. Tonello }
851efd54eaSAndrzej Pietrasiewicz
861efd54eaSAndrzej Pietrasiewicz #endif /* __U_F_H__ */
87