• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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