diff options
author | Christian Lamparter <chunkeey@web.de> | 2008-12-26 13:08:31 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 15:59:39 -0500 |
commit | 6982869d993009c02cefcca98a67b212d0e61c5f (patch) | |
tree | bda0dbb4dfe78aa7ddfaa1f221b9c0ef1b4ac789 | |
parent | 6b1c7c67603efdf0b39f6056989b0f8194cdc1f3 (diff) |
p54usb: utilize usb_reset_device for 3887
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>
-rw-r--r-- | drivers/net/wireless/p54/p54usb.c | 70 | ||||
-rw-r--r-- | drivers/net/wireless/p54/p54usb.h | 1 |
2 files changed, 58 insertions, 13 deletions
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 5de2ebfb28c7..3c31c15267b5 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c | |||
@@ -424,9 +424,44 @@ static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep, | |||
424 | data, len, &alen, 2000); | 424 | data, len, &alen, 2000); |
425 | } | 425 | } |
426 | 426 | ||
427 | static const char p54u_romboot_3887[] = "~~~~"; | ||
428 | static const char p54u_firmware_upload_3887[] = "<\r"; | ||
429 | |||
430 | static int p54u_device_reset_3887(struct ieee80211_hw *dev) | ||
431 | { | ||
432 | struct p54u_priv *priv = dev->priv; | ||
433 | int ret, lock; | ||
434 | u8 buf[4]; | ||
435 | |||
436 | ret = lock = usb_lock_device_for_reset(priv->udev, priv->intf); | ||
437 | if (ret < 0) { | ||
438 | dev_err(&priv->udev->dev, "(p54usb) unable to lock device for " | ||
439 | "reset: %d\n", ret); | ||
440 | return ret; | ||
441 | } | ||
442 | |||
443 | ret = usb_reset_device(priv->udev); | ||
444 | if (lock) | ||
445 | usb_unlock_device(priv->udev); | ||
446 | |||
447 | if (ret) { | ||
448 | dev_err(&priv->udev->dev, "(p54usb) unable to reset " | ||
449 | "device: %d\n", ret); | ||
450 | return ret; | ||
451 | } | ||
452 | |||
453 | memcpy(&buf, p54u_romboot_3887, sizeof(buf)); | ||
454 | ret = p54u_bulk_msg(priv, P54U_PIPE_DATA, | ||
455 | buf, sizeof(buf)); | ||
456 | if (ret) | ||
457 | dev_err(&priv->udev->dev, "(p54usb) unable to jump to " | ||
458 | "boot ROM: %d\n", ret); | ||
459 | |||
460 | return ret; | ||
461 | } | ||
462 | |||
427 | static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) | 463 | static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) |
428 | { | 464 | { |
429 | static char start_string[] = "~~~~<\r"; | ||
430 | struct p54u_priv *priv = dev->priv; | 465 | struct p54u_priv *priv = dev->priv; |
431 | const struct firmware *fw_entry = NULL; | 466 | const struct firmware *fw_entry = NULL; |
432 | int err, alen; | 467 | int err, alen; |
@@ -445,12 +480,9 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) | |||
445 | goto err_bufalloc; | 480 | goto err_bufalloc; |
446 | } | 481 | } |
447 | 482 | ||
448 | memcpy(buf, start_string, 4); | 483 | err = p54u_device_reset_3887(dev); |
449 | err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4); | 484 | if (err) |
450 | if (err) { | ||
451 | dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err); | ||
452 | goto err_reset; | 485 | goto err_reset; |
453 | } | ||
454 | 486 | ||
455 | err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev); | 487 | err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev); |
456 | if (err) { | 488 | if (err) { |
@@ -467,14 +499,14 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) | |||
467 | goto err_upload_failed; | 499 | goto err_upload_failed; |
468 | 500 | ||
469 | left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size); | 501 | left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size); |
470 | strcpy(buf, start_string); | 502 | strcpy(buf, p54u_firmware_upload_3887); |
471 | left -= strlen(start_string); | 503 | left -= strlen(p54u_firmware_upload_3887); |
472 | tmp += strlen(start_string); | 504 | tmp += strlen(p54u_firmware_upload_3887); |
473 | 505 | ||
474 | data = fw_entry->data; | 506 | data = fw_entry->data; |
475 | remains = fw_entry->size; | 507 | remains = fw_entry->size; |
476 | 508 | ||
477 | hdr = (struct x2_header *)(buf + strlen(start_string)); | 509 | hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887)); |
478 | memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE); | 510 | memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE); |
479 | hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR); | 511 | hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR); |
480 | hdr->fw_length = cpu_to_le32(fw_entry->size); | 512 | hdr->fw_length = cpu_to_le32(fw_entry->size); |
@@ -876,6 +908,9 @@ static int __devinit p54u_probe(struct usb_interface *intf, | |||
876 | SET_IEEE80211_DEV(dev, &intf->dev); | 908 | SET_IEEE80211_DEV(dev, &intf->dev); |
877 | usb_set_intfdata(intf, dev); | 909 | usb_set_intfdata(intf, dev); |
878 | priv->udev = udev; | 910 | priv->udev = udev; |
911 | priv->intf = intf; | ||
912 | skb_queue_head_init(&priv->rx_queue); | ||
913 | init_usb_anchor(&priv->submitted); | ||
879 | 914 | ||
880 | usb_get_dev(udev); | 915 | usb_get_dev(udev); |
881 | 916 | ||
@@ -918,9 +953,6 @@ static int __devinit p54u_probe(struct usb_interface *intf, | |||
918 | if (err) | 953 | if (err) |
919 | goto err_free_dev; | 954 | goto err_free_dev; |
920 | 955 | ||
921 | skb_queue_head_init(&priv->rx_queue); | ||
922 | init_usb_anchor(&priv->submitted); | ||
923 | |||
924 | p54u_open(dev); | 956 | p54u_open(dev); |
925 | err = p54_read_eeprom(dev); | 957 | err = p54_read_eeprom(dev); |
926 | p54u_stop(dev); | 958 | p54u_stop(dev); |
@@ -958,11 +990,23 @@ static void __devexit p54u_disconnect(struct usb_interface *intf) | |||
958 | ieee80211_free_hw(dev); | 990 | ieee80211_free_hw(dev); |
959 | } | 991 | } |
960 | 992 | ||
993 | static int p54u_pre_reset(struct usb_interface *intf) | ||
994 | { | ||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | static int p54u_post_reset(struct usb_interface *intf) | ||
999 | { | ||
1000 | return 0; | ||
1001 | } | ||
1002 | |||
961 | static struct usb_driver p54u_driver = { | 1003 | static struct usb_driver p54u_driver = { |
962 | .name = "p54usb", | 1004 | .name = "p54usb", |
963 | .id_table = p54u_table, | 1005 | .id_table = p54u_table, |
964 | .probe = p54u_probe, | 1006 | .probe = p54u_probe, |
965 | .disconnect = p54u_disconnect, | 1007 | .disconnect = p54u_disconnect, |
1008 | .pre_reset = p54u_pre_reset, | ||
1009 | .post_reset = p54u_post_reset, | ||
966 | }; | 1010 | }; |
967 | 1011 | ||
968 | static int __init p54u_init(void) | 1012 | static int __init p54u_init(void) |
diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h index 54ee738bf2af..8bc58982d8dd 100644 --- a/drivers/net/wireless/p54/p54usb.h +++ b/drivers/net/wireless/p54/p54usb.h | |||
@@ -126,6 +126,7 @@ struct p54u_rx_info { | |||
126 | struct p54u_priv { | 126 | struct p54u_priv { |
127 | struct p54_common common; | 127 | struct p54_common common; |
128 | struct usb_device *udev; | 128 | struct usb_device *udev; |
129 | struct usb_interface *intf; | ||
129 | enum { | 130 | enum { |
130 | P54U_NET2280 = 0, | 131 | P54U_NET2280 = 0, |
131 | P54U_3887 | 132 | P54U_3887 |