diff --git a/drivers/usbdev/usbdev_serial.c b/drivers/usbdev/usbdev_serial.c index 0dbe17754b..615a36df98 100644 --- a/drivers/usbdev/usbdev_serial.c +++ b/drivers/usbdev/usbdev_serial.c @@ -219,31 +219,34 @@ struct usbser_req_s { - struct usbser_req_s *flink; /* Implements a singly linked list */ - struct usbdev_req_s *req; + FAR struct usbser_req_s *flink; /* Implements a singly linked list */ + FAR struct usbdev_req_s *req; /* The contained request */ }; /* This structure describes the internal state of the driver */ struct usbser_dev_s { - struct uart_dev_s serdev; /* Serial device structure */ - struct usbdev_s *usbdev; /* usbdev driver pointer */ - ubyte config; /* Configuration number */ - ubyte nwralloc; /* Number of write requests allocated */ - ubyte nwrq; /* Number of queue write requests */ - boolean open; /* TRUE: Driver has been opened */ - boolean wravail; /* TRUE: write data is buffered */ - ubyte linest[7]; /* Fake line status */ - struct usbdev_ep_s *epintin; /* Address of Interrupt IN endpoint */ - struct usbdev_ep_s *epbulkin; /* Address of Bulk IN endpoint */ - struct usbdev_ep_s *epbulkout; /* Address of Bulk OUT endpoint */ - struct usbdev_req_s *ctrlreq; /* Control request */ - struct sq_queue_s reqlist; /* List of write request containers */ + FAR struct uart_dev_s serdev; /* Serial device structure */ + FAR struct usbdev_s *usbdev; /* usbdev driver pointer */ + ubyte config; /* Configuration number */ + ubyte nwrq; /* Number of queue write requests (in reqlist)*/ + ubyte nrdq; /* Number of queue read requests (in epbulkout) */ + boolean open; /* TRUE: Driver has been opened */ + ubyte linest[7]; /* Fake line status */ + FAR struct usbdev_ep_s *epintin; /* Address of Interrupt IN endpoint */ + FAR struct usbdev_ep_s *epbulkin; /* Address of Bulk IN endpoint */ + FAR struct usbdev_ep_s *epbulkout; /* Address of Bulk OUT endpoint */ + FAR struct usbdev_req_s *ctrlreq; /* Control request */ + struct sq_queue_s reqlist; /* List of write request containers */ - /* Pre-allocated write requests (linked in reqlist) */ + /* Pre-allocated write request containers. The write requests will + * be linked in a free list (reqlist), and used to send requests to + * EPBULKIN; Read requests will be queued in the EBULKOUT. + */ struct usbser_req_s wrreqs[CONFIG_USBSER_NWRREQS]; + struct usbser_req_s rdreqs[CONFIG_USBSER_NWRREQS]; /* Serial I/O buffers */ @@ -256,7 +259,7 @@ struct usbser_dev_s struct usbser_driver_s { struct usbdevclass_driver_s drvr; - struct usbser_dev_s *dev; + FAR struct usbser_dev_s *dev; }; /* This is what is allocated */ @@ -284,7 +287,7 @@ static int usbclass_recvpacket(FAR struct usbser_dev_s *priv, static struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep, uint16 len); static void usbclass_freereq(FAR struct usbdev_ep_s *ep, - struct usbdev_req_s *req); + FAR struct usbdev_req_s *req); /* Configuration ***********************************************************/ @@ -303,11 +306,11 @@ static int usbclass_setconfig(FAR struct usbser_dev_s *priv, /* Completion event handlers ***********************************************/ static void usbclass_setupcomplete(FAR struct usbdev_ep_s *ep, - struct usbdev_req_s *req); + FAR struct usbdev_req_s *req); static void usbclass_rdcomplete(FAR struct usbdev_ep_s *ep, - struct usbdev_req_s *req); + FAR struct usbdev_req_s *req); static void usbclass_wrcomplete(FAR struct usbdev_ep_s *ep, - struct usbdev_req_s *req); + FAR struct usbdev_req_s *req); /* USB class device ********************************************************/ @@ -478,8 +481,8 @@ static const struct usb_qualdesc_s g_qualdesc = static uint16 usbclass_fillpacket(FAR struct usbser_dev_s *priv, char *packet, uint16 size) { - uart_dev_t *serdev = &priv->serdev; - struct uart_buffer_s *xmit = &serdev->xmit; + FAR uart_dev_t *serdev = &priv->serdev; + FAR struct uart_buffer_s *xmit = &serdev->xmit; irqstate_t flags; uint16 nbytes = 0; @@ -516,7 +519,6 @@ static uint16 usbclass_fillpacket(FAR struct usbser_dev_s *priv, char *packet, u if (xmit->head == xmit->tail) { - priv->wravail = FALSE; uart_disabletxint(serdev); } @@ -537,9 +539,9 @@ static uint16 usbclass_fillpacket(FAR struct usbser_dev_s *priv, char *packet, u static int usbclass_sndpacket(FAR struct usbser_dev_s *priv) { - struct usbdev_ep_s *ep; - struct usbdev_req_s *req; - struct usbser_req_s *reqcontainer; + FAR struct usbdev_ep_s *ep; + FAR struct usbdev_req_s *req; + FAR struct usbser_req_s *reqcontainer; irqstate_t flags; int len; int ret = OK; @@ -547,6 +549,7 @@ static int usbclass_sndpacket(FAR struct usbser_dev_s *priv) #ifdef CONFIG_DEBUG if (priv == NULL) { + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); return -ENODEV; } #endif @@ -562,7 +565,11 @@ static int usbclass_sndpacket(FAR struct usbser_dev_s *priv) * to be sent). */ - while (sq_peek(&priv->reqlist)) + uvdbg("head=%d tail=%d nwrq=%d empty=%d\n", + priv->serdev.xmit.head, priv->serdev.xmit.tail, + priv->nwrq, sq_empty(&priv->reqlist)); + + while (!sq_empty(&priv->reqlist)) { /* Peek at the request in the container at the head of the list */ @@ -574,6 +581,11 @@ static int usbclass_sndpacket(FAR struct usbser_dev_s *priv) len = usbclass_fillpacket(priv, req->buf, ep->maxpacket); if (len > 0) { + /* Remove the empty contained from the request list */ + + (void)sq_remfirst(&priv->reqlist); + priv->nwrq--; + /* Then submit the request to the endpoint */ req->len = len; @@ -584,11 +596,6 @@ static int usbclass_sndpacket(FAR struct usbser_dev_s *priv) usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SUBMITFAIL), (uint16)-ret); break; } - - /* Remove the empty contained from the request list */ - - reqcontainer = (struct usbser_req_s *)sq_remfirst(&priv->reqlist); - priv->nwrq--; } else { @@ -612,8 +619,8 @@ static int usbclass_sndpacket(FAR struct usbser_dev_s *priv) static int usbclass_recvpacket(FAR struct usbser_dev_s *priv, char *packet, uint16 size) { - uart_dev_t *serdev = &priv->serdev; - struct uart_buffer_s *recv = &serdev->recv; + FAR uart_dev_t *serdev = &priv->serdev; + FAR struct uart_buffer_s *recv = &serdev->recv; uint16 nexthead; /* Get the next head index */ @@ -665,7 +672,7 @@ static int usbclass_recvpacket(FAR struct usbser_dev_s *priv, char *packet, uint static struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep, uint16 len) { - struct usbdev_req_s *req; + FAR struct usbdev_req_s *req; req = EP_ALLOCREQ(ep); if (req != NULL) @@ -774,9 +781,9 @@ static int usbclass_mkstrdesc(ubyte id, struct usb_strdesc_s *strdesc) ****************************************************************************/ #ifdef CONFIG_USBDEV_DUALSPEED -static inline void usbclass_mkepbulkdesc(const struct up_epdesc *indesc, +static inline void usbclass_mkepbulkdesc(const FAR struct up_epdesc *indesc, uint16 mxpacket, - struct usb_epdesc_s *outdesc) + FAR struct usb_epdesc_s *outdesc) { /* Copy the canned descriptor */ @@ -803,7 +810,7 @@ static sint16 usbclass_mkcfgdesc(ubyte *buf, ubyte speed) static sint16 usbclass_mkcfgdesc(ubyte *buf) #endif { - struct usb_cfgdesc_s *cfgdesc = (struct usb_cfgdesc_s*)buf; + FAR struct usb_cfgdesc_s *cfgdesc = (struct usb_cfgdesc_s*)buf; #ifdef CONFIG_USBDEV_DUALSPEED boolean highspeed = (speed == USB_SPEED_HIGH); uint16 bulkmxpacket; @@ -878,56 +885,21 @@ static sint16 usbclass_mkcfgdesc(ubyte *buf) static void usbclass_resetconfig(FAR struct usbser_dev_s *priv) { - FAR struct usbdev_s *dev = priv->usbdev; - struct usbser_req_s *reqcontainer; - irqstate_t flags; - /* Are we configured? */ if (priv->config != USBSER_CONFIGIDNONE) { + /* Yes.. but not anymore */ + priv->config = USBSER_CONFIGIDNONE; - /* Free write requests that are not in use */ - - flags = irqsave(); - while (!sq_empty(&priv->reqlist)) - { - reqcontainer = (struct usbser_req_s *)sq_remfirst(&priv->reqlist); - if (reqcontainer->req != NULL) - { - usbclass_freereq(priv->epbulkin, reqcontainer->req); - - priv->nwralloc--; /* Number of write requests allocated */ - priv->nwrq--; /* Number of write requests queued */ - } - } - irqrestore(flags); - - /* Disable and free endpoints. This should force completion of all pending + /* Disable endpoints. This should force completion of all pending * transfers. */ - if (priv->epintin) - { - EP_DISABLE(priv->epintin); - DEV_FREEEP(dev, priv->epintin); - priv->epintin = NULL; - } - - if (priv->epbulkin) - { - EP_DISABLE(priv->epbulkin); - DEV_FREEEP(dev, priv->epbulkin); - priv->epbulkin = NULL; - } - - if (priv->epbulkout) - { - EP_DISABLE(priv->epbulkout); - DEV_FREEEP(dev, priv->epbulkout); - priv->epbulkout = NULL; - } + EP_DISABLE(priv->epintin); + EP_DISABLE(priv->epbulkin); + EP_DISABLE(priv->epbulkout); } } @@ -942,14 +914,11 @@ static void usbclass_resetconfig(FAR struct usbser_dev_s *priv) static int usbclass_setconfig(FAR struct usbser_dev_s *priv, ubyte config) { - struct usbdev_s *dev = priv->usbdev; - struct usbdev_req_s *req; - struct usbser_req_s *reqcontainer; + FAR struct usbdev_req_s *req; #ifdef CONFIG_USBDEV_DUALSPEED struct usb_epdesc_s epdesc; uint16 bulkmxpacket; #endif - irqstate_t flags; int i; int ret = 0; @@ -991,33 +960,16 @@ static int usbclass_setconfig(FAR struct usbser_dev_s *priv, ubyte config) /* Configure the IN interrupt endpoint */ - priv->epintin = DEV_ALLOCEP(dev, 0, TRUE, USB_EP_ATTR_XFER_INT); - if (!priv->epintin) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPINTINALLOCFAIL), 0); - ret = -ENODEV; - goto errout; - } - ret = EP_CONFIGURE(priv->epintin, &g_epintindesc); if (ret < 0) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPINTINCONFIGFAIL), 0); goto errout; } - priv->epintin->private = priv; /* Configure the IN bulk endpoint */ - priv->epbulkin = DEV_ALLOCEP(dev, 0, TRUE, USB_EP_ATTR_XFER_BULK); - if (!priv->epbulkin) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKINALLOCFAIL), 0); - ret = -ENODEV; - goto errout; - } - #ifdef CONFIG_USBDEV_DUALSPEED if (dev->speed == USB_SPEED_HIGH) { @@ -1043,14 +995,6 @@ static int usbclass_setconfig(FAR struct usbser_dev_s *priv, ubyte config) /* Configure the OUT bulk endpoint */ - priv->epbulkout = DEV_ALLOCEP(dev, 0, FALSE, USB_EP_ATTR_XFER_BULK); - if (!priv->epbulkout) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKOUTALLOCFAIL), 0); - ret = -ENODEV; - goto errout; - } - #ifdef CONFIG_USBDEV_DUALSPEED usbclass_mkepbulkdesc(&g_epbulkoutdesc, bulkmxpacket, &epdesc); ret = EP_CONFIGURE(priv->epbulkout, &epdesc); @@ -1065,49 +1009,20 @@ static int usbclass_setconfig(FAR struct usbser_dev_s *priv, ubyte config) priv->epbulkout->private = priv; - /* Allocate and queue read requests */ + /* Queue read requests in the bulk OUT endpoint */ - for (i = 0; i < CONFIG_USBSER_NRDREQS && ret == 0; i++) + DEBUGASSERT(priv->nrdq == 0); + for (i = 0; i < CONFIG_USBSER_NRDREQS; i++) { - req = usbclass_allocreq(priv->epbulkout, priv->epbulkout->maxpacket); - if (ret == 0) + req = priv->rdreqs[i].req; + req->callback = usbclass_rdcomplete; + ret = EP_SUBMIT(priv->epbulkout, req); + if (ret != OK) { - req->callback = usbclass_rdcomplete; - ret = EP_SUBMIT(priv->epbulkout, req); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16)-ret); - } + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16)-ret); + goto errout; } - else - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDALLOCREQ), (uint16)-ret); - usbclass_resetconfig(priv); - return -ENOMEM; - } - } - - /* Allocate write request containers and put in a free list */ - - for (i = 0; i < CONFIG_USBSER_NWRREQS; i++) - { - reqcontainer = &priv->wrreqs[i]; - reqcontainer->req = usbclass_allocreq(priv->epbulkin, priv->epbulkin->maxpacket); - if (reqcontainer->req == NULL) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRALLOCREQ), (uint16)-ret); - usbclass_resetconfig(priv); - return -ENOMEM; - } - reqcontainer->req->private = reqcontainer; - reqcontainer->req->callback = usbclass_wrcomplete; - - flags = irqsave(); - sq_addlast((sq_entry_t*)reqcontainer, &priv->reqlist); - - priv->nwralloc++; /* Count of write requests allocated */ - priv->nwrq++; /* Count of write requests available */ - irqrestore(flags); + priv->nrdq++; } priv->config = config; @@ -1144,35 +1059,49 @@ static void usbclass_setupcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req static void usbclass_rdcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req) { - struct usbser_dev_s *priv = (FAR struct usbser_dev_s*)ep->private; + FAR struct usbser_dev_s *priv; int ret; - if (priv != NULL) + /* Sanity check */ + +#ifdef CONFIG_DEBUG + if (!ep || !ep->private || !req) { - switch (req->result) - { - case 0: /* Normal completion */ - usbclass_recvpacket(priv, req->buf, req->xfrd); - break; + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); + return; + } +#endif - case -ESHUTDOWN: /* Disconnection */ - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSHUTDOWN), 0); - usbclass_freereq(ep, req); - return; + /* Extract references to private data */ - default: - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDUNEXPECTED), (uint16)-req->result); - break; - }; + priv = (FAR struct usbser_dev_s*)ep->private; - /* Requeue the read request */ + /* Process the received data unless this is some unusual condition */ - req->len = ep->maxpacket; - ret = EP_SUBMIT(ep, req); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16)-req->result); - } + switch (req->result) + { + case 0: /* Normal completion */ + usbtrace(TRACE_CLASSRDCOMPLETE, priv->nrdq); + usbclass_recvpacket(priv, req->buf, req->xfrd); + break; + + case -ESHUTDOWN: /* Disconnection */ + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSHUTDOWN), 0); + priv->nrdq--; + return; + + default: /* Some other error occurred */ + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDUNEXPECTED), (uint16)-req->result); + break; + }; + + /* Requeue the read request */ + + req->len = ep->maxpacket; + ret = EP_SUBMIT(ep, req); + if (ret != OK) + { + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16)-req->result); } } @@ -1187,41 +1116,50 @@ static void usbclass_rdcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s static void usbclass_wrcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req) { - struct usbser_dev_s *priv = (FAR struct usbser_dev_s *)ep->private; - struct usbser_req_s *reqcontainer = req->private; + FAR struct usbser_dev_s *priv; + FAR struct usbser_req_s *reqcontainer; irqstate_t flags; - if (priv != NULL) + /* Sanity check */ + +#ifdef CONFIG_DEBUG + if (!ep || !ep->private || !req || !req->private) { - switch (req->result) - { - case 0: /* Normal completion */ - break; + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); + return; + } +#endif - case -ESHUTDOWN: /* Disconnection */ - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRSHUTDOWN), 0); - usbclass_freereq(ep, req); - priv->nwralloc--; /* Number of write requests allocated */ - return; + /* Extract references to our private data */ - default: - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRUNEXPECTED), (uint16)-req->result); - break; - } + priv = (FAR struct usbser_dev_s *)ep->private; + reqcontainer = (FAR struct usbser_req_s *)req->private; - /* Put write request back into the free list */ + /* Return the write request to the free list */ - if (reqcontainer == NULL) - { - flags = irqsave(); - sq_addlast((sq_entry_t*)reqcontainer, &priv->reqlist); - priv->nwrq++; - irqrestore(flags); + flags = irqsave(); + sq_addlast((sq_entry_t*)reqcontainer, &priv->reqlist); + priv->nwrq++; + irqrestore(flags); - /* And send another packet if: TX output is enabled */ + /* Send the next packet unless this was some unusual termination + * condition + */ - usbclass_sndpacket(priv); - } + switch (req->result) + { + case OK: /* Normal completion */ + usbtrace(TRACE_CLASSWRCOMPLETE, priv->nwrq); + usbclass_sndpacket(priv); + break; + + case -ESHUTDOWN: /* Disconnection */ + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRSHUTDOWN), priv->nwrq); + break; + + default: /* Some other error occurred */ + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRUNEXPECTED), (uint16)-req->result); + break; } } @@ -1239,26 +1177,113 @@ static void usbclass_wrcomplete(FAR struct usbdev_ep_s *ep, struct usbdev_req_s static int usbclass_bind(FAR struct usbdev_s *dev, FAR struct usbdevclass_driver_s *driver) { - struct usbser_dev_s *priv = ((struct usbser_driver_s*)driver)->dev; + FAR struct usbser_dev_s *priv = ((struct usbser_driver_s*)driver)->dev; + FAR struct usbser_req_s *reqcontainer; + irqstate_t flags; + int ret; + int i; usbtrace(TRACE_CLASSBIND, 0); + /* Bind the structures */ + + priv->usbdev = dev; + dev->ep0->private = priv; + /* Preallocate control request */ priv->ctrlreq = usbclass_allocreq(dev->ep0, USBSER_MXDESCLEN); if (priv->ctrlreq == NULL) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALLOCCTRLREQ), 0); - usbclass_unbind(dev); - return -ENOMEM; + ret = -ENOMEM; + goto errout; } priv->ctrlreq->callback = usbclass_setupcomplete; - /* Bind the structures */ + /* Pre-allocate all endpoints... the endpoints will not be functional + * until the SET CONFIGURATION request is processed in usbclass_setconfig. + * This is done here because there may be calls to malloc and the SET + * CONFIGURATION processing probably occurrs within interrupt handling + * logic where malloc calls will fail. + */ + + /* Pre-allocate the IN interrupt endpoint */ + + priv->epintin = DEV_ALLOCEP(dev, 0, TRUE, USB_EP_ATTR_XFER_INT); + if (!priv->epintin) + { + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPINTINALLOCFAIL), 0); + ret = -ENODEV; + goto errout; + } + priv->epintin->private = priv; + + /* Pre-allocate the IN bulk endpoint */ + + priv->epbulkin = DEV_ALLOCEP(dev, 0, TRUE, USB_EP_ATTR_XFER_BULK); + if (!priv->epbulkin) + { + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKINALLOCFAIL), 0); + ret = -ENODEV; + goto errout; + } + priv->epbulkin->private = priv; + + /* Pre-allocate the OUT bulk endpoint */ + + priv->epbulkout = DEV_ALLOCEP(dev, 0, FALSE, USB_EP_ATTR_XFER_BULK); + if (!priv->epbulkout) + { + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKOUTALLOCFAIL), 0); + ret = -ENODEV; + goto errout; + } + priv->epbulkout->private = priv; + + /* Pre-allocate read requests */ + + for (i = 0; i < CONFIG_USBSER_NRDREQS; i++) + { + reqcontainer = &priv->rdreqs[i]; + reqcontainer->req = usbclass_allocreq(priv->epbulkout, priv->epbulkout->maxpacket); + if (reqcontainer->req == NULL) + { + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDALLOCREQ), (uint16)-ret); + ret = -ENOMEM; + goto errout; + } + reqcontainer->req->private = reqcontainer; + reqcontainer->req->callback = usbclass_rdcomplete; + } + + /* Pre-allocate write request containers and put in a free list */ + + for (i = 0; i < CONFIG_USBSER_NWRREQS; i++) + { + reqcontainer = &priv->wrreqs[i]; + reqcontainer->req = usbclass_allocreq(priv->epbulkin, priv->epbulkin->maxpacket); + if (reqcontainer->req == NULL) + { + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRALLOCREQ), (uint16)-ret); + ret = -ENOMEM; + goto errout; + } + reqcontainer->req->private = reqcontainer; + reqcontainer->req->callback = usbclass_wrcomplete; + + flags = irqsave(); + sq_addlast((sq_entry_t*)reqcontainer, &priv->reqlist); + priv->nwrq++; /* Count of write requests available */ + irqrestore(flags); + } - priv->usbdev = dev; - dev->ep0->private = priv; return OK; + +errout: + usbclass_unbind(dev); + return ret; + } /**************************************************************************** @@ -1271,7 +1296,10 @@ static int usbclass_bind(FAR struct usbdev_s *dev, FAR struct usbdevclass_driver static void usbclass_unbind(FAR struct usbdev_s *dev) { - struct usbser_dev_s *priv; + FAR struct usbser_dev_s *priv; + FAR struct usbser_req_s *reqcontainer; + irqstate_t flags; + int i; usbtrace(TRACE_CLASSUNBIND, 0); @@ -1282,6 +1310,9 @@ static void usbclass_unbind(FAR struct usbdev_s *dev) return; } #endif + + /* Extract reference to private data */ + priv = (FAR struct usbser_dev_s *)dev->ep0->private; #ifdef CONFIG_DEBUG @@ -1292,18 +1323,93 @@ static void usbclass_unbind(FAR struct usbdev_s *dev) } #endif + /* Make sure that we are not already unbound */ + if (priv != NULL) { + /* Make sure that the endpoints have been unconfigured. If + * we were terminated gracefully, then the configuration should + * already have been reset. If not, then calling usbclass_resetconfig + * should cause the endpoints to immediately terminate all + * transfers and return the requests to us (with result == -ESHUTDOWN) + */ + + usbclass_resetconfig(priv); + up_mdelay(50); + + if (priv->ctrlreq != NULL) + { + usbclass_freereq(dev->ep0, priv->ctrlreq); + } + dev->ep0->private = priv; + + /* Free int interrupt IN endpoint */ + + if (priv->epintin) + { + DEV_FREEEP(dev, priv->epintin); + priv->epintin = NULL; + } + + if (priv->epbulkin) + { + DEV_FREEEP(dev, priv->epbulkin); + priv->epbulkin = NULL; + } + + /* Free the pre-allocated control request */ + if (priv->ctrlreq != NULL) { usbclass_freereq(dev->ep0, priv->ctrlreq); } - /* Clear out all data in the circular buffer */ + /* Free pre-allocated read requests (which should all have + * been returned to the free list at this time -- we don't check) + */ - priv->serdev.xmit.head = 0; - priv->serdev.xmit.tail = 0; + DEBUGASSERT(priv->nrdq == 0); + for (i = 0; i < CONFIG_USBSER_NRDREQS; i++) + { + reqcontainer = &priv->rdreqs[i]; + if (reqcontainer->req) + { + usbclass_freereq(priv->epbulkout, reqcontainer->req); + reqcontainer->req = NULL; + } + } + + /* Free the bulk OUT endpoint */ + + if (priv->epbulkout) + { + DEV_FREEEP(dev, priv->epbulkout); + priv->epbulkout = NULL; + } + + /* Free write requests that are not in use (which should be all + * of them + */ + + flags = irqsave(); + DEBUGASSERT(priv->nwrq == CONFIG_USBSER_NWRREQS); + while (!sq_empty(&priv->reqlist)) + { + reqcontainer = (struct usbser_req_s *)sq_remfirst(&priv->reqlist); + if (reqcontainer->req != NULL) + { + usbclass_freereq(priv->epbulkin, reqcontainer->req); + priv->nwrq--; /* Number of write requests queued */ + } + } + DEBUGASSERT(priv->nwrq == 0); + irqrestore(flags); } + + /* Clear out all data in the circular buffer */ + + priv->serdev.xmit.head = 0; + priv->serdev.xmit.tail = 0; } /**************************************************************************** @@ -1317,8 +1423,8 @@ static void usbclass_unbind(FAR struct usbdev_s *dev) static int usbclass_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ctrl) { - struct usbser_dev_s *priv; - struct usbdev_req_s *ctrlreq; + FAR struct usbser_dev_s *priv; + FAR struct usbdev_req_s *ctrlreq; uint16 value; uint16 index; uint16 len; @@ -1331,6 +1437,9 @@ static int usbclass_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s * return -EIO; } #endif + + /* Extract reference to private data */ + usbtrace(TRACE_CLASSSETUP, ctrl->req); priv = (FAR struct usbser_dev_s *)dev->ep0->private; @@ -1565,7 +1674,7 @@ static int usbclass_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s * static void usbclass_disconnect(FAR struct usbdev_s *dev) { - struct usbser_dev_s *priv; + FAR struct usbser_dev_s *priv; irqstate_t flags; usbtrace(TRACE_CLASSDISCONNECT, 0); @@ -1577,6 +1686,9 @@ static void usbclass_disconnect(FAR struct usbdev_s *dev) return; } #endif + + /* Extract reference to private data */ + priv = (FAR struct usbser_dev_s *)dev->ep0->private; #ifdef CONFIG_DEBUG @@ -1587,6 +1699,8 @@ static void usbclass_disconnect(FAR struct usbdev_s *dev) } #endif + /* Reset the configuration */ + flags = irqsave(); usbclass_resetconfig(priv); @@ -1611,24 +1725,34 @@ static void usbclass_disconnect(FAR struct usbdev_s *dev) static int usbser_setup(FAR struct uart_dev_s *dev) { - struct usbser_dev_s *priv = (FAR struct usbser_dev_s*)dev->priv; + FAR struct usbser_dev_s *priv; usbtrace(USBSER_CLASSAPI_SETUP, 0); + /* Sanity check */ + #if CONFIG_DEBUG - if (!priv) + if (!dev || !dev->priv) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); return -EIO; } #endif + /* Extract reference to private data */ + + priv = (FAR struct usbser_dev_s*)dev->priv; + + /* Check if we have been configured */ + if (priv->config == USBSER_CONFIGIDNONE) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SETUPNOTCONNECTED), 0); return -ENOTCONN; } + /* Mark the device as opened */ + priv->open = TRUE; return OK; } @@ -1647,19 +1771,24 @@ static int usbser_setup(FAR struct uart_dev_s *dev) static void usbser_shutdown(FAR struct uart_dev_s *dev) { - struct usbser_dev_s *priv = (FAR struct usbser_dev_s*)dev->priv; + FAR struct usbser_dev_s *priv; irqstate_t flags; usbtrace(USBSER_CLASSAPI_SHUTDOWN, 0); + /* Sanity check */ + #if CONFIG_DEBUG - if (!priv) + if (!dev || !dev->priv) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); return; } #endif + /* Extract reference to private data */ + + priv = (FAR struct usbser_dev_s*)dev->priv; flags = irqsave(); #if CONFIG_DEBUG @@ -1724,18 +1853,24 @@ static void usbser_detach(FAR struct uart_dev_s *dev) static void usbser_rxint(FAR struct uart_dev_s *dev, boolean enable) { - struct usbser_dev_s *priv = (FAR struct usbser_dev_s*)dev->priv; + FAR struct usbser_dev_s *priv; usbtrace(USBSER_CLASSAPI_RXINT, (uint16)enable); + /* Sanity check */ + #if CONFIG_DEBUG - if (!priv) + if (!dev || !dev->priv) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); return; } #endif + /* Extract reference to private data */ + + priv = (FAR struct usbser_dev_s*)dev->priv; + /* I think we can simulate this behavior by stalling and/or resuming the * OUT endpoint. */ @@ -1766,26 +1901,31 @@ static void usbser_rxint(FAR struct uart_dev_s *dev, boolean enable) static void usbser_txint(FAR struct uart_dev_s *dev, boolean enable) { - struct usbser_dev_s *priv = (FAR struct usbser_dev_s*)dev->priv; + FAR struct usbser_dev_s *priv; usbtrace(USBSER_CLASSAPI_TXINT, (uint16)enable); + /* Sanity checks */ + #if CONFIG_DEBUG - if (!priv) + if (!dev || !dev->priv) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); return; } #endif - /* Save the TX enable/disable state */ + /* Extract references to private data */ - priv->wravail = enable; + priv = (FAR struct usbser_dev_s*)dev->priv; /* If the new state is enabled and if there is data in the XMIT buffer, * send the next packet now. */ + uvdbg("enable=%d head=%d tail=%d\n", + enable, priv->serdev.xmit.head, priv->serdev.xmit.tail); + if (enable && priv->serdev.xmit.head != priv->serdev.xmit.tail) { usbclass_sndpacket(priv); @@ -1806,7 +1946,7 @@ static void usbser_txint(FAR struct uart_dev_s *dev, boolean enable) static boolean usbser_txempty(FAR struct uart_dev_s *dev) { - struct usbser_dev_s *priv = (FAR struct usbser_dev_s*)dev->priv; + FAR struct usbser_dev_s *priv = (FAR struct usbser_dev_s*)dev->priv; usbtrace(USBSER_CLASSAPI_TXEMPTY, 0); @@ -1822,7 +1962,7 @@ static boolean usbser_txempty(FAR struct uart_dev_s *dev) * reqlist, then there is no longer any TX data in flight. */ - return priv->nwrq >= priv->nwralloc; + return priv->nwrq >= CONFIG_USBSER_NWRREQS; } /**************************************************************************** @@ -1878,8 +2018,8 @@ int usbdev_serialinitialize(int minor) priv->serdev.recv.size = CONFIG_USBSER_RXBUFSIZE; priv->serdev.recv.buffer = priv->rxbuffer; - priv->serdev.xmit.size = CONFIG_USBSER_RXBUFSIZE; - priv->serdev.xmit.buffer = priv->rxbuffer; + priv->serdev.xmit.size = CONFIG_USBSER_TXBUFSIZE; + priv->serdev.xmit.buffer = priv->txbuffer; priv->serdev.ops = &g_uartops; priv->serdev.priv = priv;