summaryrefslogtreecommitdiff
path: root/nuttx
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-12-29 15:55:02 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-12-29 15:55:02 +0000
commit57c579612e47fc80e9b9237832864a90f0fc0e0d (patch)
treefba27142963f3f345944801edbdd2f82a7edc056 /nuttx
parentfb7d51e41ba6acd21e511a25f1a2e5102d3d8095 (diff)
downloadpx4-nuttx-57c579612e47fc80e9b9237832864a90f0fc0e0d.tar.gz
px4-nuttx-57c579612e47fc80e9b9237832864a90f0fc0e0d.tar.bz2
px4-nuttx-57c579612e47fc80e9b9237832864a90f0fc0e0d.zip
More PIC32 USB device driver logic (still incomplete)
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4238 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx')
-rw-r--r--nuttx/arch/mips/src/pic32mx/pic32mx-usbdev.c298
1 files changed, 199 insertions, 99 deletions
diff --git a/nuttx/arch/mips/src/pic32mx/pic32mx-usbdev.c b/nuttx/arch/mips/src/pic32mx/pic32mx-usbdev.c
index bc0f450e4..1f1bd33b8 100644
--- a/nuttx/arch/mips/src/pic32mx/pic32mx-usbdev.c
+++ b/nuttx/arch/mips/src/pic32mx/pic32mx-usbdev.c
@@ -328,6 +328,7 @@
#define PIC32MX_TRACEERR_IRQREGISTRATION 0x0019
#define PIC32MX_TRACEERR_NOTCONFIGURED 0x001a
#define PIC32MX_TRACEERR_REQABORTED 0x001b
+#define PIC32MX_TRACEERR_INVALIDSTATE 0x001c
/* Trace interrupt codes */
@@ -407,22 +408,13 @@ enum pic32mx_devstate_e
DEVSTATE_CONFIGURED, /* Configuration received */
};
-/* Control Transfer States */
-
-enum pic32mx_ctrlxfr_e
-{
- CTRLXFR_WAIT_SETUP = 0, /* Waiting for a setup packet */
- CTRLXFR_IN, /* IN control transfer in progress */
- CTRLXFR_OUT /* OUT control transfer in progress */
-};
-
/* The various states of the control pipe */
enum pic32mx_ctrlstate_e
{
- CTRLSTATE_IDLE = 0, /* No request in progress */
- CTRLSTATE_RDREQUEST, /* Read request in progress */
- CTRLSTATE_WRREQUEST, /* Write request in progress */
+ CTRLSTATE_WAITSETUP = 0, /* No request in progress, waiting for setup */
+ CTRLSTATE_RDREQUEST, /* Read request (OUT) in progress */
+ CTRLSTATE_WRREQUEST, /* Write request (IN) in progress */
CTRLSTATE_STALLED /* We are stalled */
};
@@ -467,7 +459,6 @@ struct usb_outpipe_s
uint8_t *dest;
bool inuse;
uint16_t wcount;
- void (*callback)(void);
};
struct pic32mx_ep_s
@@ -516,7 +507,6 @@ struct pic32mx_usbdev_s
struct usb_ctrlreq_s ctrl; /* Last EP0 request */
uint8_t devstate; /* Driver state (see enum pic32mx_devstate_e) */
uint8_t ctrlstate; /* Control EP state (see enum pic32mx_ctrlstate_e) */
- uint8_t ctrlxfr; /* Control transfer state (see enum pic32mx_ctrlxfr_e) */
uint8_t shortpkt; /* Short packet stated (see enum pic32mx_shortkpt_e) */
uint8_t nesofs; /* ESOF counter (for resume support) */
uint8_t selfpowered:1; /* 1: Device is self powered */
@@ -525,9 +515,6 @@ struct pic32mx_usbdev_s
uint8_t epavail; /* Bitset of available endpoints */
uint16_t imask; /* Current interrupt mask */
- volatile struct usbotg_bdtentry_s *ep0bdtout; /* BDT entry for the next EP0 OUT transaction*/
- volatile struct usbotg_bdtentry_s *ep0bdtin; /* BDT entry for the next EP0 IN transaction*/
-
/* The endpoint list */
struct pic32mx_ep_s eplist[PIC32MX_NENDPOINTS];
@@ -570,6 +557,10 @@ static int pic32mx_wrrequest(struct pic32mx_usbdev_s *priv,
struct pic32mx_ep_s *privep);
static int pic32mx_rdcomplete(struct pic32mx_usbdev_s *priv,
struct pic32mx_ep_s *privep);
+static int pic32mx_ep0rdsetup(struct pic32mx_usbdev_s *priv,
+ uint8_t *dest, int readlen);
+static int pic32mx_rdsetup(struct pic32mx_usbdev_s *priv,
+ struct pic32mx_ep_s *privep, uint8_t *dest, int readlen);
static int pic32mx_rdrequest(struct pic32mx_usbdev_s *priv,
struct pic32mx_ep_s *privep);
static void pic32mx_cancelrequests(struct pic32mx_ep_s *privep);
@@ -972,7 +963,7 @@ static int pic32mx_wrrequest(struct pic32mx_usbdev_s *priv, struct pic32mx_ep_s
*/
usbtrace(TRACE_INTDECODE(PIC32MX_TRACEINTID_EPINQEMPTY), 0);
- priv->ctrlstate = CTRLSTATE_IDLE;
+ priv->ctrlstate = CTRLSTATE_WAITSETUP;
return OK;
}
@@ -1038,7 +1029,7 @@ static int pic32mx_wrrequest(struct pic32mx_usbdev_s *priv, struct pic32mx_ep_s
usbtrace(TRACE_COMPLETE(USB_EPNO(privep->ep.eplog)), privreq->req.xfrd);
privep->txnullpkt = 0;
pic32mx_reqcomplete(privep, OK);
- priv->ctrlstate = CTRLSTATE_IDLE;
+ priv->ctrlstate = CTRLSTATE_WAITSETUP;
}
return OK;
@@ -1087,12 +1078,85 @@ static int pic32mx_rdcomplete(struct pic32mx_usbdev_s *priv,
usbtrace(TRACE_COMPLETE(epno), privreq->req.xfrd);
pic32mx_reqcomplete(privep, OK);
- priv->ctrlstate = CTRLSTATE_IDLE;
}
- /* Set up the next read operation */
+ /* Set up the next read operation */
+
+ return pic32mx_rdrequest(priv, privep);
+}
+
+/****************************************************************************
+ * Name: pic32mx_ep0rdsetup
+ ****************************************************************************/
+
+static int pic32mx_ep0rdsetup(struct pic32mx_usbdev_s *priv, uint8_t *dest,
+ int readlen)
+{
+ volatile struct usbotg_bdtentry_s *bdt = priv->eplist[EP0].bdtout;
+
+ /* Clear status bits (making sure that UOWN is cleared before doing anything
+ * else.
+ */
+
+ bdt->status &= ~(USB_BDT_UOWN|USB_BDT_BYTECOUNT_MASK|USB_BDT_DATA01);
+
+ /* Set the data pointer, data length, and enable the endpoint */
+
+ bdt->addr = (uint8_t *)PHYS_ADDR(&priv->ctrl);
+ bdt->status |= (USB_SIZEOF_CTRLREQ << USB_BDT_BYTECOUNT_SHIFT);
+
+ /* Select data0 or data 1 when enabling */
- return pic32mx_rdrequest(priv, privep);
+ if ((bdt->status & USB_BDT_DATA01) == USB_BDT_DATA0)
+ {
+ bdt->status = USB_BDT_UOWN | USB_BDT_DATA1 | USB_BDT_DTS;
+ }
+ else
+ {
+ bdt->status = USB_BDT_UOWN | USB_BDT_DATA0 | USB_BDT_DTS;
+ }
+
+ priv->ctrlstate = CTRLSTATE_RDREQUEST;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: pic32mx_rdsetup
+ ****************************************************************************/
+
+static int pic32mx_rdsetup(struct pic32mx_usbdev_s *priv,
+ struct pic32mx_ep_s *privep, uint8_t *dest, int readlen)
+{
+ volatile struct usbotg_bdtentry_s *bdt = privep->bdtout;
+
+ /* Clear status bits (making sure that UOWN is cleared before doing anything
+ * else). The DATA01 is (only) is preserved.
+ */
+
+ bdt->status &= USB_BDT_DATA01;
+
+ /* Toggle the DATA01 bit if required for ping pong support */
+
+#ifndef CONFIG_USB_PINGPONG
+ bdt->status ^= USB_BDT_DATA01;
+#endif
+
+ /* Set the data pointer, data length, and enable the endpoint */
+
+ bdt->addr = (uint8_t *)PHYS_ADDR(dest);
+
+ /* Set the data length and give the BDT to USB. Preserving
+ * only the data toggle.
+ */
+
+ bdt->status |= (readlen << USB_BDT_BYTECOUNT_SHIFT) | USB_BDT_UOWN | USB_BDT_DTS;
+
+ /* Point to the next ping pong buffer. */
+
+#ifdef CONFIG_USB_PINGPONG
+ bdt->status ^= USB_NEXT_PINGPONG;
+#endif
+ return OK;
}
/****************************************************************************
@@ -1102,10 +1166,10 @@ static int pic32mx_rdcomplete(struct pic32mx_usbdev_s *priv,
static int pic32mx_rdrequest(struct pic32mx_usbdev_s *priv,
struct pic32mx_ep_s *privep)
{
- volatile struct usbotg_bdtentry_s *bdt;
struct pic32mx_req_s *privreq;
uint8_t *dest;
int readlen;
+ int ret;
/* Check the request from the head of the endpoint request queue */
@@ -1138,31 +1202,17 @@ static int pic32mx_rdrequest(struct pic32mx_usbdev_s *priv,
dest = privreq->req.buf + privreq->req.xfrd;
readlen = MIN(privreq->req.len, privep->ep.maxpacket);
- /* Toggle the DTS bit if required */
-
- bdt = privep->bdtout;
-#ifndef CONFIG_USB_PINGPONG
- bdt->status ^= USB_BDT_DATA01;
-#endif
-
- /* Set the data pointer, data length, and enable the endpoint */
-
- bdt->addr = (uint8_t *)PHYS_ADDR(dest);
-
- /* Set the data length and give the BDT to USB. Preserving
- * only the data toggle.
- */
+ /* Handle EP0 in a few special ways */
- bdt->status &= USB_BDT_DATA01;
- bdt->status |= (readlen << USB_BDT_BYTECOUNT_SHIFT) | USB_BDT_UOWN | USB_BDT_DTS;
-
- /* Point to the next ping pong buffer. */
-
-#ifdef CONFIG_USB_PINGPONG
- bdt->status ^= USB_NEXT_PINGPONG;
-#endif
- priv->ctrlstate = CTRLSTATE_RDREQUEST;
- return OK;
+ if (USB_EPNO(privep->ep.eplog) == EP0)
+ {
+ ret = pic32mx_ep0rdsetup(priv, dest, readlen);
+ }
+ else
+ {
+ ret = pic32mx_rdsetup(priv, privep, dest, readlen);
+ }
+ return ret;
}
/****************************************************************************
@@ -1223,15 +1273,14 @@ static void pic32mx_ep0stall(struct pic32mx_usbdev_s *priv)
* the USB. Check anyway.
*/
- volatile struct usbotg_bdtentry_s *bdt = priv->ep0bdtout;
- struct pic32mx_ep_s *privep = &priv->eplist[EP0];
+ struct pic32mx_ep_s *ep0 = &priv->eplist[EP0];
- if ((bdt->status & USB_BDT_UOWN) != 0 &&
- (privep->bdtin->status & (USB_BDT_UOWN | USB_BDT_BSTALL)) == (USB_BDT_UOWN | USB_BDT_BSTALL))
+ if ((ep0->bdtout->status & USB_BDT_UOWN) != 0 &&
+ (ep0->bdtin->status & (USB_BDT_UOWN | USB_BDT_BSTALL)) == (USB_BDT_UOWN | USB_BDT_BSTALL))
{
/* Set ep0 BDT status to stall also */
- bdt->status = (USB_BDT_UOWN | USB_BDT_DATA0 | USB_BDT_DTS | USB_BDT_BSTALL);
+ ep0->bdtout->status = (USB_BDT_UOWN | USB_BDT_DATA0 | USB_BDT_DTS | USB_BDT_BSTALL);
}
/* Then clear the EP0 stall status */
@@ -1351,7 +1400,7 @@ static void pic32mx_ep0setup(struct pic32mx_usbdev_s *priv)
/* Initialize for the SETUP */
- priv->ctrlxfr = CTRLXFR_WAIT_SETUP;
+ priv->ctrlstate = CTRLSTATE_WAITSETUP;
ep0->inpipe.wcount = 0;
ep0->inpipe.inuse = 0;
@@ -1364,7 +1413,7 @@ static void pic32mx_ep0setup(struct pic32mx_usbdev_s *priv)
ullvdbg("SETUP: type=%02x req=%02x value=%04x index=%04x len=%04x\n",
priv->ctrl.type, priv->ctrl.req, value.w, index.w, len.w);
- priv->ctrlstate = CTRLSTATE_IDLE;
+ priv->ctrlstate = CTRLSTATE_WAITSETUP;
/* Dispatch any non-standard requests */
@@ -1856,7 +1905,7 @@ static void pic32mx_ep0setup(struct pic32mx_usbdev_s *priv)
/* Send the response (might be a zero-length packet) */
pic32mx_ep0done();
- priv->ctrlstate = CTRLSTATE_IDLE;
+ priv->ctrlstate = CTRLSTATE_WAITSETUP;
}
}
@@ -1888,57 +1937,47 @@ static void pic32mx_ep0in(struct pic32mx_usbdev_s *priv)
{
bool lastdts = ((bdt->status & USB_BDT_DATA01) != 0);
- if (priv->ctrlxfr == CTRLXFR_IN)
- {
- bdt->addr = (uint8_t *)PHYS_ADDR(&priv->ctrl);
- pic32mx_ep0write();
+ bdt->addr = (uint8_t *)PHYS_ADDR(&priv->ctrl);
+ pic32mx_ep0write();
- if (priv->shortpkt == SHORTPKT_SENT)
- {
- /* If a short packet has been sent, don't want to send any more,
- * stall next time if host is still trying to read.
- */
+ if (priv->shortpkt == SHORTPKT_SENT)
+ {
+ /* If a short packet has been sent, don't want to send any more,
+ * stall next time if host is still trying to read.
+ */
- bdt->status = USB_BDT_UOWN | USB_BDT_BSTALL;
+ bdt->status = USB_BDT_UOWN | USB_BDT_BSTALL;
+ }
+ else
+ {
+ if (lastdts == 0)
+ {
+ bdt->status = USB_BDT_UOWN | USB_BDT_DATA1 | USB_BDT_DTS;
}
else
{
- if (lastdts == 0)
- {
- bdt->status = USB_BDT_UOWN | USB_BDT_DATA1 | USB_BDT_DTS;
- }
- else
- {
- bdt->status = USB_BDT_UOWN | USB_BDT_DATA0 | USB_BDT_DTS;
- }
+ bdt->status = USB_BDT_UOWN | USB_BDT_DATA0 | USB_BDT_DTS;
}
}
-
- /* Must have been a CTRLXFR_OUT status stage IN packet */
-
- else
- {
- /* Handle the next queued write request */
-
-// pic32mx_wrrequest(priv, &priv->eplist[EP0]);
- pic32mx_ep0next(priv);
- }
}
/* No.. Are we processing the completion of a status response? */
- else if (priv->ctrlstate == CTRLSTATE_IDLE)
+ else if (priv->ctrlstate == CTRLSTATE_WAITSETUP)
{
/* Look at the saved SETUP command. Was it a SET ADDRESS request?
* If so, then now is the time to set the address.
*/
- if (priv->ctrl.req == USB_REQ_SETADDRESS &&
- (priv->ctrl.type & REQRECIPIENT_MASK) == (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_DEVICE))
+ if (priv->devstate == DEVSTATE_ADDRPENDING)
{
uint16_t addr = GETUINT16(priv->ctrl.value);
- DEBUGASSERT(priv->devstate == DEVSTATE_ADDRPENDING);
+ /* This should be the equivalent state */
+
+ DEBUGASSERT(priv->ctrl.req == USB_REQ_SETADDRESS &&
+ (priv->ctrl.type & REQRECIPIENT_MASK) ==
+ (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_DEVICE));
pic32mx_putreg(addr, PIC32MX_USB_ADDR);
if (addr > 0)
@@ -1950,9 +1989,17 @@ static void pic32mx_ep0in(struct pic32mx_usbdev_s *priv)
priv->devstate = DEVSTATE_DEFAULT;
}
}
+
+ /* Prepare for the next SETUP transfer */
+
+ pic32mx_ep0next(priv);
}
+
+ /* No other state is expected in this context */
+
else
{
+ usbtrace(TRACE_DEVERROR(PIC32MX_TRACEERR_INVALIDSTATE), priv->ctrlstate);
priv->ctrlstate = CTRLSTATE_STALLED;
}
}
@@ -1964,22 +2011,79 @@ static void pic32mx_ep0in(struct pic32mx_usbdev_s *priv)
static void pic32mx_ep0out(struct pic32mx_usbdev_s *priv)
{
struct pic32mx_ep_s *ep0 = &priv->eplist[EP0];
+
switch (priv->ctrlstate)
{
- case CTRLSTATE_RDREQUEST: /* Write request in progress */
- case CTRLSTATE_IDLE: /* No transfer in progress */
+ case CTRLSTATE_RDREQUEST: /* Read request in progress */
/* Process the next read request for EP0 */
pic32mx_rdcomplete(priv, ep0);
+
+ /* Was this the end of the OUT transfer? */
+
+ if (priv->ctrlstate == CTRLSTATE_WAITSETUP)
+ {
+ /* Prepare EP0 OUT for the next SETUP transaction. */
+
+ ep0->bdtout->status &= ~(USB_BDT_BYTECOUNT_MASK|USB_BDT_DATA01);
+
+ ep0->bdtout->addr = (uint8_t *)PHYS_ADDR(&priv->ctrl);
+ ep0->bdtout->status |= (USB_SIZEOF_CTRLREQ << USB_BDT_BYTECOUNT_SHIFT);
+ ep0->bdtout->status |= (USB_BDT_UOWN | USB_BDT_DATA0 | USB_BDT_DTS | USB_BDT_BSTALL);
+
+ /* Set BSTALL in case the host tries to send more data than
+ * it claims it was going to send.
+ */
+
+ ep0->bdtout->status |= USB_BDT_BSTALL;
+ ep0->outpipe.inuse = 0;
+ }
+ break;
+
+ case CTRLSTATE_WAITSETUP: /* No transfer in progress, waiting for setup */
+ {
+ /* In this case the last OUT transaction must have been a status
+ * stage of a CTRLSTATE_WRREQUEST
+ */
+
+ /* Prepare EP0 OUT for the next SETUP transaction. However,
+ * EP0 may have already been prepared if ping-pong buffering
+ * was enabled on EP0 OUT, and the last control transfer was
+ * of direction: device to host, see pic32mx_ep0done(). If
+ * it was already prepared, we do not want to do anything to
+ * the buffer descriptor table (BDT).
+ */
+
+// pic32mx_wrrequest(priv, &priv->eplist[EP0]);
+ pic32mx_ep0next(priv);
+
+#ifdef CONFIG_USB_PINGPONG
+ if (!priv->ep0ready)
+#endif
+ {
+ ep0->bdtout->status &= ~(USB_BDT_BYTECOUNT_MASK|USB_BDT_DATA01);
+
+ ep0->bdtout->addr = (uint8_t *)PHYS_ADDR(&priv->ctrl);
+ ep0->bdtout->status |= (USB_SIZEOF_CTRLREQ << USB_BDT_BYTECOUNT_SHIFT);
+ ep0->bdtout->status |= (USB_BDT_UOWN | USB_BDT_DATA0 | USB_BDT_DTS | USB_BDT_BSTALL);
+ }
+
+#ifdef CONFIG_USB_PINGPONG
+ priv->ep0ready = 0;
+#endif
+ }
break;
default:
- /* Unexpected state OR host aborted the OUT transfer before it
- * completed, STALL the endpoint in either case
- */
+ {
+ /* Unexpected state OR host aborted the OUT transfer before it
+ * completed, STALL the endpoint in either case
+ */
- priv->ctrlstate = CTRLSTATE_STALLED;
+ usbtrace(TRACE_DEVERROR(PIC32MX_TRACEERR_INVALIDSTATE), priv->ctrlstate);
+ priv->ctrlstate = CTRLSTATE_STALLED;
+ }
break;
}
}
@@ -2002,11 +2106,7 @@ static void pic32mx_ep0transfer(struct pic32mx_usbdev_s *priv, uint16_t status)
volatile struct usbotg_bdtentry_s *bdt = &g_bdt[epno];
priv->eplist[0].bdtout = bdt;
-
- /* Set the next out to the current out packet */
- priv->ep0bdtout = bdt;
-
/* Toggle it to the next ping pong buffer (if applicable) */
bdt->status ^= USB_NEXT_PINGPONG;
@@ -3072,7 +3172,7 @@ static void pic32mx_reset(struct pic32mx_usbdev_s *priv)
/* Reset the device state structure */
- priv->ctrlstate = CTRLSTATE_IDLE;
+ priv->ctrlstate = CTRLSTATE_WAITSETUP;
/* Reset endpoints */
@@ -3288,7 +3388,7 @@ static void pic32mx_hwreset(struct pic32mx_usbdev_s *priv)
/* Get ready for the first packet */
- priv->ep0bdtin = &g_bdt[EP0_IN_EVEN];
+ priv->eplist[EP0].bdtin = &g_bdt[EP0_IN_EVEN];
/* Indicate that we are now in the detached state */