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