1 /*!
2 \file cdc_acm_core.c
3 \brief CDC ACM driver
4
5 \version 2020-08-04, V1.1.0, firmware for GD32VF103
6 \version 2020-12-11, V1.1.1, firmware for GD32VF103
7 */
8
9 /*
10 Copyright (c) 2020, GigaDevice Semiconductor Inc.
11
12 Redistribution and use in source and binary forms, with or without modification,
13 are permitted provided that the following conditions are met:
14
15 1. Redistributions of source code must retain the above copyright notice, this
16 list of conditions and the following disclaimer.
17 2. Redistributions in binary form must reproduce the above copyright notice,
18 this list of conditions and the following disclaimer in the documentation
19 and/or other materials provided with the distribution.
20 3. Neither the name of the copyright holder nor the names of its contributors
21 may be used to endorse or promote products derived from this software without
22 specific prior written permission.
23
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 OF SUCH DAMAGE.
34 */
35
36 #include "cdc_acm_core.h"
37
38 #define USBD_VID 0x28E9U
39 #define USBD_PID 0x018AU
40
41 /* note:it should use the C99 standard when compiling the below codes */
42 /* USB standard device descriptor */
43 const usb_desc_dev cdc_dev_desc =
44 {
45 .header =
46 {
47 .bLength = USB_DEV_DESC_LEN,
48 .bDescriptorType = USB_DESCTYPE_DEV,
49 },
50 .bcdUSB = 0x0200U,
51 .bDeviceClass = USB_CLASS_CDC,
52 .bDeviceSubClass = 0x00U,
53 .bDeviceProtocol = 0x00U,
54 .bMaxPacketSize0 = USB_FS_EP0_MAX_LEN,
55 .idVendor = USBD_VID,
56 .idProduct = USBD_PID,
57 .bcdDevice = 0x0100U,
58 .iManufacturer = STR_IDX_MFC,
59 .iProduct = STR_IDX_PRODUCT,
60 .iSerialNumber = STR_IDX_SERIAL,
61 .bNumberConfigurations = USBD_CFG_MAX_NUM,
62 };
63
64 /* USB device configuration descriptor */
65 const usb_cdc_desc_config_set cdc_config_desc =
66 {
67 .config =
68 {
69 .header =
70 {
71 .bLength = sizeof(usb_desc_config),
72 .bDescriptorType = USB_DESCTYPE_CONFIG,
73 },
74 .wTotalLength = USB_CDC_ACM_CONFIG_DESC_SIZE,
75 .bNumInterfaces = 0x02U,
76 .bConfigurationValue = 0x01U,
77 .iConfiguration = 0x00U,
78 .bmAttributes = 0x80U,
79 .bMaxPower = 0x32U
80 },
81
82 .cmd_itf =
83 {
84 .header =
85 {
86 .bLength = sizeof(usb_desc_itf),
87 .bDescriptorType = USB_DESCTYPE_ITF
88 },
89 .bInterfaceNumber = 0x00U,
90 .bAlternateSetting = 0x00U,
91 .bNumEndpoints = 0x01U,
92 .bInterfaceClass = USB_CLASS_CDC,
93 .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
94 .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
95 .iInterface = 0x00U
96 },
97
98 .cdc_header =
99 {
100 .header =
101 {
102 .bLength = sizeof(usb_desc_header_func),
103 .bDescriptorType = USB_DESCTYPE_CS_INTERFACE
104 },
105 .bDescriptorSubtype = 0x00U,
106 .bcdCDC = 0x0110U
107 },
108
109 .cdc_call_managment =
110 {
111 .header =
112 {
113 .bLength = sizeof(usb_desc_call_managment_func),
114 .bDescriptorType = USB_DESCTYPE_CS_INTERFACE
115 },
116 .bDescriptorSubtype = 0x01U,
117 .bmCapabilities = 0x00U,
118 .bDataInterface = 0x01U
119 },
120
121 .cdc_acm =
122 {
123 .header =
124 {
125 .bLength = sizeof(usb_desc_acm_func),
126 .bDescriptorType = USB_DESCTYPE_CS_INTERFACE
127 },
128 .bDescriptorSubtype = 0x02U,
129 .bmCapabilities = 0x02U,
130 },
131
132 .cdc_union =
133 {
134 .header =
135 {
136 .bLength = sizeof(usb_desc_union_func),
137 .bDescriptorType = USB_DESCTYPE_CS_INTERFACE
138 },
139 .bDescriptorSubtype = 0x06U,
140 .bMasterInterface = 0x00U,
141 .bSlaveInterface0 = 0x01U,
142 },
143
144 .cdc_cmd_endpoint =
145 {
146 .header =
147 {
148 .bLength = sizeof(usb_desc_ep),
149 .bDescriptorType = USB_DESCTYPE_EP,
150 },
151 .bEndpointAddress = CDC_CMD_EP,
152 .bmAttributes = USB_EP_ATTR_INT,
153 .wMaxPacketSize = USB_CDC_CMD_PACKET_SIZE,
154 .bInterval = 0x0AU
155 },
156
157 .cdc_data_interface =
158 {
159 .header =
160 {
161 .bLength = sizeof(usb_desc_itf),
162 .bDescriptorType = USB_DESCTYPE_ITF,
163 },
164 .bInterfaceNumber = 0x01U,
165 .bAlternateSetting = 0x00U,
166 .bNumEndpoints = 0x02U,
167 .bInterfaceClass = USB_CLASS_DATA,
168 .bInterfaceSubClass = 0x00U,
169 .bInterfaceProtocol = USB_CDC_PROTOCOL_NONE,
170 .iInterface = 0x00U
171 },
172
173 .cdc_out_endpoint =
174 {
175 .header =
176 {
177 .bLength = sizeof(usb_desc_ep),
178 .bDescriptorType = USB_DESCTYPE_EP,
179 },
180 .bEndpointAddress = CDC_DATA_OUT_EP,
181 .bmAttributes = USB_EP_ATTR_BULK,
182 .wMaxPacketSize = USB_CDC_DATA_PACKET_SIZE,
183 .bInterval = 0x00U
184 },
185
186 .cdc_in_endpoint =
187 {
188 .header =
189 {
190 .bLength = sizeof(usb_desc_ep),
191 .bDescriptorType = USB_DESCTYPE_EP
192 },
193 .bEndpointAddress = CDC_DATA_IN_EP,
194 .bmAttributes = USB_EP_ATTR_BULK,
195 .wMaxPacketSize = USB_CDC_DATA_PACKET_SIZE,
196 .bInterval = 0x00U
197 }
198 };
199
200 /* USB language ID Descriptor */
201 static const usb_desc_LANGID usbd_language_id_desc =
202 {
203 .header =
204 {
205 .bLength = sizeof(usb_desc_LANGID),
206 .bDescriptorType = USB_DESCTYPE_STR,
207 },
208 .wLANGID = ENG_LANGID
209 };
210
211 /* USB manufacture string */
212 static const usb_desc_str manufacturer_string =
213 {
214 .header =
215 {
216 .bLength = USB_STRING_LEN(10),
217 .bDescriptorType = USB_DESCTYPE_STR,
218 },
219 .unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
220 };
221
222 /* USB product string */
223 static const usb_desc_str product_string =
224 {
225 .header =
226 {
227 .bLength = USB_STRING_LEN(12),
228 .bDescriptorType = USB_DESCTYPE_STR,
229 },
230 .unicode_string = {'G', 'D', '3', '2', '-', 'C', 'D', 'C', '_', 'A', 'C', 'M'}
231 };
232
233 /* USBD serial string */
234 static usb_desc_str serial_string =
235 {
236 .header =
237 {
238 .bLength = USB_STRING_LEN(12),
239 .bDescriptorType = USB_DESCTYPE_STR,
240 }
241 };
242
243 /* USB string descriptor set */
244 void *const usbd_cdc_strings[] =
245 {
246 [STR_IDX_LANGID] = (uint8_t *)&usbd_language_id_desc,
247 [STR_IDX_MFC] = (uint8_t *)&manufacturer_string,
248 [STR_IDX_PRODUCT] = (uint8_t *)&product_string,
249 [STR_IDX_SERIAL] = (uint8_t *)&serial_string
250 };
251
252 usb_desc cdc_desc =
253 {
254 .dev_desc = (uint8_t *)&cdc_dev_desc,
255 .config_desc = (uint8_t *)&cdc_config_desc,
256 .strings = usbd_cdc_strings
257 };
258
259 /* local function prototypes ('static') */
260 static uint8_t cdc_acm_init (usb_dev *udev, uint8_t config_index);
261 static uint8_t cdc_acm_deinit (usb_dev *udev, uint8_t config_index);
262 static uint8_t cdc_acm_req (usb_dev *udev, usb_req *req);
263 static uint8_t cdc_ctlx_out (usb_dev *udev);
264 static uint8_t cdc_acm_in (usb_dev *udev, uint8_t ep_num);
265 static uint8_t cdc_acm_out (usb_dev *udev, uint8_t ep_num);
266
267 /* USB CDC device class callbacks structure */
268 usb_class_core cdc_class =
269 {
270 .command = NO_CMD,
271 .alter_set = 0U,
272
273 .init = cdc_acm_init,
274 .deinit = cdc_acm_deinit,
275
276 .req_proc = cdc_acm_req,
277 .ctlx_out = cdc_ctlx_out,
278 .data_in = cdc_acm_in,
279 .data_out = cdc_acm_out
280 };
281
282 /*!
283 \brief check cdc acm is ready for data transfer
284 \param[in] udev: pointer to USB device instance
285 \param[out] none
286 \retval 0 if cdc is ready, 5 else
287 */
cdc_acm_check_ready(usb_dev * udev)288 uint8_t cdc_acm_check_ready(usb_dev *udev)
289 {
290 if (udev->dev.class_data[CDC_COM_INTERFACE] != NULL) {
291 usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
292
293 if ((1U == cdc->packet_receive) && (1U == cdc->packet_sent)) {
294 return 0U;
295 }
296 }
297
298 return 1U;
299 }
300
301 /*!
302 \brief send CDC ACM data
303 \param[in] udev: pointer to USB device instance
304 \param[out] none
305 \retval USB device operation status
306 */
cdc_acm_data_send(usb_dev * udev)307 void cdc_acm_data_send (usb_dev *udev)
308 {
309 usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
310
311 if (0U != cdc->receive_length) {
312 cdc->packet_sent = 0U;
313
314 usbd_ep_send (udev, CDC_DATA_IN_EP, (uint8_t*)(cdc->data), cdc->receive_length);
315
316 cdc->receive_length = 0U;
317 }
318 }
319
320 /*!
321 \brief receive CDC ACM data
322 \param[in] udev: pointer to USB device instance
323 \param[out] none
324 \retval USB device operation status
325 */
cdc_acm_data_receive(usb_dev * udev)326 void cdc_acm_data_receive (usb_dev *udev)
327 {
328 usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
329
330 cdc->packet_receive = 0U;
331 cdc->packet_sent = 0U;
332
333 usbd_ep_recev(udev, CDC_DATA_OUT_EP, (uint8_t*)(cdc->data), USB_CDC_DATA_PACKET_SIZE);
334 }
335
336 /*!
337 \brief initialize the CDC ACM device
338 \param[in] udev: pointer to USB device instance
339 \param[in] config_index: configuration index
340 \param[out] none
341 \retval USB device operation status
342 */
cdc_acm_init(usb_dev * udev,uint8_t config_index)343 static uint8_t cdc_acm_init (usb_dev *udev, uint8_t config_index)
344 {
345 static usb_cdc_handler cdc_handler;
346
347 /* initialize the data Tx endpoint */
348 usbd_ep_setup (udev, &(cdc_config_desc.cdc_in_endpoint));
349
350 /* initialize the data Rx endpoint */
351 usbd_ep_setup (udev, &(cdc_config_desc.cdc_out_endpoint));
352
353 /* initialize the command Tx endpoint */
354 usbd_ep_setup (udev, &(cdc_config_desc.cdc_cmd_endpoint));
355
356 /* initialize cdc handler structure */
357 cdc_handler.packet_receive = 1U;
358 cdc_handler.packet_sent = 1U;
359 cdc_handler.receive_length = 0U;
360
361 cdc_handler.line_coding = (acm_line){
362 .dwDTERate = 115200,
363 .bCharFormat = 0,
364 .bParityType = 0,
365 .bDataBits = 0x08
366 };
367
368 udev->dev.class_data[CDC_COM_INTERFACE] = (void *)&cdc_handler;
369
370 return USBD_OK;
371 }
372
373 /*!
374 \brief de-initialize the CDC ACM device
375 \param[in] udev: pointer to USB device instance
376 \param[in] config_index: configuration index
377 \param[out] none
378 \retval USB device operation status
379 */
cdc_acm_deinit(usb_dev * udev,uint8_t config_index)380 static uint8_t cdc_acm_deinit (usb_dev *udev, uint8_t config_index)
381 {
382 /* deinitialize the data Tx/Rx endpoint */
383 usbd_ep_clear (udev, CDC_DATA_IN_EP);
384 usbd_ep_clear (udev, CDC_DATA_OUT_EP);
385
386 /* deinitialize the command Tx endpoint */
387 usbd_ep_clear (udev, CDC_CMD_EP);
388
389 return USBD_OK;
390 }
391
392 /*!
393 \brief handle the CDC ACM class-specific requests
394 \param[in] udev: pointer to USB device instance
395 \param[in] req: device class-specific request
396 \param[out] none
397 \retval USB device operation status
398 */
cdc_acm_req(usb_dev * udev,usb_req * req)399 static uint8_t cdc_acm_req (usb_dev *udev, usb_req *req)
400 {
401 usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
402
403 usb_transc *transc = NULL;
404
405 switch (req->bRequest) {
406 case SEND_ENCAPSULATED_COMMAND:
407 /* no operation for this driver */
408 break;
409
410 case GET_ENCAPSULATED_RESPONSE:
411 /* no operation for this driver */
412 break;
413
414 case SET_COMM_FEATURE:
415 /* no operation for this driver */
416 break;
417
418 case GET_COMM_FEATURE:
419 /* no operation for this driver */
420 break;
421
422 case CLEAR_COMM_FEATURE:
423 /* no operation for this driver */
424 break;
425
426 case SET_LINE_CODING:
427 transc = &udev->dev.transc_out[0];
428
429 /* set the value of the current command to be processed */
430 udev->dev.class_core->alter_set = req->bRequest;
431
432 /* enable EP0 prepare to receive command data packet */
433 transc->remain_len = req->wLength;
434 transc->xfer_buf = cdc->cmd;
435 break;
436
437 case GET_LINE_CODING:
438 transc = &udev->dev.transc_in[0];
439
440 cdc->cmd[0] = (uint8_t)(cdc->line_coding.dwDTERate);
441 cdc->cmd[1] = (uint8_t)(cdc->line_coding.dwDTERate >> 8);
442 cdc->cmd[2] = (uint8_t)(cdc->line_coding.dwDTERate >> 16);
443 cdc->cmd[3] = (uint8_t)(cdc->line_coding.dwDTERate >> 24);
444 cdc->cmd[4] = cdc->line_coding.bCharFormat;
445 cdc->cmd[5] = cdc->line_coding.bParityType;
446 cdc->cmd[6] = cdc->line_coding.bDataBits;
447
448 transc->xfer_buf = cdc->cmd;
449 transc->remain_len = 7U;
450 break;
451
452 case SET_CONTROL_LINE_STATE:
453 /* no operation for this driver */
454 break;
455
456 case SEND_BREAK:
457 /* no operation for this driver */
458 break;
459
460 default:
461 break;
462 }
463
464 return USBD_OK;
465 }
466
467 /*!
468 \brief handle CDC ACM setup data
469 \param[in] udev: pointer to USB device instance
470 \param[out] none
471 \retval USB device operation status
472 */
cdc_ctlx_out(usb_dev * udev)473 static uint8_t cdc_ctlx_out (usb_dev *udev)
474 {
475 usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
476
477 if (udev->dev.class_core->alter_set != NO_CMD) {
478 /* process the command data */
479 cdc->line_coding.dwDTERate = (uint32_t)((uint32_t)cdc->cmd[0] |
480 ((uint32_t)cdc->cmd[1] << 8U) |
481 ((uint32_t)cdc->cmd[2] << 16U) |
482 ((uint32_t)cdc->cmd[3] << 24U));
483
484 cdc->line_coding.bCharFormat = cdc->cmd[4];
485 cdc->line_coding.bParityType = cdc->cmd[5];
486 cdc->line_coding.bDataBits = cdc->cmd[6];
487
488 udev->dev.class_core->alter_set = NO_CMD;
489 }
490
491 return USBD_OK;
492 }
493
494 /*!
495 \brief handle CDC ACM data
496 \param[in] udev: pointer to USB device instance
497 \param[in] ep_num: endpoint identifier
498 \param[out] none
499 \retval USB device operation status
500 */
cdc_acm_in(usb_dev * udev,uint8_t ep_num)501 static uint8_t cdc_acm_in (usb_dev *udev, uint8_t ep_num)
502 {
503 usb_transc *transc = &udev->dev.transc_in[EP_ID(ep_num)];
504
505 usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
506
507 if ((0U == transc->xfer_len % transc->max_len) && (0U != transc->xfer_len)) {
508 usbd_ep_send (udev, ep_num, NULL, 0U);
509 } else {
510 cdc->packet_sent = 1U;
511 }
512
513 return USBD_OK;
514 }
515
516 /*!
517 \brief handle CDC ACM data
518 \param[in] udev: pointer to USB device instance
519 \param[in] ep_num: endpoint identifier
520 \param[out] none
521 \retval USB device operation status
522 */
cdc_acm_out(usb_dev * udev,uint8_t ep_num)523 static uint8_t cdc_acm_out (usb_dev *udev, uint8_t ep_num)
524 {
525 usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
526
527 cdc->packet_receive = 1U;
528 cdc->receive_length = ((usb_core_driver *)udev)->dev.transc_out[ep_num].xfer_count;
529
530 return USBD_OK;
531 }
532