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