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