summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2008-10-08 20:19:04 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2008-10-08 20:19:04 +0000
commit61d3874bad87e1d40e0a218940492d8dc0318f8d (patch)
treea919b1784f884e1a0a4e6ded99de6f36f81a6ca8
parent914088df89ab31a51855da97ecfd55f20f207324 (diff)
downloadpx4-nuttx-61d3874bad87e1d40e0a218940492d8dc0318f8d.tar.gz
px4-nuttx-61d3874bad87e1d40e0a218940492d8dc0318f8d.tar.bz2
px4-nuttx-61d3874bad87e1d40e0a218940492d8dc0318f8d.zip
Restructure so that it does not try to malloc from interrupt level
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1001 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/drivers/usbdev/usbdev_serial.c588
1 files changed, 364 insertions, 224 deletions
diff --git a/nuttx/drivers/usbdev/usbdev_serial.c b/nuttx/drivers/usbdev/usbdev_serial.c
index 0dbe17754..615a36df9 100644
--- a/nuttx/drivers/usbdev/usbdev_serial.c
+++ b/nuttx/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 */
-
- /* Pre-allocated write requests (linked in reqlist) */
+ 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 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)
{
- priv->config = USBSER_CONFIGIDNONE;
+ /* Yes.. but not anymore */
- /* 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);
+ priv->config = USBSER_CONFIGIDNONE;
- /* 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->callback = usbclass_rdcomplete;
- ret = EP_SUBMIT(priv->epbulkout, req);
- if (ret != OK)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16)-ret);
- }
- }
- 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)
+ req = priv->rdreqs[i].req;
+ req->callback = usbclass_rdcomplete;
+ ret = EP_SUBMIT(priv->epbulkout, req);
+ if (ret != OK)
{
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRALLOCREQ), (uint16)-ret);
- usbclass_resetconfig(priv);
- return -ENOMEM;
+ usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16)-ret);
+ goto errout;
}
- 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;
- /* Clear out all data in the circular buffer */
+ /* Free int interrupt IN endpoint */
- priv->serdev.xmit.head = 0;
- priv->serdev.xmit.tail = 0;
+ 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);
+ }
+
+ /* Free pre-allocated read requests (which should all have
+ * been returned to the free list at this time -- we don't check)
+ */
+
+ 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;