drivers/usbhost/usbhost_max3421e.c: Mutual exclusion semaphore must be re-entrant.
This commit is contained in:
parent
8b2dc155a0
commit
d252c7947d
|
@ -221,8 +221,10 @@ struct max3421e_usbhost_s
|
|||
uint8_t xfrtype; /* See enum mx3421e_hxfrdn_e */
|
||||
uint8_t inflight; /* Number of Tx bytes "in-flight" (<= 128) */
|
||||
uint8_t result; /* The result of the transfer */
|
||||
uint8_t exclcount; /* Number of nested exclem locks */
|
||||
uint16_t buflen; /* Buffer length (at start of transfer) */
|
||||
uint16_t xfrd; /* Bytes transferred (at end of transfer) */
|
||||
pid_t holder; /* Current hold of the exclsem */
|
||||
sem_t exclsem; /* Support mutually exclusive access */
|
||||
sem_t pscsem; /* Semaphore to wait for a port event */
|
||||
sem_t waitsem; /* Channel wait semaphore */
|
||||
|
@ -427,6 +429,8 @@ static void max3421e_sndblock(FAR struct max3421e_usbhost_s *priv,
|
|||
|
||||
static void max3421e_takesem(sem_t *sem);
|
||||
#define max3421e_givesem(s) nxsem_post(s);
|
||||
static void max3421e_take_exclsem(FAR struct max3421e_usbhost_s *priv);
|
||||
static void max3421e_give_exclsem(FAR struct max3421e_usbhost_s *priv);
|
||||
|
||||
/* Byte stream access helper functions *****************************************/
|
||||
|
||||
|
@ -1077,6 +1081,64 @@ static void max3421e_takesem(sem_t *sem)
|
|||
while (ret == -EINTR);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max3421e_take_exclsem and max3421e_give_exclsem
|
||||
*
|
||||
* Description:
|
||||
* Implements a mutual re-entrant mutex for exclsem.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void max3421e_take_exclsem(FAR struct max3421e_usbhost_s *priv)
|
||||
{
|
||||
pid_t me = getpid();
|
||||
|
||||
/* Does this thread already hold the mutual exclusion mutex? */
|
||||
|
||||
if (priv->holder == me)
|
||||
{
|
||||
/* Yes.. just increment the count */
|
||||
|
||||
DEBUGASSERT(priv->exclcount < UINT8_MAX);
|
||||
priv->exclcount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. take the semaphore */
|
||||
|
||||
max3421e_takesem(&priv->exclsem);
|
||||
|
||||
/* Now this thread is the holder with a count of one */
|
||||
|
||||
priv->holder = me;
|
||||
priv->exclcount = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void max3421e_give_exclsem(FAR struct max3421e_usbhost_s *priv)
|
||||
{
|
||||
pid_t me = getpid();
|
||||
|
||||
DEBUGASSERT(priv->holder == me);
|
||||
|
||||
/* Is the lock nested? */
|
||||
|
||||
if (priv->exclcount > 0)
|
||||
{
|
||||
/* Yes.. just decrement the count */
|
||||
|
||||
priv->exclcount--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. give the semaphore */
|
||||
|
||||
priv->holder = (pid_t)-1;
|
||||
priv->exclcount = 0;
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max3421e_getle16
|
||||
*
|
||||
|
@ -3281,7 +3343,7 @@ static int max3421e_wait(FAR struct usbhost_connection_s *conn,
|
|||
{
|
||||
/* We must have exclusive access to the USB host hardware and state structures */
|
||||
|
||||
max3421e_takesem(&priv->exclsem);
|
||||
max3421e_take_exclsem(priv);
|
||||
|
||||
/* Is there a change in the connection state of the single root hub
|
||||
* port?
|
||||
|
@ -3302,7 +3364,7 @@ static int max3421e_wait(FAR struct usbhost_connection_s *conn,
|
|||
|
||||
usbhost_vtrace1(MAX3421E_VTRACE1_CONNECTED2, connport->connected);
|
||||
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -3321,7 +3383,7 @@ static int max3421e_wait(FAR struct usbhost_connection_s *conn,
|
|||
usbhost_vtrace1(MAX3421E_VTRACE1_HUB_CONNECTED,
|
||||
connport->connected);
|
||||
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
@ -3329,7 +3391,7 @@ static int max3421e_wait(FAR struct usbhost_connection_s *conn,
|
|||
/* Wait for the next connection event */
|
||||
|
||||
priv->pscwait = true;
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
max3421e_takesem(&priv->pscsem);
|
||||
}
|
||||
}
|
||||
|
@ -3391,7 +3453,7 @@ static int max3421e_getspeed(FAR struct max3421e_usbhost_s *priv,
|
|||
/* No, return an error */
|
||||
|
||||
usbhost_trace1(MAX3421E_TRACE1_DEVDISCONN6, 0);
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -3452,7 +3514,7 @@ static int max3421e_enumerate(FAR struct usbhost_connection_s *conn,
|
|||
|
||||
/* We must have exclusive access to the USB host hardware and state structures */
|
||||
|
||||
max3421e_takesem(&priv->exclsem);
|
||||
max3421e_take_exclsem(priv);
|
||||
|
||||
/* If this is a connection on the root hub, then we need to go to
|
||||
* little more effort to get the device speed. If it is a connection
|
||||
|
@ -3470,7 +3532,7 @@ static int max3421e_enumerate(FAR struct usbhost_connection_s *conn,
|
|||
ret = max3421e_getspeed(priv, conn, hport);
|
||||
if (ret < 0)
|
||||
{
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -3480,6 +3542,7 @@ static int max3421e_enumerate(FAR struct usbhost_connection_s *conn,
|
|||
max3421e_modifyreg(priv, MAX3421E_USBHOST_HCTL,
|
||||
USBHOST_HCTL_TOGGLES_MASK,
|
||||
USBHOST_HCTL_RCVTOG1 | USBHOST_HCTL_SNDTOG1);
|
||||
max3421e_unlock(priv);
|
||||
|
||||
/* Then let the common usbhost_enumerate do the real enumeration. */
|
||||
|
||||
|
@ -3487,7 +3550,6 @@ static int max3421e_enumerate(FAR struct usbhost_connection_s *conn,
|
|||
priv->smstate = SMSTATE_ENUM;
|
||||
|
||||
ret = usbhost_enumerate(hport, &hport->devclass);
|
||||
max3421e_unlock(priv);
|
||||
|
||||
/* The enumeration may fail either because of some HCD interfaces failure
|
||||
* or because the device class is not supported. In either case, we just
|
||||
|
@ -3511,7 +3573,7 @@ static int max3421e_enumerate(FAR struct usbhost_connection_s *conn,
|
|||
USBHOST_HCTL_RCVTOG0| USBHOST_HCTL_SNDTOG0);
|
||||
max3421e_unlock(priv);
|
||||
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -3553,7 +3615,7 @@ static int max3421e_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t
|
|||
|
||||
/* We must have exclusive access to the USB host hardware and state structures */
|
||||
|
||||
max3421e_takesem(&priv->exclsem);
|
||||
max3421e_take_exclsem(priv);
|
||||
|
||||
/* Configure the EP0 channel */
|
||||
|
||||
|
@ -3563,7 +3625,7 @@ static int max3421e_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t
|
|||
chan->maxpacket = maxpacketsize;
|
||||
chan->toggles = USBHOST_HCTL_RCVTOG0 | USBHOST_HCTL_SNDTOG0;
|
||||
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -3608,7 +3670,7 @@ static int max3421e_epalloc(FAR struct usbhost_driver_s *drvr,
|
|||
|
||||
/* We must have exclusive access to the USB host hardware and state structures */
|
||||
|
||||
max3421e_takesem(&priv->exclsem);
|
||||
max3421e_take_exclsem(priv);
|
||||
|
||||
/* Allocate a host channel for the endpoint */
|
||||
|
||||
|
@ -3616,7 +3678,7 @@ static int max3421e_epalloc(FAR struct usbhost_driver_s *drvr,
|
|||
if (chidx < 0)
|
||||
{
|
||||
usbhost_trace1(MAX3421E_TRACE1_CHANALLOC_FAIL, -chidx);
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return chidx;
|
||||
}
|
||||
|
||||
|
@ -3639,7 +3701,7 @@ static int max3421e_epalloc(FAR struct usbhost_driver_s *drvr,
|
|||
/* Return the endpoint number as the endpoint "handle" */
|
||||
|
||||
*ep = (usbhost_ep_t)chidx;
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -3671,12 +3733,12 @@ static int max3421e_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
|
|||
|
||||
/* We must have exclusive access to the USB host hardware and state structures */
|
||||
|
||||
max3421e_takesem(&priv->exclsem);
|
||||
max3421e_take_exclsem(priv);
|
||||
|
||||
/* Halt the channel and mark the channel available */
|
||||
|
||||
max3421e_chan_free(priv, (intptr_t)ep);
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -3910,7 +3972,7 @@ static int max3421e_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
|
|||
|
||||
/* We must have exclusive access to the USB host hardware and state structures */
|
||||
|
||||
max3421e_takesem(&priv->exclsem);
|
||||
max3421e_take_exclsem(priv);
|
||||
|
||||
/* Loop, retrying until the retry time expires */
|
||||
|
||||
|
@ -3954,7 +4016,7 @@ static int max3421e_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
|
|||
{
|
||||
/* All success transactions exit here */
|
||||
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -3970,7 +4032,7 @@ static int max3421e_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
|
|||
|
||||
/* All failures exit here after all retries and timeouts have been exhausted */
|
||||
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
@ -4003,7 +4065,7 @@ static int max3421e_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
|
|||
|
||||
/* We must have exclusive access to the USB host hardware and state structures */
|
||||
|
||||
max3421e_takesem(&priv->exclsem);
|
||||
max3421e_take_exclsem(priv);
|
||||
|
||||
/* Loop, retrying until the retry time expires */
|
||||
|
||||
|
@ -4049,7 +4111,7 @@ static int max3421e_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
|
|||
{
|
||||
/* All success transactions exit here */
|
||||
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -4065,7 +4127,7 @@ static int max3421e_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
|
|||
|
||||
/* All failures exit here after all retries and timeouts have been exhausted */
|
||||
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
@ -4122,7 +4184,7 @@ static ssize_t max3421e_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t
|
|||
|
||||
/* We must have exclusive access to the USB host hardware and state structures */
|
||||
|
||||
max3421e_takesem(&priv->exclsem);
|
||||
max3421e_take_exclsem(priv);
|
||||
|
||||
/* Handle IN and OUT transfer differently */
|
||||
|
||||
|
@ -4135,7 +4197,7 @@ static ssize_t max3421e_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t
|
|||
nbytes = max3421e_out_transfer(priv, chan, buffer, buflen);
|
||||
}
|
||||
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
|
@ -4191,7 +4253,7 @@ static int max3421e_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
|
|||
|
||||
/* We must have exclusive access to the USB host hardware and state structures */
|
||||
|
||||
max3421e_takesem(&priv->exclsem);
|
||||
max3421e_take_exclsem(priv);
|
||||
|
||||
/* Handle IN and OUT transfer slightly differently */
|
||||
|
||||
|
@ -4204,7 +4266,7 @@ static int max3421e_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
|
|||
ret = max3421e_out_asynch(priv, chan, buffer, buflen, callback, arg);
|
||||
}
|
||||
|
||||
max3421e_givesem(&priv->exclsem);
|
||||
max3421e_give_exclsem(priv);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_USBHOST_ASYNCH */
|
||||
|
@ -4603,6 +4665,7 @@ static inline int max3421e_sw_initialize(FAR struct max3421e_usbhost_s *priv,
|
|||
priv->connected = false;
|
||||
priv->irqset = 0;
|
||||
priv->change = false;
|
||||
priv->holder = (pid_t)-1;
|
||||
|
||||
/* Put all of the channels back in their initial, allocated state */
|
||||
|
||||
|
|
Loading…
Reference in New Issue