p54usb: utilize usb_reset_device for 3887
authorChristian Lamparter <chunkeey@web.de>
Fri, 26 Dec 2008 18:08:31 +0000 (19:08 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 29 Jan 2009 20:59:39 +0000 (15:59 -0500)
Sometimes on unload or reboot the 3887 USB devices become stuck.
<usual log entry>
kernel: usbcore: registered new interface driver p54usb
kernel: usb 2-10: (p54usb) reset failed! (-110)
kernel: p54usb: probe of 2-10:1.0 failed with error -110
[...]

and a physical unplug and replug was necessary.
However we should be able to do this in software as well,
without any user interaction.

Signed-off-by: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/p54/p54usb.h

index 5de2ebf..3c31c15 100644 (file)
@@ -424,9 +424,44 @@ static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
                            data, len, &alen, 2000);
 }
 
+static const char p54u_romboot_3887[] = "~~~~";
+static const char p54u_firmware_upload_3887[] = "<\r";
+
+static int p54u_device_reset_3887(struct ieee80211_hw *dev)
+{
+       struct p54u_priv *priv = dev->priv;
+       int ret, lock;
+       u8 buf[4];
+
+       ret = lock = usb_lock_device_for_reset(priv->udev, priv->intf);
+       if (ret < 0) {
+               dev_err(&priv->udev->dev, "(p54usb) unable to lock device for "
+                       "reset: %d\n", ret);
+               return ret;
+       }
+
+       ret = usb_reset_device(priv->udev);
+       if (lock)
+               usb_unlock_device(priv->udev);
+
+       if (ret) {
+               dev_err(&priv->udev->dev, "(p54usb) unable to reset "
+                       "device: %d\n", ret);
+               return ret;
+       }
+
+       memcpy(&buf, p54u_romboot_3887, sizeof(buf));
+       ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
+                           buf, sizeof(buf));
+       if (ret)
+               dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
+                       "boot ROM: %d\n", ret);
+
+       return ret;
+}
+
 static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
 {
-       static char start_string[] = "~~~~<\r";
        struct p54u_priv *priv = dev->priv;
        const struct firmware *fw_entry = NULL;
        int err, alen;
@@ -445,12 +480,9 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
                goto err_bufalloc;
        }
 
-       memcpy(buf, start_string, 4);
-       err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
-       if (err) {
-               dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err);
+       err = p54u_device_reset_3887(dev);
+       if (err)
                goto err_reset;
-       }
 
        err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
        if (err) {
@@ -467,14 +499,14 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
                goto err_upload_failed;
 
        left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
-       strcpy(buf, start_string);
-       left -= strlen(start_string);
-       tmp += strlen(start_string);
+       strcpy(buf, p54u_firmware_upload_3887);
+       left -= strlen(p54u_firmware_upload_3887);
+       tmp += strlen(p54u_firmware_upload_3887);
 
        data = fw_entry->data;
        remains = fw_entry->size;
 
-       hdr = (struct x2_header *)(buf + strlen(start_string));
+       hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
        memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
        hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
        hdr->fw_length = cpu_to_le32(fw_entry->size);
@@ -876,6 +908,9 @@ static int __devinit p54u_probe(struct usb_interface *intf,
        SET_IEEE80211_DEV(dev, &intf->dev);
        usb_set_intfdata(intf, dev);
        priv->udev = udev;
+       priv->intf = intf;
+       skb_queue_head_init(&priv->rx_queue);
+       init_usb_anchor(&priv->submitted);
 
        usb_get_dev(udev);
 
@@ -918,9 +953,6 @@ static int __devinit p54u_probe(struct usb_interface *intf,
        if (err)
                goto err_free_dev;
 
-       skb_queue_head_init(&priv->rx_queue);
-       init_usb_anchor(&priv->submitted);
-
        p54u_open(dev);
        err = p54_read_eeprom(dev);
        p54u_stop(dev);
@@ -958,11 +990,23 @@ static void __devexit p54u_disconnect(struct usb_interface *intf)
        ieee80211_free_hw(dev);
 }
 
+static int p54u_pre_reset(struct usb_interface *intf)
+{
+       return 0;
+}
+
+static int p54u_post_reset(struct usb_interface *intf)
+{
+       return 0;
+}
+
 static struct usb_driver p54u_driver = {
        .name   = "p54usb",
        .id_table = p54u_table,
        .probe = p54u_probe,
        .disconnect = p54u_disconnect,
+       .pre_reset = p54u_pre_reset,
+       .post_reset = p54u_post_reset,
 };
 
 static int __init p54u_init(void)
index 54ee738..8bc5898 100644 (file)
@@ -126,6 +126,7 @@ struct p54u_rx_info {
 struct p54u_priv {
        struct p54_common common;
        struct usb_device *udev;
+       struct usb_interface *intf;
        enum {
                P54U_NET2280 = 0,
                P54U_3887