1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * The macros in this file are not for public use, but only for HID driver
9  * instantiation.
10  */
11 
12 #include <zephyr/sys/util_macro.h>
13 #include <zephyr/usb/usb_ch9.h>
14 
15 #ifndef ZEPHYR_USB_DEVICE_CLASS_HID_MACROS_H_
16 #define ZEPHYR_USB_DEVICE_CLASS_HID_MACROS_H_
17 
18 /*
19  * This long list of definitions is used in HID_MPS_LESS_65 macro to determine
20  * whether an endpoint MPS is equal to or less than 64 bytes.
21  */
22 #define HID_MPS_LESS_65_0 1
23 #define HID_MPS_LESS_65_1 1
24 #define HID_MPS_LESS_65_2 1
25 #define HID_MPS_LESS_65_3 1
26 #define HID_MPS_LESS_65_4 1
27 #define HID_MPS_LESS_65_5 1
28 #define HID_MPS_LESS_65_6 1
29 #define HID_MPS_LESS_65_7 1
30 #define HID_MPS_LESS_65_8 1
31 #define HID_MPS_LESS_65_9 1
32 #define HID_MPS_LESS_65_10 1
33 #define HID_MPS_LESS_65_11 1
34 #define HID_MPS_LESS_65_12 1
35 #define HID_MPS_LESS_65_13 1
36 #define HID_MPS_LESS_65_14 1
37 #define HID_MPS_LESS_65_15 1
38 #define HID_MPS_LESS_65_16 1
39 #define HID_MPS_LESS_65_17 1
40 #define HID_MPS_LESS_65_18 1
41 #define HID_MPS_LESS_65_19 1
42 #define HID_MPS_LESS_65_20 1
43 #define HID_MPS_LESS_65_21 1
44 #define HID_MPS_LESS_65_22 1
45 #define HID_MPS_LESS_65_23 1
46 #define HID_MPS_LESS_65_24 1
47 #define HID_MPS_LESS_65_25 1
48 #define HID_MPS_LESS_65_26 1
49 #define HID_MPS_LESS_65_27 1
50 #define HID_MPS_LESS_65_28 1
51 #define HID_MPS_LESS_65_29 1
52 #define HID_MPS_LESS_65_30 1
53 #define HID_MPS_LESS_65_31 1
54 #define HID_MPS_LESS_65_32 1
55 #define HID_MPS_LESS_65_33 1
56 #define HID_MPS_LESS_65_34 1
57 #define HID_MPS_LESS_65_35 1
58 #define HID_MPS_LESS_65_36 1
59 #define HID_MPS_LESS_65_37 1
60 #define HID_MPS_LESS_65_38 1
61 #define HID_MPS_LESS_65_39 1
62 #define HID_MPS_LESS_65_40 1
63 #define HID_MPS_LESS_65_41 1
64 #define HID_MPS_LESS_65_42 1
65 #define HID_MPS_LESS_65_43 1
66 #define HID_MPS_LESS_65_44 1
67 #define HID_MPS_LESS_65_45 1
68 #define HID_MPS_LESS_65_46 1
69 #define HID_MPS_LESS_65_47 1
70 #define HID_MPS_LESS_65_48 1
71 #define HID_MPS_LESS_65_49 1
72 #define HID_MPS_LESS_65_50 1
73 #define HID_MPS_LESS_65_51 1
74 #define HID_MPS_LESS_65_52 1
75 #define HID_MPS_LESS_65_53 1
76 #define HID_MPS_LESS_65_54 1
77 #define HID_MPS_LESS_65_55 1
78 #define HID_MPS_LESS_65_56 1
79 #define HID_MPS_LESS_65_57 1
80 #define HID_MPS_LESS_65_58 1
81 #define HID_MPS_LESS_65_59 1
82 #define HID_MPS_LESS_65_60 1
83 #define HID_MPS_LESS_65_61 1
84 #define HID_MPS_LESS_65_62 1
85 #define HID_MPS_LESS_65_63 1
86 #define HID_MPS_LESS_65_64 1
87 
88 #define HID_MPS_LESS_65(x) UTIL_PRIMITIVE_CAT(HID_MPS_LESS_65_, x)
89 
90 /*
91  * If all the endpoint MPS are less than 65 bytes, we do not need to define and
92  * configure an alternate interface.
93  */
94 #define HID_ALL_MPS_LESS_65(n)							\
95 	COND_CODE_1(HID_MPS_LESS_65(DT_INST_PROP_OR(n, out_report_size, 0)),	\
96 		(HID_MPS_LESS_65(DT_INST_PROP(n, in_report_size))), (0))
97 
98 /* Get IN endpoint polling rate based on the desired speed. */
99 #define HID_IN_EP_INTERVAL(n, hs)							\
100 	COND_CODE_1(hs,									\
101 		    (USB_HS_INT_EP_INTERVAL(DT_INST_PROP(n, in_polling_period_us))),	\
102 		    (USB_FS_INT_EP_INTERVAL(DT_INST_PROP(n, in_polling_period_us))))
103 
104 /* Get OUT endpoint polling rate based on the desired speed. */
105 #define HID_OUT_EP_INTERVAL(n, hs)							\
106 	COND_CODE_1(hs,									\
107 		    (USB_HS_INT_EP_INTERVAL(DT_INST_PROP(n, out_polling_period_us))),	\
108 		    (USB_FS_INT_EP_INTERVAL(DT_INST_PROP(n, out_polling_period_us))))
109 
110 /* Get the number of endpoints, which can be either 1 or 2 */
111 #define HID_NUM_ENDPOINTS(n)							\
112 	COND_CODE_1(DT_INST_NODE_HAS_PROP(n, out_report_size), (2), (1))
113 
114 /*
115  * Either the device does not support a boot protocol, or it supports the
116  * keyboard or mouse boot protocol.
117  */
118 #define HID_INTERFACE_PROTOCOL(n) DT_INST_ENUM_IDX_OR(n, protocol_code, 0)
119 
120 /* bInterfaceSubClass must be set to 1 if a boot device protocol is supported */
121 #define HID_INTERFACE_SUBCLASS(n)						\
122 	COND_CODE_0(HID_INTERFACE_PROTOCOL(n), (0), (1))
123 
124 #define HID_INTERFACE_DEFINE(n, alt)						\
125 	{									\
126 		.bLength = sizeof(struct usb_if_descriptor),			\
127 		.bDescriptorType = USB_DESC_INTERFACE,				\
128 		.bInterfaceNumber = 0,						\
129 		.bAlternateSetting = alt,					\
130 		.bNumEndpoints = HID_NUM_ENDPOINTS(n),				\
131 		.bInterfaceClass = USB_BCC_HID,					\
132 		.bInterfaceSubClass = HID_INTERFACE_SUBCLASS(n),		\
133 		.bInterfaceProtocol = HID_INTERFACE_PROTOCOL(n),		\
134 		.iInterface = 0,						\
135 	}
136 
137 #define HID_DESCRIPTOR_DEFINE(n)						\
138 	{									\
139 		.bLength = sizeof(struct hid_descriptor),			\
140 		.bDescriptorType = USB_DESC_HID,				\
141 		.bcdHID = sys_cpu_to_le16(USB_HID_VERSION),			\
142 		.bCountryCode = 0,						\
143 		.bNumDescriptors = HID_SUBORDINATE_DESC_NUM,			\
144 		.sub[0] = {							\
145 			.bDescriptorType = USB_DESC_HID_REPORT,			\
146 			.wDescriptorLength = 0,					\
147 		},								\
148 	}									\
149 
150 /*
151  * OUT endpoint MPS for either default or alternate interface.
152  * MPS for the default interface is always limited to 64 bytes.
153  */
154 #define HID_OUT_EP_MPS(n, alt)							\
155 	COND_CODE_1(alt,							\
156 	(sys_cpu_to_le16(USB_TPL_TO_MPS(DT_INST_PROP(n, out_report_size)))),	\
157 	(sys_cpu_to_le16(MIN(DT_INST_PROP(n, out_report_size), 64U))))
158 
159 /*
160  * IN endpoint MPS for either default or alternate interface.
161  * MPS for the default interface is always limited to 64 bytes.
162  */
163 #define HID_IN_EP_MPS(n, alt)							\
164 	COND_CODE_1(alt,							\
165 	(sys_cpu_to_le16(USB_TPL_TO_MPS(DT_INST_PROP(n, in_report_size)))),	\
166 	(sys_cpu_to_le16(MIN(DT_INST_PROP(n, in_report_size), 64U))))
167 
168 #define HID_OUT_EP_DEFINE(n, hs, alt)						\
169 	{									\
170 		.bLength = sizeof(struct usb_ep_descriptor),			\
171 		.bDescriptorType = USB_DESC_ENDPOINT,				\
172 		.bEndpointAddress = 0x01,					\
173 		.bmAttributes = USB_EP_TYPE_INTERRUPT,				\
174 		.wMaxPacketSize = HID_OUT_EP_MPS(n, alt),			\
175 		.bInterval = HID_OUT_EP_INTERVAL(n, hs),			\
176 	}
177 
178 #define HID_IN_EP_DEFINE(n, hs, alt)						\
179 	{									\
180 		.bLength = sizeof(struct usb_ep_descriptor),			\
181 		.bDescriptorType = USB_DESC_ENDPOINT,				\
182 		.bEndpointAddress = 0x81,					\
183 		.bmAttributes = USB_EP_TYPE_INTERRUPT,				\
184 		.wMaxPacketSize = HID_IN_EP_MPS(n, alt),			\
185 		.bInterval = HID_IN_EP_INTERVAL(n, hs),				\
186 	}
187 
188 /*
189  * Both the optional OUT endpoint and the associated pool are only defined if
190  * there is an out-report-size property.
191  */
192 #define HID_OUT_EP_DEFINE_OR_ZERO(n, hs, alt)					\
193 	COND_CODE_1(DT_INST_NODE_HAS_PROP(n, out_report_size),			\
194 		    (HID_OUT_EP_DEFINE(n, hs, alt)),				\
195 		    ({0}))
196 
197 #define HID_OUT_POOL_DEFINE(n)							\
198 	COND_CODE_1(DT_INST_NODE_HAS_PROP(n, out_report_size),			\
199 		    (UDC_BUF_POOL_DEFINE(hid_buf_pool_out_##n,			\
200 					 CONFIG_USBD_HID_OUT_BUF_COUNT,		\
201 					 DT_INST_PROP(n, out_report_size),	\
202 					 sizeof(struct udc_buf_info), NULL)),	\
203 		    ())
204 
205 #define HID_OUT_POOL_ADDR(n)							\
206 	COND_CODE_1(DT_INST_NODE_HAS_PROP(n, out_report_size),			\
207 		    (&hid_buf_pool_out_##n), (NULL))
208 
209 #define HID_VERIFY_REPORT_SIZES(n)						\
210 	BUILD_ASSERT(USB_TPL_IS_VALID(DT_INST_PROP_OR(n, out_report_size, 0)),	\
211 		"out-report-size must be valid Total Packet Length");		\
212 	BUILD_ASSERT(USB_TPL_IS_VALID(DT_INST_PROP_OR(n, in_report_size, 0)),	\
213 		"in-report-size must be valid Total Packet Length");
214 
215 #endif /* ZEPHYR_USB_DEVICE_CLASS_HID_MACROS_H_ */
216