usb: cdc-wdm: adding list lookup indirection
Register all interfaces handled by this driver in a list, getting rid of the dependency on usb_set_intfdata. This allows further generalization and simplification of the probe/create functions. This is needed to decouple wdm_open from the driver owning the interface, and it also allows us to share all the code in wdm_create with drivers unable to do usb_set_intfdata. Signed-off-by: Bjørn Mork <bjorn@mork.no> Acked-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
0dffb4862a
commit
b0c1386080
1 changed files with 48 additions and 12 deletions
|
@ -78,6 +78,8 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
|
||||||
#define WDM_DEFAULT_BUFSIZE 256
|
#define WDM_DEFAULT_BUFSIZE 256
|
||||||
|
|
||||||
static DEFINE_MUTEX(wdm_mutex);
|
static DEFINE_MUTEX(wdm_mutex);
|
||||||
|
static DEFINE_SPINLOCK(wdm_device_list_lock);
|
||||||
|
static LIST_HEAD(wdm_device_list);
|
||||||
|
|
||||||
/* --- method tables --- */
|
/* --- method tables --- */
|
||||||
|
|
||||||
|
@ -112,10 +114,39 @@ struct wdm_device {
|
||||||
struct work_struct rxwork;
|
struct work_struct rxwork;
|
||||||
int werr;
|
int werr;
|
||||||
int rerr;
|
int rerr;
|
||||||
|
|
||||||
|
struct list_head device_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct usb_driver wdm_driver;
|
static struct usb_driver wdm_driver;
|
||||||
|
|
||||||
|
/* return intfdata if we own the interface, else look up intf in the list */
|
||||||
|
static struct wdm_device *wdm_find_device(struct usb_interface *intf)
|
||||||
|
{
|
||||||
|
struct wdm_device *desc = NULL;
|
||||||
|
|
||||||
|
spin_lock(&wdm_device_list_lock);
|
||||||
|
list_for_each_entry(desc, &wdm_device_list, device_list)
|
||||||
|
if (desc->intf == intf)
|
||||||
|
break;
|
||||||
|
spin_unlock(&wdm_device_list_lock);
|
||||||
|
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wdm_device *wdm_find_device_by_minor(int minor)
|
||||||
|
{
|
||||||
|
struct wdm_device *desc = NULL;
|
||||||
|
|
||||||
|
spin_lock(&wdm_device_list_lock);
|
||||||
|
list_for_each_entry(desc, &wdm_device_list, device_list)
|
||||||
|
if (desc->intf->minor == minor)
|
||||||
|
break;
|
||||||
|
spin_unlock(&wdm_device_list_lock);
|
||||||
|
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
/* --- callbacks --- */
|
/* --- callbacks --- */
|
||||||
static void wdm_out_callback(struct urb *urb)
|
static void wdm_out_callback(struct urb *urb)
|
||||||
{
|
{
|
||||||
|
@ -275,6 +306,9 @@ static void free_urbs(struct wdm_device *desc)
|
||||||
|
|
||||||
static void cleanup(struct wdm_device *desc)
|
static void cleanup(struct wdm_device *desc)
|
||||||
{
|
{
|
||||||
|
spin_lock(&wdm_device_list_lock);
|
||||||
|
list_del(&desc->device_list);
|
||||||
|
spin_unlock(&wdm_device_list_lock);
|
||||||
kfree(desc->sbuf);
|
kfree(desc->sbuf);
|
||||||
kfree(desc->inbuf);
|
kfree(desc->inbuf);
|
||||||
kfree(desc->orq);
|
kfree(desc->orq);
|
||||||
|
@ -532,11 +566,11 @@ static int wdm_open(struct inode *inode, struct file *file)
|
||||||
struct wdm_device *desc;
|
struct wdm_device *desc;
|
||||||
|
|
||||||
mutex_lock(&wdm_mutex);
|
mutex_lock(&wdm_mutex);
|
||||||
intf = usb_find_interface(&wdm_driver, minor);
|
desc = wdm_find_device_by_minor(minor);
|
||||||
if (!intf)
|
if (!desc)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
desc = usb_get_intfdata(intf);
|
intf = desc->intf;
|
||||||
if (test_bit(WDM_DISCONNECTING, &desc->flags))
|
if (test_bit(WDM_DISCONNECTING, &desc->flags))
|
||||||
goto out;
|
goto out;
|
||||||
file->private_data = desc;
|
file->private_data = desc;
|
||||||
|
@ -639,6 +673,7 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
|
||||||
desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
|
desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
|
||||||
if (!desc)
|
if (!desc)
|
||||||
goto out;
|
goto out;
|
||||||
|
INIT_LIST_HEAD(&desc->device_list);
|
||||||
mutex_init(&desc->rlock);
|
mutex_init(&desc->rlock);
|
||||||
mutex_init(&desc->wlock);
|
mutex_init(&desc->wlock);
|
||||||
spin_lock_init(&desc->iuspin);
|
spin_lock_init(&desc->iuspin);
|
||||||
|
@ -715,16 +750,17 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
|
||||||
desc
|
desc
|
||||||
);
|
);
|
||||||
|
|
||||||
usb_set_intfdata(intf, desc);
|
spin_lock(&wdm_device_list_lock);
|
||||||
|
list_add(&desc->device_list, &wdm_device_list);
|
||||||
|
spin_unlock(&wdm_device_list_lock);
|
||||||
|
|
||||||
rv = usb_register_dev(intf, &wdm_class);
|
rv = usb_register_dev(intf, &wdm_class);
|
||||||
if (rv < 0)
|
if (rv < 0)
|
||||||
goto err2;
|
goto err;
|
||||||
else
|
else
|
||||||
dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev));
|
dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev));
|
||||||
out:
|
out:
|
||||||
return rv;
|
return rv;
|
||||||
err2:
|
|
||||||
usb_set_intfdata(intf, NULL);
|
|
||||||
err:
|
err:
|
||||||
cleanup(desc);
|
cleanup(desc);
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -785,8 +821,8 @@ static void wdm_disconnect(struct usb_interface *intf)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
usb_deregister_dev(intf, &wdm_class);
|
usb_deregister_dev(intf, &wdm_class);
|
||||||
|
desc = wdm_find_device(intf);
|
||||||
mutex_lock(&wdm_mutex);
|
mutex_lock(&wdm_mutex);
|
||||||
desc = usb_get_intfdata(intf);
|
|
||||||
|
|
||||||
/* the spinlock makes sure no new urbs are generated in the callbacks */
|
/* the spinlock makes sure no new urbs are generated in the callbacks */
|
||||||
spin_lock_irqsave(&desc->iuspin, flags);
|
spin_lock_irqsave(&desc->iuspin, flags);
|
||||||
|
@ -810,7 +846,7 @@ static void wdm_disconnect(struct usb_interface *intf)
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
|
static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
|
||||||
{
|
{
|
||||||
struct wdm_device *desc = usb_get_intfdata(intf);
|
struct wdm_device *desc = wdm_find_device(intf);
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
|
|
||||||
dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
|
dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
|
||||||
|
@ -860,7 +896,7 @@ static int recover_from_urb_loss(struct wdm_device *desc)
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
static int wdm_resume(struct usb_interface *intf)
|
static int wdm_resume(struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
struct wdm_device *desc = usb_get_intfdata(intf);
|
struct wdm_device *desc = wdm_find_device(intf);
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor);
|
dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor);
|
||||||
|
@ -874,7 +910,7 @@ static int wdm_resume(struct usb_interface *intf)
|
||||||
|
|
||||||
static int wdm_pre_reset(struct usb_interface *intf)
|
static int wdm_pre_reset(struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
struct wdm_device *desc = usb_get_intfdata(intf);
|
struct wdm_device *desc = wdm_find_device(intf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we notify everybody using poll of
|
* we notify everybody using poll of
|
||||||
|
@ -898,7 +934,7 @@ static int wdm_pre_reset(struct usb_interface *intf)
|
||||||
|
|
||||||
static int wdm_post_reset(struct usb_interface *intf)
|
static int wdm_post_reset(struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
struct wdm_device *desc = usb_get_intfdata(intf);
|
struct wdm_device *desc = wdm_find_device(intf);
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
clear_bit(WDM_RESETTING, &desc->flags);
|
clear_bit(WDM_RESETTING, &desc->flags);
|
||||||
|
|
Loading…
Reference in a new issue