Skip to content

Commit

Permalink
Workaround for bad values read from the STM32_OTGFS_GRXSTSP register …
Browse files Browse the repository at this point in the history
…are 0xb4e48168 or 0xa80c9367 or 267E781c All of which provide out of range indexes for epout[epphy]
  • Loading branch information
David Sidrane committed Apr 25, 2015
1 parent 94818ce commit b5de8a2
Showing 1 changed file with 134 additions and 126 deletions.
260 changes: 134 additions & 126 deletions nuttx/arch/arm/src/stm32/stm32_otgfsdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -3123,134 +3123,142 @@ static inline void stm32_rxinterrupt(FAR struct stm32_usbdev_s *priv)
/* Decode status fields */

epphy = (regval & OTGFS_GRXSTSD_EPNUM_MASK) >> OTGFS_GRXSTSD_EPNUM_SHIFT;
privep = &priv->epout[epphy];

/* Handle the RX event according to the packet status field */

switch (regval & OTGFS_GRXSTSD_PKTSTS_MASK)
{
/* Global OUT NAK. This indicate that the global OUT NAK bit has taken
* effect.
*
* PKTSTS = Global OUT NAK, BCNT = 0, EPNUM = Don't Care, DPID = Don't
* Care.
*/

case OTGFS_GRXSTSD_PKTSTS_OUTNAK:
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_OUTNAK), 0);
}
break;

/* OUT data packet received.
*
* PKTSTS = DataOUT, BCNT = size of the received data OUT packet,
* EPNUM = EPNUM on which the packet was received, DPID = Actual Data PID.
*/

case OTGFS_GRXSTSD_PKTSTS_OUTRECVD:
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_OUTRECVD), epphy);
bcnt = (regval & OTGFS_GRXSTSD_BCNT_MASK) >> OTGFS_GRXSTSD_BCNT_SHIFT;
if (bcnt > 0)
{
stm32_epout_receive(privep, bcnt);
}
}
break;

/* OUT transfer completed. This indicates that an OUT data transfer for
* the specified OUT endpoint has completed. After this entry is popped
* from the receive FIFO, the core asserts a Transfer Completed interrupt
* on the specified OUT endpoint.
*
* PKTSTS = Data OUT Transfer Done, BCNT = 0, EPNUM = OUT EP Num on
* which the data transfer is complete, DPID = Don't Care.
*/

case OTGFS_GRXSTSD_PKTSTS_OUTDONE:
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_OUTDONE), epphy);
}
break;

/* SETUP transaction completed. This indicates that the Setup stage for
* the specified endpoint has completed and the Data stage has started.
* After this entry is popped from the receive FIFO, the core asserts a
* Setup interrupt on the specified control OUT endpoint (triggers an
* interrupt).
*
* PKTSTS = Setup Stage Done, BCNT = 0, EPNUM = Control EP Num,
* DPID = Don't Care.
*/

case OTGFS_GRXSTSD_PKTSTS_SETUPDONE:
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SETUPDONE), epphy);
}
break;

/* SETUP data packet received. This indicates that a SETUP packet for the
* specified endpoint is now available for reading from the receive FIFO.
*
* PKTSTS = SETUP, BCNT = 8, EPNUM = Control EP Num, DPID = D0.
*/

case OTGFS_GRXSTSD_PKTSTS_SETUPRECVD:
{
uint16_t datlen;

usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SETUPRECVD), epphy);

/* Read EP0 setup data. NOTE: If multiple SETUP packets are received,
* the last one overwrites the previous setup packets and only that
* last SETUP packet will be processed.
*/

stm32_rxfifo_read(&priv->epout[EP0], (FAR uint8_t*)&priv->ctrlreq,
USB_SIZEOF_CTRLREQ);

/* Was this an IN or an OUT SETUP packet. If it is an OUT SETUP,
* then we need to wait for the completion of the data phase to
* process the setup command. If it is an IN SETUP packet, then
* we must processing the command BEFORE we enter the DATA phase.
*
* If the data associated with the OUT SETUP packet is zero length,
* then, of course, we don't need to wait.
*/

datlen = GETUINT16(priv->ctrlreq.len);
if (USB_REQ_ISOUT(priv->ctrlreq.type) && datlen > 0)
{
/* Clear NAKSTS so that we can receive the data */

regval = stm32_getreg(STM32_OTGFS_DOEPCTL0);
regval |= OTGFS_DOEPCTL0_CNAK;
stm32_putreg(regval, STM32_OTGFS_DOEPCTL0);

/* Wait for the data phase. */

priv->ep0state = EP0STATE_SETUP_OUT;
}
else
{
/* We can process the setup data as soon as SETUP done word is
* popped of the RxFIFO.
*/

priv->ep0state = EP0STATE_SETUP_READY;
}
}
break;

