1 /****************************************************************************
2 * drivers/usbdev/cdcacm.c
3 *
4 * Copyright (C) 2011-2013, 2016-2017 Gregory Nutt. All rights reserved.
5 * Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. All rights reserved.
6 * Author: Gregory Nutt <gnutt@nuttx.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * 3. Neither the name NuttX nor the names of its contributors may be
19 * used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 ****************************************************************************/
36 /****************************************************************************
37 * Notice of Export Control Law
38 * ===============================================
39 * Huawei LiteOS may be subject to applicable export control laws and regulations,
40 * which might include those applicable to Huawei LiteOS of U.S. and the country in
41 * which you are located.
42 * Import, export and usage of Huawei LiteOS in any manner by you shall be in
43 * compliance with such applicable export control laws and regulations.
44 ****************************************************************************/
45
46 /****************************************************************************
47 * Included Files
48 ****************************************************************************/
49
50 #include <los_event.h>
51 #include <fs/fs.h>
52 #include <los_magickey.h>
53 #include <console.h>
54 #include <los_hwi.h>
55 #include <linux/spinlock.h>
56 #include "cdcacm.h"
57 #include "gadget/usbdev.h"
58
59 #ifdef CDCACM_DEBUG
60 #define FALOG(x...) dprintf(x)
61 #else
62 #define FALOG(x...) do{}while(0)
63 #endif
64
65 /****************************************************************************
66 * Pre-processor Definitions
67 ****************************************************************************/
68
69 volatile unsigned int g_usbSerialMask;
70
71 /****************************************************************************
72 * Private Types
73 ****************************************************************************/
74
75 /* Container to support a list of requests */
76
77 struct cdcacm_wrreq_s
78 {
79 struct usbdev_req_s *req; /* The contained request */
80 char *data_buffer; /* Ringbuffer starting address ,this is data buffer yet */
81 char *receive_buffer; /* Record the offset of the received data */
82 char *send_buffer; /* Record the offset of the sent data */
83 };
84
85 struct cdcacm_rdreq_s
86 {
87 struct usbdev_req_s *req; /* The contained request */
88 void *buf; /* The read event buffer */
89 size_t buflen; /* Offset to valid data in the RX request */
90 };
91
92 /* This structure describes the internal state of the driver */
93
94 struct cdcacm_dev_s
95 {
96 struct usbdev_s *usbdev; /* Usb device pointer */
97 uint8_t config; /* Configuration number */
98 uint16_t serialstate; /* State of the DSR/DCD */
99 bool bdisconnect; /* Flags of device action */
100 bool wating; /* if notify request is NULL, try submit(notify, req) again */
101 bool received_char; /* Flags of write event */
102 atomic_t shutdown; /* Device shutdown when transfer data */
103 atomic_t send_char; /* Flag of read event */
104
105 struct usb_cdc_line_state linecoding; /* Buffered line status */
106 struct usbdev_ep_s *epintin; /* Interrupt IN endpoint structure */
107 struct usbdev_ep_s *epbulkin; /* Bulk IN endpoint structure */
108 struct usbdev_ep_s *epbulkout; /* Bulk OUT endpoint structure */
109 bool epintin_enabled; /* Interrupt IN endpoint enable flag */
110 bool epbulkin_enabled; /* Bulk IN endpoint enable flag */
111 bool epbulkout_enabled; /* Bulk OUT endpoint enable flag */
112 struct usbdev_req_s *ctrlreq; /* Allocated control request */
113 struct usbdev_devinfo_s devinfo;
114
115 /* Pre-allocated write request containers. The write requests will
116 * be save here, and used to send requests to EPBULKIN ; Read requests
117 * will be save in the EBULKOUT.
118 */
119
120 struct cdcacm_wrreq_s wrreqs; /* Serial write buffer */
121 struct cdcacm_rdreq_s rdreqs; /* Serial read buffer */
122 EVENT_CB_S read_event; /* Read event */
123 uint8_t ctrl_id; /* Control id of Interface-IDs */
124 uint8_t data_id; /* Data id of Interface-IDs */
125 spinlock_t acm_lock; /* Spinlock */
126 uint32_t read_offset; /* Quick command offset */
127 };
128
129 /* The internal version of the class driver */
130
131 struct cdcacm_driver_s
132 {
133 struct usbdevclass_driver_s drvr;
134 struct cdcacm_dev_s *dev;
135 };
136
137 /* This is what is allocated */
138
139 struct cdcacm_alloc_s
140 {
141 struct cdcacm_dev_s dev;
142 struct cdcacm_driver_s drvr;
143 };
144
145 int usbdev_cdcacm_initialize (FAR struct module *mod, int n, FAR void *arg);
146
147 /* Device driver structure definition */
148
149 static driver_t g_fcdcacm_driver_t =
150 {
151 .name = "fcdcacm",
152 .methods = NULL,
153 .size = sizeof(struct cdcacm_alloc_s)
154 };
155
156 /* Private device class information */
157
158 static devclass_t g_fcdcacm_devclass;
159 DRIVER_MODULE(fcdcacm, simple, g_fcdcacm_driver_t, g_fcdcacm_devclass, usbdev_cdcacm_initialize, 0);
160
161 atomic_t g_magickey = 0;
162 bool g_readpend = false;
163
164 /****************************************************************************
165 * Private Function Prototypes
166 ****************************************************************************/
167
168 /* Transfer helpers *********************************************************/
169
170 static int cdcacm_sndpacket(FAR struct cdcacm_dev_s *priv,
171 FAR struct cdcacm_wrreq_s *wrcontainer);
172 static int cdcacm_recvpacket(FAR struct cdcacm_dev_s *priv,
173 FAR struct cdcacm_rdreq_s *rdcontainer);
174 static int cdcacm_requeue_rdrequest(FAR struct cdcacm_dev_s *priv,
175 FAR struct cdcacm_rdreq_s *rdcontainer);
176 static ssize_t cdcacm_release_rxpending(FAR struct file *filep,
177 FAR char *buffer, size_t buflen);
178
179 /* Request helpers *********************************************************/
180
181 static struct usbdev_req_s *cdcacm_allocreq(FAR struct usbdev_ep_s *ep,
182 uint16_t len);
183 static void cdcacm_freereq(FAR struct usbdev_ep_s *ep,
184 FAR struct usbdev_req_s *req);
185
186 /* Configuration ***********************************************************/
187
188 static void cdcacm_resetconfig(FAR struct cdcacm_dev_s *priv);
189
190 static int cdcacm_epconfigure(FAR struct usbdev_ep_s *ep,
191 enum cdcacm_epdesc_e epid,
192 FAR const usb_endpoint_descriptor_t *ep_desc,
193 FAR struct usbdev_s *dev,
194 bool last);
195
196 static int cdcacm_setconfig(FAR struct cdcacm_dev_s *priv,
197 FAR struct usbdev_s *dev);
198
199 /* Completion event handlers ***********************************************/
200
201 static void cdcacm_rdcomplete(FAR struct usbdev_ep_s *ep,
202 FAR struct usbdev_req_s *req);
203 static void cdcacm_wrcomplete(FAR struct usbdev_ep_s *ep,
204 FAR struct usbdev_req_s *req);
205
206 /* USB class device ********************************************************/
207
208 static int cdcacm_bind(FAR struct usbdevclass_driver_s *driver,
209 FAR struct usbdev_s *dev);
210 static int cdcacm_unbind(FAR struct usbdevclass_driver_s *driver,
211 FAR struct usbdev_s *dev);
212 static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver,
213 FAR struct usbdev_s *dev,
214 FAR const struct usb_device_request *ctrl, uint8_t *dataout,
215 size_t outlen);
216 static int cdcacm_serial_connect(FAR struct cdcacm_dev_s *priv);
217 static int cdcacm_serial_disconnect(FAR struct cdcacm_dev_s *priv);
218 static void cdcacm_disconnect(FAR struct usbdevclass_driver_s *driver,
219 FAR struct usbdev_s *dev);
220 static ssize_t cdcuart_write(FAR struct file *filep,
221 FAR const char *buffer, size_t buflen);
222 static int cdcuart_open(FAR struct file *filep);
223 static int cdcuart_ioctl(FAR struct file *filep,
224 int cmd, unsigned long arg);
225
226 /****************************************************************************
227 * Private Data
228 ****************************************************************************/
229
230 static const struct file_operations_vfs g_vfs_ops =
231 {
232 .open = cdcuart_open,
233 .close = NULL,
234 .read = cdcacm_release_rxpending,
235 .write = cdcuart_write,
236 .seek = NULL,
237 .ioctl = cdcuart_ioctl,
238 .mmap = NULL,
239 #ifndef CONFIG_DISABLE_POLL
240 .poll = NULL,
241 #endif
242 .unlink = NULL,
243 };
244
245 /* USB class device *********************************************************/
246
247 static struct usbdevclass_driverops_s g_driver_ops =
248 {
249 cdcacm_bind, /* bind */
250 cdcacm_unbind, /* unbind */
251 cdcacm_setup, /* setup */
252 cdcacm_disconnect, /* disconnect */
253 NULL, /* suspend */
254 NULL, /* resume */
255 };
256
cdcacm_receive_buf(struct cdcacm_wrreq_s * wrcontainer,FAR const char * buffer,size_t buflen)257 static void cdcacm_receive_buf(struct cdcacm_wrreq_s *wrcontainer,
258 FAR const char *buffer,
259 size_t buflen)
260 {
261 int ret;
262
263 /* Determine if the receive_buffer pointer is offset at the end of the ringbuffer */
264
265 const size_t length = RING_BUFFER_SIZE - (wrcontainer->receive_buffer - wrcontainer->data_buffer);
266 if (length > buflen)
267 {
268 ret = usbd_copy_from_user(wrcontainer->receive_buffer, length,
269 buffer, buflen);
270 if (ret != EOK)
271 {
272 usb_err("Copy from user failed!\r\n");
273 return;
274 }
275 wrcontainer->receive_buffer += buflen;
276 }
277 else
278 {
279 /* The length of console data is bigger than receive_buffer length.
280 * The second parameter "length" is the currently available remaining length of the ringbuffer.
281 */
282
283 ret = usbd_copy_from_user(wrcontainer->receive_buffer, length,
284 buffer, length);
285 if (ret)
286 {
287 usb_err("Copy from user failed!\r\n");
288 return;
289 }
290 buffer += length;
291 ret = usbd_copy_from_user(wrcontainer->data_buffer, RING_BUFFER_SIZE,
292 buffer, buflen - length);
293 if (ret != EOK)
294 {
295 usb_err("Copy from user failed!\r\n");
296 return;
297 }
298 wrcontainer->receive_buffer = wrcontainer->data_buffer + buflen - length;
299 }
300 }
301
cdcuart_write(FAR struct file * filep,FAR const char * buffer,size_t buflen)302 static ssize_t cdcuart_write(FAR struct file *filep,
303 FAR const char *buffer,
304 size_t buflen)
305 {
306 struct cdcacm_dev_s *priv;
307 struct cdcacm_wrreq_s *wrcontainer;
308 int ret;
309 uint32_t flags;
310
311 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
312 priv = (struct cdcacm_dev_s *)drv->priv;
313 if (priv == NULL)
314 {
315 usb_err("file write failed!\r\n");
316 return -ENODEV;
317 }
318
319 wrcontainer = &priv->wrreqs;
320 if (buflen)
321 {
322 cdcacm_receive_buf(wrcontainer, buffer, buflen);
323 }
324 spin_lock_irqsave(&priv->acm_lock, flags);
325 ret = cdcacm_sndpacket(priv, wrcontainer);
326 spin_unlock_irqrestore(&priv->acm_lock, flags);
327 if (ret < 0)
328 {
329 usb_err("file write failed!\r\n");
330 }
331
332 return ret;
333 }
334
335 /****************************************************************************
336 * Name: cdcacm_sndpacket
337 *
338 * Description:
339 * This function obtains write requests, transfers the TX data into the
340 * request, and submits the requests to the USB controller. This
341 * continues until either (1) there are no further packets available, or
342 * (2) there is no further data to send.
343 *
344 ****************************************************************************/
345
cdcacm_sndpacket(FAR struct cdcacm_dev_s * priv,FAR struct cdcacm_wrreq_s * wrcontainer)346 static int cdcacm_sndpacket(FAR struct cdcacm_dev_s *priv,
347 FAR struct cdcacm_wrreq_s *wrcontainer)
348 {
349 FAR struct usbdev_ep_s *ep;
350 FAR struct usbdev_req_s *req;
351 size_t data_size;
352 size_t reqlen;
353 int ret = 0;
354 uint32_t length;
355
356 if (priv == NULL)
357 {
358 return -EINVAL;
359 }
360
361 ep = priv->epbulkin;
362 req = wrcontainer->req;
363
364 #ifdef DWC3_USB_SERIAL
365 reqlen = CONFIG_CDCACM_EPBULKIN_HSSIZE;
366 #else
367 reqlen = CONFIG_CDCACM_EPBULKIN_FSSIZE;
368 #endif
369
370 while (priv->received_char == false)
371 {
372 /* The data need to submit to host */
373
374 data_size = (RING_BUFFER_SIZE + (wrcontainer->receive_buffer - wrcontainer->send_buffer)) % RING_BUFFER_SIZE;
375
376 /* Stitching the beginning and end of the ringbuffer */
377
378 length = RING_BUFFER_SIZE - (wrcontainer->send_buffer - wrcontainer->data_buffer);
379 if (data_size == 0)
380 {
381 break;
382 }
383 if (data_size > MAX_PACKET_SIZE)
384 {
385 data_size = MAX_PACKET_SIZE;
386 }
387 if (length < data_size)
388 {
389 ret = memcpy_s(req->buf, reqlen, wrcontainer->send_buffer, length);
390 if (ret != EOK)
391 {
392 usb_err("Memcpy failed!\r\n");
393 return ret;
394 }
395 ret = memcpy_s(req->buf + length, reqlen, wrcontainer->data_buffer, data_size - length);
396 if (ret != EOK)
397 {
398 usb_err("Memcpy failed!\r\n");
399 return ret;
400 }
401 wrcontainer->send_buffer = wrcontainer->data_buffer + data_size - length;
402 }
403 else
404 {
405 ret = memcpy_s(req->buf, data_size, wrcontainer->send_buffer, data_size);
406 if (ret != EOK)
407 {
408 usb_err("memcpy_s failed!\r\n");
409 return ret;
410 }
411 wrcontainer->send_buffer += data_size;
412 }
413
414 priv->received_char = true;
415
416 /* Fill the request with serial TX data.
417 * Then submit the request to the endpoint.
418 */
419
420 req->len = data_size;
421 req->priv = wrcontainer;
422 ret = EP_SUBMIT(ep, req);
423 if (ret != OK)
424 {
425 usb_err("submit filed!\r\n");
426 priv->received_char = false;
427 }
428 }
429 return ret;
430 }
431
cdcacm_fill_rdrequest(struct cdcacm_dev_s * priv,struct cdcacm_rdreq_s * rdcontainer,size_t buflen)432 static int cdcacm_fill_rdrequest(struct cdcacm_dev_s *priv,
433 struct cdcacm_rdreq_s *rdcontainer,
434 size_t buflen)
435 {
436 struct usbdev_req_s *req;
437 char *req_buf;
438 char *read_buf;
439 int nbytes;
440 int ret;
441
442 req = rdcontainer->req;
443 read_buf = rdcontainer->buf;
444 req_buf = (char *)req->buf;
445
446 /* Copy character into read buffer and retrun the nbytes */
447
448 ret = usbd_copy_to_user(read_buf, req->len, (req_buf + priv->read_offset), buflen);
449 if (ret != EOK)
450 {
451 usb_err("memcpy_s failed, %d\n", ret);
452 return -1;
453 }
454
455 nbytes = (int)buflen;
456 priv->read_offset += buflen;
457
458 if (priv->read_offset < req->xfrd)
459 {
460 ret = (int)LOS_EventWrite(&priv->read_event, USB_SERIAL_READ_EVENT);
461 if (ret != OK)
462 {
463 usb_err("write event failed!\n");
464 return -1;
465 }
466 return nbytes;
467 }
468 atomic_set(&priv->send_char, 0);
469 priv->read_offset = 0;
470 return nbytes;
471 }
472
473 /****************************************************************************
474 * Name: cdcacm_recvpacket
475 *
476 * Description:
477 * A normal completion event was received by the read completion handler
478 * at the interrupt level (with interrupts disabled). This function handles
479 * the USB packet and provides the received data to the uart RX buffer.
480 *
481 * Assumptions:
482 * Called from the USB interrupt handler with interrupts disabled.
483 *
484 ****************************************************************************/
485
cdcacm_recvpacket(FAR struct cdcacm_dev_s * priv,FAR struct cdcacm_rdreq_s * rdcontainer)486 static int cdcacm_recvpacket(FAR struct cdcacm_dev_s *priv,
487 FAR struct cdcacm_rdreq_s *rdcontainer)
488 {
489 FAR struct usbdev_req_s *req;
490 size_t buflen;
491 int nbytes = 0;
492
493 if (priv == NULL || rdcontainer == NULL)
494 {
495 usb_err("device unavailable!\r\n");
496 return -ENODEV;
497 }
498
499 if (atomic_read(&g_magickey) == 1)
500 {
501 buflen = 1;
502 }
503 else
504 {
505 buflen = rdcontainer->buflen;
506 }
507
508 if (g_readpend == true && atomic_read(&g_magickey) == 0)
509 {
510 (void)LOS_EventRead(&priv->read_event, USB_SERIAL_READ_EVENT,
511 LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
512 }
513
514 req = rdcontainer->req;
515 if (req == NULL)
516 {
517 usb_err("illagel request!\r\n");
518 return -ENODEV;
519 }
520
521 /* Process the received data unless this is some unusual condition */
522
523 switch (req->result)
524 {
525 default: /* Some other error occurred */
526 {
527 FALOG("unexpected RX status\r\n");
528 }
529
530 case 0: /* Normal completion */
531 {
532 nbytes = cdcacm_fill_rdrequest(priv, rdcontainer, buflen);
533
534 /* Tell host device is ready for next read event */
535
536 (void)cdcacm_requeue_rdrequest(priv, rdcontainer);
537 }
538 break;
539
540 case -ESHUTDOWN: /* Disconnection */
541 {
542 atomic_set(&priv->shutdown, 1);
543 atomic_set(&priv->send_char, 0);
544 FALOG("serial shutdown!\r\n");
545 }
546 break;
547 }
548 return nbytes;
549 }
550
551 /****************************************************************************
552 * Name: cdcacm_requeue_rdrequest
553 *
554 * Description:
555 * Add any pending RX packets to the upper half serial drivers RX buffer.
556 *
557 ****************************************************************************/
558
cdcacm_requeue_rdrequest(FAR struct cdcacm_dev_s * priv,FAR struct cdcacm_rdreq_s * rdcontainer)559 static int cdcacm_requeue_rdrequest(FAR struct cdcacm_dev_s *priv,
560 FAR struct cdcacm_rdreq_s *rdcontainer)
561 {
562 FAR struct usbdev_req_s *req;
563 FAR struct usbdev_ep_s *ep;
564 uint32_t flags;
565 int ret = 0;
566
567 if (priv == NULL || rdcontainer == NULL)
568 {
569 return -EINVAL;
570 }
571
572 /* Shield shutdown interrupt signal */
573
574 spin_lock_irqsave(&priv->acm_lock, flags);
575 if (atomic_read(&priv->send_char) == 0)
576 {
577
578 atomic_set(&priv->send_char, 1);
579
580 /* Requeue the read request */
581
582 req = rdcontainer->req;
583 ep = priv->epbulkout;
584 req->len = ep->maxpacket;
585 ret = EP_SUBMIT(ep, req);
586 if (ret != OK)
587 {
588 usb_err("epbulkout submit failed!\r\n");
589 atomic_set(&priv->send_char, 0);
590 }
591 }
592 spin_unlock_irqrestore(&priv->acm_lock, flags);
593 return ret;
594 }
595
596 /****************************************************************************
597 * Name: cdcacm_release_rxpending
598 *
599 * Description:
600 * Add any pending RX packets to the upper half serial drivers RX buffer.
601 *
602 ****************************************************************************/
603
cdcacm_release_rxpending(FAR struct file * filep,FAR char * buffer,size_t buflen)604 static ssize_t cdcacm_release_rxpending(FAR struct file *filep, FAR char *buffer, size_t buflen)
605 {
606 FAR struct cdcacm_dev_s *priv;
607 FAR struct cdcacm_rdreq_s *rdcontainer;
608 ssize_t nbytes = 0;
609 int ret = -1;
610
611 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
612 priv = (struct cdcacm_dev_s *)drv->priv;
613 if (priv == NULL)
614 {
615 return -EINVAL;
616 }
617
618 rdcontainer = &priv->rdreqs;
619 rdcontainer->buf = buffer;
620 rdcontainer->buflen = buflen;
621
622 if (g_readpend == true)
623 {
624 /* cdcacm_recvpacket() will return OK if the entire packet was
625 * successful buffered. In the case of RX buffer overrun,
626 * cdcacm_recvpacket() will return a failure (-ENOSPC) and will
627 * set the req->offset field
628 */
629
630 nbytes = (ssize_t)cdcacm_recvpacket(priv, rdcontainer);
631
632 /* The entire packet was processed and may be removed from the
633 * pending RX list and returned to the DCD.
634 */
635
636 /* If we are still connected, refill the USB RX buffer. */
637
638 if (atomic_read(&priv->shutdown) == 0)
639 {
640 ret = cdcacm_requeue_rdrequest(priv, rdcontainer);
641 if (ret < 0)
642 {
643 usb_err("device is not ready for receive next data \r\n");
644 return ret;
645 }
646 }
647 }
648
649 return nbytes;
650 }
651
652 /****************************************************************************
653 * Name: cdcacm_allocreq
654 *
655 * Description:
656 * Allocate a request instance along with its buffer
657 *
658 ****************************************************************************/
659
cdcacm_allocreq(FAR struct usbdev_ep_s * ep,uint16_t len)660 static struct usbdev_req_s *cdcacm_allocreq(FAR struct usbdev_ep_s *ep, uint16_t len)
661 {
662 FAR struct usbdev_req_s *req;
663 req = EP_ALLOCREQ(ep);
664 if (req != NULL)
665 {
666 req->len = len;
667 req->buf = EP_ALLOCBUFFER(ep, len);
668 if (req->buf == NULL)
669 {
670 EP_FREEREQ(ep, req);
671 return NULL;
672 }
673 #ifdef CONFIG_USBDEV_DMA
674 req->dma = (DMA_ADDR_T)VMM_TO_UNCACHED_ADDR((unsigned long)req->buf);
675 #else
676 req->dma = NULL;
677 #endif
678 }
679 return req;
680 }
681
682 /****************************************************************************
683 * Name: cdcacm_freereq
684 *
685 * Description:
686 * Free a request instance along with its buffer
687 *
688 ****************************************************************************/
689
cdcacm_freereq(FAR struct usbdev_ep_s * ep,FAR struct usbdev_req_s * req)690 static void cdcacm_freereq(FAR struct usbdev_ep_s *ep,
691 FAR struct usbdev_req_s *req)
692 {
693 if (ep != NULL && req != NULL)
694 {
695 if (req->buf != NULL)
696 {
697 EP_FREEBUFFER(ep, req->buf);
698 req->buf = NULL;
699 }
700
701 EP_FREEREQ(ep, req);
702 }
703 }
704
705 /****************************************************************************
706 * Name: cdcacm_resetconfig
707 *
708 * Description:
709 * Mark the device as not configured and disable all endpoints.
710 *
711 ****************************************************************************/
712
cdcacm_resetconfig(FAR struct cdcacm_dev_s * priv)713 static void cdcacm_resetconfig(FAR struct cdcacm_dev_s *priv)
714 {
715 if (priv == NULL)
716 {
717 usb_err("Disable ep failed!\r\n");
718 return;
719 }
720
721 /* Disable endpoints. This should force completion of all pending
722 * transfers.
723 */
724
725 if (priv->epintin_enabled == true)
726 {
727 EP_DISABLE(priv->epintin);
728 priv->epintin_enabled = false;
729 }
730
731 if (priv->epbulkin_enabled == true)
732 {
733 EP_DISABLE(priv->epbulkin);
734 priv->epbulkin_enabled = false;
735 }
736
737 if (priv->epbulkout_enabled == true)
738 {
739 EP_DISABLE(priv->epbulkout);
740 priv->epbulkout_enabled = false;
741 }
742 }
743
744 /****************************************************************************
745 * Name: cdcacm_epconfigure
746 *
747 * Description:
748 * Configure one endpoint.
749 *
750 ****************************************************************************/
751
cdcacm_epconfigure(FAR struct usbdev_ep_s * ep,enum cdcacm_epdesc_e epid,FAR const usb_endpoint_descriptor_t * ep_desc,FAR struct usbdev_s * dev,bool last)752 static int cdcacm_epconfigure(FAR struct usbdev_ep_s *ep,
753 enum cdcacm_epdesc_e epid,
754 FAR const usb_endpoint_descriptor_t *ep_desc,
755 FAR struct usbdev_s *dev,
756 bool last)
757 {
758 if (epid != CDCACM_EPINTIN)
759 {
760 usbd_configep_byspeed(dev, (struct usb_endpoint_descriptor *)ep_desc);
761 }
762 return EP_CONFIGURE(ep, ep_desc, last);
763 }
764
765 /****************************************************************************
766 * Name: cdcacm_setconfig
767 *
768 * Description:
769 * Set the device configuration by allocating and configuring endpoints and
770 * by allocating and queue read and write requests.
771 *
772 ****************************************************************************/
773
cdcacm_setconfig(FAR struct cdcacm_dev_s * priv,struct usbdev_s * dev)774 static int cdcacm_setconfig(FAR struct cdcacm_dev_s *priv,
775 struct usbdev_s *dev)
776 {
777 FAR struct cdcacm_rdreq_s *rdcontainer;
778 int ret;
779 uint32_t flags;
780
781 if (priv == NULL)
782 {
783 return -EINVAL;
784 }
785
786 rdcontainer = &priv->rdreqs;
787
788 if (priv->epintin_enabled == true)
789 {
790 EP_DISABLE(priv->epintin);
791 priv->epintin_enabled = false;
792 }
793
794 /* Configure the IN interrupt endpoint */
795
796 ret = cdcacm_epconfigure(priv->epintin, CDCACM_EPINTIN,
797 (const usb_endpoint_descriptor_t *)&g_cdcacm_hs_func_desc.nepd, dev, false);
798 if (ret < 0)
799 {
800 usb_err("config interrupt ep failed!\r\n");
801 goto errout;
802 }
803 priv->epintin_enabled = true;
804 priv->epintin->priv = priv;
805
806 if (priv->epbulkin_enabled == true)
807 {
808 EP_DISABLE(priv->epbulkin);
809 priv->epbulkin_enabled = false;
810 }
811
812 /* Configure the IN bulk endpoint */
813
814 ret = cdcacm_epconfigure(priv->epbulkin, CDCACM_EPBULKIN,
815 (const usb_endpoint_descriptor_t *)&g_cdcacm_hs_func_desc.iepd, dev, false);
816 if (ret < 0)
817 {
818 usb_err("config bulk in ep failed!\r\n");
819 goto errout;
820 }
821 priv->epbulkin_enabled = true;
822 priv->epbulkin->priv = priv;
823
824 if (priv->epbulkout_enabled == true)
825 {
826 EP_DISABLE(priv->epbulkout);
827 priv->epbulkout_enabled = false;
828 }
829
830 /* Configure the OUT bulk endpoint */
831
832 ret = cdcacm_epconfigure(priv->epbulkout, CDCACM_EPBULKOUT,
833 (const usb_endpoint_descriptor_t *)&g_cdcacm_hs_func_desc.oepd, dev, false);
834 if (ret < 0)
835 {
836 usb_err("config bulk out ep failed!\r\n");
837 goto errout;
838 }
839 priv->epbulkout_enabled = true;
840 priv->epbulkout->priv = priv;
841
842 /* Queue read requests in the bulk OUT endpoint */
843
844 ret = cdcacm_requeue_rdrequest(priv, rdcontainer);
845 if (ret != OK)
846 {
847 goto errout;
848 }
849
850 /* We are successfully configured.
851 * Tell host that device is available
852 * and ready for data transfer.
853 */
854
855 spin_lock_irqsave(&priv->acm_lock, flags);
856 ret = cdcacm_serial_connect(priv);
857 if (ret < 0)
858 {
859 usb_err("cdcacm connect failed!\r\n");
860 spin_unlock_irqrestore(&priv->acm_lock, flags);
861 goto errout;
862 }
863 atomic_set(&priv->shutdown, 0);
864 priv->bdisconnect = false;
865
866 /* tell console dprintf to virtrue serial */
867
868 g_usbSerialMask = 1;
869 spin_unlock_irqrestore(&priv->acm_lock, flags);
870
871 return OK;
872
873 errout:
874 cdcacm_resetconfig(priv);
875 return ret;
876 }
877
878 /****************************************************************************
879 * Name: cdcacm_rdcomplete
880 *
881 * Description:
882 * Handle completion of read request on the bulk OUT endpoint. This
883 * is handled like the receipt of serial data on the "UART"
884 *
885 ****************************************************************************/
886
cdcacm_rdcomplete(FAR struct usbdev_ep_s * ep,FAR struct usbdev_req_s * req)887 static void cdcacm_rdcomplete(FAR struct usbdev_ep_s *ep,
888 FAR struct usbdev_req_s *req)
889 {
890 FAR struct cdcacm_rdreq_s *rdcontainer;
891 FAR struct cdcacm_dev_s *priv;
892 uint32_t ret;
893 PRINT_ERR("%s req->xfrd:%x\r\n", __FUNCTION__, req->xfrd);
894 PRINT_ERR("%s req->xfrd:%x\r\n", __FUNCTION__, req->result);
895
896 if (ep == NULL || ep->priv == NULL || req == NULL)
897 {
898 usb_err("illegal request or ep\r\n");
899 return;
900 }
901
902 /* Extract references to private data */
903
904 priv = (struct cdcacm_dev_s *)ep->priv;
905
906 rdcontainer = &priv->rdreqs;
907
908 /* Save private data of reqd request */
909
910 rdcontainer->req = req;
911 rdcontainer->req->len = req->len;
912
913 /* Magic key */
914
915 if (CheckMagicKey(*(char *)req->buf, CONSOLE_SERIAL))
916 {
917 atomic_set(&g_magickey, 1);
918 (void)cdcacm_recvpacket(priv, rdcontainer);
919 (void)cdcacm_requeue_rdrequest(priv, rdcontainer);
920 atomic_set(&g_magickey, 0);
921 return;
922 }
923
924 ret = LOS_EventWrite(&priv->read_event, USB_SERIAL_READ_EVENT);
925 if (ret != OK)
926 {
927 usb_err("write event failed!\r\n");
928 }
929 }
930
931 /****************************************************************************
932 * Name: cdcacm_wrcomplete
933 *
934 * Description:
935 * Handle completion of write request. This function probably executes
936 * in the context of an interrupt handler.
937 *
938 ****************************************************************************/
939
cdcacm_wrcomplete(FAR struct usbdev_ep_s * ep,FAR struct usbdev_req_s * req)940 static void cdcacm_wrcomplete(FAR struct usbdev_ep_s *ep,
941 FAR struct usbdev_req_s *req)
942 {
943 FAR struct cdcacm_dev_s *priv;
944 FAR struct cdcacm_wrreq_s *wrcontainer;
945
946 /* Extract references to our private data */
947 PRINT_ERR("%s req->xfrd:%x\r\n", __FUNCTION__, req->xfrd);
948 PRINT_ERR("%s req->xfrd:%x\r\n", __FUNCTION__, req->result);
949
950 priv = (struct cdcacm_dev_s *)ep->priv;
951 if (priv == NULL)
952 {
953 usb_err("device is unavailable!\r\n");
954 return;
955 }
956 spin_lock(&priv->acm_lock);
957
958 /* protect for received_char */
959
960 wrcontainer = (struct cdcacm_wrreq_s *)req->priv;
961
962 priv->received_char = false;
963
964 /* Send the next packet unless this was some unusual termination
965 * condition
966 */
967
968 switch (req->result)
969 {
970 default: /* Some other error occurred */
971 {
972 FALOG("unexpected RX status\r\n");
973 }
974
975 case 0: /* Normal completion */
976 {
977 (void)cdcacm_sndpacket(priv, wrcontainer);
978 }
979 break;
980
981 case -ESHUTDOWN: /* Disconnection */
982 {
983 FALOG("usb device disconnect!");
984 }
985 break;
986 }
987 spin_unlock(&priv->acm_lock);
988 }
989
cdcacm_notify_complete(FAR struct usbdev_ep_s * ep,FAR struct usbdev_req_s * usbd_req)990 static void cdcacm_notify_complete(FAR struct usbdev_ep_s *ep,
991 FAR struct usbdev_req_s *usbd_req)
992 {
993 FAR struct cdcacm_dev_s *priv;
994 bool flag = false;
995 int ret;
996 uint32_t flags;
997 PRINT_ERR("%s req->xfrd:%x\r\n", __FUNCTION__, usbd_req->xfrd);
998 PRINT_ERR("%s req->xfrd:%x\r\n", __FUNCTION__, usbd_req->result);
999
1000 (void)ep;
1001 priv = usbd_req->priv;
1002 if (priv == NULL)
1003 {
1004 usb_err("No device!\r\n");
1005 return;
1006 }
1007
1008 spin_lock_irqsave(&priv->acm_lock, flags);
1009 if (usbd_req->result != -ESHUTDOWN)
1010 {
1011 flag = priv->wating;
1012 }
1013
1014 if (flag == true)
1015 {
1016 ret = cdcacm_serial_connect(priv);
1017 if (ret < 0)
1018 {
1019 usb_err("cdcacm connect failed!\r\n");
1020 }
1021 }
1022 spin_unlock_irqrestore(&priv->acm_lock, flags);
1023 }
1024
1025 /****************************************************************************
1026 * USB Class Driver Methods
1027 ****************************************************************************/
1028
1029 /****************************************************************************
1030 * Name: cdcacm_bind
1031 *
1032 * Description:
1033 * Invoked when the driver is bound to a USB device driver
1034 *
1035 ****************************************************************************/
1036
cdcacm_bind(FAR struct usbdevclass_driver_s * driver,FAR struct usbdev_s * dev)1037 static int cdcacm_bind(FAR struct usbdevclass_driver_s *driver,
1038 FAR struct usbdev_s *dev)
1039 {
1040 FAR struct cdcacm_dev_s *priv;
1041 FAR struct composite_devobj_s *devobj;
1042 FAR struct usbdev_devinfo_s *devinfo;
1043 FAR struct cdcacm_wrreq_s *wrcontainer;
1044 FAR struct cdcacm_rdreq_s *rdcontainer;
1045 FAR struct composite_dev_s *cdev;
1046 uint16_t reqlen;
1047 int ret;
1048
1049 if (driver == NULL || dev == NULL)
1050 {
1051 usb_err("Bind failed!\r\n");
1052 return -ENODEV;
1053 }
1054
1055 priv = ((struct cdcacm_driver_s *)driver)->dev;
1056
1057 /* Bind the structures */
1058
1059 priv->usbdev = dev;
1060 priv->bdisconnect = true;
1061 atomic_set(&priv->shutdown, 0);
1062
1063 /* Save the reference to our private data structure in EP0 so that it
1064 * can be recovered in ep0 completion events (Unless we are part of
1065 * a composite device and, in that case, the composite device owns
1066 * EP0).
1067 */
1068
1069 cdev = dev->ep0->priv;
1070 (VOID)LOS_EventInit(&priv->read_event);
1071 spin_lock_init(&priv->acm_lock);
1072
1073 /* Register a character driver inode the pseudo file system */
1074
1075 ret = register_driver(CDCACM_DEVNAME_FORMAT, &g_vfs_ops, 0666, priv);
1076 if (ret != 0)
1077 {
1078 usb_err("chardev register failed!");
1079 return ret;
1080 }
1081
1082 /* Preallocate control request */
1083
1084 priv->ctrlreq = cdev->ctrlreq;
1085 if (priv->ctrlreq == NULL)
1086 {
1087 ret = -EINVAL;
1088 goto errout;
1089 }
1090
1091 devobj = usbclass_devobj_get(cdev, DEV_SERIAL);
1092 if (devobj == NULL)
1093 {
1094 ret = -EINVAL;
1095 goto errout;
1096 }
1097 devinfo = &devobj->compdesc.devinfo;
1098
1099 priv->ctrl_id = (uint8_t)devinfo->ifnobase;
1100 priv->data_id = (uint8_t)devinfo->ifnobase + 1;
1101
1102 /* Pre-allocate all endpoints... the endpoints will not be functional
1103 * until the SET CONFIGURATION request is processed in cdcacm_setconfig.
1104 * This is done here because there may be calls to kmm_malloc and the SET
1105 * CONFIGURATION processing probably occurrs within interrupt handling
1106 * logic where kmm_malloc calls will fail.
1107 */
1108
1109 /* Pre-allocate the IN interrupt endpoint */
1110
1111 priv->epintin = DEV_ALLOCEP(dev, g_cdcacm_hs_func_desc.nepd.bEndpointAddress, &g_cdcacm_hs_func_desc.nepd);
1112 if (!priv->epintin)
1113 {
1114 usb_err("alloc epintin fail!");
1115 ret = -ENODEV;
1116 goto errout;
1117 }
1118 CDCACM_MKEPINTIN(devinfo) = priv->epintin->eplog;
1119 priv->epintin->priv = priv;
1120 priv->epintin->handle_req = cdcacm_allocreq(priv->epintin,
1121 sizeof(struct usb_cdc_notification) + sizeof(priv->serialstate));
1122 if (priv->epintin->handle_req == NULL)
1123 {
1124 ret = -ENOMEM;
1125 goto errout;
1126 }
1127 priv->epintin->handle_req->callback = cdcacm_notify_complete;
1128
1129 /* Pre-allocate the IN bulk endpoint */
1130
1131 priv->epbulkin = DEV_ALLOCEP(dev, g_cdcacm_hs_func_desc.iepd.bEndpointAddress, &g_cdcacm_hs_func_desc.iepd);
1132 if (!priv->epbulkin)
1133 {
1134 usb_err("alloc epbulkin fail!");
1135 ret = -ENODEV;
1136 goto errout;
1137 }
1138 CDCACM_MKEPBULKIN(devinfo) = priv->epbulkin->eplog;
1139 priv->epbulkin->priv = priv;
1140
1141 /* Pre-allocate the OUT bulk endpoint */
1142
1143 priv->epbulkout = DEV_ALLOCEP(dev, g_cdcacm_hs_func_desc.oepd.bEndpointAddress, &g_cdcacm_hs_func_desc.oepd);
1144 if (!priv->epbulkout)
1145 {
1146 usb_err("alloc epbulkout fail!");
1147 ret = -ENODEV;
1148 goto errout;
1149 }
1150 CDCACM_MKEPBULKOUT(devinfo) = priv->epbulkout->eplog;
1151 priv->epbulkout->priv = priv;
1152
1153 /* Pre-allocate read requests. The buffer size is one full packet. */
1154
1155 #ifdef DWC3_USB_SERIAL
1156 reqlen = CONFIG_CDCACM_EPBULKOUT_HSSIZE;
1157 #else
1158 reqlen = CONFIG_CDCACM_EPBULKOUT_FSSIZE;
1159 #endif
1160
1161 priv->epbulkout->maxpacket = reqlen;
1162
1163 /* initialize read req buffer */
1164
1165 rdcontainer = &priv->rdreqs;
1166
1167 /* alloc req and req->buf */
1168
1169 rdcontainer->req = cdcacm_allocreq(priv->epbulkout, reqlen);
1170 if (rdcontainer->req == NULL)
1171 {
1172 usb_err("allocreq failed!\r\n");
1173 ret = -ENOMEM;
1174 goto errout;
1175 }
1176
1177 rdcontainer->buflen = reqlen;
1178 rdcontainer->req->priv = rdcontainer;
1179 rdcontainer->req->callback = cdcacm_rdcomplete;
1180 priv->epbulkout->handle_req = rdcontainer->req;
1181
1182 /* Pre-allocate write request containers and put in a free list. The
1183 * buffer size should be larger than a full build IN packet. Otherwise,
1184 * we will send a bogus null packet at the end of each packet.
1185 *
1186 * Pick the larger of the max packet size and the configured request size.
1187 *
1188 * NOTE: These write requests are sized for the bulk IN endpoint but are
1189 * shared with interrupt IN endpoint which does not need a large buffer.
1190 */
1191
1192 #ifdef DWC3_USB_SERIAL
1193 reqlen = CONFIG_CDCACM_EPBULKIN_HSSIZE;
1194 #else
1195 reqlen = CONFIG_CDCACM_EPBULKIN_FSSIZE;
1196 #endif
1197
1198 wrcontainer = &priv->wrreqs;
1199 wrcontainer->req = cdcacm_allocreq(priv->epbulkin, reqlen);
1200 if (wrcontainer->req == NULL)
1201 {
1202 ret = -ENOMEM;
1203 goto errout;
1204 }
1205 wrcontainer->req->priv = wrcontainer;
1206 wrcontainer->req->callback = cdcacm_wrcomplete;
1207 priv->epbulkin->handle_req = wrcontainer->req;
1208
1209 /* Alloc mem for ringbuffer */
1210
1211 wrcontainer->data_buffer = malloc(RING_BUFFER_SIZE);
1212 if (wrcontainer->data_buffer == NULL)
1213 {
1214 ret = -ENOMEM;
1215 goto errout;
1216 }
1217 (void)memset_s(wrcontainer->data_buffer, RING_BUFFER_SIZE, 0, RING_BUFFER_SIZE);
1218 wrcontainer->receive_buffer = wrcontainer->data_buffer;
1219 wrcontainer->send_buffer = wrcontainer->data_buffer;
1220
1221 return OK;
1222
1223 errout:
1224 (void)cdcacm_unbind(driver, dev);
1225 return ret;
1226 }
1227
1228 /****************************************************************************
1229 * Name: cdcacm_unbind
1230 *
1231 * Description:
1232 * Invoked when the driver is unbound from a USB device driver
1233 *
1234 ****************************************************************************/
1235
cdcacm_unbind(FAR struct usbdevclass_driver_s * driver,FAR struct usbdev_s * dev)1236 static int cdcacm_unbind(FAR struct usbdevclass_driver_s *driver,
1237 FAR struct usbdev_s *dev)
1238 {
1239 FAR struct cdcacm_dev_s *priv;
1240 FAR struct cdcacm_wrreq_s *wrcontainer;
1241 FAR struct cdcacm_rdreq_s *rdcontainer;
1242 int ret = -EINVAL;
1243
1244 if (driver == NULL || dev == NULL)
1245 {
1246 usb_err("no device!\r\n");
1247 return -EINVAL;
1248 }
1249
1250 /* Extract reference to private data */
1251
1252 priv = ((FAR struct cdcacm_driver_s *)driver)->dev;
1253
1254 /* Make sure that we are not already unbound */
1255
1256 if (priv != NULL)
1257 {
1258 /* Close device */
1259
1260 cdcacm_disconnect(driver, dev);
1261
1262 if (priv->epintin->handle_req != NULL)
1263 {
1264 cdcacm_freereq(priv->epintin, priv->epintin->handle_req);
1265 priv->epintin->handle_req = NULL;
1266 }
1267
1268 /* Free the interrupt IN endpoint */
1269
1270 if (priv->epintin)
1271 {
1272 DEV_FREEEP(dev, priv->epintin);
1273 priv->epintin = NULL;
1274 }
1275
1276 /* Free pre-allocated read requests (which should all have
1277 * been returned to the free list at this time -- we don't check)
1278 */
1279
1280 rdcontainer = &priv->rdreqs;
1281 if (rdcontainer->req != NULL)
1282 {
1283 cdcacm_freereq(priv->epbulkout, rdcontainer->req);
1284 rdcontainer->req = NULL;
1285 }
1286
1287 /* Free the bulk OUT endpoint */
1288
1289 if (priv->epbulkout)
1290 {
1291 DEV_FREEEP(dev, priv->epbulkout);
1292 priv->epbulkout = NULL;
1293 }
1294
1295 /* Free write requests that are not in use (which should be all
1296 * of them)
1297 */
1298
1299 wrcontainer = &priv->wrreqs;
1300 if (wrcontainer->req != NULL)
1301 {
1302 cdcacm_freereq(priv->epbulkin, wrcontainer->req);
1303 wrcontainer->req = NULL;
1304 }
1305
1306 /* Free the bulk IN endpoint */
1307
1308 if (priv->epbulkin)
1309 {
1310 DEV_FREEEP(dev, priv->epbulkin);
1311 priv->epbulkin = NULL;
1312 }
1313
1314 /* Unregister driver */
1315
1316 ret = unregister_driver(CDCACM_DEVNAME_FORMAT);
1317 if (ret != OK)
1318 {
1319 PRINT_ERR("%s chardev unregister failed!\n", __FUNCTION__);
1320 return ret;
1321 }
1322
1323 /* Destroy read event */
1324
1325 (void)LOS_EventDestroy(&priv->read_event);
1326
1327 /* Free ringbuffer */
1328
1329 if (wrcontainer->data_buffer != NULL)
1330 {
1331 free(wrcontainer->data_buffer);
1332 wrcontainer->data_buffer = NULL;
1333 }
1334 }
1335
1336 return ret;
1337 }
1338
cdcacm_set_line_complete(FAR struct usbdev_ep_s * ep,FAR struct usbdev_req_s * req)1339 static void cdcacm_set_line_complete(FAR struct usbdev_ep_s *ep,
1340 FAR struct usbdev_req_s *req)
1341 {
1342 FAR struct cdcacm_dev_s *priv;
1343 int ret;
1344
1345 (void)ep;
1346 priv = req->priv;
1347 if (req->result != 0)
1348 {
1349 return;
1350 }
1351
1352 g_usbSerialMask = 1;
1353 ret = memcpy_s(&priv->linecoding, sizeof(struct usb_cdc_line_state), req->buf, SIZEOF_CDC_LINECODING);
1354 if (ret != EOK)
1355 {
1356 usb_err("Memcpy failed!\r\n");
1357 return;
1358 }
1359 }
1360
1361 /****************************************************************************
1362 * Name: cdcacm_setup
1363 *
1364 * Description:
1365 * Invoked for ep0 control requests. This function probably executes
1366 * in the context of an interrupt handler.
1367 *
1368 ****************************************************************************/
1369
cdcacm_setup(FAR struct usbdevclass_driver_s * driver,FAR struct usbdev_s * dev,FAR const struct usb_device_request * ctrl,uint8_t * dataout,size_t outlen)1370 static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver,
1371 FAR struct usbdev_s *dev,
1372 FAR const struct usb_device_request *ctrl,
1373 uint8_t *dataout, size_t outlen)
1374 {
1375 FAR struct cdcacm_dev_s *priv;
1376 FAR struct usbdev_req_s *req;
1377 uint16_t value;
1378 uint16_t index;
1379 uint16_t len;
1380 int val = -EOPNOTSUPP;
1381 int ret;
1382
1383 (void)dataout;
1384 (void)outlen;
1385 if (driver == NULL || dev == NULL || ctrl == NULL)
1386 {
1387 return -EINVAL;
1388 }
1389
1390 /* Extract reference to private data */
1391
1392 priv = ((struct cdcacm_driver_s *)driver)->dev;
1393 if (priv == NULL)
1394 {
1395 return -ENODEV;
1396 }
1397
1398 req = priv->ctrlreq;
1399
1400 /* Extract the little-endian 16-bit values to host order */
1401
1402 value = UGETW(ctrl->wValue);
1403 index = UGETW(ctrl->wIndex);
1404 len = UGETW(ctrl->wLength);
1405
1406 FALOG("type=%02x req=%02x value=%04x index=%04x len=%04x\n",
1407 ctrl->bmRequestType, ctrl->bRequest, value, index, len);
1408 if (UT_GET_TYPE(ctrl->bmRequestType) == UT_STANDARD)
1409 {
1410 /**********************************************************************
1411 * Standard Requests
1412 **********************************************************************/
1413
1414 switch (ctrl->bRequest)
1415 {
1416 case USB_REQ_SET_CONFIGURATION:
1417 if (ctrl->bmRequestType == 0)
1418 {
1419 val = cdcacm_setconfig(priv, dev);
1420 return val;
1421 }
1422 break;
1423
1424 case USB_REQ_SET_INTERFACE:
1425 break;
1426
1427 /* If the serial device is used in as part of a composite device,
1428 * then the overall composite class configuration is managed by logic
1429 * in the composite device implementation.
1430 */
1431
1432 default:
1433 break;
1434 }
1435 }
1436 else if (UT_GET_TYPE(ctrl->bmRequestType) == UT_CLASS)
1437 {
1438 switch (ctrl->bRequest)
1439 {
1440 /* ACM_GET_LINE_CODING requests current DTE rate, stop-bits, parity,
1441 * and number-of-character bits. (Optional)
1442 */
1443
1444 case ACM_GET_LINE_CODING:
1445 if (ctrl->bmRequestType == (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) &&
1446 index == priv->devinfo.ifnobase) /* bmRequestType = 0xa1, bRequest = 0x21 */
1447 {
1448 if(index != priv->ctrl_id)
1449 {
1450 goto failed_out;
1451 }
1452
1453 /* Return the current line status from the private data structure. */
1454
1455 val = (int)min_t(unsigned, len, sizeof(struct usb_cdc_line_state));
1456 ret = memcpy_s(req->buf, USB_COMP_EP0_BUFSIZ, &priv->linecoding, (uint32_t)val);
1457 if (ret != EOK)
1458 {
1459 usb_err("memcpy_s fail, ret:%d\n", ret);
1460 return ret;
1461 }
1462 }
1463 else
1464 {
1465 goto failed_out;
1466 }
1467 break;
1468
1469 /* ACM_SET_LINE_CODING configures DTE rate, stop-bits, parity, and
1470 * number-of-character bits. (Optional)
1471 */
1472
1473 case ACM_SET_LINE_CODING:
1474 if (ctrl->bmRequestType == (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) &&
1475 len == SIZEOF_CDC_LINECODING && /* dataout && len == outlen && */
1476 index == priv->devinfo.ifnobase) /* bmRequestType = 0x21, bRequest = 0x20 */
1477 {
1478 if (len != sizeof(struct usb_cdc_line_state) ||
1479 index != priv->ctrl_id)
1480 {
1481 goto failed_out;
1482 }
1483
1484 /* Save the new line coding in the private data structure.
1485 * NOTE: that this is conditional now because not all device
1486 * controller drivers supported provision of EP0 OUT data
1487 * with the setup command.
1488 */
1489
1490 req->priv = priv;
1491 req->callback = cdcacm_set_line_complete;
1492
1493 /* Respond with a zero length packet */
1494
1495 val = len;
1496 }
1497 else
1498 {
1499 goto failed_out;
1500 }
1501 break;
1502
1503 /* ACM_SET_CTRL_LINE_STATE: RS-232 signal used to tell the DCE
1504 * device the DTE device is now present. (Optional)
1505 */
1506
1507 case ACM_SET_CTRL_LINE_STATE:
1508 if (ctrl->bmRequestType == (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) &&
1509 index == priv->devinfo.ifnobase) /* bmRequestType = 0x21, bRequest = 0x22 */
1510 {
1511 if(index != priv->ctrl_id)
1512 {
1513 goto failed_out;
1514 }
1515
1516 /* Save the control line state in the private data
1517 * structure. Only bits 0 and 1 have meaning. Respond with a zero length packet.
1518 */
1519
1520 val = 0;
1521 }
1522 else
1523 {
1524 goto failed_out;
1525 }
1526 break;
1527 default:
1528 break;
1529 failed_out:
1530 usb_err("type=%02x req=%02x value=%04x index=%04x len=%04x\n",
1531 ctrl->bmRequestType, ctrl->bRequest, value, index, len);
1532 }
1533 }
1534
1535 if (val >= 0)
1536 {
1537 /* Configure the response */
1538
1539 req->len = (uint32_t)val;
1540 val = EP_SUBMIT(dev->ep0, req);
1541 if (val != OK)
1542 {
1543 usb_err("acm response on err %d\n", val);
1544 req->result = OK;
1545 }
1546 }
1547 return val;
1548 }
1549
cdcacm_serial_connect_state(const struct cdcacm_dev_s * priv,struct usbdev_req_s * req,const void * data,uint16_t value,uint32_t len)1550 static uint32_t cdcacm_serial_connect_state(const struct cdcacm_dev_s *priv,
1551 struct usbdev_req_s *req,
1552 const void *data,
1553 uint16_t value,
1554 uint32_t len)
1555 {
1556 struct usb_cdc_notification *state_buf;
1557 void *buf;
1558 uint32_t length;
1559 uint32_t ret;
1560
1561 state_buf = (struct usb_cdc_notification *)req->buf;
1562
1563 /* bmRequestType = 0xa1 , bNotification = 0x20 */
1564
1565 state_buf->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
1566 state_buf->bNotification = ACM_NOTIFY_SERIAL_STATE;
1567 USETW(state_buf->wValue, value);
1568 USETW(state_buf->wIndex, priv->ctrl_id);
1569 USETW(state_buf->wLength, len);
1570 length = sizeof(struct usb_cdc_notification) + len;
1571
1572 buf = state_buf + STAE_BUFFER_OFFSET;
1573 ret = (uint32_t)memcpy_s(buf, sizeof(struct usb_cdc_notification), data, len);
1574 if (ret != EOK)
1575 {
1576 usb_err("memcpy failed!\r\n");
1577 return ret;
1578 }
1579
1580 return length;
1581 }
1582
cdcacm_serial_connect(FAR struct cdcacm_dev_s * priv)1583 static int cdcacm_serial_connect(FAR struct cdcacm_dev_s *priv)
1584 {
1585 FAR struct usbdev_ep_s *ep;
1586 FAR struct usbdev_req_s *req;
1587 uint32_t length;
1588 int ret;
1589
1590 if (priv == NULL)
1591 {
1592 usb_err("no device can be found!\r\n");
1593 return -ENODEV;
1594 }
1595
1596 /* DCD:online; DSR:ready for data transhfer */
1597
1598 priv->serialstate |= CDCACM_UART_DSR | CDCACM_UART_DCD;
1599 ep = priv->epintin;
1600 if (ep == NULL)
1601 {
1602 return -EINVAL;
1603 }
1604 req = ep->handle_req;
1605 if (req == NULL)
1606 {
1607 priv->wating = true;
1608 return 0;
1609 }
1610
1611 /* Status of serial for connect and disconnect */
1612
1613 length = cdcacm_serial_connect_state(priv, req, &priv->serialstate, 0, sizeof(priv->serialstate));
1614
1615 req->priv = priv;
1616 req->len = length;
1617
1618 /* submit serial notify state */
1619
1620 ret = EP_SUBMIT(ep, req);
1621 if (ret != OK)
1622 {
1623 usb_err("can not send notify data to host\r\n");
1624 }
1625 priv->wating = false;
1626 return ret;
1627 }
1628
cdcacm_serial_disconnect(FAR struct cdcacm_dev_s * priv)1629 static int cdcacm_serial_disconnect(FAR struct cdcacm_dev_s *priv)
1630 {
1631 FAR struct usbdev_req_s *req;
1632 FAR struct usbdev_ep_s *ep;
1633 uint32_t length;
1634 int ret;
1635
1636 g_usbSerialMask = 0;
1637 priv->received_char = false;
1638
1639 /* Offline, close data transfer */
1640
1641 priv->serialstate &= ~CDC_UART_CONSISTENT;
1642 ep = priv->epintin;
1643 req = ep->handle_req;
1644
1645 /* Status of serial for connect and disconnect */
1646
1647 length = cdcacm_serial_connect_state(priv, req, &priv->serialstate, 0, sizeof(priv->serialstate));
1648
1649 req->len = length;
1650
1651 /* Submit serial notify state */
1652
1653 ret = EP_SUBMIT(ep, req);
1654 if (ret != OK)
1655 {
1656 usb_err("Can not send notify data to host!\r\n");
1657 }
1658
1659 return ret;
1660 }
1661
cdcuart_open(FAR struct file * filep)1662 static int cdcuart_open(FAR struct file *filep)
1663 {
1664 /* do nothing */
1665
1666 (void)filep;
1667 return 0;
1668 }
1669
1670 /****************************************************************************
1671 * Name: cdcuart_ioctl
1672 *
1673 * Description:
1674 * All ioctl calls will be routed through this method
1675 *
1676 ****************************************************************************/
1677
cdcuart_ioctl(FAR struct file * filep,int cmd,unsigned long arg)1678 static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
1679 {
1680 //FAR struct inode *inode;
1681 FAR struct cdcacm_dev_s *priv;
1682
1683 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
1684 priv = (struct cdcacm_dev_s *)drv->priv;
1685 if (priv == NULL)
1686 {
1687 usb_err("No Device!\r\n");
1688 return -ENODEV;
1689 }
1690 switch (cmd)
1691 {
1692 /* CAICO_REGISTERCB
1693 * Register a callback for serial event notification. Argument:
1694 * cdcacm_callback_t. See cdcacm_callback_t type definition below.
1695 * NOTE: The callback will most likely invoked at the interrupt level.
1696 * The called back function should, therefore, limit its operations to
1697 * invoking some kind of IPC to handle the serial event in some normal
1698 * task environment.
1699 */
1700
1701 case CONSOLE_CMD_RD_BLOCK_SERIAL:
1702 {
1703 if (arg != 0)
1704 {
1705 g_readpend = true;
1706 }
1707 else
1708 {
1709 g_readpend = false;
1710 (void)LOS_EventWrite(&priv->read_event, USB_SERIAL_READ_EVENT);
1711 }
1712 }
1713 break;
1714
1715 default:
1716 usb_err("Unknown CMD!\r\n");
1717 break;
1718 }
1719
1720 return OK;
1721 }
1722
1723 /****************************************************************************
1724 * Name: cdcacm_disconnect
1725 *
1726 * Description:
1727 * Invoked after all transfers have been stopped, when the host is
1728 * disconnected. This function is probably called from the context of an
1729 * interrupt handler.
1730 *
1731 ****************************************************************************/
1732
cdcacm_disconnect(FAR struct usbdevclass_driver_s * driver,FAR struct usbdev_s * dev)1733 static void cdcacm_disconnect(FAR struct usbdevclass_driver_s *driver,
1734 FAR struct usbdev_s *dev)
1735 {
1736 FAR struct cdcacm_dev_s *priv;
1737
1738 (void)dev;
1739 if (driver == NULL)
1740 {
1741 usb_err("driver pointer is NULL!\r\n");
1742 return;
1743 }
1744
1745 priv = ((FAR struct cdcacm_driver_s *)driver)->dev;
1746 if (priv == NULL)
1747 {
1748 usb_err("No device!\r\n");
1749 return;
1750 }
1751
1752 if (priv->bdisconnect == false)
1753 {
1754 (void)cdcacm_serial_disconnect(priv);
1755 cdcacm_resetconfig(priv);
1756 priv->bdisconnect = true;
1757 }
1758 }
1759
1760 /****************************************************************************
1761 * Public Functions
1762 ****************************************************************************/
1763
userial_mask_get(void)1764 volatile unsigned int userial_mask_get(void)
1765 {
1766 return g_usbSerialMask;
1767 }
1768
userial_mask_set(unsigned int val)1769 void userial_mask_set(unsigned int val)
1770 {
1771 g_usbSerialMask = val;
1772 }
1773
1774 /****************************************************************************
1775 * Name: cdcacm_classobject
1776 *
1777 * Description:
1778 * Register USB serial port (and USB serial console if so configured) and
1779 * return the class object.
1780 *
1781 * Input Parameters:
1782 * devinfo - Describes the low level bindings of an usb device.
1783 * classdev - The location to return the CDC serial class' device
1784 * instance.
1785 *
1786 * Returned Value:
1787 * A pointer to the allocated class object (NULL on failure).
1788 *
1789 ****************************************************************************/
1790
cdcacm_classobject(int minor,FAR struct usbdev_devinfo_s * devinfo,FAR struct usbdevclass_driver_s ** classdev)1791 int cdcacm_classobject(int minor,
1792 FAR struct usbdev_devinfo_s *devinfo,
1793 FAR struct usbdevclass_driver_s **classdev)
1794 {
1795 FAR struct cdcacm_alloc_s *alloc;
1796 FAR struct cdcacm_dev_s *priv;
1797 FAR struct cdcacm_driver_s *drvr;
1798
1799 (void)minor;
1800
1801 /* Allocate the structures needed */
1802
1803 alloc = (FAR struct cdcacm_alloc_s *)malloc(sizeof(struct cdcacm_alloc_s));
1804 if (alloc == NULL)
1805 {
1806 usb_err("%s: malloc fialed!\r\n", __FUNCTION__);
1807 return -ENOMEM;
1808 }
1809
1810 /* Convenience pointers into the allocated blob */
1811
1812 priv = &alloc->dev;
1813 drvr = &alloc->drvr;
1814
1815 /* Initialize the USB serial driver structure */
1816
1817 (void)memset_s(priv, sizeof(struct cdcacm_dev_s), 0, sizeof(struct cdcacm_dev_s));
1818 (void)memcpy_s(&priv->devinfo, sizeof(struct usbdev_devinfo_s), devinfo, sizeof(struct usbdev_devinfo_s));
1819
1820 /* Fake line status */
1821
1822 USETDW(priv->linecoding.dwDTERate, 9600); /* Baud = 9600 */
1823 priv->linecoding.bCharFormat = UCDC_STOP_BIT_1; /* Stop bits */
1824 priv->linecoding.bParityType = UCDC_PARITY_NONE; /* No parity */
1825 priv->linecoding.bDataBits = 8; /* 8 data bits */
1826
1827 /* Initialize the USB class driver structure */
1828
1829 drvr->drvr.speed = USB_SPEED_HIGH;
1830 drvr->drvr.ops = &g_driver_ops;
1831 drvr->dev = priv;
1832 *classdev = &drvr->drvr;
1833
1834 return 0;
1835 }
1836
1837 /****************************************************************************
1838 * Name: cdcacm_uninitialize
1839 *
1840 * Description:
1841 * Un-initialize the USB storage class driver. This function is used
1842 * internally by the USB composite driver to uninitialize the CDC/ACM
1843 * driver. This same interface is available (with an untyped input
1844 * parameter) when the CDC/ACM driver is used standalone.
1845 *
1846 * Input Parameters:
1847 * There is one parameter, it differs in typing depending upon whether the
1848 * CDC/ACM driver is an internal part of a composite device, or a standalone
1849 * USB driver:
1850 *
1851 * classdev - The class object returned by cdcacm_classobject()
1852 * handle - The opaque handle representing the class object returned by
1853 * a previous call to cdcacm_initialize().
1854 *
1855 * Returned Value:
1856 * None
1857 *
1858 ****************************************************************************/
1859
cdcacm_uninitialize(FAR struct usbdevclass_driver_s * devclass_drvr)1860 void cdcacm_uninitialize(FAR struct usbdevclass_driver_s *devclass_drvr)
1861 {
1862 FAR struct cdcacm_driver_s *drvr = (struct cdcacm_driver_s *)devclass_drvr;
1863 FAR struct cdcacm_alloc_s *alloc;
1864
1865 if (drvr == NULL)
1866 {
1867 usb_err("Invalid pointer!\r\n");
1868 return;
1869 }
1870
1871 alloc = container_of(drvr, struct cdcacm_alloc_s, drvr);
1872 free(alloc);
1873 }
1874
1875 /****************************************************************************
1876 * Name: cdcacm_get_composite_devdesc
1877 *
1878 * Description:
1879 * Helper function to fill in some constants into the composite
1880 * configuration struct.
1881 *
1882 * Input Parameters:
1883 * dev - Pointer to the configuration struct we should fill
1884 *
1885 * Returned Value:
1886 * None
1887 *
1888 ****************************************************************************/
1889
cdcacm_get_composite_devdesc(struct composite_devdesc_s * dev)1890 void cdcacm_get_composite_devdesc(struct composite_devdesc_s *dev)
1891 {
1892 (void)memset_s(dev, sizeof(struct composite_devdesc_s), 0, sizeof(struct composite_devdesc_s));
1893
1894 dev->mkdevdesc = cdcacm_mkdevdesc;
1895 dev->mkconfdesc = cdcacm_mkcfgdesc;
1896 dev->mkstrdesc = cdcacm_mkstrdesc;
1897
1898 dev->nconfigs = CDCACM_NCONFIGS; /* Number of configurations supported */
1899 dev->configid = CDCACM_CONFIGID; /* The only supported configuration ID */
1900
1901 /* Interfaces.
1902 *
1903 * ifnobase must be provided by board-specific logic
1904 */
1905
1906 dev->devinfo.ninterfaces = CDCACM_NINTERFACES; /* Number of interfaces in the configuration */
1907
1908 /* Strings.
1909 *
1910 * strbase must be provided by board-specific logic
1911 */
1912
1913 dev->devinfo.nstrings = CDCACM_NSTRIDS; /* Number of Strings */
1914
1915 /* Endpoints.
1916 *
1917 * Endpoint numbers must be provided by board-specific logic.
1918 */
1919
1920 dev->devinfo.nendpoints = CDCACM_NUM_EPS; /* Number of Endpoint */
1921 }
1922
1923 /* Init composite public action */
1924
usbdev_cdcacm_initialize_sub(FAR struct composite_devdesc_s * dev,int ifnobase,int minor)1925 void usbdev_cdcacm_initialize_sub(FAR struct composite_devdesc_s *dev, int ifnobase, int minor)
1926 {
1927 /* Ask the serial driver to fill in the constants we didn't
1928 * know here.
1929 */
1930
1931 cdcacm_get_composite_devdesc(dev);
1932
1933 /* Overwrite and correct some values... */
1934
1935 dev->classobject = cdcacm_classobject;
1936 dev->uninitialize = cdcacm_uninitialize;
1937
1938 /* init ifnobase of usbdev_devinfo_s for judegment wIndex */
1939
1940 dev->devinfo.ifnobase = ifnobase; /* Offset to Interface-IDs */
1941 dev->minor = minor; /* The minor interface number */
1942
1943 /* Strings */
1944
1945 dev->devinfo.strbase = 0; /* Offset to String Numbers */
1946 }
1947
usbdev_cdcacm_initialize(FAR struct module * mod,int n,FAR void * arg)1948 int usbdev_cdcacm_initialize (FAR struct module *mod, int n, FAR void *arg)
1949 {
1950 FAR struct composite_softc *com_s = (struct composite_softc *)arg;
1951 struct composite_devdesc_s dev;
1952 int ret;
1953
1954 (void)mod;
1955 (void)n;
1956 if (com_s == NULL)
1957 {
1958 return -1;
1959 }
1960
1961 usbdev_cdcacm_initialize_sub(&dev, 0, DEV_SERIAL);
1962 ret = composite_initialize(com_s, 1, &dev);
1963 if (ret)
1964 {
1965 return -1;
1966 }
1967 PRINTK(" ** Serial device initialized successfully! **\n ");
1968
1969 return 0;
1970 }
1971