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 }