This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 20401c202ef0aedbe26376b24aa8c08084ccd20f
Author: dongjiuzhu1 <[email protected]>
AuthorDate: Wed Nov 8 14:44:49 2023 +0800

    driver/usbdev: add unlink flags to better release endpoint resource
    
    Signed-off-by: dongjiuzhu1 <[email protected]>
---
 drivers/usbdev/usbdev_fs.c | 50 ++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 44 insertions(+), 6 deletions(-)

diff --git a/drivers/usbdev/usbdev_fs.c b/drivers/usbdev/usbdev_fs.c
index f3a8341cf8..e04c02e8ba 100644
--- a/drivers/usbdev/usbdev_fs.c
+++ b/drivers/usbdev/usbdev_fs.c
@@ -67,8 +67,10 @@ typedef struct usbdev_fs_waiter_sem_s
 struct usbdev_fs_ep_s
 {
   uint8_t                     crefs;      /* Count of opened instances */
+  bool                        unlinked;   /* Indicates if the driver has been 
unlinked */
   mutex_t                     lock;       /* Enforces device exclusive access 
*/
   FAR struct usbdev_ep_s     *ep;         /* EP entry */
+  FAR struct usbdev_fs_dev_s *dev;        /* USB device */
   FAR usbdev_fs_waiter_sem_t *sems;       /* List of blocking request */
   struct sq_queue_s           reqq;       /* Available request containers */
   FAR struct usbdev_fs_req_s *reqbuffer;  /* Request buffer */
@@ -496,7 +498,9 @@ static int usbdev_fs_close(FAR struct file *filep)
 {
   FAR struct inode *inode = filep->f_inode;
   FAR struct usbdev_fs_ep_s *fs_ep = inode->i_private;
+  FAR struct usbdev_fs_dev_s *fs = fs_ep->dev;
   int ret;
+  int i;
 
   /* Get exclusive access to the device structures */
 
@@ -512,7 +516,30 @@ static int usbdev_fs_close(FAR struct file *filep)
 
   assert(fs_ep->crefs >= 0);
 
-  nxmutex_unlock(&fs_ep->lock);
+  if (fs_ep->unlinked && fs_ep->crefs == 0)
+    {
+      bool do_free = true;
+
+      nxmutex_destroy(&fs_ep->lock);
+      for (i = 0; i < fs->devinfo.nendpoints; i++)
+        {
+          if (fs->eps[i].crefs > 0)
+            {
+              do_free = false;
+            }
+        }
+
+      if (do_free)
+        {
+          kmm_free(fs->eps);
+          fs->eps = NULL;
+        }
+    }
+  else
+    {
+      nxmutex_unlock(&fs_ep->lock);
+    }
+
   return OK;
 }
 
@@ -975,10 +1002,12 @@ static void usbdev_fs_ep_unbind(FAR const char *devname,
       fs_ep->ep = NULL;
     }
 
-  fs_ep->crefs = 0;
   unregister_driver(devname);
-
-  nxmutex_destroy(&fs_ep->lock);
+  fs_ep->unlinked = true;
+  if (fs_ep->crefs <= 0)
+    {
+      nxmutex_destroy(&fs_ep->lock);
+    }
 }
 
 /****************************************************************************
@@ -1122,6 +1151,7 @@ static int usbdev_fs_classbind(FAR struct 
usbdevclass_driver_s *driver,
 
   for (i = 0; i < devinfo->nendpoints; i++)
     {
+      fs->eps[i].dev = fs;
       snprintf(devname, sizeof(devname), "%s/ep%d",
                devinfo->name, i + 1);
       ret = usbdev_fs_ep_bind(devname, dev,
@@ -1157,6 +1187,7 @@ static void usbdev_fs_classunbind(FAR struct 
usbdevclass_driver_s *driver,
     driver, FAR struct usbdev_fs_driver_s, drvr);
   FAR struct usbdev_fs_dev_s *fs = &fs_drvr->dev;
   FAR struct usbdev_devinfo_s *devinfo = &fs->devinfo;
+  bool do_free = true;
   char devname[32];
   uint16_t i;
 
@@ -1169,10 +1200,17 @@ static void usbdev_fs_classunbind(FAR struct 
usbdevclass_driver_s *driver,
           usbdev_fs_ep_unbind(devname, dev,
                               devinfo->epinfos[i],
                               &fs->eps[i]);
+          if (fs->eps[i].crefs > 0)
+            {
+              do_free = false;
+            }
         }
 
-      kmm_free(fs->eps);
-      fs->eps = NULL;
+      if (do_free)
+        {
+          kmm_free(fs->eps);
+          fs->eps = NULL;
+        }
     }
 
   fs->cdev = NULL;

Reply via email to