cdc_subset: deal with a device that needs reset for timeout

This device needs to be reset to recover from a timeout.
Unfortunately this can be handled only at the level of
the subdrivers.

Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Oliver Neukum 2014-08-01 14:01:51 +02:00 committed by David S. Miller
parent 06ebb06d49
commit dbcdd4d58c
3 changed files with 35 additions and 3 deletions

View File

@ -85,14 +85,28 @@ static int always_connected (struct usbnet *dev)
* *
*-------------------------------------------------------------------------*/ *-------------------------------------------------------------------------*/
static void m5632_recover(struct usbnet *dev)
{
struct usb_device *udev = dev->udev;
struct usb_interface *intf = dev->intf;
int r;
r = usb_lock_device_for_reset(udev, intf);
if (r < 0)
return;
usb_reset_device(udev);
usb_unlock_device(udev);
}
static const struct driver_info ali_m5632_info = { static const struct driver_info ali_m5632_info = {
.description = "ALi M5632", .description = "ALi M5632",
.flags = FLAG_POINTTOPOINT, .flags = FLAG_POINTTOPOINT,
.recover = m5632_recover,
}; };
#endif #endif
#ifdef CONFIG_USB_AN2720 #ifdef CONFIG_USB_AN2720
#define HAVE_HARDWARE #define HAVE_HARDWARE
@ -326,12 +340,23 @@ static const struct usb_device_id products [] = {
MODULE_DEVICE_TABLE(usb, products); MODULE_DEVICE_TABLE(usb, products);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static int dummy_prereset(struct usb_interface *intf)
{
return 0;
}
static int dummy_postreset(struct usb_interface *intf)
{
return 0;
}
static struct usb_driver cdc_subset_driver = { static struct usb_driver cdc_subset_driver = {
.name = "cdc_subset", .name = "cdc_subset",
.probe = usbnet_probe, .probe = usbnet_probe,
.suspend = usbnet_suspend, .suspend = usbnet_suspend,
.resume = usbnet_resume, .resume = usbnet_resume,
.pre_reset = dummy_prereset,
.post_reset = dummy_postreset,
.disconnect = usbnet_disconnect, .disconnect = usbnet_disconnect,
.id_table = products, .id_table = products,
.disable_hub_initiated_lpm = 1, .disable_hub_initiated_lpm = 1,

View File

@ -1218,8 +1218,12 @@ void usbnet_tx_timeout (struct net_device *net)
unlink_urbs (dev, &dev->txq); unlink_urbs (dev, &dev->txq);
tasklet_schedule (&dev->bh); tasklet_schedule (&dev->bh);
/* this needs to be handled individually because the generic layer
// FIXME: device recovery -- reset? * doesn't know what is sufficient and could not restore private
* information if a remedy of an unconditional reset were used.
*/
if (dev->driver_info->recover)
(dev->driver_info->recover)(dev);
} }
EXPORT_SYMBOL_GPL(usbnet_tx_timeout); EXPORT_SYMBOL_GPL(usbnet_tx_timeout);

View File

@ -148,6 +148,9 @@ struct driver_info {
struct sk_buff *(*tx_fixup)(struct usbnet *dev, struct sk_buff *(*tx_fixup)(struct usbnet *dev,
struct sk_buff *skb, gfp_t flags); struct sk_buff *skb, gfp_t flags);
/* recover from timeout */
void (*recover)(struct usbnet *dev);
/* early initialization code, can sleep. This is for minidrivers /* early initialization code, can sleep. This is for minidrivers
* having 'subminidrivers' that need to do extra initialization * having 'subminidrivers' that need to do extra initialization
* right after minidriver have initialized hardware. */ * right after minidriver have initialized hardware. */