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:
Eero Nurkkala 2022-09-06 13:14:01 +03:00 committed by Xiang Xiao
parent e0bb281e7a
commit 4df8b16060
3 changed files with 101 additions and 24 deletions

View File

@ -27,7 +27,7 @@
#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_HS(ep) 512
#define MPFS_EP0_MAXPACKET 64

View File

@ -138,10 +138,11 @@
#define mpfs_rqempty(q) ((q)->head == NULL)
#define mpfs_rqpeek(q) ((q)->head)
#define MPFS_EPSET_ALL (0xff) /* All endpoints */
#define MPFS_EPSET_NOTEP0 (0xfe) /* All endpoints except EP0 */
#define MPFS_EPSET_ALL (0x1ff) /* All endpoints */
#define MPFS_EPSET_NOTEP0 (0x1fe) /* All endpoints except EP0 */
#define MPFS_EP_BIT(ep) (1 << (ep))
#define MPFS_MAX_MULTIPACKET_SIZE (0x3fff)
#define MPFS_EPIN_START (MPFS_USB_NENDPOINTS / 2)
/****************************************************************************
* Private Types
@ -652,9 +653,19 @@ static int mpfs_req_wrsetup(struct mpfs_usbdev_s *priv,
uint8_t epno;
int nbytes;
int ret;
int idx;
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);
/* 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 */
priv->eplist[epno].descb[1]->addr = (uintptr_t)buf;
packetsize = priv->eplist[epno].descb[1]->pktsize;
priv->eplist[idx].descb[1]->addr = (uintptr_t)buf;
packetsize = priv->eplist[idx].descb[1]->pktsize;
/* 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 */
}
priv->eplist[epno].descb[1]->pktsize = packetsize;
priv->eplist[idx].descb[1]->pktsize = packetsize;
/* 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);
if (ret != OK)
{
privep->epstate = USB_EPSTATE_IDLE;
return ret;
}
@ -731,6 +743,7 @@ static int mpfs_req_wrsetup(struct mpfs_usbdev_s *priv,
ret = mpfs_write_tx_fifo(buf, nbytes, epno);
if (ret != OK)
{
privep->epstate = USB_EPSTATE_IDLE;
return ret;
}
}
@ -906,6 +919,7 @@ static int mpfs_req_write(struct mpfs_usbdev_s *priv,
ret = mpfs_req_wrsetup(priv, privep, privreq);
if (ret != OK)
{
mpfs_req_complete(privep, 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->xfrd = 0;
privreq->inflight = 0;
flags = enter_critical_section();
/* 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:
* priv - USB device abstraction
* epset - Set of bits, one bit reflects one endpoint
* in - If the EP is direction IN
*
* Returned Value:
* 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 *
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;
irqstate_t flags;
@ -2008,15 +2024,34 @@ mpfs_ep_reserve(struct mpfs_usbdev_s *priv, uint8_t epset)
flags = enter_critical_section();
epset &= priv->epavail;
if (epset != 0)
{
/* Select the lowest bit in the set of matching, available endpoints
* (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)
{
/* 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);
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);
}
if (in)
{
epset <<= MPFS_EPIN_START;
}
/* Check if the selected endpoint number is available */
privep = mpfs_ep_reserve(priv, epset);
privep = mpfs_ep_reserve(priv, epset, in);
if (privep == NULL)
{
return NULL;
@ -2509,6 +2551,7 @@ static void mpfs_ep0_setup(struct mpfs_usbdev_s *priv)
uint8_t epno;
int nbytes = 0; /* Assume zero-length packet */
int ret;
int idx;
/* Terminate any pending requests */
@ -2570,6 +2613,15 @@ static void mpfs_ep0_setup(struct mpfs_usbdev_s *priv)
case USB_REQ_RECIPIENT_ENDPOINT:
{
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);
if (epno >= MPFS_USB_NENDPOINTS)
{
@ -2579,7 +2631,7 @@ static void mpfs_ep0_setup(struct mpfs_usbdev_s *priv)
}
else
{
privep = &priv->eplist[epno];
privep = &priv->eplist[idx];
response.w = 0; /* Not stalled */
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 &&
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;
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 &&
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;
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)
{
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);
@ -3080,14 +3153,13 @@ static void mpfs_ep_tx_interrupt(struct mpfs_usbdev_s *priv, int epno)
*
* Input Parameters:
* priv - USB device abstraction
* epno - The endpoint number
*
* Returned Value:
* 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;
uint16_t count0;
@ -3096,9 +3168,9 @@ static void mpfs_ctrl_ep_interrupt(struct mpfs_usbdev_s *priv, int epno)
/* 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 */
@ -3198,8 +3270,6 @@ static void mpfs_ctrl_ep_interrupt(struct mpfs_usbdev_s *priv, int epno)
{
uint16_t rlen;
DEBUGASSERT(epno == EP0);
/* Yes.. back to the IDLE state */
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)
{
mpfs_ctrl_ep_interrupt(priv, 0);
mpfs_ctrl_ep_interrupt(priv);
}
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].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 */

View File

@ -252,8 +252,8 @@ void *board_composite_connect(int port, int configid)
/* Endpoints */
dev[0].devinfo.epno[CDCACM_EP_BULKIN_IDX] = 3;
dev[0].devinfo.epno[CDCACM_EP_BULKOUT_IDX] = 4;
dev[0].devinfo.epno[CDCACM_EP_INTIN_IDX] = 5;
dev[0].devinfo.epno[CDCACM_EP_BULKOUT_IDX] = 3;
dev[0].devinfo.epno[CDCACM_EP_INTIN_IDX] = 4;
/* Count up the base numbers */