Signed-off-by: Bjørn Mork <bjorn@xxxxxxx> --- drivers/usb/class/cdc-wdm.c | 71 ++++++++++++++++++++++++++++++++++++++---- 1 files changed, 64 insertions(+), 7 deletions(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 684e89b..af93df9 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -77,6 +77,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids); #define WDM_DEFAULT_BUFSIZE 256 static DEFINE_MUTEX(wdm_mutex); +static LIST_HEAD(wdm_device_list); /* --- method tables --- */ @@ -111,13 +112,45 @@ struct wdm_device { struct work_struct rxwork; int werr; int rerr; + + struct list_head device_list; }; 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_get_device(struct usb_interface *intf) { - struct wdm_device *desc = usb_get_intfdata(intf); + struct wdm_device *desc = NULL; + + pr_debug("%s: intf->dev.driver=%p, &wdm_driver=%p\n", __func__, to_usb_driver(intf->dev.driver), &wdm_driver); + + mutex_lock(&wdm_mutex); + if (to_usb_driver(intf->dev.driver) == &wdm_driver) + desc = usb_get_intfdata(intf); + else + list_for_each_entry(desc, &wdm_device_list, device_list) + if (desc->intf == intf) + break; + mutex_unlock(&wdm_mutex); + + return desc; +} + +/* caller holds wdm_mutex */ +static struct wdm_device *wdm_get_device_by_minor(int minor) +{ + struct wdm_device *desc = NULL; + + list_for_each_entry(desc, &wdm_device_list, device_list) { + pr_debug("%s: looking at %s (%p)\n", __func__, dev_name(&desc->intf->dev), desc->intf); + if (desc->intf->minor == minor) + break; + } + + if (desc) + pr_debug("%s: returning desc->intf=%p for minor=%u\n", __func__, desc->intf, minor); + return desc; } @@ -524,11 +557,11 @@ static int wdm_open(struct inode *inode, struct file *file) struct wdm_device *desc; mutex_lock(&wdm_mutex); - intf = usb_find_interface(&wdm_driver, minor); - if (!intf) + desc = wdm_get_device_by_minor(minor); + if (!desc) goto out; - desc = wdm_get_device(intf); + intf = desc->intf; if (test_bit(WDM_DISCONNECTING, &desc->flags)) goto out; file->private_data = desc; @@ -715,6 +748,10 @@ static struct wdm_device *wdm_create(struct usb_interface *intf, u16 bufsize) desc ); + mutex_lock(&wdm_mutex); + list_add(&desc->device_list, &wdm_device_list); + mutex_unlock(&wdm_mutex); + return desc; err: @@ -807,8 +844,10 @@ static void wdm_destroy(struct wdm_device *desc) cancel_work_sync(&desc->rxwork); mutex_unlock(&desc->wlock); mutex_unlock(&desc->rlock); - if (!desc->count) + if (!desc->count) { + list_del(&desc->device_list); cleanup(desc); + } mutex_unlock(&wdm_mutex); } @@ -816,7 +855,9 @@ static void wdm_destroy(struct wdm_device *desc) static void wdm_disconnect(struct usb_interface *intf) { struct wdm_device *desc = wdm_get_device(intf); - wdm_destroy(desc); + + if (desc) + wdm_destroy(desc); } #ifdef CONFIG_PM @@ -825,6 +866,9 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) struct wdm_device *desc = wdm_get_device(intf); int rv = 0; + if (!desc) + goto out; + dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); /* if this is an autosuspend the caller does the locking */ @@ -852,6 +896,7 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) mutex_unlock(&desc->rlock); } +out: return rv; } #endif @@ -873,13 +918,17 @@ static int recover_from_urb_loss(struct wdm_device *desc) static int wdm_resume(struct usb_interface *intf) { struct wdm_device *desc = wdm_get_device(intf); - int rv; + int rv = 0; + + if (!desc) + goto out; dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor); clear_bit(WDM_SUSPENDING, &desc->flags); rv = recover_from_urb_loss(desc); +out: return rv; } #endif @@ -888,6 +937,9 @@ static int wdm_pre_reset(struct usb_interface *intf) { struct wdm_device *desc = wdm_get_device(intf); + if (!desc) + goto out; + mutex_lock(&desc->rlock); mutex_lock(&desc->wlock); kill_urbs(desc); @@ -902,6 +954,7 @@ static int wdm_pre_reset(struct usb_interface *intf) desc->rerr = -EINTR; spin_unlock_irq(&desc->iuspin); wake_up_all(&desc->wait); +out: return 0; } @@ -910,9 +963,13 @@ static int wdm_post_reset(struct usb_interface *intf) struct wdm_device *desc = wdm_get_device(intf); int rv; + if (!desc) + goto out; + rv = recover_from_urb_loss(desc); mutex_unlock(&desc->wlock); mutex_unlock(&desc->rlock); +out: return 0; } -- 1.7.8.3 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html