1 /*
2  * Copyright (c) 2024, sakumisu
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "usbd_core.h"
7 #include "usbd_hid.h"
8 
9 #define USBD_VID           0xffff
10 #define USBD_PID           0xffff
11 #define USBD_MAX_POWER     100
12 #define USBD_LANGID_STRING 1033
13 
14 #define HID_INT_EP          0x81
15 #define HID_INT_EP_SIZE     8
16 #define HID_INT_EP_INTERVAL 10
17 
18 #define USB_HID_CONFIG_DESC_SIZ       34
19 #define HID_KEYBOARD_REPORT_DESC_SIZE 63
20 
21 #ifdef CONFIG_USBDEV_ADVANCE_DESC
22 static const uint8_t device_descriptor[] = {
23     USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01)
24 };
25 
26 static const uint8_t config_descriptor[] = {
27     USB_CONFIG_DESCRIPTOR_INIT(USB_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
28 
29     /************** Descriptor of Joystick Mouse interface ****************/
30     /* 09 */
31     0x09,                          /* bLength: Interface Descriptor size */
32     USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
33     0x00,                          /* bInterfaceNumber: Number of Interface */
34     0x00,                          /* bAlternateSetting: Alternate setting */
35     0x01,                          /* bNumEndpoints */
36     0x03,                          /* bInterfaceClass: HID */
37     0x01,                          /* bInterfaceSubClass : 1=BOOT, 0=no boot */
38     0x01,                          /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
39     0,                             /* iInterface: Index of string descriptor */
40     /******************** Descriptor of Joystick Mouse HID ********************/
41     /* 18 */
42     0x09,                    /* bLength: HID Descriptor size */
43     HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */
44     0x11,                    /* bcdHID: HID Class Spec release number */
45     0x01,
46     0x00,                          /* bCountryCode: Hardware target country */
47     0x01,                          /* bNumDescriptors: Number of HID class descriptors to follow */
48     0x22,                          /* bDescriptorType */
49     HID_KEYBOARD_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
50     0x00,
51     /******************** Descriptor of Mouse endpoint ********************/
52     /* 27 */
53     0x07,                         /* bLength: Endpoint Descriptor size */
54     USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
55     HID_INT_EP,                   /* bEndpointAddress: Endpoint Address (IN) */
56     0x03,                         /* bmAttributes: Interrupt endpoint */
57     HID_INT_EP_SIZE,              /* wMaxPacketSize: 4 Byte max */
58     0x00,
59     HID_INT_EP_INTERVAL, /* bInterval: Polling Interval */
60     /* 34 */
61 };
62 
63 static const uint8_t device_quality_descriptor[] = {
64     ///////////////////////////////////////
65     /// device qualifier descriptor
66     ///////////////////////////////////////
67     0x0a,
68     USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
69     0x00,
70     0x02,
71     0x00,
72     0x00,
73     0x00,
74     0x40,
75     0x00,
76     0x00,
77 };
78 
79 static const char *string_descriptors[] = {
80     (const char[]){ 0x09, 0x04 }, /* Langid */
81     "CherryUSB",                  /* Manufacturer */
82     "CherryUSB HID DEMO",         /* Product */
83     "2022123456",                 /* Serial Number */
84 };
85 
device_descriptor_callback(uint8_t speed)86 static const uint8_t *device_descriptor_callback(uint8_t speed)
87 {
88     return device_descriptor;
89 }
90 
config_descriptor_callback(uint8_t speed)91 static const uint8_t *config_descriptor_callback(uint8_t speed)
92 {
93     return config_descriptor;
94 }
95 
device_quality_descriptor_callback(uint8_t speed)96 static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
97 {
98     return device_quality_descriptor;
99 }
100 
string_descriptor_callback(uint8_t speed,uint8_t index)101 static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
102 {
103     if (index > 3) {
104         return NULL;
105     }
106     return string_descriptors[index];
107 }
108 
109 const struct usb_descriptor hid_descriptor = {
110     .device_descriptor_callback = device_descriptor_callback,
111     .config_descriptor_callback = config_descriptor_callback,
112     .device_quality_descriptor_callback = device_quality_descriptor_callback,
113     .string_descriptor_callback = string_descriptor_callback
114 };
115 #else
116 static const uint8_t hid_descriptor[] = {
117     USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01),
118     USB_CONFIG_DESCRIPTOR_INIT(USB_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
119 
120     /************** Descriptor of Joystick Mouse interface ****************/
121     /* 09 */
122     0x09,                          /* bLength: Interface Descriptor size */
123     USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
124     0x00,                          /* bInterfaceNumber: Number of Interface */
125     0x00,                          /* bAlternateSetting: Alternate setting */
126     0x01,                          /* bNumEndpoints */
127     0x03,                          /* bInterfaceClass: HID */
128     0x01,                          /* bInterfaceSubClass : 1=BOOT, 0=no boot */
129     0x01,                          /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
130     0,                             /* iInterface: Index of string descriptor */
131     /******************** Descriptor of Joystick Mouse HID ********************/
132     /* 18 */
133     0x09,                    /* bLength: HID Descriptor size */
134     HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */
135     0x11,                    /* bcdHID: HID Class Spec release number */
136     0x01,
137     0x00,                          /* bCountryCode: Hardware target country */
138     0x01,                          /* bNumDescriptors: Number of HID class descriptors to follow */
139     0x22,                          /* bDescriptorType */
140     HID_KEYBOARD_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
141     0x00,
142     /******************** Descriptor of Mouse endpoint ********************/
143     /* 27 */
144     0x07,                         /* bLength: Endpoint Descriptor size */
145     USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
146     HID_INT_EP,                   /* bEndpointAddress: Endpoint Address (IN) */
147     0x03,                         /* bmAttributes: Interrupt endpoint */
148     HID_INT_EP_SIZE,              /* wMaxPacketSize: 4 Byte max */
149     0x00,
150     HID_INT_EP_INTERVAL, /* bInterval: Polling Interval */
151     /* 34 */
152     ///////////////////////////////////////
153     /// string0 descriptor
154     ///////////////////////////////////////
155     USB_LANGID_INIT(USBD_LANGID_STRING),
156     ///////////////////////////////////////
157     /// string1 descriptor
158     ///////////////////////////////////////
159     0x14,                       /* bLength */
160     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
161     'C', 0x00,                  /* wcChar0 */
162     'h', 0x00,                  /* wcChar1 */
163     'e', 0x00,                  /* wcChar2 */
164     'r', 0x00,                  /* wcChar3 */
165     'r', 0x00,                  /* wcChar4 */
166     'y', 0x00,                  /* wcChar5 */
167     'U', 0x00,                  /* wcChar6 */
168     'S', 0x00,                  /* wcChar7 */
169     'B', 0x00,                  /* wcChar8 */
170     ///////////////////////////////////////
171     /// string2 descriptor
172     ///////////////////////////////////////
173     0x26,                       /* bLength */
174     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
175     'C', 0x00,                  /* wcChar0 */
176     'h', 0x00,                  /* wcChar1 */
177     'e', 0x00,                  /* wcChar2 */
178     'r', 0x00,                  /* wcChar3 */
179     'r', 0x00,                  /* wcChar4 */
180     'y', 0x00,                  /* wcChar5 */
181     'U', 0x00,                  /* wcChar6 */
182     'S', 0x00,                  /* wcChar7 */
183     'B', 0x00,                  /* wcChar8 */
184     ' ', 0x00,                  /* wcChar9 */
185     'H', 0x00,                  /* wcChar10 */
186     'I', 0x00,                  /* wcChar11 */
187     'D', 0x00,                  /* wcChar12 */
188     ' ', 0x00,                  /* wcChar13 */
189     'D', 0x00,                  /* wcChar14 */
190     'E', 0x00,                  /* wcChar15 */
191     'M', 0x00,                  /* wcChar16 */
192     'O', 0x00,                  /* wcChar17 */
193     ///////////////////////////////////////
194     /// string3 descriptor
195     ///////////////////////////////////////
196     0x16,                       /* bLength */
197     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
198     '2', 0x00,                  /* wcChar0 */
199     '0', 0x00,                  /* wcChar1 */
200     '2', 0x00,                  /* wcChar2 */
201     '2', 0x00,                  /* wcChar3 */
202     '1', 0x00,                  /* wcChar4 */
203     '2', 0x00,                  /* wcChar5 */
204     '3', 0x00,                  /* wcChar6 */
205     '4', 0x00,                  /* wcChar7 */
206     '5', 0x00,                  /* wcChar8 */
207     '6', 0x00,                  /* wcChar9 */
208 #ifdef CONFIG_USB_HS
209     ///////////////////////////////////////
210     /// device qualifier descriptor
211     ///////////////////////////////////////
212     0x0a,
213     USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
214     0x00,
215     0x02,
216     0x00,
217     0x00,
218     0x00,
219     0x40,
220     0x00,
221     0x00,
222 #endif
223     0x00
224 };
225 #endif
226 
227 /* USB HID device Configuration Descriptor */
228 static uint8_t hid_desc[9] __ALIGN_END = {
229     /* 18 */
230     0x09,                    /* bLength: HID Descriptor size */
231     HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */
232     0x11,                    /* bcdHID: HID Class Spec release number */
233     0x01,
234     0x00,                          /* bCountryCode: Hardware target country */
235     0x01,                          /* bNumDescriptors: Number of HID class descriptors to follow */
236     0x22,                          /* bDescriptorType */
237     HID_KEYBOARD_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
238     0x00,
239 };
240 
241 static const uint8_t hid_keyboard_report_desc[HID_KEYBOARD_REPORT_DESC_SIZE] = {
242     0x05, 0x01, // USAGE_PAGE (Generic Desktop)
243     0x09, 0x06, // USAGE (Keyboard)
244     0xa1, 0x01, // COLLECTION (Application)
245     0x05, 0x07, // USAGE_PAGE (Keyboard)
246     0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
247     0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
248     0x15, 0x00, // LOGICAL_MINIMUM (0)
249     0x25, 0x01, // LOGICAL_MAXIMUM (1)
250     0x75, 0x01, // REPORT_SIZE (1)
251     0x95, 0x08, // REPORT_COUNT (8)
252     0x81, 0x02, // INPUT (Data,Var,Abs)
253     0x95, 0x01, // REPORT_COUNT (1)
254     0x75, 0x08, // REPORT_SIZE (8)
255     0x81, 0x03, // INPUT (Cnst,Var,Abs)
256     0x95, 0x05, // REPORT_COUNT (5)
257     0x75, 0x01, // REPORT_SIZE (1)
258     0x05, 0x08, // USAGE_PAGE (LEDs)
259     0x19, 0x01, // USAGE_MINIMUM (Num Lock)
260     0x29, 0x05, // USAGE_MAXIMUM (Kana)
261     0x91, 0x02, // OUTPUT (Data,Var,Abs)
262     0x95, 0x01, // REPORT_COUNT (1)
263     0x75, 0x03, // REPORT_SIZE (3)
264     0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
265     0x95, 0x06, // REPORT_COUNT (6)
266     0x75, 0x08, // REPORT_SIZE (8)
267     0x15, 0x00, // LOGICAL_MINIMUM (0)
268     0x25, 0xFF, // LOGICAL_MAXIMUM (255)
269     0x05, 0x07, // USAGE_PAGE (Keyboard)
270     0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
271     0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
272     0x81, 0x00, // INPUT (Data,Ary,Abs)
273     0xc0        // END_COLLECTION
274 };
275 
276 #define HID_STATE_IDLE 0
277 #define HID_STATE_BUSY 1
278 
279 /*!< hid state ! Data can be sent only when state is idle  */
280 static volatile uint8_t hid_state = HID_STATE_IDLE;
281 
usbd_event_handler(uint8_t busid,uint8_t event)282 static void usbd_event_handler(uint8_t busid, uint8_t event)
283 {
284     switch (event) {
285         case USBD_EVENT_RESET:
286             break;
287         case USBD_EVENT_CONNECTED:
288             break;
289         case USBD_EVENT_DISCONNECTED:
290             break;
291         case USBD_EVENT_RESUME:
292             break;
293         case USBD_EVENT_SUSPEND:
294             break;
295         case USBD_EVENT_CONFIGURED:
296             hid_state = HID_STATE_IDLE;
297             break;
298         case USBD_EVENT_SET_REMOTE_WAKEUP:
299             break;
300         case USBD_EVENT_CLR_REMOTE_WAKEUP:
301             break;
302 
303         default:
304             break;
305     }
306 }
307 
usbd_hid_int_callback(uint8_t busid,uint8_t ep,uint32_t nbytes)308 void usbd_hid_int_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
309 {
310     hid_state = HID_STATE_IDLE;
311 }
312 
313 static struct usbd_endpoint hid_in_ep = {
314     .ep_cb = usbd_hid_int_callback,
315     .ep_addr = HID_INT_EP
316 };
317 
318 struct usbd_interface intf0;
319 
hid_keyboard_init(uint8_t busid,uintptr_t reg_base)320 void hid_keyboard_init(uint8_t busid, uintptr_t reg_base)
321 {
322 #ifdef CONFIG_USBDEV_ADVANCE_DESC
323     usbd_desc_register(busid, &hid_descriptor);
324 #else
325     usbd_desc_register(busid, hid_descriptor);
326 #endif
327     usbd_add_interface(busid, usbd_hid_init_intf(busid, &intf0, hid_keyboard_report_desc, HID_KEYBOARD_REPORT_DESC_SIZE));
328     usbd_add_endpoint(busid, &hid_in_ep);
329 
330     usbd_initialize(busid, reg_base, usbd_event_handler);
331 }
332 
333 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[64];
334 
hid_keyboard_test(uint8_t busid)335 void hid_keyboard_test(uint8_t busid)
336 {
337     const uint8_t sendbuffer[8] = { 0x00, 0x00, HID_KBD_USAGE_A, 0x00, 0x00, 0x00, 0x00, 0x00 };
338 
339     if(usb_device_is_configured(busid) == false) {
340         return;
341     }
342 
343     memcpy(write_buffer, sendbuffer, 8);
344     hid_state = HID_STATE_BUSY;
345     usbd_ep_start_write(busid, HID_INT_EP, write_buffer, 8);
346     while (hid_state == HID_STATE_BUSY) {
347     }
348 }
349