Hi, this implements autosuspend support for the asix subdriver of usbnet. It works by autoresume when the device is opened and autosuspending when it is closed. The logic is all put into the generic framework. All the subdriver has to do is setting the flag.
To support this the suspend() method is changed so that the device is not reported unready until resumption, as this prevents a new address being assigned to the device, blocking autoresumption. This method will have to be revisited if the freezer is removed, but the old routine is also buggy without the freezer, as it switches the device off while it may still be used. It works for me, but I'd like general comments. Regards Oliver --- --- a/drivers/net/usb/usbnet.h 2007-07-30 14:23:08.000000000 +0200 +++ b/drivers/net/usb/usbnet.h 2007-07-31 11:08:12.000000000 +0200 @@ -28,6 +28,7 @@ struct usbnet { /* housekeeping */ struct usb_device *udev; + struct usb_interface *intf; struct driver_info *driver_info; const char *driver_name; wait_queue_head_t *wait; --- a/drivers/net/usb/usbnet.c 2007-07-30 14:27:40.000000000 +0200 +++ b/drivers/net/usb/usbnet.c 2007-07-31 11:07:51.000000000 +0200 @@ -590,6 +590,7 @@ static int usbnet_stop (struct net_devic dev->flags = 0; del_timer_sync (&dev->delay); tasklet_kill (&dev->bh); + usb_autopm_put_interface(dev->intf); return 0; } @@ -603,9 +604,19 @@ static int usbnet_stop (struct net_devic static int usbnet_open (struct net_device *net) { struct usbnet *dev = netdev_priv(net); - int retval = 0; + int retval; struct driver_info *info = dev->driver_info; + if ((retval = usb_autopm_get_interface(dev->intf)) < 0) { + if (netif_msg_ifup (dev)) + devinfo (dev, + "resumption fail (%d) usbnet usb-%s-%s, %s", + retval, + dev->udev->bus->bus_name, dev->udev->devpath, + info->description); + goto done_nopm; + } + // put into "known safe" state if (info->reset && (retval = info->reset (dev)) < 0) { if (netif_msg_ifup (dev)) @@ -659,7 +670,10 @@ static int usbnet_open (struct net_devic // delay posting reads until we're fully open tasklet_schedule (&dev->bh); + return retval; done: + usb_autopm_put_interface(dev->intf); +done_nopm: return retval; } @@ -1143,6 +1157,7 @@ usbnet_probe (struct usb_interface *udev dev = netdev_priv(net); dev->udev = xdev; + dev->intf = udev; dev->driver_info = info; dev->driver_name = name; dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV @@ -1273,6 +1288,9 @@ int usbnet_suspend (struct usb_interface netif_device_detach (dev->net); (void) unlink_urbs (dev, &dev->rxq); (void) unlink_urbs (dev, &dev->txq); + /* reattach so runtime management can use and + * wake the device */ + netif_device_attach (dev->net); } return 0; } @@ -1282,10 +1300,9 @@ int usbnet_resume (struct usb_interface { struct usbnet *dev = usb_get_intfdata(intf); - if (!--dev->suspend_count) { - netif_device_attach (dev->net); + if (!--dev->suspend_count) tasklet_schedule (&dev->bh); - } + return 0; } EXPORT_SYMBOL_GPL(usbnet_resume); --- a/drivers/net/usb/asix.c 2007-07-30 14:18:38.000000000 +0200 +++ b/drivers/net/usb/asix.c 2007-07-30 16:04:45.000000000 +0200 @@ -844,6 +844,7 @@ static int ax88172_bind(struct usbnet *d dev->mii.phy_id_mask = 0x3f; dev->mii.reg_num_mask = 0x1f; dev->mii.phy_id = asix_get_phy_addr(dev); + dev->intf = intf; dev->net->do_ioctl = asix_ioctl; dev->net->set_multicast_list = ax88172_set_multicast; @@ -969,6 +970,7 @@ static int ax88772_bind(struct usbnet *d dev->mii.mdio_write = asix_mdio_write; dev->mii.phy_id_mask = 0x1f; dev->mii.reg_num_mask = 0x1f; + dev->intf = intf; dev->net->do_ioctl = asix_ioctl; dev->mii.phy_id = asix_get_phy_addr(dev); @@ -1267,6 +1269,7 @@ static int ax88178_bind(struct usbnet *d dev->mii.supports_gmii = 1; dev->net->do_ioctl = asix_ioctl; dev->mii.phy_id = asix_get_phy_addr(dev); + dev->intf = intf; dev->net->set_multicast_list = asix_set_multicast; dev->net->ethtool_ops = &ax88178_ethtool_ops; dev->net->change_mtu = &ax88178_change_mtu; @@ -1474,6 +1477,7 @@ static struct usb_driver asix_driver = { .suspend = usbnet_suspend, .resume = usbnet_resume, .disconnect = usbnet_disconnect, + .supports_autosuspend = 1, }; static int __init asix_init(void) ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel