drivers/usbhost: use small lock to protect usbhost cdcacm

replace critical_section with spinlock

Signed-off-by: yangsong8 <yangsong8@xiaomi.com>
This commit is contained in:
yangsong8
2025-06-21 15:48:52 +08:00
committed by Xiang Xiao
parent 62f7a8fa22
commit 23cec99002
+31 -26
View File
@@ -25,6 +25,7 @@
****************************************************************************/ ****************************************************************************/
#include <nuttx/config.h> #include <nuttx/config.h>
#include <nuttx/spinlock.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -255,6 +256,7 @@ struct usbhost_cdcacm_s
uint16_t rxndx; /* Index to the next byte in the RX packet buffer */ uint16_t rxndx; /* Index to the next byte in the RX packet buffer */
int16_t crefs; /* Reference count on the driver instance */ int16_t crefs; /* Reference count on the driver instance */
int16_t nbytes; /* The number of bytes actually transferred */ int16_t nbytes; /* The number of bytes actually transferred */
spinlock_t spinlock; /* Used to protect critical section */
mutex_t lock; /* Used to maintain mutual exclusive access */ mutex_t lock; /* Used to maintain mutual exclusive access */
struct work_s ntwork; /* For asynchronous notification work */ struct work_s ntwork; /* For asynchronous notification work */
struct work_s rxwork; /* For RX packet work */ struct work_s rxwork; /* For RX packet work */
@@ -474,6 +476,8 @@ static FAR struct usbhost_freestate_s *g_freelist;
static uint32_t g_devinuse; static uint32_t g_devinuse;
static spinlock_t g_lock = SP_UNLOCKED;
/**************************************************************************** /****************************************************************************
* Private Functions * Private Functions
****************************************************************************/ ****************************************************************************/
@@ -507,14 +511,14 @@ static FAR struct usbhost_cdcacm_s *usbhost_allocclass(void)
* our pre-allocated class instances from the free list. * our pre-allocated class instances from the free list.
*/ */
flags = enter_critical_section(); flags = spin_lock_irqsave(&g_lock);
entry = g_freelist; entry = g_freelist;
if (entry) if (entry)
{ {
g_freelist = entry->flink; g_freelist = entry->flink;
} }
leave_critical_section(flags); spin_unlock_irqrestore(&g_lock, flags);
uinfo("Allocated: %p\n", entry); uinfo("Allocated: %p\n", entry);
return (FAR struct usbhost_cdcacm_s *)entry; return (FAR struct usbhost_cdcacm_s *)entry;
} }
@@ -562,10 +566,10 @@ static void usbhost_freeclass(FAR struct usbhost_cdcacm_s *usbclass)
/* Just put the pre-allocated class structure back on the freelist */ /* Just put the pre-allocated class structure back on the freelist */
flags = enter_critical_section(); flags = spin_lock_irqsave(&g_lock);
entry->flink = g_freelist; entry->flink = g_freelist;
g_freelist = entry; g_freelist = entry;
leave_critical_section(flags); spin_unlock_irqrestore(&g_lock, flags);
} }
#else #else
static void usbhost_freeclass(FAR struct usbhost_cdcacm_s *usbclass) static void usbhost_freeclass(FAR struct usbhost_cdcacm_s *usbclass)
@@ -594,7 +598,7 @@ static int usbhost_devno_alloc(FAR struct usbhost_cdcacm_s *priv)
irqstate_t flags; irqstate_t flags;
int devno; int devno;
flags = enter_critical_section(); flags = spin_lock_irqsave(&g_lock);
for (devno = 0; devno < 32; devno++) for (devno = 0; devno < 32; devno++)
{ {
uint32_t bitno = 1 << devno; uint32_t bitno = 1 << devno;
@@ -602,12 +606,12 @@ static int usbhost_devno_alloc(FAR struct usbhost_cdcacm_s *priv)
{ {
g_devinuse |= bitno; g_devinuse |= bitno;
priv->minor = devno; priv->minor = devno;
leave_critical_section(flags); spin_unlock_irqrestore(&g_lock, flags);
return OK; return OK;
} }
} }
leave_critical_section(flags); spin_unlock_irqrestore(&g_lock, flags);
return -EMFILE; return -EMFILE;
} }
@@ -625,9 +629,9 @@ static void usbhost_devno_free(FAR struct usbhost_cdcacm_s *priv)
if (devno >= 0 && devno < 32) if (devno >= 0 && devno < 32)
{ {
irqstate_t flags = enter_critical_section(); irqstate_t flags = spin_lock_irqsave(&g_lock);
g_devinuse &= ~(1 << devno); g_devinuse &= ~(1 << devno);
leave_critical_section(flags); spin_unlock_irqrestore(&g_lock, flags);
} }
} }
@@ -1905,6 +1909,7 @@ usbhost_create(FAR struct usbhost_hubport_s *hport,
*/ */
nxmutex_init(&priv->lock); nxmutex_init(&priv->lock);
spin_lock_init(&priv->spinlock);
/* Set up the serial lower-half interface */ /* Set up the serial lower-half interface */
@@ -2123,6 +2128,7 @@ static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass)
(FAR struct usbhost_cdcacm_s *)usbclass; (FAR struct usbhost_cdcacm_s *)usbclass;
FAR struct usbhost_hubport_s *hport; FAR struct usbhost_hubport_s *hport;
irqstate_t flags; irqstate_t flags;
int16_t crefs;
int ret; int ret;
DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL); DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL);
@@ -2132,8 +2138,10 @@ static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass)
* is no longer available. * is no longer available.
*/ */
flags = enter_critical_section(); flags = spin_lock_irqsave(&priv->spinlock);
priv->disconnected = true; priv->disconnected = true;
crefs = priv->crefs;
spin_unlock_irqrestore(&priv->spinlock, flags);
/* Let the upper half driver know that serial device is no longer /* Let the upper half driver know that serial device is no longer
* connected. * connected.
@@ -2174,8 +2182,8 @@ static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass)
* serial driver. * serial driver.
*/ */
uinfo("crefs: %d\n", priv->crefs); uinfo("crefs: %d\n", crefs);
if (priv->crefs == 1) if (crefs == 1)
{ {
/* Destroy the class instance. If we are executing from an interrupt /* Destroy the class instance. If we are executing from an interrupt
* handler, then defer the destruction to the worker thread. * handler, then defer the destruction to the worker thread.
@@ -2200,7 +2208,6 @@ static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass)
} }
} }
leave_critical_section(flags);
return OK; return OK;
} }
@@ -2241,7 +2248,7 @@ static int usbhost_setup(FAR struct uart_dev_s *uartdev)
* isconnect events. * isconnect events.
*/ */
flags = enter_critical_section(); flags = spin_lock_irqsave(&priv->spinlock);
if (priv->disconnected) if (priv->disconnected)
{ {
/* No... the block driver is no longer bound to the class. That means /* No... the block driver is no longer bound to the class. That means
@@ -2259,7 +2266,7 @@ static int usbhost_setup(FAR struct uart_dev_s *uartdev)
ret = OK; ret = OK;
} }
leave_critical_section(flags); spin_unlock_irqrestore(&priv->spinlock, flags);
nxmutex_unlock(&priv->lock); nxmutex_unlock(&priv->lock);
return ret; return ret;
} }
@@ -2286,20 +2293,13 @@ static void usbhost_shutdown(FAR struct uart_dev_s *uartdev)
DEBUGASSERT(priv->crefs > 1); DEBUGASSERT(priv->crefs > 1);
nxmutex_lock(&priv->lock); nxmutex_lock(&priv->lock);
priv->crefs--;
/* Release the semaphore. The following operations when crefs == 1 are
* safe because we know that there is no outstanding open references to
* the block driver.
*/
nxmutex_unlock(&priv->lock);
/* We need to disable interrupts momentarily to assure that there are /* We need to disable interrupts momentarily to assure that there are
* no asynchronous disconnect events. * no asynchronous disconnect events.
*/ */
flags = enter_critical_section(); flags = spin_lock_irqsave(&priv->spinlock);
priv->crefs--;
/* Check if the USB CDC/ACM device is still connected. If the /* Check if the USB CDC/ACM device is still connected. If the
* CDC/ACM device is not connected and the reference count just * CDC/ACM device is not connected and the reference count just
@@ -2312,10 +2312,15 @@ static void usbhost_shutdown(FAR struct uart_dev_s *uartdev)
/* Destroy the class instance */ /* Destroy the class instance */
DEBUGASSERT(priv->crefs == 1); DEBUGASSERT(priv->crefs == 1);
spin_unlock_irqrestore(&priv->spinlock, flags);
nxmutex_unlock(&priv->lock);
usbhost_destroy(priv); usbhost_destroy(priv);
} }
else
leave_critical_section(flags); {
spin_unlock_irqrestore(&priv->spinlock, flags);
nxmutex_unlock(&priv->lock);
}
} }
/**************************************************************************** /****************************************************************************