default:
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS),
(regval & OTGFS_GRXSTSD_PKTSTS_MASK) >> OTGFS_GRXSTSD_PKTSTS_SHIFT);
}
break;
}
/* Workaround for bad values read from the STM32_OTGFS_GRXSTSP register
* happens regval is 0xb4e48168 or 0xa80c9367 or 267E781c
* All of which provide out of range indexes for epout[epphy]
*/

if (epphy < STM32_NENDPOINTS)
{
privep = &priv->epout[epphy];

/* Handle the RX event according to the packet status field */

switch (regval & OTGFS_GRXSTSD_PKTSTS_MASK)
{
/* Global OUT NAK. This indicate that the global OUT NAK bit has taken
* effect.
*
* PKTSTS = Global OUT NAK, BCNT = 0, EPNUM = Don't Care, DPID = Don't
* Care.
*/

case OTGFS_GRXSTSD_PKTSTS_OUTNAK:
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_OUTNAK), 0);
}
break;

/* OUT data packet received.
*
* PKTSTS = DataOUT, BCNT = size of the received data OUT packet,
* EPNUM = EPNUM on which the packet was received, DPID = Actual Data PID.
*/

case OTGFS_GRXSTSD_PKTSTS_OUTRECVD:
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_OUTRECVD), epphy);
bcnt = (regval & OTGFS_GRXSTSD_BCNT_MASK) >> OTGFS_GRXSTSD_BCNT_SHIFT;
if (bcnt > 0)
{
stm32_epout_receive(privep, bcnt);
}
}
break;

/* OUT transfer completed. This indicates that an OUT data transfer for
* the specified OUT endpoint has completed. After this entry is popped
* from the receive FIFO, the core asserts a Transfer Completed interrupt
* on the specified OUT endpoint.
*
* PKTSTS = Data OUT Transfer Done, BCNT = 0, EPNUM = OUT EP Num on
* which the data transfer is complete, DPID = Don't Care.
*/

case OTGFS_GRXSTSD_PKTSTS_OUTDONE:
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_OUTDONE), epphy);
}
break;

/* SETUP transaction completed. This indicates that the Setup stage for
* the specified endpoint has completed and the Data stage has started.
* After this entry is popped from the receive FIFO, the core asserts a
* Setup interrupt on the specified control OUT endpoint (triggers an
* interrupt).
*
* PKTSTS = Setup Stage Done, BCNT = 0, EPNUM = Control EP Num,
* DPID = Don't Care.
*/

case OTGFS_GRXSTSD_PKTSTS_SETUPDONE:
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SETUPDONE), epphy);
}
break;

/* SETUP data packet received. This indicates that a SETUP packet for the
* specified endpoint is now available for reading from the receive FIFO.
*
* PKTSTS = SETUP, BCNT = 8, EPNUM = Control EP Num, DPID = D0.
*/

case OTGFS_GRXSTSD_PKTSTS_SETUPRECVD:
{
uint16_t datlen;

usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SETUPRECVD), epphy);

/* Read EP0 setup data. NOTE: If multiple SETUP packets are received,
* the last one overwrites the previous setup packets and only that
* last SETUP packet will be processed.
*/

stm32_rxfifo_read(&priv->epout[EP0], (FAR uint8_t*)&priv->ctrlreq,
USB_SIZEOF_CTRLREQ);

/* Was this an IN or an OUT SETUP packet. If it is an OUT SETUP,
* then we need to wait for the completion of the data phase to
* process the setup command. If it is an IN SETUP packet, then
* we must processing the command BEFORE we enter the DATA phase.
*
* If the data associated with the OUT SETUP packet is zero length,
* then, of course, we don't need to wait.
*/

datlen = GETUINT16(priv->ctrlreq.len);
if (USB_REQ_ISOUT(priv->ctrlreq.type) && datlen > 0)
{
/* Clear NAKSTS so that we can receive the data */

regval = stm32_getreg(STM32_OTGFS_DOEPCTL0);
regval |= OTGFS_DOEPCTL0_CNAK;
stm32_putreg(regval, STM32_OTGFS_DOEPCTL0);

/* Wait for the data phase. */

priv->ep0state = EP0STATE_SETUP_OUT;
}
else
{
/* We can process the setup data as soon as SETUP done word is
* popped of the RxFIFO.
*/

priv->ep0state = EP0STATE_SETUP_READY;
}
}
break;

default:
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS),
(regval & OTGFS_GRXSTSD_PKTSTS_MASK) >> OTGFS_GRXSTSD_PKTSTS_SHIFT);
}
break;
}
}
/* Enable the Rx Status Queue Level interrupt */

regval = stm32_getreg(STM32_OTGFS_GINTMSK);
Expand Down

0 comments on commit b5de8a2

Please sign in to comment.