1 /*
2  * Copyright (c) 2024, sakumisu
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "usbd_core.h"
7 #include "usbd_cdc_acm.h"
8 
9 /*!< endpoint address */
10 #define CDC_IN_EP  0x81
11 #define CDC_OUT_EP 0x01
12 #define CDC_INT_EP 0x85
13 
14 #define CDC_IN_EP2  0x82
15 #define CDC_OUT_EP2 0x02
16 #define CDC_INT_EP2 0x86
17 
18 #define CDC_IN_EP3  0x83
19 #define CDC_OUT_EP3 0x03
20 #define CDC_INT_EP3 0x87
21 
22 #define CDC_IN_EP4  0x84
23 #define CDC_OUT_EP4 0x04
24 #define CDC_INT_EP4 0x88
25 
26 #define USBD_VID           0xFFFF
27 #define USBD_PID           0xFFFF
28 #define USBD_MAX_POWER     100
29 #define USBD_LANGID_STRING 1033
30 
31 /*!< config descriptor size */
32 #define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN * 4)
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_USBDEV_ADVANCE_DESC
41 static const uint8_t device_descriptor[] = {
42     USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
43 };
44 
45 static const uint8_t config_descriptor[] = {
46     USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x08, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
47     CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
48     CDC_ACM_DESCRIPTOR_INIT(0x02, CDC_INT_EP2, CDC_OUT_EP2, CDC_IN_EP2, CDC_MAX_MPS, 0x02),
49     CDC_ACM_DESCRIPTOR_INIT(0x04, CDC_INT_EP3, CDC_OUT_EP3, CDC_IN_EP3, CDC_MAX_MPS, 0x02),
50     CDC_ACM_DESCRIPTOR_INIT(0x06, CDC_INT_EP4, CDC_OUT_EP4, CDC_IN_EP4, CDC_MAX_MPS, 0x02)
51 };
52 
53 static const uint8_t device_quality_descriptor[] = {
54     ///////////////////////////////////////
55     /// device qualifier descriptor
56     ///////////////////////////////////////
57     0x0a,
58     USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
59     0x00,
60     0x02,
61     0x00,
62     0x00,
63     0x00,
64     0x40,
65     0x00,
66     0x00,
67 };
68 
69 static const char *string_descriptors[] = {
70     (const char[]){ 0x09, 0x04 }, /* Langid */
71     "CherryUSB",                  /* Manufacturer */
72     "CherryUSB CDC MULTI DEMO",   /* Product */
73     "2022123456",                 /* Serial Number */
74 };
75 
device_descriptor_callback(uint8_t speed)76 static const uint8_t *device_descriptor_callback(uint8_t speed)
77 {
78     return device_descriptor;
79 }
80 
config_descriptor_callback(uint8_t speed)81 static const uint8_t *config_descriptor_callback(uint8_t speed)
82 {
83     return config_descriptor;
84 }
85 
device_quality_descriptor_callback(uint8_t speed)86 static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
87 {
88     return device_quality_descriptor;
89 }
90 
string_descriptor_callback(uint8_t speed,uint8_t index)91 static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
92 {
93     if (index > 3) {
94         return NULL;
95     }
96     return string_descriptors[index];
97 }
98 
99 const struct usb_descriptor cdc_multi_descriptor = {
100     .device_descriptor_callback = device_descriptor_callback,
101     .config_descriptor_callback = config_descriptor_callback,
102     .device_quality_descriptor_callback = device_quality_descriptor_callback,
103     .string_descriptor_callback = string_descriptor_callback
104 };
105 #else
106 /*!< global descriptor */
107 static const uint8_t cdc_multi_descriptor[] = {
108     USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
109     USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x08, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
110     CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
111     CDC_ACM_DESCRIPTOR_INIT(0x02, CDC_INT_EP2, CDC_OUT_EP2, CDC_IN_EP2, CDC_MAX_MPS, 0x02),
112     CDC_ACM_DESCRIPTOR_INIT(0x04, CDC_INT_EP3, CDC_OUT_EP3, CDC_IN_EP3, CDC_MAX_MPS, 0x02),
113     CDC_ACM_DESCRIPTOR_INIT(0x06, CDC_INT_EP4, CDC_OUT_EP4, CDC_IN_EP4, CDC_MAX_MPS, 0x02),
114     ///////////////////////////////////////
115     /// string0 descriptor
116     ///////////////////////////////////////
117     USB_LANGID_INIT(USBD_LANGID_STRING),
118     ///////////////////////////////////////
119     /// string1 descriptor
120     ///////////////////////////////////////
121     0x14,                       /* bLength */
122     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
123     'C', 0x00,                  /* wcChar0 */
124     'h', 0x00,                  /* wcChar1 */
125     'e', 0x00,                  /* wcChar2 */
126     'r', 0x00,                  /* wcChar3 */
127     'r', 0x00,                  /* wcChar4 */
128     'y', 0x00,                  /* wcChar5 */
129     'U', 0x00,                  /* wcChar6 */
130     'S', 0x00,                  /* wcChar7 */
131     'B', 0x00,                  /* wcChar8 */
132     ///////////////////////////////////////
133     /// string2 descriptor
134     ///////////////////////////////////////
135     0x26,                       /* bLength */
136     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
137     'C', 0x00,                  /* wcChar0 */
138     'h', 0x00,                  /* wcChar1 */
139     'e', 0x00,                  /* wcChar2 */
140     'r', 0x00,                  /* wcChar3 */
141     'r', 0x00,                  /* wcChar4 */
142     'y', 0x00,                  /* wcChar5 */
143     'U', 0x00,                  /* wcChar6 */
144     'S', 0x00,                  /* wcChar7 */
145     'B', 0x00,                  /* wcChar8 */
146     ' ', 0x00,                  /* wcChar9 */
147     'C', 0x00,                  /* wcChar10 */
148     'D', 0x00,                  /* wcChar11 */
149     'C', 0x00,                  /* wcChar12 */
150     ' ', 0x00,                  /* wcChar13 */
151     'D', 0x00,                  /* wcChar14 */
152     'E', 0x00,                  /* wcChar15 */
153     'M', 0x00,                  /* wcChar16 */
154     'O', 0x00,                  /* wcChar17 */
155     ///////////////////////////////////////
156     /// string3 descriptor
157     ///////////////////////////////////////
158     0x16,                       /* bLength */
159     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
160     '2', 0x00,                  /* wcChar0 */
161     '0', 0x00,                  /* wcChar1 */
162     '2', 0x00,                  /* wcChar2 */
163     '2', 0x00,                  /* wcChar3 */
164     '1', 0x00,                  /* wcChar4 */
165     '2', 0x00,                  /* wcChar5 */
166     '3', 0x00,                  /* wcChar6 */
167     '4', 0x00,                  /* wcChar7 */
168     '5', 0x00,                  /* wcChar8 */
169     '6', 0x00,                  /* wcChar9 */
170 #ifdef CONFIG_USB_HS
171     ///////////////////////////////////////
172     /// device qualifier descriptor
173     ///////////////////////////////////////
174     0x0a,
175     USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
176     0x00,
177     0x02,
178     0x00,
179     0x00,
180     0x00,
181     0x40,
182     0x00,
183     0x00,
184 #endif
185     0x00
186 };
187 #endif
188 
189 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[4][2048];
190 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[4][2048];
191 
192 volatile bool ep_tx_busy_flag = false;
193 
usbd_event_handler(uint8_t busid,uint8_t event)194 static void usbd_event_handler(uint8_t busid, uint8_t event)
195 {
196     switch (event) {
197         case USBD_EVENT_RESET:
198             break;
199         case USBD_EVENT_CONNECTED:
200             break;
201         case USBD_EVENT_DISCONNECTED:
202             break;
203         case USBD_EVENT_RESUME:
204             break;
205         case USBD_EVENT_SUSPEND:
206             break;
207         case USBD_EVENT_CONFIGURED:
208             ep_tx_busy_flag = false;
209             /* setup first out ep read transfer */
210             usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048);
211             usbd_ep_start_read(busid, CDC_OUT_EP2, read_buffer, 2048);
212             usbd_ep_start_read(busid, CDC_OUT_EP3, read_buffer, 2048);
213             usbd_ep_start_read(busid, CDC_OUT_EP4, read_buffer, 2048);
214             break;
215         case USBD_EVENT_SET_REMOTE_WAKEUP:
216             break;
217         case USBD_EVENT_CLR_REMOTE_WAKEUP:
218             break;
219 
220         default:
221             break;
222     }
223 }
224 
usbd_cdc_acm_bulk_out(uint8_t busid,uint8_t ep,uint32_t nbytes)225 void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
226 {
227     USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
228     /* setup next out ep read transfer */
229     usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048);
230 }
231 
usbd_cdc_acm_bulk_in(uint8_t busid,uint8_t ep,uint32_t nbytes)232 void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
233 {
234     USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
235 
236     if ((nbytes % CDC_MAX_MPS) == 0 && nbytes) {
237         /* send zlp */
238         usbd_ep_start_write(CDC_IN_EP, NULL, 0);
239     } else {
240         ep_tx_busy_flag = false;
241     }
242 }
243 
244 struct usbd_endpoint cdc_out_ep1 = {
245     .ep_addr = CDC_OUT_EP,
246     .ep_cb = usbd_cdc_acm_bulk_out
247 };
248 
249 struct usbd_endpoint cdc_in_ep1 = {
250     .ep_addr = CDC_IN_EP,
251     .ep_cb = usbd_cdc_acm_bulk_in
252 };
253 
254 struct usbd_endpoint cdc_out_ep2 = {
255     .ep_addr = CDC_OUT_EP2,
256     .ep_cb = usbd_cdc_acm_bulk_out
257 };
258 
259 struct usbd_endpoint cdc_in_ep2 = {
260     .ep_addr = CDC_IN_EP2,
261     .ep_cb = usbd_cdc_acm_bulk_in
262 };
263 
264 struct usbd_endpoint cdc_out_ep3 = {
265     .ep_addr = CDC_OUT_EP3,
266     .ep_cb = usbd_cdc_acm_bulk_out
267 };
268 
269 struct usbd_endpoint cdc_in_ep3 = {
270     .ep_addr = CDC_IN_EP3,
271     .ep_cb = usbd_cdc_acm_bulk_in
272 };
273 
274 struct usbd_endpoint cdc_out_ep4 = {
275     .ep_addr = CDC_OUT_EP4,
276     .ep_cb = usbd_cdc_acm_bulk_out
277 };
278 
279 struct usbd_endpoint cdc_in_ep4 = {
280     .ep_addr = CDC_IN_EP4,
281     .ep_cb = usbd_cdc_acm_bulk_in
282 };
283 
284 struct usbd_interface intf0;
285 struct usbd_interface intf1;
286 struct usbd_interface intf2;
287 struct usbd_interface intf3;
288 struct usbd_interface intf4;
289 struct usbd_interface intf5;
290 struct usbd_interface intf6;
291 struct usbd_interface intf7;
292 
cdc_acm_multi_init(uint8_t busid,uintptr_t reg_base)293 void cdc_acm_multi_init(uint8_t busid, uintptr_t reg_base)
294 {
295 #ifdef CONFIG_USBDEV_ADVANCE_DESC
296     usbd_desc_register(busid, &cdc_multi_descriptor);
297 #else
298     usbd_desc_register(busid, cdc_multi_descriptor);
299 #endif
300     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0));
301     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
302     usbd_add_endpoint(busid, &cdc_out_ep1);
303     usbd_add_endpoint(busid, &cdc_in_ep1);
304 
305     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf2));
306     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf3));
307     usbd_add_endpoint(busid, &cdc_out_ep2);
308     usbd_add_endpoint(busid, &cdc_in_ep2);
309 
310     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf4));
311     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf5));
312     usbd_add_endpoint(busid, &cdc_out_ep3);
313     usbd_add_endpoint(busid, &cdc_in_ep3);
314 
315     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf6));
316     usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf7));
317     usbd_add_endpoint(busid, &cdc_out_ep4);
318     usbd_add_endpoint(busid, &cdc_in_ep4);
319 
320     usbd_initialize(busid, reg_base, usbd_event_handler);
321 }