Updates to the PIC32 USB driver (still kind of buggy); Fix for STM32 CAN2 -- Need to enable CAN1 clocking to use CAN2
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4493 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
ea932c224a
commit
e74e3c7195
@ -287,9 +287,9 @@ static inline void rcc_enableapb1(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_STM32_CAN2
|
#ifdef CONFIG_STM32_CAN2
|
||||||
/* CAN2 clock enable */
|
/* CAN2 clock enable. NOTE: CAN2 needs CAN1 clock as well. */
|
||||||
|
|
||||||
regval |= RCC_APB1ENR_CAN2EN;
|
regval |= (RCC_APB1ENR_CAN1EN | RCC_APB1ENR_CAN2EN);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_STM32_BKP
|
#ifdef CONFIG_STM32_BKP
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* arch/arm/src/stm32/stm32f20xxx_rcc.c
|
* arch/arm/src/stm32/stm32f20xxx_rcc.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -420,9 +420,9 @@ static inline void rcc_enableapb1(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_STM32_CAN2
|
#if CONFIG_STM32_CAN2
|
||||||
/* CAN 2 clock enable */
|
/* CAN2 clock enable. NOTE: CAN2 needs CAN1 clock as well. */
|
||||||
|
|
||||||
regval |= RCC_APB1ENR_CAN2EN;
|
regval |= (RCC_APB1ENR_CAN1EN | RCC_APB1ENR_CAN2EN);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Power interface clock enable. The PWR block is always enabled so that
|
/* Power interface clock enable. The PWR block is always enabled so that
|
||||||
|
@ -420,9 +420,9 @@ static inline void rcc_enableapb1(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_STM32_CAN2
|
#ifdef CONFIG_STM32_CAN2
|
||||||
/* CAN 2 clock enable */
|
/* CAN2 clock enable. NOTE: CAN2 needs CAN1 clock as well. */
|
||||||
|
|
||||||
regval |= RCC_APB1ENR_CAN2EN;
|
regval |= (RCC_APB1ENR_CAN1EN | RCC_APB1ENR_CAN2EN);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Power interface clock enable. The PWR block is always enabled so that
|
/* Power interface clock enable. The PWR block is always enabled so that
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <wdog.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
#include <nuttx/arch.h>
|
#include <nuttx/arch.h>
|
||||||
@ -167,7 +168,10 @@
|
|||||||
/* Request queue operations *************************************************/
|
/* Request queue operations *************************************************/
|
||||||
|
|
||||||
#define pic32mx_rqempty(q) ((q)->head == NULL)
|
#define pic32mx_rqempty(q) ((q)->head == NULL)
|
||||||
#define pic32mx_rqpeek(q) ((q)->head)
|
#define pic32mx_rqhead(q) ((q)->head)
|
||||||
|
#define pic32mx_rqtail(q) ((q)->tail)
|
||||||
|
|
||||||
|
#define RESTART_DELAY (150 * CLOCKS_PER_SEC / 1000)
|
||||||
|
|
||||||
/* USB trace ****************************************************************/
|
/* USB trace ****************************************************************/
|
||||||
/* Trace error codes */
|
/* Trace error codes */
|
||||||
@ -349,7 +353,7 @@ union wb_u
|
|||||||
struct pic32mx_req_s
|
struct pic32mx_req_s
|
||||||
{
|
{
|
||||||
struct usbdev_req_s req; /* Standard USB request */
|
struct usbdev_req_s req; /* Standard USB request */
|
||||||
uint16_t inflight; /* The number of bytes "in-flight" */
|
uint16_t inflight[2]; /* The number of bytes "in-flight" */
|
||||||
struct pic32mx_req_s *flink; /* Supports a singly linked list */
|
struct pic32mx_req_s *flink; /* Supports a singly linked list */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -410,6 +414,8 @@ struct pic32mx_usbdev_s
|
|||||||
uint8_t ep0done:1; /* EP0 OUT already prepared */
|
uint8_t ep0done:1; /* EP0 OUT already prepared */
|
||||||
uint8_t rxbusy:1; /* EP0 OUT data transfer in progress */
|
uint8_t rxbusy:1; /* EP0 OUT data transfer in progress */
|
||||||
uint16_t epavail; /* Bitset of available endpoints */
|
uint16_t epavail; /* Bitset of available endpoints */
|
||||||
|
uint16_t epstalled; /* Bitset of stalled endpoints */
|
||||||
|
WDOG_ID wdog; /* Supports the restart delay */
|
||||||
|
|
||||||
/* The endpoint list */
|
/* The endpoint list */
|
||||||
|
|
||||||
@ -443,9 +449,6 @@ static void pic32mx_addfirst(struct pic32mx_queue_s *queue,
|
|||||||
|
|
||||||
/* Request Helpers **********************************************************/
|
/* Request Helpers **********************************************************/
|
||||||
|
|
||||||
static inline void
|
|
||||||
pic32mx_abortrequest(struct pic32mx_ep_s *privep,
|
|
||||||
struct pic32mx_req_s *privreq, int16_t result);
|
|
||||||
static void pic32mx_reqreturn(struct pic32mx_ep_s *privep,
|
static void pic32mx_reqreturn(struct pic32mx_ep_s *privep,
|
||||||
struct pic32mx_req_s *privreq, int16_t result);
|
struct pic32mx_req_s *privreq, int16_t result);
|
||||||
static void pic32mx_reqcomplete(struct pic32mx_ep_s *privep,
|
static void pic32mx_reqcomplete(struct pic32mx_ep_s *privep,
|
||||||
@ -455,9 +458,12 @@ static void pic32mx_epwrite(struct pic32mx_ep_s *privep,
|
|||||||
const uint8_t *src, uint32_t nbytes);
|
const uint8_t *src, uint32_t nbytes);
|
||||||
static void pic32mx_wrcomplete(struct pic32mx_usbdev_s *priv,
|
static void pic32mx_wrcomplete(struct pic32mx_usbdev_s *priv,
|
||||||
struct pic32mx_ep_s *privep);
|
struct pic32mx_ep_s *privep);
|
||||||
static void pic32mx_rqrestart(struct pic32mx_usbdev_s *priv,
|
static void pic32mx_rqrestart(int argc, uint32_t arg1, ...);
|
||||||
struct pic32mx_ep_s *privep);
|
static void pic32mx_delayedrestart(struct pic32mx_usbdev_s *priv,
|
||||||
|
uint8_t epno);
|
||||||
static void pic32mx_rqstop(struct pic32mx_ep_s *privep);
|
static void pic32mx_rqstop(struct pic32mx_ep_s *privep);
|
||||||
|
static int pic32mx_wrstart(struct pic32mx_usbdev_s *priv,
|
||||||
|
struct pic32mx_ep_s *privep);
|
||||||
static int pic32mx_wrrequest(struct pic32mx_usbdev_s *priv,
|
static int pic32mx_wrrequest(struct pic32mx_usbdev_s *priv,
|
||||||
struct pic32mx_ep_s *privep);
|
struct pic32mx_ep_s *privep);
|
||||||
static int pic32mx_rdcomplete(struct pic32mx_usbdev_s *priv,
|
static int pic32mx_rdcomplete(struct pic32mx_usbdev_s *priv,
|
||||||
@ -761,24 +767,6 @@ static void pic32mx_addfirst(struct pic32mx_queue_s *queue, struct pic32mx_req_s
|
|||||||
queue->head = req;
|
queue->head = req;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: pic32mx_abortrequest
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
pic32mx_abortrequest(struct pic32mx_ep_s *privep, struct pic32mx_req_s *privreq, int16_t result)
|
|
||||||
{
|
|
||||||
usbtrace(TRACE_DEVERROR(PIC32MX_TRACEERR_REQABORTED), (uint16_t)USB_EPNO(privep->ep.eplog));
|
|
||||||
|
|
||||||
/* Save the result in the request structure */
|
|
||||||
|
|
||||||
privreq->req.result = result;
|
|
||||||
|
|
||||||
/* Callback to the request completion handler */
|
|
||||||
|
|
||||||
privreq->req.callback(&privep->ep, &privreq->req);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: pic32mx_reqreturn
|
* Name: pic32mx_reqreturn
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -889,12 +877,12 @@ static void pic32mx_wrcomplete(struct pic32mx_usbdev_s *priv,
|
|||||||
int bytesleft;
|
int bytesleft;
|
||||||
int epno;
|
int epno;
|
||||||
|
|
||||||
/* Check the request from the head of the endpoint's active request queue.
|
/* Check the request at the head of the endpoint's active request queue.
|
||||||
* Since we got here from a write completion event, the active request queue
|
* Since we got here from a write completion event, the active request queue
|
||||||
* should not be empty.
|
* should not be empty.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
privreq = pic32mx_rqpeek(&privep->active);
|
privreq = pic32mx_rqhead(&privep->active);
|
||||||
DEBUGASSERT(privreq != NULL);
|
DEBUGASSERT(privreq != NULL);
|
||||||
|
|
||||||
/* An outgoing IN packet has completed. bdtin should point to the BDT
|
/* An outgoing IN packet has completed. bdtin should point to the BDT
|
||||||
@ -904,8 +892,9 @@ static void pic32mx_wrcomplete(struct pic32mx_usbdev_s *priv,
|
|||||||
bdtin = privep->bdtin;
|
bdtin = privep->bdtin;
|
||||||
epno = USB_EPNO(privep->ep.eplog);
|
epno = USB_EPNO(privep->ep.eplog);
|
||||||
|
|
||||||
ullvdbg("EP%d: len=%d xfrd=%d [%p]\n",
|
ullvdbg("EP%d: len=%d xfrd=%d inflight={%d, %d}\n",
|
||||||
epno, privreq->req.len, privreq->req.xfrd);
|
epno, privreq->req.len, privreq->req.xfrd,
|
||||||
|
privreq->inflight[0], privreq->inflight[1]);
|
||||||
bdtdbg("EP%d BDT IN [%p] {%08x, %08x}\n",
|
bdtdbg("EP%d BDT IN [%p] {%08x, %08x}\n",
|
||||||
epno, bdtin, bdtin->status, bdtin->addr);
|
epno, bdtin, bdtin->status, bdtin->addr);
|
||||||
|
|
||||||
@ -932,8 +921,9 @@ static void pic32mx_wrcomplete(struct pic32mx_usbdev_s *priv,
|
|||||||
|
|
||||||
/* Update the number of bytes transferred. */
|
/* Update the number of bytes transferred. */
|
||||||
|
|
||||||
privreq->req.xfrd += privreq->inflight;
|
privreq->req.xfrd += privreq->inflight[0];
|
||||||
privreq->inflight = 0;
|
privreq->inflight[0] = privreq->inflight[1];
|
||||||
|
privreq->inflight[1] = 0;
|
||||||
bytesleft = privreq->req.len - privreq->req.xfrd;
|
bytesleft = privreq->req.len - privreq->req.xfrd;
|
||||||
|
|
||||||
/* If all of the bytes were sent (bytesleft == 0) and no NULL packet is
|
/* If all of the bytes were sent (bytesleft == 0) and no NULL packet is
|
||||||
@ -964,45 +954,74 @@ static void pic32mx_wrcomplete(struct pic32mx_usbdev_s *priv,
|
|||||||
* Name: pic32mx_rqrestart
|
* Name: pic32mx_rqrestart
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void pic32mx_rqrestart(struct pic32mx_usbdev_s *priv,
|
static void pic32mx_rqrestart(int argc, uint32_t arg1, ...)
|
||||||
struct pic32mx_ep_s *privep)
|
|
||||||
{
|
{
|
||||||
|
struct pic32mx_usbdev_s *priv;
|
||||||
|
struct pic32mx_ep_s *privep;
|
||||||
struct pic32mx_req_s *privreq;
|
struct pic32mx_req_s *privreq;
|
||||||
int ret;
|
uint16_t epstalled;
|
||||||
|
uint16_t mask;
|
||||||
|
int epno;
|
||||||
|
|
||||||
|
/* Recover the pointer to the driver structure */
|
||||||
|
|
||||||
|
priv = (struct pic32mx_usbdev_s *)((uintptr_t)arg1);
|
||||||
|
DEBUGASSERT(priv != NULL);
|
||||||
|
|
||||||
|
/* Sample and clear the set of endpoints that have recovered from a stall */
|
||||||
|
|
||||||
|
epstalled = priv->epstalled;
|
||||||
|
priv->epstalled = 0;
|
||||||
|
|
||||||
|
/* Loop, checking each bit in the epstalled bit set */
|
||||||
|
|
||||||
|
for (epno = 0; epstalled && epno < PIC32MX_NENDPOINTS; epno++)
|
||||||
|
{
|
||||||
|
/* Has this encpoint recovered from a stall? */
|
||||||
|
|
||||||
|
mask = (1 << epno);
|
||||||
|
if ((epstalled & mask) != 0)
|
||||||
|
{
|
||||||
|
/* Yes, this endpoint needs to be restarteed */
|
||||||
|
|
||||||
|
epstalled &= ~mask;
|
||||||
|
privep = &priv->eplist[epno];
|
||||||
|
|
||||||
/* Reset some endpoint state variables */
|
/* Reset some endpoint state variables */
|
||||||
|
|
||||||
|
privep->stalled = false;
|
||||||
privep->txnullpkt = false;
|
privep->txnullpkt = false;
|
||||||
|
|
||||||
/* Loop, rstarting all of the requests that we can */
|
/* Check the request at the head of the endpoint's active request queue */
|
||||||
|
|
||||||
for (;;)
|
privreq = pic32mx_rqhead(&privep->pend);
|
||||||
|
if (privreq)
|
||||||
{
|
{
|
||||||
/* Check the request from the head of the endpoint's active request queue */
|
|
||||||
|
|
||||||
privreq = pic32mx_rqpeek(&privep->pend);
|
|
||||||
if (!privreq)
|
|
||||||
{
|
|
||||||
/* No more requests... We are finished */
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restart transmission after we have recovered from a stall */
|
/* Restart transmission after we have recovered from a stall */
|
||||||
|
|
||||||
privreq->req.xfrd = 0;
|
privreq->req.xfrd = 0;
|
||||||
privreq->inflight = 0;
|
privreq->inflight[0] = 0;
|
||||||
|
privreq->inflight[1] = 0;
|
||||||
|
|
||||||
ret = pic32mx_wrrequest(priv, privep);
|
(void)pic32mx_wrrequest(priv, privep);
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
/* We count not start this request (probably because the hardware
|
|
||||||
* has accepted all of the requests that it can).
|
|
||||||
*/
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: pic32mx_delayedrestart
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void pic32mx_delayedrestart(struct pic32mx_usbdev_s *priv, uint8_t epno)
|
||||||
|
{
|
||||||
|
/* Add endpoint to the set of endpoints that need to be restarted */
|
||||||
|
|
||||||
|
priv->epstalled |= (1 << epno);
|
||||||
|
|
||||||
|
/* And start (or re-start) the watchdog timer */
|
||||||
|
|
||||||
|
wd_start(priv->wdog, RESTART_DELAY, pic32mx_rqrestart, 1, (uint32_t)priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -1024,10 +1043,11 @@ static void pic32mx_rqstop(struct pic32mx_ep_s *privep)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: pic32mx_wrrequest
|
* Name: pic32mx_wrstart
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int pic32mx_wrrequest(struct pic32mx_usbdev_s *priv, struct pic32mx_ep_s *privep)
|
static int pic32mx_wrstart(struct pic32mx_usbdev_s *priv,
|
||||||
|
struct pic32mx_ep_s *privep)
|
||||||
{
|
{
|
||||||
volatile struct usbotg_bdtentry_s *bdt;
|
volatile struct usbotg_bdtentry_s *bdt;
|
||||||
struct pic32mx_req_s *privreq;
|
struct pic32mx_req_s *privreq;
|
||||||
@ -1035,6 +1055,8 @@ static int pic32mx_wrrequest(struct pic32mx_usbdev_s *priv, struct pic32mx_ep_s
|
|||||||
uint8_t epno;
|
uint8_t epno;
|
||||||
int nbytes;
|
int nbytes;
|
||||||
int bytesleft;
|
int bytesleft;
|
||||||
|
int xfrd;
|
||||||
|
int index;
|
||||||
|
|
||||||
/* We get here when either (1) an IN endpoint completion interrupt occurs,
|
/* We get here when either (1) an IN endpoint completion interrupt occurs,
|
||||||
* or (2) a new write request is reqeived from the class.
|
* or (2) a new write request is reqeived from the class.
|
||||||
@ -1044,22 +1066,6 @@ static int pic32mx_wrrequest(struct pic32mx_usbdev_s *priv, struct pic32mx_ep_s
|
|||||||
|
|
||||||
epno = USB_EPNO(privep->ep.eplog);
|
epno = USB_EPNO(privep->ep.eplog);
|
||||||
|
|
||||||
/* Check the request from the head of the endpoint's pending request queue */
|
|
||||||
|
|
||||||
privreq = pic32mx_rqpeek(&privep->pend);
|
|
||||||
if (!privreq)
|
|
||||||
{
|
|
||||||
/* There are no queue TX requests to be sent. */
|
|
||||||
|
|
||||||
usbtrace(TRACE_INTDECODE(PIC32MX_TRACEINTID_EPINQEMPTY), epno);
|
|
||||||
|
|
||||||
/* Return -ENODATA to indicate that there are no further requests
|
|
||||||
* to be processed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
return -ENODATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Decide which BDT to use. bdtin points to the "current" BDT. That is,
|
/* Decide which BDT to use. bdtin points to the "current" BDT. That is,
|
||||||
* the one that either (1) avaialble for next transfer, or (2) the one
|
* the one that either (1) avaialble for next transfer, or (2) the one
|
||||||
* that is currently busy with the current transfer. If the current
|
* that is currently busy with the current transfer. If the current
|
||||||
@ -1068,6 +1074,8 @@ static int pic32mx_wrrequest(struct pic32mx_usbdev_s *priv, struct pic32mx_ep_s
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
bdt = privep->bdtin;
|
bdt = privep->bdtin;
|
||||||
|
index = 0;
|
||||||
|
|
||||||
if (bdt->status || bdt->addr)
|
if (bdt->status || bdt->addr)
|
||||||
{
|
{
|
||||||
/* The current BDT is not available, check the other BDT */
|
/* The current BDT is not available, check the other BDT */
|
||||||
@ -1093,18 +1101,91 @@ static int pic32mx_wrrequest(struct pic32mx_usbdev_s *priv, struct pic32mx_ep_s
|
|||||||
/* Yes... use the other BDT */
|
/* Yes... use the other BDT */
|
||||||
|
|
||||||
bdt = otherbdt;
|
bdt = otherbdt;
|
||||||
|
index = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ullvdbg("epno=%d req=%p: len=%d xfrd=%d nullpkt=%d\n",
|
/* A BDT is available. Which request should we be operating on? The last
|
||||||
epno, privreq, privreq->req.len, privreq->req.xfrd, privep->txnullpkt);
|
* incomplete, active request would be at the tail of the active list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
privreq = pic32mx_rqtail(&privep->active);
|
||||||
|
|
||||||
|
/* This request would be NULL if there is no incomplete, active request. */
|
||||||
|
|
||||||
|
if (privreq)
|
||||||
|
{
|
||||||
|
/* Get the number of bytes left to be transferred in the request */
|
||||||
|
|
||||||
|
xfrd = privreq->req.xfrd;
|
||||||
|
bytesleft = privreq->req.len - xfrd;
|
||||||
|
|
||||||
|
/* Even if the request is incomplete, transfer of all the requested
|
||||||
|
* bytes may already been started. NOTE: inflight[1] should be zero
|
||||||
|
* because we know that there is a BDT availalbe.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEBUGASSERT(privreq->inflight[1] == 0);
|
||||||
|
|
||||||
|
/* Has the transfer been initiated for all of the bytes? */
|
||||||
|
|
||||||
|
if (bytesleft > privreq->inflight[0])
|
||||||
|
{
|
||||||
|
/* No.. we have more work to do with this request */
|
||||||
|
|
||||||
|
xfrd += privreq->inflight[0];
|
||||||
|
bytesleft -= privreq->inflight[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Yes.. we need to get the next request from the head of the
|
||||||
|
* pending request list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
privreq = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If privreq is NULL here then either (1) there is no active request, or
|
||||||
|
* (2) the (only) active request is fully queued. In either case, we need
|
||||||
|
* to get the next request from the head of the pending request list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!privreq)
|
||||||
|
{
|
||||||
|
/* Remove the next request from the head of the pending request list */
|
||||||
|
|
||||||
|
privreq = pic32mx_remfirst(&privep->pend);
|
||||||
|
if (!privreq)
|
||||||
|
{
|
||||||
|
/* The pending request list is empty. There are no queued TX
|
||||||
|
* requests to be sent.
|
||||||
|
*/
|
||||||
|
|
||||||
|
usbtrace(TRACE_INTDECODE(PIC32MX_TRACEINTID_EPINQEMPTY), epno);
|
||||||
|
|
||||||
|
/* Return -ENODATA to indicate that there are no further requests
|
||||||
|
* to be processed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return -ENODATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add this request to the tail of the active request list */
|
||||||
|
|
||||||
|
pic32mx_addlast(&privep->active, privreq);
|
||||||
|
|
||||||
|
/* Set up the first transfer for this request */
|
||||||
|
|
||||||
|
xfrd = 0;
|
||||||
|
bytesleft = privreq->req.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
ullvdbg("epno=%d req=%p: len=%d xfrd=%d index=%d nullpkt=%d\n",
|
||||||
|
epno, privreq, privreq->req.len, xfrd, index, privep->txnullpkt);
|
||||||
|
|
||||||
/* Get the number of bytes left to be sent in the packet */
|
/* Get the number of bytes left to be sent in the packet */
|
||||||
|
|
||||||
bytesleft = privreq->req.len - privreq->req.xfrd;
|
|
||||||
nbytes = bytesleft;
|
nbytes = bytesleft;
|
||||||
|
|
||||||
/* Send the next packet */
|
|
||||||
|
|
||||||
if (nbytes > 0)
|
if (nbytes > 0)
|
||||||
{
|
{
|
||||||
/* Either send the maxpacketsize or all of the remaining data in
|
/* Either send the maxpacketsize or all of the remaining data in
|
||||||
@ -1131,7 +1212,7 @@ static int pic32mx_wrrequest(struct pic32mx_usbdev_s *priv, struct pic32mx_ep_s
|
|||||||
|
|
||||||
/* Send the packet (might be a null packet with nbytes == 0) */
|
/* Send the packet (might be a null packet with nbytes == 0) */
|
||||||
|
|
||||||
buf = privreq->req.buf + privreq->req.xfrd;
|
buf = privreq->req.buf + xfrd;
|
||||||
|
|
||||||
/* Setup the writes to the endpoints */
|
/* Setup the writes to the endpoints */
|
||||||
|
|
||||||
@ -1146,19 +1227,39 @@ static int pic32mx_wrrequest(struct pic32mx_usbdev_s *priv, struct pic32mx_ep_s
|
|||||||
priv->ctrlstate = CTRLSTATE_WRREQUEST;
|
priv->ctrlstate = CTRLSTATE_WRREQUEST;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move the request from the head of the pending list to the tail of
|
|
||||||
* the active list.
|
|
||||||
*/
|
|
||||||
|
|
||||||
privreq = pic32mx_remfirst(&privep->pend);
|
|
||||||
pic32mx_addlast(&privep->active, privreq);
|
|
||||||
|
|
||||||
/* Update for the next data IN interrupt */
|
/* Update for the next data IN interrupt */
|
||||||
|
|
||||||
privreq->inflight = nbytes;
|
privreq->inflight[index] = nbytes;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: pic32mx_wrrequest
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int pic32mx_wrrequest(struct pic32mx_usbdev_s *priv, struct pic32mx_ep_s *privep)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Always try to start two transfers in order to take advantage of the
|
||||||
|
* PIC32MX's ping pong buffering.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = pic32mx_wrstart(priv, privep);
|
||||||
|
if (ret == OK)
|
||||||
|
{
|
||||||
|
/* Note: We need to return the error condition only if nothing was
|
||||||
|
* queued
|
||||||
|
*/
|
||||||
|
|
||||||
|
(void)pic32mx_wrstart(priv, privep);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We return OK to indicate that a write request is still in progress */
|
||||||
|
|
||||||
|
return pic32mx_rqhead(&privep->active) == NULL ? -ENODATA : OK;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: pic32mx_rdcomplete
|
* Name: pic32mx_rdcomplete
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -1173,7 +1274,7 @@ static int pic32mx_rdcomplete(struct pic32mx_usbdev_s *priv,
|
|||||||
|
|
||||||
/* Check the request at the head of the endpoint's active request queue */
|
/* Check the request at the head of the endpoint's active request queue */
|
||||||
|
|
||||||
privreq = pic32mx_rqpeek(&privep->active);
|
privreq = pic32mx_rqhead(&privep->active);
|
||||||
if (!privreq)
|
if (!privreq)
|
||||||
{
|
{
|
||||||
/* There is no packet to receive any data. Then why are we here? */
|
/* There is no packet to receive any data. Then why are we here? */
|
||||||
@ -1452,9 +1553,9 @@ static int pic32mx_rdrequest(struct pic32mx_usbdev_s *priv,
|
|||||||
int readlen;
|
int readlen;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Check the request from the head of the endpoint request queue */
|
/* Check the request at the head of the endpoint request queue */
|
||||||
|
|
||||||
privreq = pic32mx_rqpeek(&privep->pend);
|
privreq = pic32mx_rqhead(&privep->pend);
|
||||||
if (!privreq)
|
if (!privreq)
|
||||||
{
|
{
|
||||||
/* There is no packet to receive any data. */
|
/* There is no packet to receive any data. */
|
||||||
@ -3229,53 +3330,51 @@ static int pic32mx_epsubmit(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
|
|||||||
epno = USB_EPNO(ep->eplog);
|
epno = USB_EPNO(ep->eplog);
|
||||||
req->result = -EINPROGRESS;
|
req->result = -EINPROGRESS;
|
||||||
req->xfrd = 0;
|
req->xfrd = 0;
|
||||||
privreq->inflight = 0;
|
privreq->inflight[0] = 0;
|
||||||
|
privreq->inflight[1] = 0;
|
||||||
flags = irqsave();
|
flags = irqsave();
|
||||||
|
|
||||||
/* If we are stalled, then drop all requests on the floor */
|
/* Add the new request to the request queue for the OUT endpoint */
|
||||||
|
|
||||||
if (privep->stalled)
|
pic32mx_addlast(&privep->pend, privreq);
|
||||||
{
|
|
||||||
pic32mx_abortrequest(privep, privreq, -EBUSY);
|
|
||||||
ulldbg("ERROR: stalled\n");
|
|
||||||
ret = -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle IN (device-to-host) requests. NOTE: If the class device is
|
/* Handle IN (device-to-host) requests. NOTE: If the class device is
|
||||||
* using the bi-directional EP0, then we assume that they intend the EP0
|
* using the bi-directional EP0, then we assume that they intend the EP0
|
||||||
* IN functionality.
|
* IN functionality.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
else if (USB_ISEPIN(ep->eplog) || epno == EP0)
|
if (USB_ISEPIN(ep->eplog) || epno == EP0)
|
||||||
{
|
{
|
||||||
/* Add the new request to the request queue for the IN endpoint */
|
|
||||||
|
|
||||||
pic32mx_addlast(&privep->pend, privreq);
|
|
||||||
usbtrace(TRACE_INREQQUEUED(epno), req->len);
|
usbtrace(TRACE_INREQQUEUED(epno), req->len);
|
||||||
|
|
||||||
/* If an IN endpoint BDT is available, then transfer the data now */
|
/* If the endpoint is not stalled and an IN endpoint BDT is available,
|
||||||
|
* then transfer the data now.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!privep->stalled)
|
||||||
|
{
|
||||||
(void)pic32mx_wrrequest(priv, privep);
|
(void)pic32mx_wrrequest(priv, privep);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Handle OUT (host-to-device) requests */
|
/* Handle OUT (host-to-device) requests */
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Add the new request to the request queue for the OUT endpoint */
|
|
||||||
|
|
||||||
privep->txnullpkt = 0;
|
|
||||||
pic32mx_addlast(&privep->pend, privreq);
|
|
||||||
usbtrace(TRACE_OUTREQQUEUED(epno), req->len);
|
usbtrace(TRACE_OUTREQQUEUED(epno), req->len);
|
||||||
|
|
||||||
/* Set up the read operation. Because the PIC32MX supports ping-pong
|
/* Set up the read operation (unless the endpoint is stalled). Because
|
||||||
* buffering. There may be two pending read requests. The following
|
* the PIC32MX supports ping-pong* buffering. There may be two pending
|
||||||
* call will attempt to setup a read using this request for this
|
* read requests. The following call will attempt to setup a read
|
||||||
* endpoint. It is not harmful if this fails.
|
* using this request for this endpoint. It is not harmful if this
|
||||||
|
* fails.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (!privep->stalled)
|
||||||
|
{
|
||||||
(void)pic32mx_rdrequest(priv, privep);
|
(void)pic32mx_rdrequest(priv, privep);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
irqrestore(flags);
|
irqrestore(flags);
|
||||||
return ret;
|
return ret;
|
||||||
@ -3316,6 +3415,7 @@ static int pic32mx_epbdtstall(struct usbdev_ep_s *ep, bool resume, bool epin)
|
|||||||
struct pic32mx_ep_s *privep;
|
struct pic32mx_ep_s *privep;
|
||||||
struct pic32mx_usbdev_s *priv;
|
struct pic32mx_usbdev_s *priv;
|
||||||
volatile struct usbotg_bdtentry_s *bdt;
|
volatile struct usbotg_bdtentry_s *bdt;
|
||||||
|
volatile struct usbotg_bdtentry_s *otherbdt;
|
||||||
uint32_t regaddr;
|
uint32_t regaddr;
|
||||||
uint16_t regval;
|
uint16_t regval;
|
||||||
uint8_t epno;
|
uint8_t epno;
|
||||||
@ -3330,9 +3430,17 @@ static int pic32mx_epbdtstall(struct usbdev_ep_s *ep, bool resume, bool epin)
|
|||||||
|
|
||||||
if (epin)
|
if (epin)
|
||||||
{
|
{
|
||||||
/* Get the even BDT */
|
/* Get a pointer to the current IN BDT */
|
||||||
|
|
||||||
bdt = &g_bdt[EP(epno, EP_DIR_IN, EP_PP_EVEN)];
|
bdt = privep->bdtin;
|
||||||
|
|
||||||
|
/* Get the other BDT */
|
||||||
|
|
||||||
|
otherbdt = &g_bdt[EP(epno, EP_DIR_IN, EP_PP_EVEN)];
|
||||||
|
if (otherbdt == bdt)
|
||||||
|
{
|
||||||
|
otherbdt++;
|
||||||
|
}
|
||||||
|
|
||||||
/* Reset the data toggle */
|
/* Reset the data toggle */
|
||||||
|
|
||||||
@ -3343,9 +3451,17 @@ static int pic32mx_epbdtstall(struct usbdev_ep_s *ep, bool resume, bool epin)
|
|||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Get the even BDT */
|
/* Get a pointer to the current OUT BDT */
|
||||||
|
|
||||||
bdt = &g_bdt[EP(epno, EP_DIR_OUT, EP_PP_EVEN)];
|
bdt = privep->bdtout;
|
||||||
|
|
||||||
|
/* Get a pointer to the other BDT */
|
||||||
|
|
||||||
|
otherbdt = &g_bdt[EP(epno, EP_DIR_OUT, EP_PP_EVEN)];
|
||||||
|
if (otherbdt == bdt)
|
||||||
|
{
|
||||||
|
otherbdt++;
|
||||||
|
}
|
||||||
|
|
||||||
/* Reset the data toggle */
|
/* Reset the data toggle */
|
||||||
|
|
||||||
@ -3359,7 +3475,6 @@ static int pic32mx_epbdtstall(struct usbdev_ep_s *ep, bool resume, bool epin)
|
|||||||
/* Resuming a stalled endpoint */
|
/* Resuming a stalled endpoint */
|
||||||
|
|
||||||
usbtrace(TRACE_EPRESUME, epno);
|
usbtrace(TRACE_EPRESUME, epno);
|
||||||
privep->stalled = false;
|
|
||||||
|
|
||||||
/* Point to the appropriate EP register */
|
/* Point to the appropriate EP register */
|
||||||
|
|
||||||
@ -3381,41 +3496,44 @@ static int pic32mx_epbdtstall(struct usbdev_ep_s *ep, bool resume, bool epin)
|
|||||||
uint32_t bytecount = (USB_SIZEOF_CTRLREQ << USB_BDT_BYTECOUNT_SHIFT);
|
uint32_t bytecount = (USB_SIZEOF_CTRLREQ << USB_BDT_BYTECOUNT_SHIFT);
|
||||||
uint32_t physaddr = PHYS_ADDR(&priv->ctrl);
|
uint32_t physaddr = PHYS_ADDR(&priv->ctrl);
|
||||||
|
|
||||||
/* Configure the EVEN BDT to receive a SETUP command. */
|
/* Configure the other BDT to receive a SETUP command. */
|
||||||
|
|
||||||
|
otherbdt->addr = (uint8_t*)physaddr;
|
||||||
|
otherbdt->status = (USB_BDT_UOWN | bytecount);
|
||||||
|
|
||||||
|
/* Configure the current BDT to receive a SETUP command. */
|
||||||
|
|
||||||
bdt->addr = (uint8_t*)physaddr;
|
bdt->addr = (uint8_t*)physaddr;
|
||||||
bdt->status = (USB_BDT_UOWN | bytecount);
|
bdt->status = (USB_BDT_UOWN | bytecount);
|
||||||
|
|
||||||
bdtdbg("EP0 BDT IN [%p] {%08x, %08x}\n",
|
bdtdbg("EP0 BDT IN [%p] {%08x, %08x}\n",
|
||||||
bdt, bdt->status, bdt->addr);
|
bdt, bdt->status, bdt->addr);
|
||||||
|
|
||||||
/* Configure the ODD BDT to receive a SETUP command. */
|
|
||||||
|
|
||||||
bdt++;
|
|
||||||
bdt->addr = (uint8_t*)physaddr;
|
|
||||||
bdt->status = (USB_BDT_UOWN | bytecount);
|
|
||||||
bdtdbg("EP0 BDT IN [%p] {%08x, %08x}\n",
|
bdtdbg("EP0 BDT IN [%p] {%08x, %08x}\n",
|
||||||
bdt, bdt->status, bdt->addr);
|
otherbdt, otherbdt->status, otherbdt->addr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Return the EVEN BDT to the CPU. */
|
/* Return the other BDT to the CPU. */
|
||||||
|
|
||||||
|
otherbdt->addr = 0;
|
||||||
|
otherbdt->status = 0;
|
||||||
|
|
||||||
|
/* Return the current BDT to the CPU. */
|
||||||
|
|
||||||
bdt->addr = 0;
|
bdt->addr = 0;
|
||||||
bdt->status = 0;
|
bdt->status = 0;
|
||||||
|
|
||||||
bdtdbg("EP%d BDT %s [%p] {%08x, %08x}\n",
|
bdtdbg("EP%d BDT %s [%p] {%08x, %08x}\n",
|
||||||
epno, epin ? "IN" : "OUT", bdt, bdt->status, bdt->addr);
|
epno, epin ? "IN" : "OUT", bdt, bdt->status, bdt->addr);
|
||||||
|
|
||||||
/* Return the ODD BDT to the CPU. */
|
|
||||||
|
|
||||||
bdt++;
|
|
||||||
bdt->addr = 0;
|
|
||||||
bdt->status = 0;
|
|
||||||
bdtdbg("EP%d BDT %s [%p] {%08x, %08x}\n",
|
bdtdbg("EP%d BDT %s [%p] {%08x, %08x}\n",
|
||||||
epno, epin ? "IN" : "OUT", bdt, bdt->status, bdt->addr);
|
epno, epin ? "IN" : "OUT", otherbdt, otherbdt->status, otherbdt->addr);
|
||||||
|
|
||||||
/* Restart any queued requests */
|
/* Restart any queued requests (after a delay so that we can be assured
|
||||||
|
* that the hardware has recovered from the stall -- I don't know of any
|
||||||
|
* other way to assure this.).
|
||||||
|
*/
|
||||||
|
|
||||||
pic32mx_rqrestart(priv, privep);
|
pic32mx_delayedrestart(priv, epno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3426,20 +3544,20 @@ static int pic32mx_epbdtstall(struct usbdev_ep_s *ep, bool resume, bool epin)
|
|||||||
usbtrace(TRACE_EPSTALL, epno);
|
usbtrace(TRACE_EPSTALL, epno);
|
||||||
privep->stalled = true;
|
privep->stalled = true;
|
||||||
|
|
||||||
/* Stall the EVEN BDT. */
|
/* Stall the other BDT. */
|
||||||
|
|
||||||
|
otherbdt->status = (USB_BDT_UOWN | USB_BDT_BSTALL);
|
||||||
|
otherbdt->addr = 0;
|
||||||
|
|
||||||
|
/* Stall the current BDT. */
|
||||||
|
|
||||||
bdt->status = (USB_BDT_UOWN | USB_BDT_BSTALL);
|
bdt->status = (USB_BDT_UOWN | USB_BDT_BSTALL);
|
||||||
bdt->addr = 0;
|
bdt->addr = 0;
|
||||||
|
|
||||||
bdtdbg("EP%d BDT %s [%p] {%08x, %08x}\n",
|
bdtdbg("EP%d BDT %s [%p] {%08x, %08x}\n",
|
||||||
epno, epin ? "IN" : "OUT", bdt, bdt->status, bdt->addr);
|
epno, epin ? "IN" : "OUT", bdt, bdt->status, bdt->addr);
|
||||||
|
|
||||||
/* Stall the ODD BDT. */
|
|
||||||
|
|
||||||
bdt++;
|
|
||||||
bdt->status = (USB_BDT_UOWN | USB_BDT_BSTALL);
|
|
||||||
bdt->addr = 0;
|
|
||||||
bdtdbg("EP%d BDT %s [%p] {%08x, %08x}\n",
|
bdtdbg("EP%d BDT %s [%p] {%08x, %08x}\n",
|
||||||
epno, epin ? "IN" : "OUT", bdt, bdt->status, bdt->addr);
|
epno, epin ? "IN" : "OUT", otherbdt, otherbdt->status, otherbdt->addr);
|
||||||
|
|
||||||
/* Stop any queued requests. Hmmm.. is there a race condition here? */
|
/* Stop any queued requests. Hmmm.. is there a race condition here? */
|
||||||
|
|
||||||
@ -4101,6 +4219,14 @@ void up_usbinitialize(void)
|
|||||||
|
|
||||||
pic32mx_stateinit(priv);
|
pic32mx_stateinit(priv);
|
||||||
|
|
||||||
|
/* Then perform a few one-time intialization operstions. First, initialize
|
||||||
|
* the watchdog timer that is used to perform a delayed queue restart
|
||||||
|
* after recovering from a stall.
|
||||||
|
*/
|
||||||
|
|
||||||
|
priv->epstalled = 0;
|
||||||
|
priv->wdog = wd_create();
|
||||||
|
|
||||||
/* Attach USB controller interrupt handler. The hardware will not be
|
/* Attach USB controller interrupt handler. The hardware will not be
|
||||||
* initialized and interrupts will not be enabled until the class device
|
* initialized and interrupts will not be enabled until the class device
|
||||||
* driver is bound. Getting the IRQs here only makes sure that we have
|
* driver is bound. Getting the IRQs here only makes sure that we have
|
||||||
|
Loading…
Reference in New Issue
Block a user