1 /*
2 * Copyright (c) 2022, sakumisu
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include "usbh_core.h"
7 #include "usbh_hid.h"
8
9 #undef USB_DBG_TAG
10 #define USB_DBG_TAG "usbh_hid"
11 #include "usb_log.h"
12
13 #define DEV_FORMAT "/dev/input%d"
14
15 /* general descriptor field offsets */
16 #define DESC_bLength 0 /** Length offset */
17 #define DESC_bDescriptorType 1 /** Descriptor type offset */
18
19 /* interface descriptor field offsets */
20 #define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
21 #define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
22
23 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hid_buf[CONFIG_USBHOST_MAX_HID_CLASS][USB_ALIGN_UP(64, CONFIG_USB_ALIGN_SIZE)];
24
25 static struct usbh_hid g_hid_class[CONFIG_USBHOST_MAX_HID_CLASS];
26 static uint32_t g_devinuse = 0;
27
usbh_hid_class_alloc(void)28 static struct usbh_hid *usbh_hid_class_alloc(void)
29 {
30 uint8_t devno;
31
32 for (devno = 0; devno < CONFIG_USBHOST_MAX_HID_CLASS; devno++) {
33 if ((g_devinuse & (1U << devno)) == 0) {
34 g_devinuse |= (1U << devno);
35 memset(&g_hid_class[devno], 0, sizeof(struct usbh_hid));
36 g_hid_class[devno].minor = devno;
37 return &g_hid_class[devno];
38 }
39 }
40 return NULL;
41 }
42
usbh_hid_class_free(struct usbh_hid * hid_class)43 static void usbh_hid_class_free(struct usbh_hid *hid_class)
44 {
45 uint8_t devno = hid_class->minor;
46
47 if (devno < 32) {
48 g_devinuse &= ~(1U << devno);
49 }
50 memset(hid_class, 0, sizeof(struct usbh_hid));
51 }
52
usbh_hid_get_report_descriptor(struct usbh_hid * hid_class,uint8_t * buffer,uint32_t buflen)53 int usbh_hid_get_report_descriptor(struct usbh_hid *hid_class, uint8_t *buffer, uint32_t buflen)
54 {
55 struct usb_setup_packet *setup;
56
57 if (!hid_class || !hid_class->hport) {
58 return -USB_ERR_INVAL;
59 }
60 setup = hid_class->hport->setup;
61
62 setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
63 setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
64 setup->wValue = HID_DESCRIPTOR_TYPE_HID_REPORT << 8;
65 setup->wIndex = hid_class->intf;
66 setup->wLength = buflen;
67
68 return usbh_control_transfer(hid_class->hport, setup, buffer);
69 }
70
usbh_hid_set_idle(struct usbh_hid * hid_class,uint8_t report_id,uint8_t duration)71 int usbh_hid_set_idle(struct usbh_hid *hid_class, uint8_t report_id, uint8_t duration)
72 {
73 struct usb_setup_packet *setup;
74
75 if (!hid_class || !hid_class->hport) {
76 return -USB_ERR_INVAL;
77 }
78 setup = hid_class->hport->setup;
79
80 setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
81 setup->bRequest = HID_REQUEST_SET_IDLE;
82 setup->wValue = (duration << 8) | report_id;
83 setup->wIndex = hid_class->intf;
84 setup->wLength = 0;
85
86 return usbh_control_transfer(hid_class->hport, setup, NULL);
87 }
88
usbh_hid_get_idle(struct usbh_hid * hid_class,uint8_t * buffer)89 int usbh_hid_get_idle(struct usbh_hid *hid_class, uint8_t *buffer)
90 {
91 struct usb_setup_packet *setup;
92 int ret;
93
94 if (!hid_class || !hid_class->hport) {
95 return -USB_ERR_INVAL;
96 }
97 setup = hid_class->hport->setup;
98
99 setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
100 setup->bRequest = HID_REQUEST_GET_IDLE;
101 setup->wValue = 0;
102 setup->wIndex = hid_class->intf;
103 setup->wLength = 1;
104
105 ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf[hid_class->minor]);
106 if (ret < 8) {
107 return ret;
108 }
109 memcpy(buffer, g_hid_buf[hid_class->minor], MIN(ret - 8, 1));
110 return ret;
111 }
112
usbh_hid_set_protocol(struct usbh_hid * hid_class,uint8_t protocol)113 int usbh_hid_set_protocol(struct usbh_hid *hid_class, uint8_t protocol)
114 {
115 struct usb_setup_packet *setup;
116
117 if (!hid_class || !hid_class->hport) {
118 return -USB_ERR_INVAL;
119 }
120 setup = hid_class->hport->setup;
121
122 setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
123 setup->bRequest = HID_REQUEST_SET_PROTOCOL;
124 setup->wValue = protocol;
125 setup->wIndex = 0;
126 setup->wLength = 0;
127
128 return usbh_control_transfer(hid_class->hport, setup, NULL);
129 }
130
usbh_hid_get_protocol(struct usbh_hid * hid_class,uint8_t * protocol)131 int usbh_hid_get_protocol(struct usbh_hid *hid_class, uint8_t *protocol)
132 {
133 struct usb_setup_packet *setup;
134 int ret;
135
136 if (!hid_class || !hid_class->hport) {
137 return -USB_ERR_INVAL;
138 }
139 setup = hid_class->hport->setup;
140
141 setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
142 setup->bRequest = HID_REQUEST_GET_PROTOCOL;
143 setup->wValue = 0;
144 setup->wIndex = hid_class->intf;
145 setup->wLength = 1;
146
147 ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf[hid_class->minor]);
148 if (ret < 8) {
149 return ret;
150 }
151 memcpy(protocol, g_hid_buf[hid_class->minor], MIN(ret - 8, 1));
152 return ret;
153 }
154
usbh_hid_set_report(struct usbh_hid * hid_class,uint8_t report_type,uint8_t report_id,uint8_t * buffer,uint32_t buflen)155 int usbh_hid_set_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t report_id, uint8_t *buffer, uint32_t buflen)
156 {
157 struct usb_setup_packet *setup;
158
159 if (!hid_class || !hid_class->hport) {
160 return -USB_ERR_INVAL;
161 }
162 setup = hid_class->hport->setup;
163
164 setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
165 setup->bRequest = HID_REQUEST_SET_REPORT;
166 setup->wValue = (uint16_t)(((uint32_t)report_type << 8U) | (uint32_t)report_id);
167 setup->wIndex = 0;
168 setup->wLength = buflen;
169
170 return usbh_control_transfer(hid_class->hport, setup, buffer);
171 }
172
usbh_hid_get_report(struct usbh_hid * hid_class,uint8_t report_type,uint8_t report_id,uint8_t * buffer,uint32_t buflen)173 int usbh_hid_get_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t report_id, uint8_t *buffer, uint32_t buflen)
174 {
175 struct usb_setup_packet *setup;
176 int ret;
177
178 if (!hid_class || !hid_class->hport) {
179 return -USB_ERR_INVAL;
180 }
181 setup = hid_class->hport->setup;
182
183 setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
184 setup->bRequest = HID_REQUEST_GET_REPORT;
185 setup->wValue = (uint16_t)(((uint32_t)report_type << 8U) | (uint32_t)report_id);
186 setup->wIndex = 0;
187 setup->wLength = buflen;
188
189 ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf[hid_class->minor]);
190 if (ret < 8) {
191 return ret;
192 }
193 memcpy(buffer, g_hid_buf[hid_class->minor], MIN(ret - 8, buflen));
194 return ret;
195 }
196
usbh_hid_connect(struct usbh_hubport * hport,uint8_t intf)197 int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
198 {
199 struct usb_endpoint_descriptor *ep_desc;
200 int ret;
201 uint8_t cur_iface = 0xff;
202 uint8_t *p;
203 bool found = false;
204
205 struct usbh_hid *hid_class = usbh_hid_class_alloc();
206 if (hid_class == NULL) {
207 USB_LOG_ERR("Fail to alloc hid_class\r\n");
208 return -USB_ERR_NOMEM;
209 }
210
211 hid_class->hport = hport;
212 hid_class->intf = intf;
213
214 hport->config.intf[intf].priv = hid_class;
215
216 p = hport->raw_config_desc;
217 while (p[DESC_bLength]) {
218 switch (p[DESC_bDescriptorType]) {
219 case USB_DESCRIPTOR_TYPE_INTERFACE:
220 cur_iface = p[INTF_DESC_bInterfaceNumber];
221 if (cur_iface == intf) {
222 hid_class->protocol = p[7];
223 struct usb_hid_descriptor *desc = (struct usb_hid_descriptor *)(p + 9);
224
225 if (desc->bDescriptorType != HID_DESCRIPTOR_TYPE_HID) {
226 USB_LOG_ERR("HID descriptor not found\r\n");
227 return -USB_ERR_INVAL;
228 }
229
230 if (desc->subdesc[0].bDescriptorType != HID_DESCRIPTOR_TYPE_HID_REPORT) {
231 USB_LOG_ERR("HID report descriptor not found\r\n");
232 return -USB_ERR_INVAL;
233 }
234
235 hid_class->report_size = desc->subdesc[0].wDescriptorLength;
236 found = true;
237 goto found;
238 }
239 break;
240 default:
241 break;
242 }
243 /* skip to next descriptor */
244 p += p[DESC_bLength];
245 }
246
247 if (found == false) {
248 USB_LOG_ERR("HID interface not found\r\n");
249 return -USB_ERR_INVAL;
250 }
251 found:
252 // /* 0x0 = boot protocol, 0x1 = report protocol */
253 // ret = usbh_hid_set_protocol(hid_class, 0x1);
254 // if (ret < 0) {
255 // return ret;
256 // }
257
258 ret = usbh_hid_set_idle(hid_class, 0, 0);
259 if (ret < 0) {
260 USB_LOG_WRN("Do not support set idle\r\n");
261 }
262
263 /* We read report desc but do nothing (because of too much memory usage for parsing report desc, parsed by users) */
264 ret = usbh_hid_get_report_descriptor(hid_class, g_hid_buf[hid_class->minor], MIN(sizeof(g_hid_buf[hid_class->minor]), hid_class->report_size));
265 if (ret < 0) {
266 return ret;
267 }
268
269 for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
270 ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
271 if (ep_desc->bEndpointAddress & 0x80) {
272 USBH_EP_INIT(hid_class->intin, ep_desc);
273 } else {
274 USBH_EP_INIT(hid_class->intout, ep_desc);
275 }
276 }
277
278 snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, hid_class->minor);
279
280 USB_LOG_INFO("Register HID Class:%s\r\n", hport->config.intf[intf].devname);
281
282 usbh_hid_run(hid_class);
283 return ret;
284 }
285
usbh_hid_disconnect(struct usbh_hubport * hport,uint8_t intf)286 int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
287 {
288 int ret = 0;
289
290 struct usbh_hid *hid_class = (struct usbh_hid *)hport->config.intf[intf].priv;
291
292 if (hid_class) {
293 if (hid_class->intin) {
294 usbh_kill_urb(&hid_class->intin_urb);
295 }
296
297 if (hid_class->intout) {
298 usbh_kill_urb(&hid_class->intout_urb);
299 }
300
301 if (hport->config.intf[intf].devname[0] != '\0') {
302 usb_osal_thread_schedule_other();
303 USB_LOG_INFO("Unregister HID Class:%s\r\n", hport->config.intf[intf].devname);
304 usbh_hid_stop(hid_class);
305 }
306
307 usbh_hid_class_free(hid_class);
308 }
309
310 return ret;
311 }
312
usbh_hid_run(struct usbh_hid * hid_class)313 __WEAK void usbh_hid_run(struct usbh_hid *hid_class)
314 {
315 (void)hid_class;
316 }
317
usbh_hid_stop(struct usbh_hid * hid_class)318 __WEAK void usbh_hid_stop(struct usbh_hid *hid_class)
319 {
320 (void)hid_class;
321 }
322
323 const struct usbh_class_driver hid_class_driver = {
324 .driver_name = "hid",
325 .connect = usbh_hid_connect,
326 .disconnect = usbh_hid_disconnect
327 };
328
329 CLASS_INFO_DEFINE const struct usbh_class_info hid_custom_class_info = {
330 .match_flags = USB_CLASS_MATCH_INTF_CLASS,
331 .bInterfaceClass = USB_DEVICE_CLASS_HID,
332 .bInterfaceSubClass = 0x00,
333 .bInterfaceProtocol = 0x00,
334 .id_table = NULL,
335 .class_driver = &hid_class_driver
336 };
337