Newer
Older
int nbytes;
int bytesleft;
/* Check the request from the head of the endpoint request queue */
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPINQEMPTY), 0);
uvdbg("len=%d xfrd=%d nullpkt=%d\n",
privreq->req.len, privreq->req.xfrd, privep->txnullpkt);
/* Ignore any attempt to send a zero length packet on anything but EP0IN */
if (privreq->req.len == 0)
{
if (privep->epphy == LPC214X_EP0_IN)
{
lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0);
}
else
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EPINNULLPACKET), 0);
}
/* In any event, the request is complete */
lpc214x_reqcomplete(privep, OK);
return OK;
}
/* Otherwise send the data in the packet (in the DMA on case, we
* may be resuming transfer already in progress.
*/
#warning REVISIT... If the EP supports double buffering, then we can do better
/* Get the number of bytes left to be sent in the packet */
bytesleft = privreq->req.len - privreq->req.xfrd;
/* Send the next packet if (1) there are more bytes to be sent, or
* (2) the last packet sent was exactly maxpacketsize (bytesleft == 0)
*/
usbtrace(TRACE_WRITE(privep->epphy), privreq->req.xfrd);
if (bytesleft > 0 || privep->txnullpkt)
/* Indicate that there is data in the TX FIFO. This will be cleared
* when the EPIN interrupt is received
*/
/* Try to send maxpacketsize -- unless we don't have that many
* bytes to send.
if (bytesleft > privep->ep.maxpacket)
nbytes = privep->ep.maxpacket;
privep->txnullpkt = 0;
}
else
{
nbytes = bytesleft;
privep->txnullpkt = (bytesleft == privep->ep.maxpacket);
}
/* Send the largest number of bytes that we can in this packet */
buf = privreq->req.buf + privreq->req.xfrd;
lpc214x_epwrite(privep->epphy, buf, nbytes);
/* Update for the next time through the loop */
/* If all of the bytes were sent (including any final null packet)
* then we are finished with the transfer
*/
if (bytesleft <= 0 || !privep->txnullpkt)
{
usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
privep->txnullpkt = 0;
lpc214x_reqcomplete(privep, OK);
}
/*******************************************************************************
* Name: lpc214x_rdrequest
*
* Description:
* Receive to the next queued read request
*
*******************************************************************************/
static int lpc214x_rdrequest(struct lpc214x_ep_s *privep)
{
struct lpc214x_req_s *privreq;
ubyte *buf;
int nbytesread;
/* Check the request from the head of the endpoint request queue */
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPOUTQEMPTY), 0);
uvdbg("len=%d xfrd=%d nullpkt=%d\n",
privreq->req.len, privreq->req.xfrd, privep->txnullpkt);
/* Ignore any attempt to receive a zero length packet */
if (privreq->req.len == 0)
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EPOUTNULLPACKET), 0);
lpc214x_reqcomplete(privep, OK);
return OK;
}
#warning REVISIT... Unless the EP supports double buffering, only one packet may be received
usbtrace(TRACE_READ(privep->epphy), privreq->req.xfrd);
for (;;)
{
/* Receive the next packet if (1) there are more bytes to be receive, or
* (2) the last packet was exactly maxpacketsize.
*/
buf = privreq->req.buf + privreq->req.xfrd;
nbytesread = lpc214x_epread(privep->epphy, buf, privep->ep.maxpacket);
if (nbytesread < 0)
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EPREAD), nbytesread);
return ERROR;
}
/* If the receive buffer is full or if the last packet was not full
* then we are finished with the transfer.
*/
privreq->req.xfrd += nbytesread;
if (privreq->req.xfrd >= privreq->req.len || nbytesread < privep->ep.maxpacket)
{
usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
lpc214x_reqcomplete(privep, OK);
return OK;
}
}
return OK; /* Won't get here */
}
/*******************************************************************************
* Name: lpc214x_cancelrequests
*
* Description:
* Cancel all pending requests for an endpoint
*
*******************************************************************************/
static void lpc214x_cancelrequests(struct lpc214x_ep_s *privep)
{
lpc214x_reqcomplete(privep, -ESHUTDOWN);
}
}
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
/*******************************************************************************
* Name: lpc214x_epfindbyaddr
*
* Description:
* Find the physical endpoint structure corresponding to a logic endpoint
* address
*
*******************************************************************************/
static struct lpc214x_ep_s *lpc214x_epfindbyaddr(struct lpc214x_usbdev_s *priv,
uint16 eplog)
{
struct lpc214x_ep_s *privep;
int i;
/* Endpoint zero is a special case */
if (USB_EPNO(eplog) == 0)
{
return &priv->eplist[0];
}
/* Handle the remaining */
for (i = 1; i < LPC214X_NPHYSENDPOINTS; i++)
{
privep = &priv->eplist[i];
/* Same logical endpoint number? (includes direction bit) */
if (eplog == privep->ep.eplog)
{
/* Return endpoint found */
return privep;
}
}
/* Return endpoint not found */
return NULL;
}
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
/*******************************************************************************
* Name: lpc214x_eprealize
*
* Description:
* Enable or disable an endpoint
*
*******************************************************************************/
static void lpc214x_eprealize(struct lpc214x_ep_s *privep, boolean prio, uint32 packetsize)
{
struct lpc214x_usbdev_s *priv = privep->dev;
uint32 mask;
uint32 reg;
/* Initialize endpoint software priority */
mask = 1 << privep->epphy;
if (prio)
{
priv->softprio = priv->softprio | mask;
}
else
{
priv->softprio = priv->softprio & ~mask;
}
/* Clear realize interrupt bit */
lpc214x_putreg(USBDEV_DEVINT_EPRLZED, LPC214X_USBDEV_DEVINTCLR);
/* Realize the endpoint */
reg = lpc214x_getreg(LPC214X_USBDEV_REEP);
reg |= (1 << privep->epphy);
lpc214x_putreg(reg, LPC214X_USBDEV_REEP);
/* Set endpoint maximum packet size */
lpc214x_putreg(privep->epphy, LPC214X_USBDEV_EPIND);
lpc214x_putreg(packetsize, LPC214X_USBDEV_MAXPSIZE);
/* Wait for Realize complete */
while ((lpc214x_getreg(LPC214X_USBDEV_DEVINTST) & USBDEV_DEVINT_EPRLZED) == 0);
/* Clear realize interrupt bit */
lpc214x_putreg(USBDEV_DEVINT_EPRLZED,LPC214X_USBDEV_DEVINTCLR);
}
/*******************************************************************************
* Name: lpc214x_epclrinterrupt
*
* Description:
* Clear the EP interrupt flag and return the current EP status
*
*******************************************************************************/
static ubyte lpc214x_epclrinterrupt(ubyte epphy)
{
/* Clear the endpoint interrupt */
lpc214x_putreg(1 << epphy, LPC214X_USBDEV_EPINTCLR);
/* Wait for data in the command data register */
while ((lpc214x_getreg(LPC214X_USBDEV_DEVINTST) & USBDEV_DEVINT_CDFULL) == 0);
/* Return the value of the command data register */
return lpc214x_getreg(LPC214X_USBDEV_CMDDATA);
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
}
/*******************************************************************************
* Name: lpc214x_ep0configure
*
* Description:
* Configure endpoint 0
*
*******************************************************************************/
static inline void lpc214x_ep0configure(struct lpc214x_usbdev_s *priv)
{
uint32 inten;
/* EndPoint 0 initialization */
lpc214x_eprealize(&priv->eplist[LPC214X_CTRLEP_OUT], 0, CONFIG_USBDEV_EP0_MAXSIZE);
lpc214x_eprealize(&priv->eplist[LPC214X_CTRLEP_IN], 1, CONFIG_USBDEV_EP0_MAXSIZE);
/* Enable EP0 interrupts (not DMA) */
inten = lpc214x_getreg(LPC214X_USBDEV_EPINTEN);
inten |= 3; /* EP0 Rx and Tx */
lpc214x_putreg(inten, LPC214X_USBDEV_EPINTEN);
}
/*******************************************************************************
* Name: lpc214x_dmareset
*
* Description: Reset USB DMA
*
*******************************************************************************/
#ifdef CONFIG_LPC214X_USBDEV_DMA
static inline void lpc214x_dmareset(uint32 enable)
{
int i;
/* Disable All DMA interrupts */
lpc214x_putreg(0, LPC214X_USBDEV_DMAINTEN);
lpc214x_putreg(0xffffffff, LPC214X_USBDEV_EPDMADIS);
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
/* DMA Request clear */
putreq32(0xffffffff, LPC214X_USBDEV_DMARCLR);
/* End of Transfer Interrupt Clear */
putreq32(0xffffffff, LPC214X_USBDEV_EOTINTCLR);
/* New DD Request Interrupt Clear */
putreq32(0xffffffff, LPC214X_USBDEV_NDDRINTCLR);
/* System Error Interrupt Clear */
putreq32(0xffffffff, LPC214X_USBDEV_SYSERRINTCLR);
/* Nullify all pointers in the UDCA */
for (i = 0; i < LPC214X_NPHYSENDPOINTS; ++i)
{
USB_UDCA[i] = NULL;
}
/* Set USB UDCA Head register */
lpc214x_putreg((uint32)USB_UDCA, LPC214X_USBDEV_UDCAH);
/* Invalidate all DMA descriptors */
for (i = 0; i < CONFIG_LPC214X_USBDEV_NDMADESCRIPTORS; ++i)
{
memset(&USB_DDESC[i], 0, USB_DDESCSIZE);
}
/* Enable DMA interrupts */
lpc214x_putreg(enable, LPC214X_USBDEV_DMAINTEN);
}
#endif
/*******************************************************************************
* Name: lpc214x_usbreset
*
* Description:
* Reset Usb engine
*
*******************************************************************************/
static void lpc214x_usbreset(struct lpc214x_usbdev_s *priv)
{
/* Disable all endpoint interrupts */
lpc214x_putreg(0, LPC214X_USBDEV_EPINTEN);
/* Frame is Hp interrupt */
lpc214x_putreg(1, LPC214X_USBDEV_DEVINTPRI);
/* Clear all pending interrupts */
lpc214x_putreg(0xffffffff, LPC214X_USBDEV_EPINTCLR);
lpc214x_putreg(0xffffffff, LPC214X_USBDEV_DEVINTCLR);
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
/* Periperhal address is needed */
priv->paddrset = 0;
/* Endpoints not yet configured */
lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 0);
/* EndPoint 0 initialization */
lpc214x_ep0configure(priv);
#ifdef CONFIG_LPC214X_USBDEV_DMA
/* Enable End_of_Transfer_Interrupt and System_Error_Interrupt USB DMA
* interrupts
*/
lpc214x_dmareset(CONFIG_LPC214X_USBDEV_DMAINTMASK);
#endif
/* Enable Device interrupts */
lpc214x_putreg(USB_SLOW_INT|USB_DEVSTATUS_INT|USB_FAST_INT|USB_FRAME_INT|USB_ERROR_INT,
LPC214X_USBDEV_DEVINTEN);
}
/*******************************************************************************
* Name: lpc214x_dispatchrequest
*
* Description:
* Provide unhandled setup actions to the class driver. This is logically part
* of the USB interrupt handler.
*
*******************************************************************************/
static void lpc214x_dispatchrequest(struct lpc214x_usbdev_s *priv,
{
int ret;
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DISPATCH), 0);
if (priv && priv->driver)
{
/* Forward to the control request to the class driver implementation */
ret = CLASS_SETUP(priv->driver, &priv->usbdev, ctrl);
if (ret < 0)
{
/* Stall on failure */
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_DISPATCHSTALL), 0);
priv->stalled = 1;
}
}
}
/*******************************************************************************
* Name: lpc214x_ep0setup
*
* Description:
* USB Ctrl EP Setup Event. This is logically part of the USB interrupt
* handler. This event occurs when a setup packet is receive on EP0 OUT.
*
*******************************************************************************/
static inline void lpc214x_ep0setup(struct lpc214x_usbdev_s *priv)
{
struct lpc214x_ep_s *ep0 = &priv->eplist[LPC214X_EP0_OUT];
struct lpc214x_req_s *privreq = lpc214x_rqpeek(ep0);
ubyte response[2];
int ret;
/* Starting a control request? */
if (priv->usbdev.speed == USB_SPEED_UNKNOWN)
{
priv->usbdev.speed = USB_SPEED_FULL;
lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 1);
}
/* Terminate any pending requests */
{
sint16 result = OK;
if (privreq->req.xfrd != privreq->req.len)
{
result = -EPROTO;
}
usbtrace(TRACE_COMPLETE(ep0->epphy), privreq->req.xfrd);
lpc214x_reqcomplete(ep0, result);
}
/* Assume NOT stalled */
ep0->stalled = 0;
priv->stalled = 0;
/* Read EP0 data */
ret = lpc214x_epread(LPC214X_EP0_OUT, (ubyte*)&ctrl, USB_SIZEOF_CTRLREQ);
if (ret <= 0)
{
return;
}
/* And extract the little-endian 16-bit values to host order */
value = GETUINT16(ctrl.value);
index = GETUINT16(ctrl.index);
len = GETUINT16(ctrl.len);
uvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n",
/* Dispatch any non-standard requests */
if ((ctrl.type & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD)
return;
}
/* Handle standard request. Pick off the things of interest to the
* USB device controller driver; pass what is left to the class driver
*/
{
case USB_REQ_GETSTATUS:
{
/* type: device-to-host; recipient = device, interface, endpoint
* value: 0
* index: zero interface endpoint
* len: 2; data = status
*/
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_GETSTATUS), 0);
if (!priv->paddrset || len != 2 ||
(ctrl.type & USB_REQ_DIR_IN) == 0 || value != 0)
{
priv->stalled = 1;
}
else
{
{
case USB_REQ_RECIPIENT_ENDPOINT:
{
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EPGETSTATUS), 0);
privep = lpc214x_epfindbyaddr(priv, index);
if (!privep)
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADEPGETSTATUS), 0);
priv->stalled = 1;
}
else
{
if ((lpc214x_usbcmd(CMD_USB_EP_SELECT|privep->epphy, 0) & CMD_USB_EPSELECT_ST) != 0)
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
{
response[0] = 1; /* Stalled */
}
else
{
response[0] = 0; /* Not stalled */
}
response[1] = 0;
lpc214x_epwrite(LPC214X_EP0_IN, response, 2);
priv->ep0state = LPC214X_EP0SHORTWRITE;
}
}
break;
case USB_REQ_RECIPIENT_DEVICE:
{
if (index == 0)
{
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_DEVGETSTATUS), 0);
/* Features: Remote Wakeup=YES; selfpowered=? */
response[0] = (priv->selfpowered << USB_FEATURE_SELFPOWERED) |
(1 << USB_FEATURE_REMOTEWAKEUP);
response[1] = 0;
lpc214x_epwrite(LPC214X_EP0_IN, response, 2);
priv->ep0state = LPC214X_EP0SHORTWRITE;
}
else
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADDEVGETSTATUS), 0);
priv->stalled = 1;
}
}
break;
case USB_REQ_RECIPIENT_INTERFACE:
{
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_IFGETSTATUS), 0);
response[0] = 0;
response[1] = 0;
lpc214x_epwrite(LPC214X_EP0_IN, response, 2);
priv->ep0state = LPC214X_EP0SHORTWRITE;
}
break;
default:
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADGETSTATUS), 0);
priv->stalled = 1;
}
break;
}
}
}
break;
case USB_REQ_CLEARFEATURE:
{
/* type: host-to-device; recipient = device, interface or endpoint
* value: feature selector
* index: zero interface endpoint;
* len: zero, data = none
*/
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_CLEARFEATURE), 0);
if ((ctrl.type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_ENDPOINT)
else if (priv->paddrset != 0 && value == USB_FEATURE_ENDPOINTHALT && len == 0 &&
(privep = lpc214x_epfindbyaddr(priv, index)) != NULL)
lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0);
priv->ep0state = LPC214X_EP0STATUSIN;
}
else
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADCLEARFEATURE), 0);
priv->stalled = 1;
}
}
break;
case USB_REQ_SETFEATURE:
{
/* type: host-to-device; recipient = device, interface, endpoint
* value: feature selector
* index: zero interface endpoint;
* len: 0; data = none
*/
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_SETFEATURE), 0);
if (((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) &&
else if ((ctrl.type & USB_REQ_RECIPIENT_MASK) != USB_REQ_RECIPIENT_ENDPOINT)
else if (priv->paddrset != 0 && value == USB_FEATURE_ENDPOINTHALT && len == 0 &&
(privep = lpc214x_epfindbyaddr(priv, index)) != NULL)
lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0);
priv->ep0state = LPC214X_EP0STATUSIN;
}
else
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADSETFEATURE), 0);
priv->stalled = 1;
}
}
break;
case USB_REQ_SETADDRESS:
{
/* type: host-to-device; recipient = device
* value: device address
* index: 0
* len: 0; data = none
*/
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EP0SETUPSETADDRESS), value);
if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
/* Save the address. We cannot actually change to the next address until
* the completion of the status phase.
*/
priv->paddr = ctrl.value[0];
/* Note that if we send the SETADDRESS command twice, that will force the
* address change. Otherwise, the hardware will automatically set the
* address at the end of the status phase.
*/
lpc214x_usbcmd(CMD_USB_DEV_SETADDRESS, CMD_USB_SETADDRESS_DEVEN | priv->paddr);
/* Send a NULL packet. The status phase completes when the null packet has
* been sent successfully.
*/
lpc214x_epwrite(LPC214X_EP0_IN, NULL, 0);
priv->ep0state = LPC214X_EP0SETADDRESS;
}
else
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADSETADDRESS), 0);
priv->stalled = 1;
}
}
break;
case USB_REQ_GETDESCRIPTOR:
/* type: device-to-host; recipient = device
* value: descriptor type and index
* index: 0 or language ID;
* len: descriptor len; data = descriptor
*/
/* type: host-to-device; recipient = device
* value: descriptor type and index
* index: 0 or language ID;
* len: descriptor len; data = descriptor
*/
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_GETSETDESC), 0);
if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE)
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADGETSETDESC), 0);
priv->stalled = 1;
}
}
break;
case USB_REQ_GETCONFIGURATION:
/* type: device-to-host; recipient = device
* value: 0;
* index: 0;
* len: 1; data = configuration value
*/
{
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_GETCONFIG), 0);
if (priv->paddrset && (ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
{
lpc214x_dispatchrequest(priv, &ctrl);
}
else
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADGETCONFIG), 0);
priv->stalled = 1;
}
}
break;
case USB_REQ_SETCONFIGURATION:
/* type: host-to-device; recipient = device
* value: configuration value
* index: 0;
* len: 0; data = none
*/
{
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_SETCONFIG), 0);
if ((ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
{
lpc214x_dispatchrequest(priv, &ctrl);
}
else
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_BADSETCONFIG), 0);
priv->stalled = 1;
}
}
break;
/* type: device-to-host; recipient = interface
* value: 0
* index: interface;
* len: 1; data = alt interface
*/
/* type: host-to-device; recipient = interface
* value: alternate setting
* index: interface;
* len: 0; data = none
*/
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_GETSETIF), 0);
lpc214x_dispatchrequest(priv, &ctrl);
}
break;
case USB_REQ_SYNCHFRAME:
/* type: device-to-host; recipient = endpoint
* value: 0
* index: endpoint;
* len: 2; data = frame number
*/
{
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_SYNCHFRAME), 0);
}
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_INVALIDCTRLREQ), 0);
priv->stalled = 1;
}
break;
}
if (priv->stalled)
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EP0SETUPSTALLED), priv->ep0state);
lpc214x_epstall(&ep0->ep, FALSE);
lpc214x_epstall(&ep0->ep, FALSE);
}
}
/*******************************************************************************
* Name: lpc214x_ep0dataoutinterrupt
*
* Description:
* USB Ctrl EP Data OUT Event. This is logically part of the USB interrupt
* handler. Each non-isochronous OUT endpoint gives an interrupt when they
* receive a packet without error.
*
*******************************************************************************/
static inline void lpc214x_ep0dataoutinterrupt(struct lpc214x_usbdev_s *priv)
{
struct lpc214x_ep_s *ep0;
uint32 pktlen;
/* Copy new setup packet into setup buffer */
switch (priv->ep0state)
{
case LPC214X_EP0SHORTWRITE:
{
priv->ep0state = LPC214X_EP0STATUSOUT;
pktlen = lpc214x_epread(LPC214X_EP0_OUT, NULL, CONFIG_USBDEV_EP0_MAXSIZE);
if (LPC214X_READOVERRUN(pktlen))
{
lpc214x_ep0setup(priv);
}
}
break;
case LPC214X_EP0SHORTWRSENT:
{
priv->ep0state = LPC214X_EP0REQUEST;
pktlen = lpc214x_epread(LPC214X_EP0_OUT, NULL, CONFIG_USBDEV_EP0_MAXSIZE);
if (LPC214X_READOVERRUN(pktlen))
{
lpc214x_ep0setup(priv);
}
}
break;
/* Process the next request action (if any) */
lpc214x_rdrequest(&priv->eplist[LPC214X_EP0_OUT]);
}
break;
default:
priv->stalled = 1;
break;
}
if (priv->stalled)
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EP0OUTSTALLED), priv->ep0state);
ep0 = &priv->eplist[LPC214X_EP0_OUT];
lpc214x_epstall(&ep0->ep, FALSE);
lpc214x_epstall(&ep0->ep, FALSE);
}
return;
}
/*******************************************************************************
* Name: lpc214x_ep0dataininterrupt
*
* Description:
* USB Ctrl EP Data IN Event. This is logically part of the USB interrupt
* handler. All non-isochronous IN endpoints give this interrupt when a
* packet is successfully transmitted (OR a NAK handshake is sent on the bus
* provided that the interrupt on NAK feature is enabled).
*
*******************************************************************************/
static inline void lpc214x_ep0dataininterrupt(struct lpc214x_usbdev_s *priv)
{
struct lpc214x_ep_s *ep0;
switch (priv->ep0state)
{
case LPC214X_EP0STATUSOUT:
case LPC214X_EP0STATUSIN:
priv->ep0state = LPC214X_EP0REQUEST;
break;
case LPC214X_EP0SHORTWRITE:
priv->ep0state = LPC214X_EP0SHORTWRSENT;
break;
case LPC214X_EP0SETADDRESS:
{
/* If the address was set to a non-zero value, then thiscompletes the
* default phase, and begins the address phase (still not fully configured)
usbtrace(TRACE_INTDECODE(LPC214X_TRACEINTID_EP0INSETADDRESS), (uint16)priv->paddr);
lpc214x_usbcmd(CMD_USB_DEV_CONFIG, 0);
priv->ep0state = LPC214X_EP0REQUEST;
case LPC214X_EP0REQUEST:
{
/* Process the next request action (if any) */
ep0 = &priv->eplist[LPC214X_EP0_IN];
ep0->txbusy = 0;
lpc214x_wrrequest(ep0);
default:
priv->stalled = 1;
break;
}
if (priv->stalled)
{
usbtrace(TRACE_DEVERROR(LPC214X_TRACEERR_EP0INSTALLED), priv->ep0state);
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
ep0 = &priv->eplist[LPC214X_EP0_IN];
lpc214x_epstall(&ep0->ep, FALSE);
lpc214x_epstall(&ep0->ep, FALSE);
}
}
/*******************************************************************************
* Name: lpc214x_usbinterrupt
*
* Description:
* USB interrupt handler
*
*******************************************************************************/
static int lpc214x_usbinterrupt(int irq, FAR void *context)
{
struct lpc214x_usbdev_s *priv = &g_usbdev;
struct lpc214x_ep_s *privep ;
uint32 devintstatus; /* Sampled state of the device interrupt status register */
uint32 epintstatus; /* Sampled state of the endpoint interrupt status register */
#ifdef CONFIG_LPC214X_USBDEV_DMA
uint32 dmaintstatus; /* Sampled state of dma interrupt status register */
#endif
uint32 softprio; /* Current priority interrupt bitset */
uint32 pending; /* Pending subset of priority interrupt bitset */
ubyte epphy; /* Physical endpoint number being processed */
int i;
usbtrace(TRACE_INTENTRY(LPC214X_TRACEINTID_USB), 0);
/* Read the device interrupt status register */
devintstatus = lpc214x_getreg(LPC214X_USBDEV_DEVINTST);
#ifdef CONFIG_LPC214X_USBDEV_DMA