mirror of
https://github.com/apache/nuttx.git
synced 2026-05-28 11:56:10 +08:00
risc-v/mpfs: usb: provide more endpoints
The underlying hardware supports 9 endpoints: - EP0 - 4x IN EPs - 4x OUT EPs Currently the driver assumes every EP number is unique. This limits the amount of EPs to 1 + 4 = 5. Utilize the EPs in such a manner that all may be used. Also fix a few error handling related bugs. Update the composite driver to match the current situation as well. Signed-off-by: Eero Nurkkala <eero.nurkkala@offcode.fi>
This commit is contained in:
committed by
Xiang Xiao
parent
e0bb281e7a
commit
4df8b16060
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
#define SOFT_RESET_REG_MASK 0x03u
|
#define SOFT_RESET_REG_MASK 0x03u
|
||||||
|
|
||||||
#define MPFS_USB_NENDPOINTS 8 /* 4 IN and 4 OUT endpoints */
|
#define MPFS_USB_NENDPOINTS 9 /* EP0 + 4x IN and 4x OUT EPs */
|
||||||
#define MPFS_USB_MAXPACKETSIZE(ep) 64
|
#define MPFS_USB_MAXPACKETSIZE(ep) 64
|
||||||
#define MPFS_USB_MAXPACKETSIZE_HS(ep) 512
|
#define MPFS_USB_MAXPACKETSIZE_HS(ep) 512
|
||||||
#define MPFS_EP0_MAXPACKET 64
|
#define MPFS_EP0_MAXPACKET 64
|
||||||
|
|||||||
@@ -138,10 +138,11 @@
|
|||||||
#define mpfs_rqempty(q) ((q)->head == NULL)
|
#define mpfs_rqempty(q) ((q)->head == NULL)
|
||||||
#define mpfs_rqpeek(q) ((q)->head)
|
#define mpfs_rqpeek(q) ((q)->head)
|
||||||
|
|
||||||
#define MPFS_EPSET_ALL (0xff) /* All endpoints */
|
#define MPFS_EPSET_ALL (0x1ff) /* All endpoints */
|
||||||
#define MPFS_EPSET_NOTEP0 (0xfe) /* All endpoints except EP0 */
|
#define MPFS_EPSET_NOTEP0 (0x1fe) /* All endpoints except EP0 */
|
||||||
#define MPFS_EP_BIT(ep) (1 << (ep))
|
#define MPFS_EP_BIT(ep) (1 << (ep))
|
||||||
#define MPFS_MAX_MULTIPACKET_SIZE (0x3fff)
|
#define MPFS_MAX_MULTIPACKET_SIZE (0x3fff)
|
||||||
|
#define MPFS_EPIN_START (MPFS_USB_NENDPOINTS / 2)
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Types
|
* Private Types
|
||||||
@@ -652,9 +653,19 @@ static int mpfs_req_wrsetup(struct mpfs_usbdev_s *priv,
|
|||||||
uint8_t epno;
|
uint8_t epno;
|
||||||
int nbytes;
|
int nbytes;
|
||||||
int ret;
|
int ret;
|
||||||
|
int idx;
|
||||||
|
|
||||||
epno = USB_EPNO(privep->ep.eplog);
|
epno = USB_EPNO(privep->ep.eplog);
|
||||||
|
|
||||||
|
if (USB_ISEPIN(privep->ep.eplog))
|
||||||
|
{
|
||||||
|
idx = epno + MPFS_EPIN_START;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx = epno;
|
||||||
|
}
|
||||||
|
|
||||||
mpfs_putreg8(epno, MPFS_USB_INDEX);
|
mpfs_putreg8(epno, MPFS_USB_INDEX);
|
||||||
|
|
||||||
/* Get the number of bytes remaining to be sent. */
|
/* Get the number of bytes remaining to be sent. */
|
||||||
@@ -686,8 +697,8 @@ static int mpfs_req_wrsetup(struct mpfs_usbdev_s *priv,
|
|||||||
|
|
||||||
/* Setup TX transfer using ep configured maxpacket size */
|
/* Setup TX transfer using ep configured maxpacket size */
|
||||||
|
|
||||||
priv->eplist[epno].descb[1]->addr = (uintptr_t)buf;
|
priv->eplist[idx].descb[1]->addr = (uintptr_t)buf;
|
||||||
packetsize = priv->eplist[epno].descb[1]->pktsize;
|
packetsize = priv->eplist[idx].descb[1]->pktsize;
|
||||||
|
|
||||||
/* Set automatic ZLP sending if requested on req */
|
/* Set automatic ZLP sending if requested on req */
|
||||||
|
|
||||||
@@ -696,7 +707,7 @@ static int mpfs_req_wrsetup(struct mpfs_usbdev_s *priv,
|
|||||||
/* Handle this properly when DMA supported */
|
/* Handle this properly when DMA supported */
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->eplist[epno].descb[1]->pktsize = packetsize;
|
priv->eplist[idx].descb[1]->pktsize = packetsize;
|
||||||
|
|
||||||
/* Indicate that we are in the sending state */
|
/* Indicate that we are in the sending state */
|
||||||
|
|
||||||
@@ -707,6 +718,7 @@ static int mpfs_req_wrsetup(struct mpfs_usbdev_s *priv,
|
|||||||
ret = mpfs_write_tx_fifo(buf, packetsize, epno);
|
ret = mpfs_write_tx_fifo(buf, packetsize, epno);
|
||||||
if (ret != OK)
|
if (ret != OK)
|
||||||
{
|
{
|
||||||
|
privep->epstate = USB_EPSTATE_IDLE;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -731,6 +743,7 @@ static int mpfs_req_wrsetup(struct mpfs_usbdev_s *priv,
|
|||||||
ret = mpfs_write_tx_fifo(buf, nbytes, epno);
|
ret = mpfs_write_tx_fifo(buf, nbytes, epno);
|
||||||
if (ret != OK)
|
if (ret != OK)
|
||||||
{
|
{
|
||||||
|
privep->epstate = USB_EPSTATE_IDLE;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -906,6 +919,7 @@ static int mpfs_req_write(struct mpfs_usbdev_s *priv,
|
|||||||
ret = mpfs_req_wrsetup(priv, privep, privreq);
|
ret = mpfs_req_wrsetup(priv, privep, privreq);
|
||||||
if (ret != OK)
|
if (ret != OK)
|
||||||
{
|
{
|
||||||
|
mpfs_req_complete(privep, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1711,6 +1725,7 @@ static int mpfs_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
|
|||||||
req->result = -EINPROGRESS;
|
req->result = -EINPROGRESS;
|
||||||
req->xfrd = 0;
|
req->xfrd = 0;
|
||||||
privreq->inflight = 0;
|
privreq->inflight = 0;
|
||||||
|
|
||||||
flags = enter_critical_section();
|
flags = enter_critical_section();
|
||||||
|
|
||||||
/* Handle IN (device-to-host) requests. NOTE: If the class device is
|
/* Handle IN (device-to-host) requests. NOTE: If the class device is
|
||||||
@@ -1993,6 +2008,7 @@ static int mpfs_ep_stallresume(struct usbdev_ep_s *ep, bool resume)
|
|||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
* priv - USB device abstraction
|
* priv - USB device abstraction
|
||||||
* epset - Set of bits, one bit reflects one endpoint
|
* epset - Set of bits, one bit reflects one endpoint
|
||||||
|
* in - If the EP is direction IN
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* Endpoint structure or NULL in case of error
|
* Endpoint structure or NULL in case of error
|
||||||
@@ -2000,7 +2016,7 @@ static int mpfs_ep_stallresume(struct usbdev_ep_s *ep, bool resume)
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static inline struct mpfs_ep_s *
|
static inline struct mpfs_ep_s *
|
||||||
mpfs_ep_reserve(struct mpfs_usbdev_s *priv, uint8_t epset)
|
mpfs_ep_reserve(struct mpfs_usbdev_s *priv, uint16_t epset, bool in)
|
||||||
{
|
{
|
||||||
struct mpfs_ep_s *privep = NULL;
|
struct mpfs_ep_s *privep = NULL;
|
||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
@@ -2008,15 +2024,34 @@ mpfs_ep_reserve(struct mpfs_usbdev_s *priv, uint8_t epset)
|
|||||||
|
|
||||||
flags = enter_critical_section();
|
flags = enter_critical_section();
|
||||||
epset &= priv->epavail;
|
epset &= priv->epavail;
|
||||||
|
|
||||||
if (epset != 0)
|
if (epset != 0)
|
||||||
{
|
{
|
||||||
/* Select the lowest bit in the set of matching, available endpoints
|
/* Select the lowest bit in the set of matching, available endpoints
|
||||||
* (skipping EP0)
|
* (skipping EP0)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (epndx = 1; epndx < MPFS_USB_NENDPOINTS; epndx++)
|
int max;
|
||||||
|
|
||||||
|
if (in)
|
||||||
{
|
{
|
||||||
uint8_t bit = MPFS_EP_BIT(epndx);
|
/* 5, 6, 7 and 8 */
|
||||||
|
|
||||||
|
max = MPFS_USB_NENDPOINTS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* 1, 2, 3 and 4 */
|
||||||
|
|
||||||
|
max = MPFS_EPIN_START + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (epndx = 1 + (MPFS_USB_NENDPOINTS / 2) * in;
|
||||||
|
epndx < max;
|
||||||
|
epndx++)
|
||||||
|
{
|
||||||
|
uint16_t bit = MPFS_EP_BIT(epndx);
|
||||||
|
|
||||||
if ((epset & bit) != 0)
|
if ((epset & bit) != 0)
|
||||||
{
|
{
|
||||||
/* Mark the endpoint no longer available */
|
/* Mark the endpoint no longer available */
|
||||||
@@ -2033,6 +2068,8 @@ mpfs_ep_reserve(struct mpfs_usbdev_s *priv, uint8_t epset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUGASSERT(privep != NULL);
|
||||||
|
|
||||||
leave_critical_section(flags);
|
leave_critical_section(flags);
|
||||||
return privep;
|
return privep;
|
||||||
}
|
}
|
||||||
@@ -2088,9 +2125,14 @@ static struct usbdev_ep_s *mpfs_allocep(struct usbdev_s *dev, uint8_t epno,
|
|||||||
epset = MPFS_EP_BIT(epno);
|
epset = MPFS_EP_BIT(epno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in)
|
||||||
|
{
|
||||||
|
epset <<= MPFS_EPIN_START;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if the selected endpoint number is available */
|
/* Check if the selected endpoint number is available */
|
||||||
|
|
||||||
privep = mpfs_ep_reserve(priv, epset);
|
privep = mpfs_ep_reserve(priv, epset, in);
|
||||||
if (privep == NULL)
|
if (privep == NULL)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -2509,6 +2551,7 @@ static void mpfs_ep0_setup(struct mpfs_usbdev_s *priv)
|
|||||||
uint8_t epno;
|
uint8_t epno;
|
||||||
int nbytes = 0; /* Assume zero-length packet */
|
int nbytes = 0; /* Assume zero-length packet */
|
||||||
int ret;
|
int ret;
|
||||||
|
int idx;
|
||||||
|
|
||||||
/* Terminate any pending requests */
|
/* Terminate any pending requests */
|
||||||
|
|
||||||
@@ -2570,6 +2613,15 @@ static void mpfs_ep0_setup(struct mpfs_usbdev_s *priv)
|
|||||||
case USB_REQ_RECIPIENT_ENDPOINT:
|
case USB_REQ_RECIPIENT_ENDPOINT:
|
||||||
{
|
{
|
||||||
epno = USB_EPNO(index.b[LSB]);
|
epno = USB_EPNO(index.b[LSB]);
|
||||||
|
if (USB_ISEPIN(index.b[LSB]))
|
||||||
|
{
|
||||||
|
idx = epno + MPFS_EPIN_START;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx = epno;
|
||||||
|
}
|
||||||
|
|
||||||
usbtrace(TRACE_INTDECODE(MPFS_TRACEINTID_GETSTATUS), epno);
|
usbtrace(TRACE_INTDECODE(MPFS_TRACEINTID_GETSTATUS), epno);
|
||||||
if (epno >= MPFS_USB_NENDPOINTS)
|
if (epno >= MPFS_USB_NENDPOINTS)
|
||||||
{
|
{
|
||||||
@@ -2579,7 +2631,7 @@ static void mpfs_ep0_setup(struct mpfs_usbdev_s *priv)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
privep = &priv->eplist[epno];
|
privep = &priv->eplist[idx];
|
||||||
response.w = 0; /* Not stalled */
|
response.w = 0; /* Not stalled */
|
||||||
nbytes = 2; /* Response size: 2 bytes */
|
nbytes = 2; /* Response size: 2 bytes */
|
||||||
|
|
||||||
@@ -2665,7 +2717,16 @@ static void mpfs_ep0_setup(struct mpfs_usbdev_s *priv)
|
|||||||
if (epno < MPFS_USB_NENDPOINTS && index.b[MSB] == 0 &&
|
if (epno < MPFS_USB_NENDPOINTS && index.b[MSB] == 0 &&
|
||||||
value.w == USB_FEATURE_ENDPOINTHALT && len.w == 0)
|
value.w == USB_FEATURE_ENDPOINTHALT && len.w == 0)
|
||||||
{
|
{
|
||||||
privep = &priv->eplist[epno];
|
if (USB_ISEPIN(index.b[LSB]))
|
||||||
|
{
|
||||||
|
idx = epno + MPFS_EPIN_START;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx = epno;
|
||||||
|
}
|
||||||
|
|
||||||
|
privep = &priv->eplist[idx];
|
||||||
privep->halted = false;
|
privep->halted = false;
|
||||||
|
|
||||||
ret = mpfs_ep_resume(privep);
|
ret = mpfs_ep_resume(privep);
|
||||||
@@ -2719,7 +2780,16 @@ static void mpfs_ep0_setup(struct mpfs_usbdev_s *priv)
|
|||||||
if (epno < MPFS_USB_NENDPOINTS && index.b[MSB] == 0 &&
|
if (epno < MPFS_USB_NENDPOINTS && index.b[MSB] == 0 &&
|
||||||
value.w == USB_FEATURE_ENDPOINTHALT && len.w == 0)
|
value.w == USB_FEATURE_ENDPOINTHALT && len.w == 0)
|
||||||
{
|
{
|
||||||
privep = &priv->eplist[epno];
|
if (USB_ISEPIN(index.b[LSB]))
|
||||||
|
{
|
||||||
|
idx = epno + MPFS_EPIN_START;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx = epno;
|
||||||
|
}
|
||||||
|
|
||||||
|
privep = &priv->eplist[idx];
|
||||||
privep->halted = true;
|
privep->halted = true;
|
||||||
|
|
||||||
ret = mpfs_ep_stall(privep);
|
ret = mpfs_ep_stall(privep);
|
||||||
@@ -3035,7 +3105,10 @@ static void mpfs_ep_rx_interrupt(struct mpfs_usbdev_s *priv, int epno)
|
|||||||
static void mpfs_ep_tx_interrupt(struct mpfs_usbdev_s *priv, int epno)
|
static void mpfs_ep_tx_interrupt(struct mpfs_usbdev_s *priv, int epno)
|
||||||
{
|
{
|
||||||
struct mpfs_ep_s *privep;
|
struct mpfs_ep_s *privep;
|
||||||
privep = &priv->eplist[epno];
|
|
||||||
|
privep = &priv->eplist[epno + MPFS_EPIN_START];
|
||||||
|
|
||||||
|
DEBUGASSERT((epno + MPFS_EPIN_START) < MPFS_USB_NENDPOINTS);
|
||||||
|
|
||||||
mpfs_putreg8(epno, MPFS_USB_INDEX);
|
mpfs_putreg8(epno, MPFS_USB_INDEX);
|
||||||
|
|
||||||
@@ -3080,14 +3153,13 @@ static void mpfs_ep_tx_interrupt(struct mpfs_usbdev_s *priv, int epno)
|
|||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
* priv - USB device abstraction
|
* priv - USB device abstraction
|
||||||
* epno - The endpoint number
|
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* None
|
* None
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void mpfs_ctrl_ep_interrupt(struct mpfs_usbdev_s *priv, int epno)
|
static void mpfs_ctrl_ep_interrupt(struct mpfs_usbdev_s *priv)
|
||||||
{
|
{
|
||||||
struct mpfs_ep_s *privep;
|
struct mpfs_ep_s *privep;
|
||||||
uint16_t count0;
|
uint16_t count0;
|
||||||
@@ -3096,9 +3168,9 @@ static void mpfs_ctrl_ep_interrupt(struct mpfs_usbdev_s *priv, int epno)
|
|||||||
|
|
||||||
/* Get the endpoint structure */
|
/* Get the endpoint structure */
|
||||||
|
|
||||||
privep = &priv->eplist[epno];
|
privep = &priv->eplist[EP0];
|
||||||
|
|
||||||
mpfs_putreg8(epno, MPFS_USB_INDEX);
|
mpfs_putreg8(EP0, MPFS_USB_INDEX);
|
||||||
|
|
||||||
/* Make sure we're in device mode */
|
/* Make sure we're in device mode */
|
||||||
|
|
||||||
@@ -3198,8 +3270,6 @@ static void mpfs_ctrl_ep_interrupt(struct mpfs_usbdev_s *priv, int epno)
|
|||||||
{
|
{
|
||||||
uint16_t rlen;
|
uint16_t rlen;
|
||||||
|
|
||||||
DEBUGASSERT(epno == EP0);
|
|
||||||
|
|
||||||
/* Yes.. back to the IDLE state */
|
/* Yes.. back to the IDLE state */
|
||||||
|
|
||||||
privep->epstate = USB_EPSTATE_IDLE;
|
privep->epstate = USB_EPSTATE_IDLE;
|
||||||
@@ -3311,7 +3381,7 @@ static int mpfs_usb_interrupt(int irq, void *context, void *arg)
|
|||||||
|
|
||||||
if ((pending_tx_ep & 0x01) != 0)
|
if ((pending_tx_ep & 0x01) != 0)
|
||||||
{
|
{
|
||||||
mpfs_ctrl_ep_interrupt(priv, 0);
|
mpfs_ctrl_ep_interrupt(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pending_tx_ep != 0)
|
if (pending_tx_ep != 0)
|
||||||
@@ -3667,7 +3737,14 @@ static void mpfs_sw_setup(struct mpfs_usbdev_s *priv)
|
|||||||
|
|
||||||
priv->eplist[epno].ep.ops = &g_epops;
|
priv->eplist[epno].ep.ops = &g_epops;
|
||||||
priv->eplist[epno].dev = priv;
|
priv->eplist[epno].dev = priv;
|
||||||
priv->eplist[epno].ep.eplog = epno;
|
if (epno < (MPFS_EPIN_START + 1))
|
||||||
|
{
|
||||||
|
priv->eplist[epno].ep.eplog = epno;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
priv->eplist[epno].ep.eplog = epno - MPFS_EPIN_START;
|
||||||
|
}
|
||||||
|
|
||||||
/* We will use a maxpacket size for supported for each endpoint */
|
/* We will use a maxpacket size for supported for each endpoint */
|
||||||
|
|
||||||
|
|||||||
@@ -252,8 +252,8 @@ void *board_composite_connect(int port, int configid)
|
|||||||
/* Endpoints */
|
/* Endpoints */
|
||||||
|
|
||||||
dev[0].devinfo.epno[CDCACM_EP_BULKIN_IDX] = 3;
|
dev[0].devinfo.epno[CDCACM_EP_BULKIN_IDX] = 3;
|
||||||
dev[0].devinfo.epno[CDCACM_EP_BULKOUT_IDX] = 4;
|
dev[0].devinfo.epno[CDCACM_EP_BULKOUT_IDX] = 3;
|
||||||
dev[0].devinfo.epno[CDCACM_EP_INTIN_IDX] = 5;
|
dev[0].devinfo.epno[CDCACM_EP_INTIN_IDX] = 4;
|
||||||
|
|
||||||
/* Count up the base numbers */
|
/* Count up the base numbers */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user