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