1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2012-10-02     Yi Qiu       first version
9  * 2012-12-12     heyuanjie87  change endpoints and function handler
10  * 2013-06-25     heyuanjie87  remove SOF mechinism
11  * 2013-07-20     Yi Qiu       do more test
12  * 2016-02-01     Urey         Fix some error
13  * 2021-10-14     mazhiyuan    Fix some error
14  */
15 
16 #include <rthw.h>
17 #include <rtdevice.h>
18 #include "drivers/usb_device.h"
19 #include "cdc.h"
20 
21 #ifdef RT_USB_DEVICE_CDC
22 
23 #define DBG_TAG           "usbdevice_cdc"
24 #define DBG_LVL           DBG_INFO
25 #include <rtdbg.h>
26 
27 #define VCOM_INTF_STR_INDEX 5
28 #ifdef RT_VCOM_TX_TIMEOUT
29 #define VCOM_TX_TIMEOUT      RT_VCOM_TX_TIMEOUT
30 #else /*!RT_VCOM_TX_TIMEOUT*/
31 #define VCOM_TX_TIMEOUT      1000
32 #endif /*RT_VCOM_TX_TIMEOUT*/
33 
34 #ifdef RT_CDC_RX_BUFSIZE
35 #define CDC_RX_BUFSIZE          RT_CDC_RX_BUFSIZE
36 #else
37 #define CDC_RX_BUFSIZE          128
38 #endif
39 #define CDC_MAX_PACKET_SIZE     64
40 #define VCOM_DEVICE             "vcom"
41 
42 #ifdef RT_VCOM_TASK_STK_SIZE
43 #define VCOM_TASK_STK_SIZE      RT_VCOM_TASK_STK_SIZE
44 #else /*!RT_VCOM_TASK_STK_SIZE*/
45 #define VCOM_TASK_STK_SIZE      512
46 #endif /*RT_VCOM_TASK_STK_SIZE*/
47 
48 #ifdef RT_VCOM_TX_USE_DMA
49 #define VCOM_TX_USE_DMA
50 #endif /*RT_VCOM_TX_USE_DMA*/
51 
52 #ifdef RT_VCOM_SERNO
53 #define _SER_NO RT_VCOM_SERNO
54 #else /*!RT_VCOM_SERNO*/
55 #define _SER_NO  "32021919830108"
56 #endif /*RT_VCOM_SERNO*/
57 
58 #ifdef RT_VCOM_SER_LEN
59 #define _SER_NO_LEN RT_VCOM_SER_LEN
60 #else /*!RT_VCOM_SER_LEN*/
61 #define _SER_NO_LEN 14 /*rt_strlen("32021919830108")*/
62 #endif /*RT_VCOM_SER_LEN*/
63 
64 rt_align(RT_ALIGN_SIZE)
65 static rt_uint8_t vcom_thread_stack[VCOM_TASK_STK_SIZE];
66 static struct rt_thread vcom_thread;
67 static struct ucdc_line_coding line_coding;
68 
69 #define CDC_TX_BUFSIZE    1024
70 #define CDC_BULKIN_MAXSIZE (CDC_TX_BUFSIZE / 8)
71 
72 #define CDC_TX_HAS_DATE   0x01
73 #define CDC_TX_HAS_SPACE  0x02
74 
75 struct vcom
76 {
77     struct rt_serial_device serial;
78     uep_t ep_out;
79     uep_t ep_in;
80     uep_t ep_cmd;
81     rt_bool_t connected;
82     rt_bool_t in_sending;
83     struct rt_completion wait;
84     rt_uint8_t rx_rbp[CDC_RX_BUFSIZE];
85     struct rt_ringbuffer rx_ringbuffer;
86     rt_uint8_t tx_rbp[CDC_TX_BUFSIZE];
87     struct rt_ringbuffer tx_ringbuffer;
88     struct rt_event  tx_event;
89 };
90 
91 struct vcom_tx_msg
92 {
93     struct rt_serial_device * serial;
94     const char *buf;
95     rt_size_t size;
96 };
97 
98 rt_align(4)
99 static struct udevice_descriptor dev_desc =
100 {
101     USB_DESC_LENGTH_DEVICE,     //bLength;
102     USB_DESC_TYPE_DEVICE,       //type;
103     USB_BCD_VERSION,            //bcdUSB;
104     USB_CLASS_CDC,              //bDeviceClass;
105     0x02,                       //bDeviceSubClass;
106     0x00,                       //bDeviceProtocol;
107     CDC_MAX_PACKET_SIZE,        //bMaxPacketSize0;
108     _VENDOR_ID,                 //idVendor;
109     _PRODUCT_ID,                //idProduct;
110     USB_BCD_DEVICE,             //bcdDevice;
111     USB_STRING_MANU_INDEX,      //iManufacturer;
112     USB_STRING_PRODUCT_INDEX,   //iProduct;
113     USB_STRING_SERIAL_INDEX,    //iSerialNumber;
114     USB_DYNAMIC,                //bNumConfigurations;
115 };
116 
117 //FS and HS needed
118 rt_align(4)
119 static struct usb_qualifier_descriptor dev_qualifier =
120 {
121     sizeof(dev_qualifier),          //bLength
122     USB_DESC_TYPE_DEVICEQUALIFIER,  //bDescriptorType
123     0x0200,                         //bcdUSB
124     USB_CLASS_CDC,                  //bDeviceClass
125     0x02,                           //bDeviceSubClass
126     0x00,                           //bDeviceProtocol
127     64,                             //bMaxPacketSize0
128     0x01,                           //bNumConfigurations
129     0,
130 };
131 
132 /* communcation interface descriptor */
133 rt_align(4)
134 const static struct ucdc_comm_descriptor _comm_desc =
135 {
136 #ifdef RT_USB_DEVICE_COMPOSITE
137     /* Interface Association Descriptor */
138     {
139         USB_DESC_LENGTH_IAD,
140         USB_DESC_TYPE_IAD,
141         USB_DYNAMIC,
142         0x02,
143         USB_CDC_CLASS_COMM,
144         USB_CDC_SUBCLASS_ACM,
145         USB_CDC_PROTOCOL_V25TER,
146         0x00,
147     },
148 #endif
149     /* Interface Descriptor */
150     {
151         USB_DESC_LENGTH_INTERFACE,
152         USB_DESC_TYPE_INTERFACE,
153         USB_DYNAMIC,
154         0x00,
155         0x01,
156         USB_CDC_CLASS_COMM,
157         USB_CDC_SUBCLASS_ACM,
158         USB_CDC_PROTOCOL_V25TER,
159 #ifdef RT_USB_DEVICE_COMPOSITE
160         VCOM_INTF_STR_INDEX,
161 #else
162         0,
163 #endif
164     },
165     /* Header Functional Descriptor */
166     {
167         0x05,
168         USB_CDC_CS_INTERFACE,
169         USB_CDC_SCS_HEADER,
170         0x0110,
171     },
172     /* Call Management Functional Descriptor */
173     {
174         0x05,
175         USB_CDC_CS_INTERFACE,
176         USB_CDC_SCS_CALL_MGMT,
177         0x00,
178         USB_DYNAMIC,
179     },
180     /* Abstract Control Management Functional Descriptor */
181     {
182         0x04,
183         USB_CDC_CS_INTERFACE,
184         USB_CDC_SCS_ACM,
185         0x02,
186     },
187     /* Union Functional Descriptor */
188     {
189         0x05,
190         USB_CDC_CS_INTERFACE,
191         USB_CDC_SCS_UNION,
192         USB_DYNAMIC,
193         USB_DYNAMIC,
194     },
195     /* Endpoint Descriptor */
196     {
197         USB_DESC_LENGTH_ENDPOINT,
198         USB_DESC_TYPE_ENDPOINT,
199         USB_DYNAMIC | USB_DIR_IN,
200         USB_EP_ATTR_INT,
201         0x08,
202         0xFF,
203     },
204 };
205 
206 /* data interface descriptor */
207 rt_align(4)
208 const static struct ucdc_data_descriptor _data_desc =
209 {
210     /* interface descriptor */
211     {
212         USB_DESC_LENGTH_INTERFACE,
213         USB_DESC_TYPE_INTERFACE,
214         USB_DYNAMIC,
215         0x00,
216         0x02,
217         USB_CDC_CLASS_DATA,
218         0x00,
219         0x00,
220         0x00,
221     },
222     /* endpoint, bulk out */
223     {
224         USB_DESC_LENGTH_ENDPOINT,
225         USB_DESC_TYPE_ENDPOINT,
226         USB_DYNAMIC | USB_DIR_OUT,
227         USB_EP_ATTR_BULK,
228         USB_CDC_BUFSIZE,
229         0x00,
230     },
231     /* endpoint, bulk in */
232     {
233         USB_DESC_LENGTH_ENDPOINT,
234         USB_DESC_TYPE_ENDPOINT,
235         USB_DYNAMIC | USB_DIR_IN,
236         USB_EP_ATTR_BULK,
237         USB_CDC_BUFSIZE,
238         0x00,
239     },
240 };
241 rt_align(4)
242 static char serno[_SER_NO_LEN + 1] = {'\0'};
243 rt_weak rt_err_t vcom_get_stored_serno(char *serno, int size);
244 
vcom_get_stored_serno(char * serno,int size)245 rt_err_t vcom_get_stored_serno(char *serno, int size)
246 {
247     return -RT_ERROR;
248 }
249 rt_align(4)
250 const static char* _ustring[] =
251 {
252     "Language",
253     "RT-Thread Team.",
254     "RTT Virtual Serial",
255     serno,
256     "Configuration",
257     "Interface",
258 };
259 static void rt_usb_vcom_init(struct ufunction *func);
260 
_vcom_reset_state(ufunction_t func)261 static void _vcom_reset_state(ufunction_t func)
262 {
263     struct vcom* data;
264     rt_base_t level;
265 
266     RT_ASSERT(func != RT_NULL)
267 
268     data = (struct vcom*)func->user_data;
269 
270     level = rt_hw_interrupt_disable();
271     data->connected = RT_FALSE;
272     data->in_sending = RT_FALSE;
273     /*rt_kprintf("reset USB serial\n", cnt);*/
274     rt_hw_interrupt_enable(level);
275 }
276 
277 /**
278  * This function will handle cdc bulk in endpoint request.
279  *
280  * @param func the usb function object.
281  * @param size request size.
282  *
283  * @return RT_EOK.
284  */
_ep_in_handler(ufunction_t func,rt_size_t size)285 static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
286 {
287     struct vcom *data;
288     rt_size_t request_size;
289 
290     RT_ASSERT(func != RT_NULL);
291 
292     data = (struct vcom*)func->user_data;
293     request_size = data->ep_in->request.size;
294     LOG_D("_ep_in_handler %d", request_size);
295     if ((request_size != 0) && ((request_size % EP_MAXPACKET(data->ep_in)) == 0))
296     {
297         /* don't have data right now. Send a zero-length-packet to
298          * terminate the transaction.
299          *
300          * FIXME: actually, this might not be the right place to send zlp.
301          * Only the rt_device_write could know how much data is sending. */
302         data->in_sending = RT_TRUE;
303 
304         data->ep_in->request.buffer = RT_NULL;
305         data->ep_in->request.size = 0;
306         data->ep_in->request.req_type = UIO_REQUEST_WRITE;
307         rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
308 
309         return RT_EOK;
310     }
311 
312     rt_completion_done(&data->wait);
313 
314     return RT_EOK;
315 }
316 
317 /**
318  * This function will handle cdc bulk out endpoint request.
319  *
320  * @param func the usb function object.
321  * @param size request size.
322  *
323  * @return RT_EOK.
324  */
_ep_out_handler(ufunction_t func,rt_size_t size)325 static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
326 {
327     rt_base_t level;
328     struct vcom *data;
329 
330     RT_ASSERT(func != RT_NULL);
331 
332     LOG_D("_ep_out_handler %d", size);
333 
334     data = (struct vcom*)func->user_data;
335     /* ensure serial is active */
336     if((data->serial.parent.flag & RT_DEVICE_FLAG_ACTIVATED)
337         && (data->serial.parent.open_flag & RT_DEVICE_OFLAG_OPEN))
338     {
339         /* receive data from USB VCOM */
340         level = rt_hw_interrupt_disable();
341 
342         rt_ringbuffer_put(&data->rx_ringbuffer, data->ep_out->buffer, size);
343         rt_hw_interrupt_enable(level);
344 
345         /* notify receive data */
346         rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_RX_IND);
347     }
348 
349     data->ep_out->request.buffer = data->ep_out->buffer;
350     data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
351     data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
352     rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
353 
354     return RT_EOK;
355 }
356 
357 /**
358  * This function will handle cdc interrupt in endpoint request.
359  *
360  * @param device the usb device object.
361  * @param size request size.
362  *
363  * @return RT_EOK.
364  */
_ep_cmd_handler(ufunction_t func,rt_size_t size)365 static rt_err_t _ep_cmd_handler(ufunction_t func, rt_size_t size)
366 {
367     RT_ASSERT(func != RT_NULL);
368 
369     LOG_D("_ep_cmd_handler");
370 
371     return RT_EOK;
372 }
373 
374 /**
375  * This function will handle cdc_get_line_coding request.
376  *
377  * @param device the usb device object.
378  * @param setup the setup request.
379  *
380  * @return RT_EOK on successful.
381  */
_cdc_get_line_coding(udevice_t device,ureq_t setup)382 static rt_err_t _cdc_get_line_coding(udevice_t device, ureq_t setup)
383 {
384     struct ucdc_line_coding data;
385     rt_uint16_t size;
386 
387     RT_ASSERT(device != RT_NULL);
388     RT_ASSERT(setup != RT_NULL);
389 
390     LOG_D("_cdc_get_line_coding");
391 
392     data.dwDTERate = 115200;
393     data.bCharFormat = 0;
394     data.bDataBits = 8;
395     data.bParityType = 0;
396     size = setup->wLength > 7 ? 7 : setup->wLength;
397 
398     rt_usbd_ep0_write(device, (void*)&data, size);
399 
400     return RT_EOK;
401 }
402 
_cdc_set_line_coding_callback(udevice_t device,rt_size_t size)403 static rt_err_t _cdc_set_line_coding_callback(udevice_t device, rt_size_t size)
404 {
405     LOG_D("_cdc_set_line_coding_callback");
406 
407     dcd_ep0_send_status(device->dcd);
408 
409     return RT_EOK;
410 }
411 
412 /**
413  * This function will handle cdc_set_line_coding request.
414  *
415  * @param device the usb device object.
416  * @param setup the setup request.
417  *
418  * @return RT_EOK on successful.
419  */
_cdc_set_line_coding(udevice_t device,ureq_t setup)420 static rt_err_t _cdc_set_line_coding(udevice_t device, ureq_t setup)
421 {
422     RT_ASSERT(device != RT_NULL);
423     RT_ASSERT(setup != RT_NULL);
424 
425     LOG_D("_cdc_set_line_coding");
426 
427     rt_usbd_ep0_read(device, (void*)&line_coding, sizeof(struct ucdc_line_coding),
428         _cdc_set_line_coding_callback);
429 
430     return RT_EOK;
431 }
432 
433 /**
434  * This function will handle cdc interface request.
435  *
436  * @param device the usb device object.
437  * @param setup the setup request.
438  *
439  * @return RT_EOK on successful.
440  */
_interface_handler(ufunction_t func,ureq_t setup)441 static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
442 {
443     struct vcom *data;
444 
445     RT_ASSERT(func != RT_NULL);
446     RT_ASSERT(func->device != RT_NULL);
447     RT_ASSERT(setup != RT_NULL);
448 
449     data = (struct vcom*)func->user_data;
450 
451     switch(setup->bRequest)
452     {
453     case CDC_SEND_ENCAPSULATED_COMMAND:
454         break;
455     case CDC_GET_ENCAPSULATED_RESPONSE:
456         break;
457     case CDC_SET_COMM_FEATURE:
458         break;
459     case CDC_GET_COMM_FEATURE:
460         break;
461     case CDC_CLEAR_COMM_FEATURE:
462         break;
463     case CDC_SET_LINE_CODING:
464         _cdc_set_line_coding(func->device, setup);
465         break;
466     case CDC_GET_LINE_CODING:
467         _cdc_get_line_coding(func->device, setup);
468         break;
469     case CDC_SET_CONTROL_LINE_STATE:
470         data->connected = (setup->wValue & 0x01) > 0?RT_TRUE:RT_FALSE;
471         LOG_D("vcom state:%d ", data->connected);
472         dcd_ep0_send_status(func->device->dcd);
473         break;
474     case CDC_SEND_BREAK:
475         break;
476     default:
477         rt_kprintf("unknown cdc request\n",setup->request_type);
478         return -RT_ERROR;
479     }
480 
481     return RT_EOK;
482 }
483 
484 /**
485  * This function will run cdc function, it will be called on handle set configuration request.
486  *
487  * @param func the usb function object.
488  *
489  * @return RT_EOK on successful.
490  */
_function_enable(ufunction_t func)491 static rt_err_t _function_enable(ufunction_t func)
492 {
493     struct vcom *data;
494 
495     RT_ASSERT(func != RT_NULL);
496 
497     LOG_D("cdc function enable");
498 
499     _vcom_reset_state(func);
500 
501     data = (struct vcom*)func->user_data;
502     data->ep_out->buffer = rt_malloc(CDC_RX_BUFSIZE);
503     RT_ASSERT(data->ep_out->buffer != RT_NULL);
504 
505 #ifdef RT_USING_SERIAL_V2
506     data->serial.serial_rx = &data->rx_ringbuffer;
507 #endif
508 
509     data->ep_out->request.buffer = data->ep_out->buffer;
510     data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
511 
512     data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
513     rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
514 
515     return RT_EOK;
516 }
517 
518 /**
519  * This function will stop cdc function, it will be called on handle set configuration request.
520  *
521  * @param func the usb function object.
522  *
523  * @return RT_EOK on successful.
524  */
_function_disable(ufunction_t func)525 static rt_err_t _function_disable(ufunction_t func)
526 {
527     struct vcom *data;
528 
529     RT_ASSERT(func != RT_NULL);
530 
531     LOG_D("cdc function disable");
532 
533     _vcom_reset_state(func);
534 
535     data = (struct vcom*)func->user_data;
536     if(data->ep_out->buffer != RT_NULL)
537     {
538         rt_free(data->ep_out->buffer);
539         data->ep_out->buffer = RT_NULL;
540     }
541 
542     return RT_EOK;
543 }
544 
545 static struct ufunction_ops ops =
546 {
547     _function_enable,
548     _function_disable,
549     RT_NULL,
550 };
551 
552 /**
553  * This function will configure cdc descriptor.
554  *
555  * @param comm the communication interface number.
556  * @param data the data interface number.
557  *
558  * @return RT_EOK on successful.
559  */
_cdc_descriptor_config(ucdc_comm_desc_t comm,rt_uint8_t cintf_nr,ucdc_data_desc_t data,rt_uint8_t dintf_nr)560 static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm,
561     rt_uint8_t cintf_nr, ucdc_data_desc_t data, rt_uint8_t dintf_nr)
562 {
563     comm->call_mgmt_desc.data_interface = dintf_nr;
564     comm->union_desc.master_interface = cintf_nr;
565     comm->union_desc.slave_interface0 = dintf_nr;
566 #ifdef RT_USB_DEVICE_COMPOSITE
567     comm->iad_desc.bFirstInterface = cintf_nr;
568 #endif
569 
570     return RT_EOK;
571 }
572 
573 /**
574  * This function will create a cdc function instance.
575  *
576  * @param device the usb device object.
577  *
578  * @return RT_EOK on successful.
579  */
rt_usbd_function_cdc_create(udevice_t device)580 ufunction_t rt_usbd_function_cdc_create(udevice_t device)
581 {
582     ufunction_t func;
583     struct vcom* data;
584     uintf_t intf_comm, intf_data;
585     ualtsetting_t comm_setting, data_setting;
586     ucdc_data_desc_t data_desc;
587     ucdc_comm_desc_t comm_desc;
588 
589     /* parameter check */
590     RT_ASSERT(device != RT_NULL);
591 
592     rt_memset(serno, 0, _SER_NO_LEN + 1);
593     if(vcom_get_stored_serno(serno, _SER_NO_LEN) != RT_EOK)
594     {
595         rt_memset(serno, 0, _SER_NO_LEN + 1);
596         rt_memcpy(serno, _SER_NO, rt_strlen(_SER_NO));
597     }
598 #ifdef RT_USB_DEVICE_COMPOSITE
599     rt_usbd_device_set_interface_string(device, VCOM_INTF_STR_INDEX, _ustring[2]);
600 #else
601     /* set usb device string description */
602     rt_usbd_device_set_string(device, _ustring);
603 #endif
604     /* create a cdc function */
605     func = rt_usbd_function_new(device, &dev_desc, &ops);
606 
607     /* support HS */
608     rt_usbd_device_set_qualifier(device, &dev_qualifier);
609 
610     /* allocate memory for cdc vcom data */
611     data = (struct vcom*)rt_malloc(sizeof(struct vcom));
612     RT_ASSERT(data != RT_NULL);
613     rt_memset(data, 0, sizeof(struct vcom));
614     func->user_data = (void*)data;
615 
616     /* initilize vcom */
617     rt_usb_vcom_init(func);
618 
619     /* create a cdc communication interface and a cdc data interface */
620     intf_comm = rt_usbd_interface_new(device, _interface_handler);
621     intf_data = rt_usbd_interface_new(device, _interface_handler);
622 
623     /* create a communication alternate setting and a data alternate setting */
624     comm_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_comm_descriptor));
625     data_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_data_descriptor));
626 
627     /* config desc in alternate setting */
628     rt_usbd_altsetting_config_descriptor(comm_setting, &_comm_desc,
629                                          (rt_off_t)&((ucdc_comm_desc_t)0)->intf_desc);
630     rt_usbd_altsetting_config_descriptor(data_setting, &_data_desc, 0);
631     /* configure the cdc interface descriptor */
632     _cdc_descriptor_config(comm_setting->desc, intf_comm->intf_num, data_setting->desc, intf_data->intf_num);
633 
634     /* create a command endpoint */
635     comm_desc = (ucdc_comm_desc_t)comm_setting->desc;
636     data->ep_cmd = rt_usbd_endpoint_new(&comm_desc->ep_desc, _ep_cmd_handler);
637 
638     /* add the command endpoint to the cdc communication interface */
639     rt_usbd_altsetting_add_endpoint(comm_setting, data->ep_cmd);
640 
641     /* add the communication alternate setting to the communication interface,
642        then set default setting of the interface */
643     rt_usbd_interface_add_altsetting(intf_comm, comm_setting);
644     rt_usbd_set_altsetting(intf_comm, 0);
645 
646     /* add the communication interface to the cdc function */
647     rt_usbd_function_add_interface(func, intf_comm);
648 
649     /* create a bulk in and a bulk endpoint */
650     data_desc = (ucdc_data_desc_t)data_setting->desc;
651     data->ep_out = rt_usbd_endpoint_new(&data_desc->ep_out_desc, _ep_out_handler);
652     data->ep_in = rt_usbd_endpoint_new(&data_desc->ep_in_desc, _ep_in_handler);
653 
654     /* add the bulk out and bulk in endpoints to the data alternate setting */
655     rt_usbd_altsetting_add_endpoint(data_setting, data->ep_in);
656     rt_usbd_altsetting_add_endpoint(data_setting, data->ep_out);
657 
658     /* add the data alternate setting to the data interface
659             then set default setting of the interface */
660     rt_usbd_interface_add_altsetting(intf_data, data_setting);
661     rt_usbd_set_altsetting(intf_data, 0);
662 
663     /* add the cdc data interface to cdc function */
664     rt_usbd_function_add_interface(func, intf_data);
665 
666     return func;
667 }
668 
669 /**
670 * UART device in RT-Thread
671 */
_vcom_configure(struct rt_serial_device * serial,struct serial_configure * cfg)672 static rt_err_t _vcom_configure(struct rt_serial_device *serial,
673                                 struct serial_configure *cfg)
674 {
675     return RT_EOK;
676 }
677 
_vcom_control(struct rt_serial_device * serial,int cmd,void * arg)678 static rt_err_t _vcom_control(struct rt_serial_device *serial,
679                               int cmd, void *arg)
680 {
681     struct ufunction *func;
682     struct vcom *data;
683 
684     func = (struct ufunction*)serial->parent.user_data;
685     data = (struct vcom*)func->user_data;
686 
687     switch (cmd)
688     {
689     case RT_DEVICE_CTRL_CLR_INT:
690         /* disable rx irq */
691         break;
692     case RT_DEVICE_CTRL_SET_INT:
693         /* enable rx irq */
694         break;
695     case RT_USBD_CLASS_CTRL_CONNECTED:
696         (*(rt_bool_t*)arg) = data->connected;
697         break;
698     }
699 
700     return RT_EOK;
701 }
702 
_vcom_getc(struct rt_serial_device * serial)703 static int _vcom_getc(struct rt_serial_device *serial)
704 {
705     int result;
706     rt_uint8_t ch;
707     rt_base_t level;
708     struct ufunction *func;
709     struct vcom *data;
710 
711     func = (struct ufunction*)serial->parent.user_data;
712     data = (struct vcom*)func->user_data;
713 
714     result = -1;
715 
716     level = rt_hw_interrupt_disable();
717 
718     if(rt_ringbuffer_getchar(&data->rx_ringbuffer, &ch) != 0)
719     {
720         result = ch;
721     }
722 
723     rt_hw_interrupt_enable(level);
724 
725     return result;
726 }
727 
_vcom_rb_block_put(struct vcom * data,const rt_uint8_t * buf,rt_size_t size)728 static rt_ssize_t _vcom_rb_block_put(struct vcom *data, const rt_uint8_t *buf, rt_size_t size)
729 {
730     rt_base_t level;
731     rt_size_t   put_len = 0;
732     rt_size_t   w_ptr = 0;
733     rt_uint32_t res;
734     rt_size_t   remain_size = size;
735 
736     while (remain_size)
737     {
738         level = rt_hw_interrupt_disable();
739         put_len = rt_ringbuffer_put(&data->tx_ringbuffer, (const rt_uint8_t *)&buf[w_ptr], remain_size);
740         rt_hw_interrupt_enable(level);
741         w_ptr += put_len;
742         remain_size -= put_len;
743         if (put_len == 0)
744         {
745             rt_event_recv(&data->tx_event, CDC_TX_HAS_SPACE,
746                     RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
747                     VCOM_TX_TIMEOUT, &res);
748         }
749         else
750         {
751             rt_event_send(&data->tx_event, CDC_TX_HAS_DATE);
752         }
753     }
754 
755     return size;
756 }
757 
758 #ifdef RT_USING_SERIAL_V1
_vcom_tx(struct rt_serial_device * serial,rt_uint8_t * buf,rt_size_t size,int direction)759 static rt_ssize_t _vcom_tx(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction)
760 #else
761 static rt_ssize_t _vcom_tx(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, rt_uint32_t tx_flag)
762 #endif
763 {
764     struct ufunction *func;
765     struct vcom *data;
766     rt_uint32_t send_size = 0;
767     rt_size_t ptr = 0;
768     rt_uint8_t crlf[2] = {'\r', '\n',};
769 
770     func = (struct ufunction*)serial->parent.user_data;
771     data = (struct vcom*)func->user_data;
772 
773     RT_ASSERT(serial != RT_NULL);
774     RT_ASSERT(buf != RT_NULL);
775 
776     LOG_D("%s",__func__);
777 
778     if (data->connected)
779     {
780         if((serial->parent.open_flag & RT_DEVICE_FLAG_STREAM))
781         {
782             while(send_size < size)
783             {
784                 while(ptr < size && buf[ptr] != '\n')
785                 {
786                     ptr++;
787                 }
788                 if(ptr < size)
789                 {
790                     send_size += _vcom_rb_block_put(data, (const rt_uint8_t *)&buf[send_size], ptr - send_size);
791                     _vcom_rb_block_put(data, crlf, 2);
792                     send_size++;
793                     ptr++;
794                 }
795                 else if (ptr == size)
796                 {
797                     send_size += _vcom_rb_block_put(data, (const rt_uint8_t *)&buf[send_size], ptr - send_size);
798                 }
799                 else
800                 {
801                     break;
802                 }
803             }
804         }
805         else
806         {
807             while (send_size < size)
808             {
809                 send_size += _vcom_rb_block_put(data, (rt_uint8_t *)&buf[send_size], size - send_size);
810             }
811         }
812     }
813     else
814     {
815         /* recover dataqueue resources */
816         rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DMADONE);
817     }
818 
819     return size;
820 }
_vcom_putc(struct rt_serial_device * serial,char c)821 static int _vcom_putc(struct rt_serial_device *serial, char c)
822 {
823     rt_base_t level;
824     struct ufunction *func;
825     struct vcom *data;
826 
827     func = (struct ufunction*)serial->parent.user_data;
828     data = (struct vcom*)func->user_data;
829 
830     RT_ASSERT(serial != RT_NULL);
831 
832     if (data->connected)
833     {
834         if(c == '\n' && (serial->parent.open_flag & RT_DEVICE_FLAG_STREAM))
835         {
836             level = rt_hw_interrupt_disable();
837             rt_ringbuffer_putchar_force(&data->tx_ringbuffer, '\r');
838             rt_hw_interrupt_enable(level);
839             rt_event_send(&data->tx_event, CDC_TX_HAS_DATE);
840         }
841         level = rt_hw_interrupt_disable();
842         rt_ringbuffer_putchar_force(&data->tx_ringbuffer, c);
843         rt_hw_interrupt_enable(level);
844         rt_event_send(&data->tx_event, CDC_TX_HAS_DATE);
845     }
846 
847     return 1;
848 }
849 
850 static const struct rt_uart_ops usb_vcom_ops =
851 {
852     _vcom_configure,
853     _vcom_control,
854     _vcom_putc,
855     _vcom_getc,
856     _vcom_tx
857 };
858 
859 /* Vcom Tx Thread */
vcom_tx_thread_entry(void * parameter)860 static void vcom_tx_thread_entry(void* parameter)
861 {
862     rt_base_t level;
863     rt_uint32_t res;
864     struct ufunction *func = (struct ufunction *)parameter;
865     struct vcom *data = (struct vcom*)func->user_data;
866     rt_uint8_t ch[CDC_BULKIN_MAXSIZE];
867 
868     while (1)
869     {
870         if
871         (
872             (rt_event_recv(&data->tx_event, CDC_TX_HAS_DATE,
873                     RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
874                     RT_WAITING_FOREVER, &res) != RT_EOK) ||
875                                  (!(res & CDC_TX_HAS_DATE))
876         )
877         {
878             continue;
879         }
880         if(!(res & CDC_TX_HAS_DATE))
881         {
882             continue;
883         }
884         while(rt_ringbuffer_data_len(&data->tx_ringbuffer))
885         {
886             level = rt_hw_interrupt_disable();
887             res = rt_ringbuffer_get(&data->tx_ringbuffer, ch, CDC_BULKIN_MAXSIZE);
888             rt_hw_interrupt_enable(level);
889 
890             if(!res)
891             {
892                 continue;
893             }
894             if (!data->connected)
895             {
896 #ifdef RT_USING_SERIAL_V1
897 #ifndef VCOM_TX_USE_DMA
898                 if(data->serial.parent.open_flag & RT_DEVICE_FLAG_INT_TX)
899 #else
900                 if(data->serial.parent.open_flag & RT_DEVICE_FLAG_DMA_TX)
901 #endif
902 #endif
903 #ifdef RT_USING_SERIAL_V2
904                 if(data->serial.parent.open_flag & RT_DEVICE_FLAG_TX_BLOCKING)
905 #endif
906                 {
907                 /* drop msg */
908 #ifndef VCOM_TX_USE_DMA
909                     rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DONE);
910 #else
911                     rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DMADONE);
912 #endif
913                 }
914                 continue;
915             }
916             rt_completion_init(&data->wait);
917             data->ep_in->request.buffer     = ch;
918             data->ep_in->request.size       = res;
919 
920             data->ep_in->request.req_type   = UIO_REQUEST_WRITE;
921 
922             rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
923 
924             if (rt_completion_wait(&data->wait, VCOM_TX_TIMEOUT) != RT_EOK)
925             {
926                 LOG_D("vcom tx timeout");
927             }
928 #ifdef RT_USING_SERIAL_V1
929 #ifndef VCOM_TX_USE_DMA
930             if(data->serial.parent.open_flag & RT_DEVICE_FLAG_INT_TX)
931 #else
932             if(data->serial.parent.open_flag & RT_DEVICE_FLAG_DMA_TX)
933 #endif
934 #endif
935 #ifdef RT_USING_SERIAL_V2
936             if(data->serial.parent.open_flag & RT_DEVICE_FLAG_TX_BLOCKING)
937 #endif
938             {
939 #ifndef VCOM_TX_USE_DMA
940                 rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DONE);
941 #else
942                 rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DMADONE);
943 #endif
944                 rt_event_send(&data->tx_event, CDC_TX_HAS_SPACE);
945             }
946         }
947 
948     }
949 }
950 
rt_usb_vcom_init(struct ufunction * func)951 static void rt_usb_vcom_init(struct ufunction *func)
952 {
953     rt_err_t result = RT_EOK;
954     struct serial_configure config;
955     struct vcom *data = (struct vcom*)func->user_data;
956 
957     /* initialize ring buffer */
958     rt_ringbuffer_init(&data->rx_ringbuffer, data->rx_rbp, CDC_RX_BUFSIZE);
959     rt_ringbuffer_init(&data->tx_ringbuffer, data->tx_rbp, CDC_TX_BUFSIZE);
960 
961     rt_event_init(&data->tx_event, "vcom", RT_IPC_FLAG_FIFO);
962 
963     config.baud_rate    = BAUD_RATE_115200;
964     config.data_bits    = DATA_BITS_8;
965     config.stop_bits    = STOP_BITS_1;
966     config.parity       = PARITY_NONE;
967     config.bit_order    = BIT_ORDER_LSB;
968     config.invert       = NRZ_NORMAL;
969 #if defined(RT_USING_SERIAL_V1)
970     config.bufsz        = CDC_RX_BUFSIZE;
971 #elif defined(RT_USING_SERIAL_V2)
972     config.rx_bufsz     = CDC_RX_BUFSIZE;
973     config.tx_bufsz     = CDC_TX_BUFSIZE;
974 #endif
975     data->serial.ops        = &usb_vcom_ops;
976     data->serial.serial_rx  = RT_NULL;
977     data->serial.config     = config;
978 
979     /* register vcom device */
980     rt_hw_serial_register(&data->serial, VCOM_DEVICE,
981 #ifndef VCOM_TX_USE_DMA
982                           RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX,
983 #else
984                           RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_TX,
985 #endif
986                           func);
987 
988     /* init usb device thread */
989     rt_thread_init(&vcom_thread, "vcom",
990                    vcom_tx_thread_entry, func,
991                    vcom_thread_stack, VCOM_TASK_STK_SIZE,
992                    16, 20);
993     result = rt_thread_startup(&vcom_thread);
994     RT_ASSERT(result == RT_EOK);
995 }
996 struct udclass vcom_class =
997 {
998     .rt_usbd_function_create = rt_usbd_function_cdc_create
999 };
1000 
rt_usbd_vcom_class_register(void)1001 int rt_usbd_vcom_class_register(void)
1002 {
1003     rt_usbd_class_register(&vcom_class);
1004     return 0;
1005 }
1006 INIT_PREV_EXPORT(rt_usbd_vcom_class_register);
1007 
1008 #endif
1009