1 /*
2 * Copyright (c) 2024, sakumisu
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include "usbd_core.h"
7 #include "usbd_msc.h"
8 #include "usbd_cdc_acm.h"
9 #include "usbd_hid.h"
10
11 /*!< endpoint address */
12 #define CDC_IN_EP 0x81
13 #define CDC_OUT_EP 0x02
14 #define CDC_INT_EP 0x83
15
16 #define MSC_IN_EP 0x84
17 #define MSC_OUT_EP 0x05
18
19 /*!< endpoint address */
20 #define HID_INT_EP 0x86
21 #define HID_INT_EP_SIZE 4
22 #define HID_INT_EP_INTERVAL 10
23
24 #define USBD_VID 0xFFFF
25 #define USBD_PID 0xFFFF
26 #define USBD_MAX_POWER 100
27 #define USBD_LANGID_STRING 1033
28
29 /*!< report descriptor size */
30 #define HID_MOUSE_REPORT_DESC_SIZE 74
31
32 #define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN + MSC_DESCRIPTOR_LEN + 25)
33
34 #ifdef CONFIG_USB_HS
35 #define CDC_MAX_MPS 512
36 #else
37 #define CDC_MAX_MPS 64
38 #endif
39
40 #ifdef CONFIG_USB_HS
41 #define MSC_MAX_MPS 512
42 #else
43 #define MSC_MAX_MPS 64
44 #endif
45
46 #ifdef CONFIG_USBDEV_ADVANCE_DESC
47 static const uint8_t device_descriptor[] = {
48 USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01)
49 };
50
51 static const uint8_t config_descriptor[] = {
52 USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x04, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
53 CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
54 MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, MSC_MAX_MPS, 0x02),
55 /************** Descriptor of Joystick Mouse interface ****************/
56 /* 09 */
57 0x09, /* bLength: Interface Descriptor size */
58 USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
59 0x03, /* bInterfaceNumber: Number of Interface */
60 0x00, /* bAlternateSetting: Alternate setting */
61 0x01, /* bNumEndpoints */
62 0x03, /* bInterfaceClass: HID */
63 0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
64 0x02, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
65 0, /* iInterface: Index of string descriptor */
66 /******************** Descriptor of Joystick Mouse HID ********************/
67 /* 18 */
68 0x09, /* bLength: HID Descriptor size */
69 HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */
70 0x11, /* bcdHID: HID Class Spec release number */
71 0x01,
72 0x00, /* bCountryCode: Hardware target country */
73 0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
74 0x22, /* bDescriptorType */
75 HID_MOUSE_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
76 0x00,
77 /******************** Descriptor of Mouse endpoint ********************/
78 /* 27 */
79 0x07, /* bLength: Endpoint Descriptor size */
80 USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
81 HID_INT_EP, /* bEndpointAddress: Endpoint Address (IN) */
82 0x03, /* bmAttributes: Interrupt endpoint */
83 HID_INT_EP_SIZE, /* wMaxPacketSize: 4 Byte max */
84 0x00,
85 HID_INT_EP_INTERVAL, /* bInterval: Polling Interval */
86 };
87
88 static const uint8_t device_quality_descriptor[] = {
89 ///////////////////////////////////////
90 /// device qualifier descriptor
91 ///////////////////////////////////////
92 0x0a,
93 USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
94 0x00,
95 0x02,
96 0x00,
97 0x00,
98 0x00,
99 0x40,
100 0x00,
101 0x00,
102 };
103
104 static const char *string_descriptors[] = {
105 (const char[]){ 0x09, 0x04 }, /* Langid */
106 "CherryUSB", /* Manufacturer */
107 "CherryUSB CDC MSC HID DEMO", /* Product */
108 "2022123456", /* Serial Number */
109 };
110
device_descriptor_callback(uint8_t speed)111 static const uint8_t *device_descriptor_callback(uint8_t speed)
112 {
113 return device_descriptor;
114 }
115
config_descriptor_callback(uint8_t speed)116 static const uint8_t *config_descriptor_callback(uint8_t speed)
117 {
118 return config_descriptor;
119 }
120
device_quality_descriptor_callback(uint8_t speed)121 static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
122 {
123 return device_quality_descriptor;
124 }
125
string_descriptor_callback(uint8_t speed,uint8_t index)126 static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
127 {
128 if (index > 3) {
129 return NULL;
130 }
131 return string_descriptors[index];
132 }
133
134 const struct usb_descriptor cdc_acm_hid_msc_descriptor = {
135 .device_descriptor_callback = device_descriptor_callback,
136 .config_descriptor_callback = config_descriptor_callback,
137 .device_quality_descriptor_callback = device_quality_descriptor_callback,
138 .string_descriptor_callback = string_descriptor_callback
139 };
140 #else
141 const uint8_t cdc_acm_hid_msc_descriptor[] = {
142 USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01),
143 USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x04, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
144 CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
145 MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, MSC_MAX_MPS, 0x02),
146 /************** Descriptor of Joystick Mouse interface ****************/
147 /* 09 */
148 0x09, /* bLength: Interface Descriptor size */
149 USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
150 0x03, /* bInterfaceNumber: Number of Interface */
151 0x00, /* bAlternateSetting: Alternate setting */
152 0x01, /* bNumEndpoints */
153 0x03, /* bInterfaceClass: HID */
154 0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
155 0x02, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
156 0, /* iInterface: Index of string descriptor */
157 /******************** Descriptor of Joystick Mouse HID ********************/
158 /* 18 */
159 0x09, /* bLength: HID Descriptor size */
160 HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */
161 0x11, /* bcdHID: HID Class Spec release number */
162 0x01,
163 0x00, /* bCountryCode: Hardware target country */
164 0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
165 0x22, /* bDescriptorType */
166 HID_MOUSE_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
167 0x00,
168 /******************** Descriptor of Mouse endpoint ********************/
169 /* 27 */
170 0x07, /* bLength: Endpoint Descriptor size */
171 USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
172 HID_INT_EP, /* bEndpointAddress: Endpoint Address (IN) */
173 0x03, /* bmAttributes: Interrupt endpoint */
174 HID_INT_EP_SIZE, /* wMaxPacketSize: 4 Byte max */
175 0x00,
176 HID_INT_EP_INTERVAL, /* bInterval: Polling Interval */
177 ///////////////////////////////////////
178 /// string0 descriptor
179 ///////////////////////////////////////
180 USB_LANGID_INIT(USBD_LANGID_STRING),
181 ///////////////////////////////////////
182 /// string1 descriptor
183 ///////////////////////////////////////
184 0x14, /* bLength */
185 USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
186 'C', 0x00, /* wcChar0 */
187 'h', 0x00, /* wcChar1 */
188 'e', 0x00, /* wcChar2 */
189 'r', 0x00, /* wcChar3 */
190 'r', 0x00, /* wcChar4 */
191 'y', 0x00, /* wcChar5 */
192 'U', 0x00, /* wcChar6 */
193 'S', 0x00, /* wcChar7 */
194 'B', 0x00, /* wcChar8 */
195 ///////////////////////////////////////
196 /// string2 descriptor
197 ///////////////////////////////////////
198 0x26, /* bLength */
199 USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
200 'C', 0x00, /* wcChar0 */
201 'h', 0x00, /* wcChar1 */
202 'e', 0x00, /* wcChar2 */
203 'r', 0x00, /* wcChar3 */
204 'r', 0x00, /* wcChar4 */
205 'y', 0x00, /* wcChar5 */
206 'U', 0x00, /* wcChar6 */
207 'S', 0x00, /* wcChar7 */
208 'B', 0x00, /* wcChar8 */
209 ' ', 0x00, /* wcChar9 */
210 'C', 0x00, /* wcChar10 */
211 'M', 0x00, /* wcChar11 */
212 'H', 0x00, /* wcChar12 */
213 ' ', 0x00, /* wcChar13 */
214 'D', 0x00, /* wcChar14 */
215 'E', 0x00, /* wcChar15 */
216 'M', 0x00, /* wcChar16 */
217 'O', 0x00, /* wcChar17 */
218 ///////////////////////////////////////
219 /// string3 descriptor
220 ///////////////////////////////////////
221 0x16, /* bLength */
222 USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
223 '2', 0x00, /* wcChar0 */
224 '0', 0x00, /* wcChar1 */
225 '2', 0x00, /* wcChar2 */
226 '2', 0x00, /* wcChar3 */
227 '1', 0x00, /* wcChar4 */
228 '2', 0x00, /* wcChar5 */
229 '3', 0x00, /* wcChar6 */
230 '4', 0x00, /* wcChar7 */
231 '5', 0x00, /* wcChar8 */
232 '6', 0x00, /* wcChar9 */
233 #ifdef CONFIG_USB_HS
234 ///////////////////////////////////////
235 /// device qualifier descriptor
236 ///////////////////////////////////////
237 0x0a,
238 USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
239 0x00,
240 0x02,
241 0x00,
242 0x00,
243 0x00,
244 0x40,
245 0x00,
246 0x00,
247 #endif
248 0x00
249 };
250 #endif
251
252 /*!< hid mouse report descriptor */
253 static const uint8_t hid_mouse_report_desc[HID_MOUSE_REPORT_DESC_SIZE] = {
254 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
255 0x09, 0x02, // USAGE (Mouse)
256 0xA1, 0x01, // COLLECTION (Application)
257 0x09, 0x01, // USAGE (Pointer)
258
259 0xA1, 0x00, // COLLECTION (Physical)
260 0x05, 0x09, // USAGE_PAGE (Button)
261 0x19, 0x01, // USAGE_MINIMUM (Button 1)
262 0x29, 0x03, // USAGE_MAXIMUM (Button 3)
263
264 0x15, 0x00, // LOGICAL_MINIMUM (0)
265 0x25, 0x01, // LOGICAL_MAXIMUM (1)
266 0x95, 0x03, // REPORT_COUNT (3)
267 0x75, 0x01, // REPORT_SIZE (1)
268
269 0x81, 0x02, // INPUT (Data,Var,Abs)
270 0x95, 0x01, // REPORT_COUNT (1)
271 0x75, 0x05, // REPORT_SIZE (5)
272 0x81, 0x01, // INPUT (Cnst,Var,Abs)
273
274 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
275 0x09, 0x30, // USAGE (X)
276 0x09, 0x31, // USAGE (Y)
277 0x09, 0x38,
278
279 0x15, 0x81, // LOGICAL_MINIMUM (-127)
280 0x25, 0x7F, // LOGICAL_MAXIMUM (127)
281 0x75, 0x08, // REPORT_SIZE (8)
282 0x95, 0x03, // REPORT_COUNT (2)
283
284 0x81, 0x06, // INPUT (Data,Var,Rel)
285 0xC0, 0x09,
286 0x3c, 0x05,
287 0xff, 0x09,
288
289 0x01, 0x15,
290 0x00, 0x25,
291 0x01, 0x75,
292 0x01, 0x95,
293
294 0x02, 0xb1,
295 0x22, 0x75,
296 0x06, 0x95,
297 0x01, 0xb1,
298
299 0x01, 0xc0 // END_COLLECTION
300 };
301
302 /*!< mouse report struct */
303 struct hid_mouse {
304 uint8_t buttons;
305 int8_t x;
306 int8_t y;
307 int8_t wheel;
308 };
309
310 /*!< mouse report */
311 static struct hid_mouse mouse_cfg;
312
313 #define HID_STATE_IDLE 0
314 #define HID_STATE_BUSY 1
315
316 /*!< hid state ! Data can be sent only when state is idle */
317 static volatile uint8_t hid_state = HID_STATE_IDLE;
318
319 /* function ------------------------------------------------------------------*/
usbd_hid_int_callback(uint8_t busid,uint8_t ep,uint32_t nbytes)320 static void usbd_hid_int_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
321 {
322 hid_state = HID_STATE_IDLE;
323 }
324
325 /*!< endpoint call back */
326 static struct usbd_endpoint hid_in_ep = {
327 .ep_cb = usbd_hid_int_callback,
328 .ep_addr = HID_INT_EP
329 };
330
331 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048];
332 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[2048];
333
334 volatile bool ep_tx_busy_flag = false;
335
usbd_event_handler(uint8_t busid,uint8_t event)336 static void usbd_event_handler(uint8_t busid, uint8_t event)
337 {
338 switch (event) {
339 case USBD_EVENT_RESET:
340 break;
341 case USBD_EVENT_CONNECTED:
342 break;
343 case USBD_EVENT_DISCONNECTED:
344 break;
345 case USBD_EVENT_RESUME:
346 break;
347 case USBD_EVENT_SUSPEND:
348 break;
349 case USBD_EVENT_CONFIGURED:
350 ep_tx_busy_flag = false;
351 hid_state = HID_STATE_IDLE;
352 /* setup first out ep read transfer */
353 usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048);
354 break;
355 case USBD_EVENT_SET_REMOTE_WAKEUP:
356 break;
357 case USBD_EVENT_CLR_REMOTE_WAKEUP:
358 break;
359
360 default:
361 break;
362 }
363 }
364
usbd_cdc_acm_bulk_out(uint8_t busid,uint8_t ep,uint32_t nbytes)365 void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
366 {
367 USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
368 /* setup next out ep read transfer */
369 usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048);
370 }
371
usbd_cdc_acm_bulk_in(uint8_t busid,uint8_t ep,uint32_t nbytes)372 void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
373 {
374 USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
375
376 if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
377 /* send zlp */
378 usbd_ep_start_write(busid, CDC_IN_EP, NULL, 0);
379 } else {
380 ep_tx_busy_flag = false;
381 }
382 }
383
384 /*!< endpoint call back */
385 struct usbd_endpoint cdc_out_ep = {
386 .ep_addr = CDC_OUT_EP,
387 .ep_cb = usbd_cdc_acm_bulk_out
388 };
389
390 struct usbd_endpoint cdc_in_ep = {
391 .ep_addr = CDC_IN_EP,
392 .ep_cb = usbd_cdc_acm_bulk_in
393 };
394
395 struct usbd_interface intf0;
396 struct usbd_interface intf1;
397 struct usbd_interface intf2;
398 struct usbd_interface intf3;
399
cdc_acm_hid_msc_descriptor_init(uint8_t busid,uintptr_t reg_base)400 void cdc_acm_hid_msc_descriptor_init(uint8_t busid, uintptr_t reg_base)
401 {
402 #ifdef CONFIG_USBDEV_ADVANCE_DESC
403 usbd_desc_register(busid, &cdc_acm_hid_msc_descriptor);
404 #else
405 usbd_desc_register(busid, cdc_acm_hid_msc_descriptor);
406 #endif
407 usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0));
408 usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
409 usbd_add_endpoint(busid, &cdc_out_ep);
410 usbd_add_endpoint(busid, &cdc_in_ep);
411
412 usbd_add_interface(busid, usbd_msc_init_intf(busid, &intf2, MSC_OUT_EP, MSC_IN_EP));
413
414 usbd_add_interface(busid, usbd_hid_init_intf(busid, &intf3, hid_mouse_report_desc, HID_MOUSE_REPORT_DESC_SIZE));
415 usbd_add_endpoint(busid, &hid_in_ep);
416
417 /*!< init mouse report data */
418 mouse_cfg.buttons = 0;
419 mouse_cfg.wheel = 0;
420 mouse_cfg.x = 0;
421 mouse_cfg.y = 0;
422
423 usbd_initialize(busid, reg_base, usbd_event_handler);
424 }
425
426 /**
427 * @brief hid mouse test
428 * @pre none
429 * @param[in] none
430 * @retval none
431 */
hid_mouse_test(uint8_t busid)432 void hid_mouse_test(uint8_t busid)
433 {
434 if(usb_device_is_configured(busid) == false) {
435 return;
436 }
437 /*!< move mouse pointer */
438 mouse_cfg.x += 10;
439 mouse_cfg.y = 0;
440
441 hid_state = HID_STATE_BUSY;
442 usbd_ep_start_write(busid, HID_INT_EP, (uint8_t *)&mouse_cfg, 4);
443 while (hid_state == HID_STATE_BUSY) {
444 }
445 }
446
447 volatile uint8_t dtr_enable = 0;
448
usbd_cdc_acm_set_dtr(uint8_t busid,uint8_t intf,bool dtr)449 void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr)
450 {
451 if (dtr) {
452 dtr_enable = 1;
453 } else {
454 dtr_enable = 0;
455 }
456 }
457
cdc_acm_data_send_with_dtr_test(uint8_t busid)458 void cdc_acm_data_send_with_dtr_test(uint8_t busid)
459 {
460 if (dtr_enable) {
461 memset(&write_buffer[10], 'a', 2038);
462 ep_tx_busy_flag = true;
463 usbd_ep_start_write(busid, CDC_IN_EP, write_buffer, 2048);
464 while (ep_tx_busy_flag) {
465 }
466 }
467 }
468
469 #define BLOCK_SIZE 512
470 #define BLOCK_COUNT 10
471
472 typedef struct
473 {
474 uint8_t BlockSpace[BLOCK_SIZE];
475 } BLOCK_TYPE;
476
477 BLOCK_TYPE mass_block[BLOCK_COUNT];
478
usbd_msc_get_cap(uint8_t busid,uint8_t lun,uint32_t * block_num,uint32_t * block_size)479 void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint32_t *block_size)
480 {
481 *block_num = 1000; //Pretend having so many buffer,not has actually.
482 *block_size = BLOCK_SIZE;
483 }
usbd_msc_sector_read(uint8_t busid,uint8_t lun,uint32_t sector,uint8_t * buffer,uint32_t length)484 int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
485 {
486 if (sector < 10)
487 memcpy(buffer, mass_block[sector].BlockSpace, length);
488 return 0;
489 }
490
usbd_msc_sector_write(uint8_t busid,uint8_t lun,uint32_t sector,uint8_t * buffer,uint32_t length)491 int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
492 {
493 if (sector < 10)
494 memcpy(mass_block[sector].BlockSpace, buffer, length);
495 return 0;
496 }
497