Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

driver/usbdev: Solve some problems of USB hotplug #11161

Merged
merged 5 commits into from Nov 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
40 changes: 38 additions & 2 deletions arch/sim/src/sim/posix/sim_rawgadget.c
Expand Up @@ -26,6 +26,7 @@
#include <sys/types.h>
#include <sys/ioctl.h>

#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -199,6 +200,7 @@ struct usb_raw_gadget_dev_t
struct usb_raw_control_io_s ep0_ctrl;
struct usb_raw_ep_entry_s eps_entry[USB_RAW_EPS_NUM_MAX];
struct usb_raw_eps_info_s eps_info;
bool loop_stop;
};

/****************************************************************************
Expand All @@ -218,6 +220,16 @@ static struct usb_raw_gadget_dev_t g_raw_gadget_dev =
* Private Functions
****************************************************************************/

static void host_raw_handle_signal(int signum)
{
struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev;

if (signum == SIGUSR2)
{
dev->loop_stop = true;
}
}

static void host_raw_fifocreate(struct usb_raw_fifo_s *fifo,
uint16_t elem_size, uint16_t elem_num)
{
Expand Down Expand Up @@ -586,8 +598,13 @@ static void *host_raw_ep0handle(void *arg)
struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev;
struct usb_raw_ep_entry_s *entry = &dev->eps_entry[0];
struct usb_raw_control_event_s event;
struct sigaction action;

memset(&action, 0, sizeof(action));
action.sa_handler = host_raw_handle_signal;
sigaction(SIGUSR2, &action, NULL);

while (dev->fd >= 0)
while (!dev->loop_stop)
{
event.inner.type = 0;
event.inner.length = sizeof(event.ctrl);
Expand Down Expand Up @@ -621,8 +638,13 @@ static void *host_raw_ephandle(void *arg)
struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev;
struct usb_raw_ep_entry_s *entry = arg;
struct usb_raw_data_io_s *io;
struct sigaction action;

while (dev->fd >= 0)
memset(&action, 0, sizeof(action));
action.sa_handler = host_raw_handle_signal;
sigaction(SIGUSR2, &action, NULL);

while (!dev->loop_stop)
{
io = (struct usb_raw_data_io_s *)
host_raw_fifoalloc(&entry->fifo);
Expand Down Expand Up @@ -687,6 +709,7 @@ int host_usbdev_init(uint32_t speed)
host_raw_vbusdraw(fd, 0x32);
host_raw_configure(fd);
dev->fd = fd;
dev->loop_stop = false;

host_raw_fifocreate(&dev->eps_entry[0].fifo,
(sizeof(struct host_usb_ctrlreq_s)
Expand All @@ -700,7 +723,20 @@ int host_usbdev_init(uint32_t speed)
int host_usbdev_deinit(void)
{
struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev;
int i;

for (i = 0; i < USB_RAW_EPS_NUM_MAX &&
dev->eps_entry[i].ep_thread > 0; i++)
{
pthread_kill(dev->eps_entry[i].ep_thread, SIGUSR2);
pthread_join(dev->eps_entry[i].ep_thread, NULL);
}

pthread_kill(dev->ep0_thread, SIGUSR2);
pthread_join(dev->ep0_thread, NULL);
host_raw_close(dev->fd);
dev->fd = -1;

return 0;
}

Expand Down
7 changes: 4 additions & 3 deletions arch/sim/src/sim/sim_usbdev.c
Expand Up @@ -428,7 +428,7 @@ static int sim_reqwrite(struct sim_usbdev_s *priv, struct sim_ep_s *privep)
}

/****************************************************************************
* Name: sim_ep_configure
* Name: sim_usbdev_getctrlreq
****************************************************************************/

static void sim_usbdev_getctrlreq(struct usb_ctrlreq_s *usb_req,
Expand All @@ -445,7 +445,7 @@ static void sim_usbdev_getctrlreq(struct usb_ctrlreq_s *usb_req,
}

/****************************************************************************
* Name: sim_ep_configure
* Name: sim_usbdev_setepdesc
****************************************************************************/

static void sim_usbdev_setepdesc(struct host_usb_epdesc_s *host_epdesc,
Expand Down Expand Up @@ -1131,7 +1131,7 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)
*/

flags = enter_critical_section();
host_usbdev_deinit();
CLASS_DISCONNECT(driver, &priv->usbdev);
leave_critical_section(flags);

/* Unbind the class driver */
Expand All @@ -1145,6 +1145,7 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)
/* Disconnect device */

host_usbdev_pullup(false);
host_usbdev_deinit();

/* Unhook the driver */

Expand Down
79 changes: 73 additions & 6 deletions drivers/usbdev/usbdev_fs.c
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */

Expand All @@ -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;
}

Expand Down Expand Up @@ -541,6 +568,14 @@ static ssize_t usbdev_fs_read(FAR struct file *filep, FAR char *buffer,
return ret;
}

/* Check if the usbdev device has been unbind */

if (fs_ep->unlinked)
{
nxmutex_unlock(&fs_ep->lock);
return -ENOTCONN;
}

/* Check for available data */

if (sq_empty(&fs_ep->reqq))
Expand Down Expand Up @@ -644,6 +679,14 @@ static ssize_t usbdev_fs_write(FAR struct file *filep,
return ret;
}

/* Check if the usbdev device has been unbind */

if (fs_ep->unlinked)
{
nxmutex_unlock(&fs_ep->lock);
return -ENOTCONN;
}

/* Check for available write request */

if (sq_empty(&fs_ep->reqq))
Expand Down Expand Up @@ -747,6 +790,14 @@ static int usbdev_fs_poll(FAR struct file *filep, FAR struct pollfd *fds,
return ret;
}

/* Check if the usbdev device has been unbind */

if (fs_ep->unlinked)
{
nxmutex_unlock(&fs_ep->lock);
return -ENOTCONN;
}

if (!setup)
{
/* This is a request to tear down the poll. */
Expand Down Expand Up @@ -975,10 +1026,17 @@ static void usbdev_fs_ep_unbind(FAR const char *devname,
fs_ep->ep = NULL;
}

fs_ep->crefs = 0;
unregister_driver(devname);
fs_ep->unlinked = true;

/* Notify the usbdev device has been unbind */

poll_notify(fs_ep->fds, CONFIG_USBDEV_FS_NPOLLWAITERS, POLLHUP | POLLERR);

nxmutex_destroy(&fs_ep->lock);
if (fs_ep->crefs <= 0)
{
nxmutex_destroy(&fs_ep->lock);
}
}

/****************************************************************************
Expand Down Expand Up @@ -1122,6 +1180,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,
Expand Down Expand Up @@ -1157,22 +1216,30 @@ 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;

if (fs->eps != NULL)
{
for (i = 0; i < devinfo->ninterfaces; i++)
for (i = 0; i < devinfo->nendpoints; i++)
{
snprintf(devname, sizeof(devname), "%s/ep%d",
devinfo->name, i + 1);
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;
Expand Down