1 /*
2 * Copyright (c) 2022 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "usbd_core.h"
9 #include "usbd_hid.h"
10
11
12 /*!< hidraw in endpoint */
13 #define HIDRAW_IN_EP 0x81
14 #ifdef CONFIG_USB_HS
15 #define HIDRAW_IN_EP_SIZE 1024
16 #define HIDRAW_IN_INTERVAL 4
17 #else
18 #define HIDRAW_IN_EP_SIZE 64
19 #define HIDRAW_IN_INTERVAL 10
20 #endif
21 /*!< hidraw out endpoint */
22 #define HIDRAW_OUT_EP 0x02
23 #ifdef CONFIG_USB_HS
24 #define HIDRAW_OUT_EP_SIZE 1024
25 #define HIDRAW_OUT_EP_INTERVAL 4
26 #else
27 #define HIDRAW_OUT_EP_SIZE 64
28 #define HIDRAW_OUT_EP_INTERVAL 10
29 #endif
30
31 #define USBD_VID 0xffff
32 #define USBD_PID 0xffff
33 #define USBD_MAX_POWER 100
34 #define USBD_LANGID_STRING 1033
35
36 /*!< config descriptor size */
37 #define USB_HID_CONFIG_DESC_SIZ (9 + 9 + 9 + 7 + 7)
38
39 /*!< custom hid report descriptor size */
40 #define HID_CUSTOM_REPORT_DESC_SIZE 38
41
42 #ifdef CONFIG_USBDEV_ADVANCE_DESC
43 static const uint8_t device_descriptor[] = {
44 USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01)
45 };
46
47 static const uint8_t config_descriptor[] = {
48 USB_CONFIG_DESCRIPTOR_INIT(USB_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
49 /************** Descriptor of Custom interface *****************/
50 0x09, /* bLength: Interface Descriptor size */
51 USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
52 0x00, /* bInterfaceNumber: Number of Interface */
53 0x00, /* bAlternateSetting: Alternate setting */
54 0x02, /* bNumEndpoints */
55 0x03, /* bInterfaceClass: HID */
56 0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
57 0x00, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
58 0, /* iInterface: Index of string descriptor */
59 /******************** Descriptor of Custom HID ********************/
60 0x09, /* bLength: HID Descriptor size */
61 HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */
62 0x11, /* bcdHID: HID Class Spec release number */
63 0x01,
64 0x00, /* bCountryCode: Hardware target country */
65 0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
66 0x22, /* bDescriptorType */
67 HID_CUSTOM_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
68 0x00,
69 /******************** Descriptor of Custom in endpoint ********************/
70 0x07, /* bLength: Endpoint Descriptor size */
71 USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
72 HIDRAW_IN_EP, /* bEndpointAddress: Endpoint Address (IN) */
73 0x03, /* bmAttributes: Interrupt endpoint */
74 WBVAL(HIDRAW_IN_EP_SIZE), /* wMaxPacketSize: 4 Byte max */
75 HIDRAW_IN_INTERVAL, /* bInterval: Polling Interval */
76 /******************** Descriptor of Custom out endpoint ********************/
77 0x07, /* bLength: Endpoint Descriptor size */
78 USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
79 HIDRAW_OUT_EP, /* bEndpointAddress: Endpoint Address (IN) */
80 0x03, /* bmAttributes: Interrupt endpoint */
81 WBVAL(HIDRAW_OUT_EP_SIZE), /* wMaxPacketSize: 4 Byte max */
82 HIDRAW_OUT_EP_INTERVAL, /* bInterval: Polling Interval */
83 /* 73 */
84 };
85
86 static const uint8_t device_quality_descriptor[] = {
87 ///////////////////////////////////////
88 /// device qualifier descriptor
89 ///////////////////////////////////////
90 0x0a,
91 USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
92 0x00,
93 0x02,
94 0x00,
95 0x00,
96 0x00,
97 0x40,
98 0x00,
99 0x00,
100 };
101
102 static const char *string_descriptors[] = {
103 (const char[]){ 0x09, 0x04 }, /* Langid */
104 "CherryUSB", /* Manufacturer */
105 "CherryUSB HID DEMO", /* Product */
106 "2022123456", /* Serial Number */
107 };
108
device_descriptor_callback(uint8_t speed)109 static const uint8_t *device_descriptor_callback(uint8_t speed)
110 {
111 return device_descriptor;
112 }
113
config_descriptor_callback(uint8_t speed)114 static const uint8_t *config_descriptor_callback(uint8_t speed)
115 {
116 return config_descriptor;
117 }
118
device_quality_descriptor_callback(uint8_t speed)119 static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
120 {
121 return device_quality_descriptor;
122 }
123
string_descriptor_callback(uint8_t speed,uint8_t index)124 static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
125 {
126 if (index > 3) {
127 return NULL;
128 }
129 return string_descriptors[index];
130 }
131
132 const struct usb_descriptor hid_descriptor = {
133 .device_descriptor_callback = device_descriptor_callback,
134 .config_descriptor_callback = config_descriptor_callback,
135 .device_quality_descriptor_callback = device_quality_descriptor_callback,
136 .string_descriptor_callback = string_descriptor_callback
137 };
138 #else
139 /*!< global descriptor */
140 static const uint8_t hid_descriptor[] = {
141 USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01),
142 USB_CONFIG_DESCRIPTOR_INIT(USB_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
143 /************** Descriptor of Custom interface *****************/
144 0x09, /* bLength: Interface Descriptor size */
145 USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
146 0x00, /* bInterfaceNumber: Number of Interface */
147 0x00, /* bAlternateSetting: Alternate setting */
148 0x02, /* bNumEndpoints */
149 0x03, /* bInterfaceClass: HID */
150 0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
151 0x00, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
152 0, /* iInterface: Index of string descriptor */
153 /******************** Descriptor of Custom HID ********************/
154 0x09, /* bLength: HID Descriptor size */
155 HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */
156 0x11, /* bcdHID: HID Class Spec release number */
157 0x01,
158 0x00, /* bCountryCode: Hardware target country */
159 0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
160 0x22, /* bDescriptorType */
161 HID_CUSTOM_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
162 0x00,
163 /******************** Descriptor of Custom in endpoint ********************/
164 0x07, /* bLength: Endpoint Descriptor size */
165 USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
166 HIDRAW_IN_EP, /* bEndpointAddress: Endpoint Address (IN) */
167 0x03, /* bmAttributes: Interrupt endpoint */
168 WBVAL(HIDRAW_IN_EP_SIZE), /* wMaxPacketSize: 4 Byte max */
169 HIDRAW_IN_INTERVAL, /* bInterval: Polling Interval */
170 /******************** Descriptor of Custom out endpoint ********************/
171 0x07, /* bLength: Endpoint Descriptor size */
172 USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
173 HIDRAW_OUT_EP, /* bEndpointAddress: Endpoint Address (IN) */
174 0x03, /* bmAttributes: Interrupt endpoint */
175 WBVAL(HIDRAW_OUT_EP_SIZE), /* wMaxPacketSize: 4 Byte max */
176 HIDRAW_OUT_EP_INTERVAL, /* bInterval: Polling Interval */
177 /* 73 */
178 /*
179 * string0 descriptor
180 */
181 USB_LANGID_INIT(USBD_LANGID_STRING),
182 /*
183 * string1 descriptor
184 */
185 0x14, /* bLength */
186 USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
187 'C', 0x00, /* wcChar0 */
188 'h', 0x00, /* wcChar1 */
189 'e', 0x00, /* wcChar2 */
190 'r', 0x00, /* wcChar3 */
191 'r', 0x00, /* wcChar4 */
192 'y', 0x00, /* wcChar5 */
193 'U', 0x00, /* wcChar6 */
194 'S', 0x00, /* wcChar7 */
195 'B', 0x00, /* wcChar8 */
196 /*
197 * string2 descriptor
198 */
199 0x26, /* bLength */
200 USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
201 'C', 0x00, /* wcChar0 */
202 'h', 0x00, /* wcChar1 */
203 'e', 0x00, /* wcChar2 */
204 'r', 0x00, /* wcChar3 */
205 'r', 0x00, /* wcChar4 */
206 'y', 0x00, /* wcChar5 */
207 'U', 0x00, /* wcChar6 */
208 'S', 0x00, /* wcChar7 */
209 'B', 0x00, /* wcChar8 */
210 ' ', 0x00, /* wcChar9 */
211 'H', 0x00, /* wcChar10 */
212 'I', 0x00, /* wcChar11 */
213 'D', 0x00, /* wcChar12 */
214 ' ', 0x00, /* wcChar13 */
215 'D', 0x00, /* wcChar14 */
216 'E', 0x00, /* wcChar15 */
217 'M', 0x00, /* wcChar16 */
218 'O', 0x00, /* wcChar17 */
219 /*
220 * string3 descriptor
221 */
222 0x16, /* bLength */
223 USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
224 '2', 0x00, /* wcChar0 */
225 '0', 0x00, /* wcChar1 */
226 '2', 0x00, /* wcChar2 */
227 '2', 0x00, /* wcChar3 */
228 '1', 0x00, /* wcChar4 */
229 '2', 0x00, /* wcChar5 */
230 '3', 0x00, /* wcChar6 */
231 '4', 0x00, /* wcChar7 */
232 '5', 0x00, /* wcChar8 */
233 '6', 0x00, /* wcChar9 */
234 #ifdef CONFIG_USB_HS
235 /*
236 * device qualifier descriptor
237 */
238 0x0a,
239 USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
240 0x00,
241 0x02,
242 0x00,
243 0x00,
244 0x00,
245 0x40,
246 0x00,
247 0x00,
248 #endif
249 0x00
250 };
251 #endif
252
253 /*!< custom hid report descriptor */
254 static const uint8_t hid_custom_report_desc[HID_CUSTOM_REPORT_DESC_SIZE] = {
255 #ifdef CONFIG_USB_HS
256 /* USER CODE BEGIN 0 */
257 0x06, 0x00, 0xff, /* USAGE_PAGE (Vendor Defined Page 1) */
258 0x09, 0x01, /* USAGE (Vendor Usage 1) */
259 0xa1, 0x01, /* COLLECTION (Application) */
260 0x85, 0x02, /* REPORT ID (0x02) */
261 0x09, 0x02, /* USAGE (Vendor Usage 1) */
262 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
263 0x25, 0xff, /*LOGICAL_MAXIMUM (255) */
264 0x75, 0x08, /* REPORT_SIZE (8) */
265 0x96, 0xff, 0x03, /* REPORT_COUNT (63) */
266 0x81, 0x02, /* INPUT (Data,Var,Abs) */
267 /* <___________________________________________________> */
268 0x85, 0x01, /* REPORT ID (0x01) */
269 0x09, 0x03, /* USAGE (Vendor Usage 1) */
270 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
271 0x25, 0xff, /* LOGICAL_MAXIMUM (255) */
272 0x75, 0x08, /* REPORT_SIZE (8) */
273 0x96, 0xff, 0x03, /* REPORT_COUNT (63) */
274 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
275 /* USER CODE END 0 */
276 0xC0 /* END_COLLECTION */
277 #else
278 /* USER CODE BEGIN 0 */
279 0x06, 0x00, 0xff, /* USAGE_PAGE (Vendor Defined Page 1) */
280 0x09, 0x01, /* USAGE (Vendor Usage 1) */
281 0xa1, 0x01, /* COLLECTION (Application) */
282 0x85, 0x02, /* REPORT ID (0x02) */
283 0x09, 0x01, /* USAGE (Vendor Usage 1) */
284 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
285 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */
286 0x95, 0x40 - 1, /* REPORT_COUNT (63) */
287 0x75, 0x08, /* REPORT_SIZE (8) */
288 0x81, 0x02, /* INPUT (Data,Var,Abs) */
289 /* <___________________________________________________> */
290 0x85, 0x01, /* REPORT ID (0x01) */
291 0x09, 0x01, /* USAGE (Vendor Usage 1) */
292 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
293 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */
294 0x95, 0x40 - 1, /* REPORT_COUNT (63) */
295 0x75, 0x08, /* REPORT_SIZE (8) */
296 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
297 /* USER CODE END 0 */
298 0xC0 /* END_COLLECTION */
299 #endif
300 };
301
302 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[HIDRAW_OUT_EP_SIZE];
303 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t send_buffer[HIDRAW_IN_EP_SIZE];
304
305 #define HID_STATE_IDLE 0
306 #define HID_STATE_BUSY 1
307
308 /*!< hid state ! Data can be sent only when state is idle */
309 static volatile uint8_t custom_state;
310
usbd_event_handler(uint8_t busid,uint8_t event)311 static void usbd_event_handler(uint8_t busid, uint8_t event)
312 {
313 switch (event) {
314 case USBD_EVENT_RESET:
315 break;
316 case USBD_EVENT_CONNECTED:
317 break;
318 case USBD_EVENT_DISCONNECTED:
319 break;
320 case USBD_EVENT_RESUME:
321 break;
322 case USBD_EVENT_SUSPEND:
323 break;
324 case USBD_EVENT_CONFIGURED:
325 /* setup first out ep read transfer */
326 usbd_ep_start_read(busid, HIDRAW_OUT_EP, read_buffer, HIDRAW_OUT_EP_SIZE);
327 break;
328 case USBD_EVENT_SET_REMOTE_WAKEUP:
329 break;
330 case USBD_EVENT_CLR_REMOTE_WAKEUP:
331 break;
332
333 default:
334 break;
335 }
336 }
337
usbd_hid_custom_in_callback(uint8_t busid,uint8_t ep,uint32_t nbytes)338 static void usbd_hid_custom_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
339 {
340 (void)busid;
341 (void)ep;
342 USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
343 custom_state = HID_STATE_IDLE;
344 }
345
usbd_hid_custom_out_callback(uint8_t busid,uint8_t ep,uint32_t nbytes)346 static void usbd_hid_custom_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
347 {
348 USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
349 usbd_ep_start_read(busid, ep, read_buffer, HIDRAW_IN_EP_SIZE);
350 read_buffer[0] = 0x02; /* IN: report id */
351 usbd_ep_start_write(busid, HIDRAW_IN_EP, read_buffer, nbytes);
352 }
353
354 static struct usbd_endpoint custom_in_ep = {
355 .ep_cb = usbd_hid_custom_in_callback,
356 .ep_addr = HIDRAW_IN_EP
357 };
358
359 static struct usbd_endpoint custom_out_ep = {
360 .ep_cb = usbd_hid_custom_out_callback,
361 .ep_addr = HIDRAW_OUT_EP
362 };
363
364 /* function ------------------------------------------------------------------*/
365 /**
366 * @brief hid custom init
367 * @pre none
368 * @param[in] none
369 * @retval none
370 */
371 struct usbd_interface intf0;
372
hid_custom_init(uint8_t busid,uintptr_t reg_base)373 void hid_custom_init(uint8_t busid, uintptr_t reg_base)
374 {
375 #ifdef CONFIG_USBDEV_ADVANCE_DESC
376 usbd_desc_register(busid, &hid_descriptor);
377 #else
378 usbd_desc_register(busid, hid_descriptor);
379 #endif
380 usbd_add_interface(busid, usbd_hid_init_intf(busid, &intf0, hid_custom_report_desc, HID_CUSTOM_REPORT_DESC_SIZE));
381 usbd_add_endpoint(busid, &custom_in_ep);
382 usbd_add_endpoint(busid, &custom_out_ep);
383
384 usbd_initialize(busid, reg_base, usbd_event_handler);
385 }
386