diff options
author | Christian Lamparter <chunkeey@web.de> | 2009-04-25 15:12:09 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-05-06 15:14:41 -0400 |
commit | 1ca5f2e94c40b04d5dec437cd41fd5ba12aaac31 (patch) | |
tree | 7aff5fa8798e8d4e4cb90ba2e516ad01e4575167 /drivers/net/wireless/p54/p54usb.c | |
parent | a406ac0dc15b22807b65f5a6590b9cb34d99d4ab (diff) |
p54usb: rework driver for resume
This patch redo the driver code so that p54usb no longer hangs
the kernel on resume.
Signed-off-by: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/p54/p54usb.c')
-rw-r--r-- | drivers/net/wireless/p54/p54usb.c | 256 |
1 files changed, 165 insertions, 91 deletions
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 44ab3ccac910..ec6c95474f1a 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c | |||
@@ -81,6 +81,29 @@ static struct usb_device_id p54u_table[] __devinitdata = { | |||
81 | 81 | ||
82 | MODULE_DEVICE_TABLE(usb, p54u_table); | 82 | MODULE_DEVICE_TABLE(usb, p54u_table); |
83 | 83 | ||
84 | static const struct { | ||
85 | u32 intf; | ||
86 | enum p54u_hw_type type; | ||
87 | char fw[FIRMWARE_NAME_MAX]; | ||
88 | char fw_legacy[FIRMWARE_NAME_MAX]; | ||
89 | char hw[20]; | ||
90 | } p54u_fwlist[__NUM_P54U_HWTYPES] = { | ||
91 | { | ||
92 | .type = P54U_NET2280, | ||
93 | .intf = FW_LM86, | ||
94 | .fw = "isl3886usb", | ||
95 | .fw_legacy = "isl3890usb", | ||
96 | .hw = "ISL3886 + net2280", | ||
97 | }, | ||
98 | { | ||
99 | .type = P54U_3887, | ||
100 | .intf = FW_LM87, | ||
101 | .fw = "isl3887usb", | ||
102 | .fw_legacy = "isl3887usb_bare", | ||
103 | .hw = "ISL3887", | ||
104 | }, | ||
105 | }; | ||
106 | |||
84 | static void p54u_rx_cb(struct urb *urb) | 107 | static void p54u_rx_cb(struct urb *urb) |
85 | { | 108 | { |
86 | struct sk_buff *skb = (struct sk_buff *) urb->context; | 109 | struct sk_buff *skb = (struct sk_buff *) urb->context; |
@@ -125,11 +148,7 @@ static void p54u_rx_cb(struct urb *urb) | |||
125 | } | 148 | } |
126 | skb_reset_tail_pointer(skb); | 149 | skb_reset_tail_pointer(skb); |
127 | skb_trim(skb, 0); | 150 | skb_trim(skb, 0); |
128 | if (urb->transfer_buffer != skb_tail_pointer(skb)) { | 151 | urb->transfer_buffer = skb_tail_pointer(skb); |
129 | /* this should not happen */ | ||
130 | WARN_ON(1); | ||
131 | urb->transfer_buffer = skb_tail_pointer(skb); | ||
132 | } | ||
133 | } | 152 | } |
134 | skb_queue_tail(&priv->rx_queue, skb); | 153 | skb_queue_tail(&priv->rx_queue, skb); |
135 | usb_anchor_urb(urb, &priv->submitted); | 154 | usb_anchor_urb(urb, &priv->submitted); |
@@ -378,20 +397,16 @@ static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep, | |||
378 | data, len, &alen, 2000); | 397 | data, len, &alen, 2000); |
379 | } | 398 | } |
380 | 399 | ||
381 | static const char p54u_romboot_3887[] = "~~~~"; | 400 | static int p54u_device_reset(struct ieee80211_hw *dev) |
382 | static const char p54u_firmware_upload_3887[] = "<\r"; | ||
383 | |||
384 | static int p54u_device_reset_3887(struct ieee80211_hw *dev) | ||
385 | { | 401 | { |
386 | struct p54u_priv *priv = dev->priv; | 402 | struct p54u_priv *priv = dev->priv; |
387 | int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING); | 403 | int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING); |
388 | u8 buf[4]; | ||
389 | 404 | ||
390 | if (lock) { | 405 | if (lock) { |
391 | ret = usb_lock_device_for_reset(priv->udev, priv->intf); | 406 | ret = usb_lock_device_for_reset(priv->udev, priv->intf); |
392 | if (ret < 0) { | 407 | if (ret < 0) { |
393 | dev_err(&priv->udev->dev, "(p54usb) unable to lock " | 408 | dev_err(&priv->udev->dev, "(p54usb) unable to lock " |
394 | " device for reset: %d\n", ret); | 409 | "device for reset (%d)!\n", ret); |
395 | return ret; | 410 | return ret; |
396 | } | 411 | } |
397 | } | 412 | } |
@@ -400,26 +415,34 @@ static int p54u_device_reset_3887(struct ieee80211_hw *dev) | |||
400 | if (lock) | 415 | if (lock) |
401 | usb_unlock_device(priv->udev); | 416 | usb_unlock_device(priv->udev); |
402 | 417 | ||
403 | if (ret) { | 418 | if (ret) |
404 | dev_err(&priv->udev->dev, "(p54usb) unable to reset " | 419 | dev_err(&priv->udev->dev, "(p54usb) unable to reset " |
405 | "device: %d\n", ret); | 420 | "device (%d)!\n", ret); |
406 | return ret; | 421 | |
407 | } | 422 | return ret; |
423 | } | ||
424 | |||
425 | static const char p54u_romboot_3887[] = "~~~~"; | ||
426 | static int p54u_firmware_reset_3887(struct ieee80211_hw *dev) | ||
427 | { | ||
428 | struct p54u_priv *priv = dev->priv; | ||
429 | u8 buf[4]; | ||
430 | int ret; | ||
408 | 431 | ||
409 | memcpy(&buf, p54u_romboot_3887, sizeof(buf)); | 432 | memcpy(&buf, p54u_romboot_3887, sizeof(buf)); |
410 | ret = p54u_bulk_msg(priv, P54U_PIPE_DATA, | 433 | ret = p54u_bulk_msg(priv, P54U_PIPE_DATA, |
411 | buf, sizeof(buf)); | 434 | buf, sizeof(buf)); |
412 | if (ret) | 435 | if (ret) |
413 | dev_err(&priv->udev->dev, "(p54usb) unable to jump to " | 436 | dev_err(&priv->udev->dev, "(p54usb) unable to jump to " |
414 | "boot ROM: %d\n", ret); | 437 | "boot ROM (%d)!\n", ret); |
415 | 438 | ||
416 | return ret; | 439 | return ret; |
417 | } | 440 | } |
418 | 441 | ||
442 | static const char p54u_firmware_upload_3887[] = "<\r"; | ||
419 | static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) | 443 | static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) |
420 | { | 444 | { |
421 | struct p54u_priv *priv = dev->priv; | 445 | struct p54u_priv *priv = dev->priv; |
422 | const struct firmware *fw_entry = NULL; | ||
423 | int err, alen; | 446 | int err, alen; |
424 | u8 carry = 0; | 447 | u8 carry = 0; |
425 | u8 *buf, *tmp; | 448 | u8 *buf, *tmp; |
@@ -428,51 +451,29 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) | |||
428 | struct x2_header *hdr; | 451 | struct x2_header *hdr; |
429 | unsigned long timeout; | 452 | unsigned long timeout; |
430 | 453 | ||
454 | err = p54u_firmware_reset_3887(dev); | ||
455 | if (err) | ||
456 | return err; | ||
457 | |||
431 | tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL); | 458 | tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL); |
432 | if (!buf) { | 459 | if (!buf) { |
433 | dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware" | 460 | dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware" |
434 | "upload buffer!\n"); | 461 | "upload buffer!\n"); |
435 | err = -ENOMEM; | 462 | return -ENOMEM; |
436 | goto err_bufalloc; | ||
437 | } | ||
438 | |||
439 | err = p54u_device_reset_3887(dev); | ||
440 | if (err) | ||
441 | goto err_reset; | ||
442 | |||
443 | err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev); | ||
444 | if (err) { | ||
445 | dev_err(&priv->udev->dev, "p54usb: cannot find firmware " | ||
446 | "(isl3887usb)\n"); | ||
447 | err = request_firmware(&fw_entry, "isl3887usb_bare", | ||
448 | &priv->udev->dev); | ||
449 | if (err) | ||
450 | goto err_req_fw_failed; | ||
451 | } | ||
452 | |||
453 | err = p54_parse_firmware(dev, fw_entry); | ||
454 | if (err) | ||
455 | goto err_upload_failed; | ||
456 | |||
457 | if (priv->common.fw_interface != FW_LM87) { | ||
458 | dev_err(&priv->udev->dev, "wrong firmware, " | ||
459 | "please get a LM87 firmware and try again.\n"); | ||
460 | err = -EINVAL; | ||
461 | goto err_upload_failed; | ||
462 | } | 463 | } |
463 | 464 | ||
464 | left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size); | 465 | left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size); |
465 | strcpy(buf, p54u_firmware_upload_3887); | 466 | strcpy(buf, p54u_firmware_upload_3887); |
466 | left -= strlen(p54u_firmware_upload_3887); | 467 | left -= strlen(p54u_firmware_upload_3887); |
467 | tmp += strlen(p54u_firmware_upload_3887); | 468 | tmp += strlen(p54u_firmware_upload_3887); |
468 | 469 | ||
469 | data = fw_entry->data; | 470 | data = priv->fw->data; |
470 | remains = fw_entry->size; | 471 | remains = priv->fw->size; |
471 | 472 | ||
472 | hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887)); | 473 | hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887)); |
473 | memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE); | 474 | memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE); |
474 | hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR); | 475 | hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR); |
475 | hdr->fw_length = cpu_to_le32(fw_entry->size); | 476 | hdr->fw_length = cpu_to_le32(priv->fw->size); |
476 | hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr, | 477 | hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr, |
477 | sizeof(u32)*2)); | 478 | sizeof(u32)*2)); |
478 | left -= sizeof(*hdr); | 479 | left -= sizeof(*hdr); |
@@ -514,7 +515,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) | |||
514 | left = block_size = min((unsigned int)P54U_FW_BLOCK, remains); | 515 | left = block_size = min((unsigned int)P54U_FW_BLOCK, remains); |
515 | } | 516 | } |
516 | 517 | ||
517 | *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size)); | 518 | *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data, |
519 | priv->fw->size)); | ||
518 | err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); | 520 | err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); |
519 | if (err) { | 521 | if (err) { |
520 | dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n"); | 522 | dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n"); |
@@ -565,19 +567,14 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) | |||
565 | if (err) | 567 | if (err) |
566 | goto err_upload_failed; | 568 | goto err_upload_failed; |
567 | 569 | ||
568 | err_upload_failed: | 570 | err_upload_failed: |
569 | release_firmware(fw_entry); | ||
570 | err_req_fw_failed: | ||
571 | err_reset: | ||
572 | kfree(buf); | 571 | kfree(buf); |
573 | err_bufalloc: | ||
574 | return err; | 572 | return err; |
575 | } | 573 | } |
576 | 574 | ||
577 | static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) | 575 | static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) |
578 | { | 576 | { |
579 | struct p54u_priv *priv = dev->priv; | 577 | struct p54u_priv *priv = dev->priv; |
580 | const struct firmware *fw_entry = NULL; | ||
581 | const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE; | 578 | const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE; |
582 | int err, alen; | 579 | int err, alen; |
583 | void *buf; | 580 | void *buf; |
@@ -592,33 +589,6 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) | |||
592 | return -ENOMEM; | 589 | return -ENOMEM; |
593 | } | 590 | } |
594 | 591 | ||
595 | err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev); | ||
596 | if (err) { | ||
597 | dev_err(&priv->udev->dev, "(p54usb) cannot find firmware " | ||
598 | "(isl3886usb)\n"); | ||
599 | err = request_firmware(&fw_entry, "isl3890usb", | ||
600 | &priv->udev->dev); | ||
601 | if (err) { | ||
602 | kfree(buf); | ||
603 | return err; | ||
604 | } | ||
605 | } | ||
606 | |||
607 | err = p54_parse_firmware(dev, fw_entry); | ||
608 | if (err) { | ||
609 | kfree(buf); | ||
610 | release_firmware(fw_entry); | ||
611 | return err; | ||
612 | } | ||
613 | |||
614 | if (priv->common.fw_interface != FW_LM86) { | ||
615 | dev_err(&priv->udev->dev, "wrong firmware, " | ||
616 | "please get a LM86(USB) firmware and try again.\n"); | ||
617 | kfree(buf); | ||
618 | release_firmware(fw_entry); | ||
619 | return -EINVAL; | ||
620 | } | ||
621 | |||
622 | #define P54U_WRITE(type, addr, data) \ | 592 | #define P54U_WRITE(type, addr, data) \ |
623 | do {\ | 593 | do {\ |
624 | err = p54u_write(priv, buf, type,\ | 594 | err = p54u_write(priv, buf, type,\ |
@@ -718,8 +688,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) | |||
718 | P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); | 688 | P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); |
719 | 689 | ||
720 | /* finally, we can upload firmware now! */ | 690 | /* finally, we can upload firmware now! */ |
721 | remains = fw_entry->size; | 691 | remains = priv->fw->size; |
722 | data = fw_entry->data; | 692 | data = priv->fw->data; |
723 | offset = ISL38XX_DEV_FIRMWARE_ADDR; | 693 | offset = ISL38XX_DEV_FIRMWARE_ADDR; |
724 | 694 | ||
725 | while (remains) { | 695 | while (remains) { |
@@ -828,12 +798,54 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) | |||
828 | #undef P54U_WRITE | 798 | #undef P54U_WRITE |
829 | #undef P54U_READ | 799 | #undef P54U_READ |
830 | 800 | ||
831 | fail: | 801 | fail: |
832 | release_firmware(fw_entry); | ||
833 | kfree(buf); | 802 | kfree(buf); |
834 | return err; | 803 | return err; |
835 | } | 804 | } |
836 | 805 | ||
806 | static int p54u_load_firmware(struct ieee80211_hw *dev) | ||
807 | { | ||
808 | struct p54u_priv *priv = dev->priv; | ||
809 | int err, i; | ||
810 | |||
811 | BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES); | ||
812 | |||
813 | for (i = 0; i < __NUM_P54U_HWTYPES; i++) | ||
814 | if (p54u_fwlist[i].type == priv->hw_type) | ||
815 | break; | ||
816 | |||
817 | if (i == __NUM_P54U_HWTYPES) | ||
818 | return -EOPNOTSUPP; | ||
819 | |||
820 | err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev); | ||
821 | if (err) { | ||
822 | dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s " | ||
823 | "(%d)!\n", p54u_fwlist[i].fw, err); | ||
824 | |||
825 | err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy, | ||
826 | &priv->udev->dev); | ||
827 | if (err) | ||
828 | return err; | ||
829 | } | ||
830 | |||
831 | err = p54_parse_firmware(dev, priv->fw); | ||
832 | if (err) | ||
833 | goto out; | ||
834 | |||
835 | if (priv->common.fw_interface != p54u_fwlist[i].intf) { | ||
836 | dev_err(&priv->udev->dev, "wrong firmware, please get " | ||
837 | "a firmware for \"%s\" and try again.\n", | ||
838 | p54u_fwlist[i].hw); | ||
839 | err = -EINVAL; | ||
840 | } | ||
841 | |||
842 | out: | ||
843 | if (err) | ||
844 | release_firmware(priv->fw); | ||
845 | |||
846 | return err; | ||
847 | } | ||
848 | |||
837 | static int p54u_open(struct ieee80211_hw *dev) | 849 | static int p54u_open(struct ieee80211_hw *dev) |
838 | { | 850 | { |
839 | struct p54u_priv *priv = dev->priv; | 851 | struct p54u_priv *priv = dev->priv; |
@@ -875,6 +887,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, | |||
875 | } | 887 | } |
876 | 888 | ||
877 | priv = dev->priv; | 889 | priv = dev->priv; |
890 | priv->hw_type = P54U_INVALID_HW; | ||
878 | 891 | ||
879 | SET_IEEE80211_DEV(dev, &intf->dev); | 892 | SET_IEEE80211_DEV(dev, &intf->dev); |
880 | usb_set_intfdata(intf, dev); | 893 | usb_set_intfdata(intf, dev); |
@@ -906,34 +919,46 @@ static int __devinit p54u_probe(struct usb_interface *intf, | |||
906 | priv->common.open = p54u_open; | 919 | priv->common.open = p54u_open; |
907 | priv->common.stop = p54u_stop; | 920 | priv->common.stop = p54u_stop; |
908 | if (recognized_pipes < P54U_PIPE_NUMBER) { | 921 | if (recognized_pipes < P54U_PIPE_NUMBER) { |
922 | /* ISL3887 needs a full reset on resume */ | ||
923 | udev->reset_resume = 1; | ||
924 | err = p54u_device_reset(dev); | ||
925 | |||
909 | priv->hw_type = P54U_3887; | 926 | priv->hw_type = P54U_3887; |
910 | dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr); | 927 | dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr); |
911 | priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr); | 928 | priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr); |
912 | priv->common.tx = p54u_tx_lm87; | 929 | priv->common.tx = p54u_tx_lm87; |
913 | err = p54u_upload_firmware_3887(dev); | 930 | priv->upload_fw = p54u_upload_firmware_3887; |
914 | } else { | 931 | } else { |
915 | priv->hw_type = P54U_NET2280; | 932 | priv->hw_type = P54U_NET2280; |
916 | dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr); | 933 | dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr); |
917 | priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr); | 934 | priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr); |
918 | priv->common.tx = p54u_tx_net2280; | 935 | priv->common.tx = p54u_tx_net2280; |
919 | err = p54u_upload_firmware_net2280(dev); | 936 | priv->upload_fw = p54u_upload_firmware_net2280; |
920 | } | 937 | } |
938 | err = p54u_load_firmware(dev); | ||
921 | if (err) | 939 | if (err) |
922 | goto err_free_dev; | 940 | goto err_free_dev; |
923 | 941 | ||
942 | err = priv->upload_fw(dev); | ||
943 | if (err) | ||
944 | goto err_free_fw; | ||
945 | |||
924 | p54u_open(dev); | 946 | p54u_open(dev); |
925 | err = p54_read_eeprom(dev); | 947 | err = p54_read_eeprom(dev); |
926 | p54u_stop(dev); | 948 | p54u_stop(dev); |
927 | if (err) | 949 | if (err) |
928 | goto err_free_dev; | 950 | goto err_free_fw; |
929 | 951 | ||
930 | err = p54_register_common(dev, &udev->dev); | 952 | err = p54_register_common(dev, &udev->dev); |
931 | if (err) | 953 | if (err) |
932 | goto err_free_dev; | 954 | goto err_free_fw; |
933 | 955 | ||
934 | return 0; | 956 | return 0; |
935 | 957 | ||
936 | err_free_dev: | 958 | err_free_fw: |
959 | release_firmware(priv->fw); | ||
960 | |||
961 | err_free_dev: | ||
937 | ieee80211_free_hw(dev); | 962 | ieee80211_free_hw(dev); |
938 | usb_set_intfdata(intf, NULL); | 963 | usb_set_intfdata(intf, NULL); |
939 | usb_put_dev(udev); | 964 | usb_put_dev(udev); |
@@ -952,20 +977,64 @@ static void __devexit p54u_disconnect(struct usb_interface *intf) | |||
952 | 977 | ||
953 | priv = dev->priv; | 978 | priv = dev->priv; |
954 | usb_put_dev(interface_to_usbdev(intf)); | 979 | usb_put_dev(interface_to_usbdev(intf)); |
980 | release_firmware(priv->fw); | ||
955 | p54_free_common(dev); | 981 | p54_free_common(dev); |
956 | ieee80211_free_hw(dev); | 982 | ieee80211_free_hw(dev); |
957 | } | 983 | } |
958 | 984 | ||
959 | static int p54u_pre_reset(struct usb_interface *intf) | 985 | static int p54u_pre_reset(struct usb_interface *intf) |
960 | { | 986 | { |
987 | struct ieee80211_hw *dev = usb_get_intfdata(intf); | ||
988 | |||
989 | if (!dev) | ||
990 | return -ENODEV; | ||
991 | |||
992 | p54u_stop(dev); | ||
961 | return 0; | 993 | return 0; |
962 | } | 994 | } |
963 | 995 | ||
996 | static int p54u_resume(struct usb_interface *intf) | ||
997 | { | ||
998 | struct ieee80211_hw *dev = usb_get_intfdata(intf); | ||
999 | struct p54u_priv *priv; | ||
1000 | |||
1001 | if (!dev) | ||
1002 | return -ENODEV; | ||
1003 | |||
1004 | priv = dev->priv; | ||
1005 | if (unlikely(!(priv->upload_fw && priv->fw))) | ||
1006 | return 0; | ||
1007 | |||
1008 | return priv->upload_fw(dev); | ||
1009 | } | ||
1010 | |||
964 | static int p54u_post_reset(struct usb_interface *intf) | 1011 | static int p54u_post_reset(struct usb_interface *intf) |
965 | { | 1012 | { |
1013 | struct ieee80211_hw *dev = usb_get_intfdata(intf); | ||
1014 | struct p54u_priv *priv; | ||
1015 | int err; | ||
1016 | |||
1017 | err = p54u_resume(intf); | ||
1018 | if (err) | ||
1019 | return err; | ||
1020 | |||
1021 | /* reinitialize old device state */ | ||
1022 | priv = dev->priv; | ||
1023 | if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) | ||
1024 | ieee80211_restart_hw(dev); | ||
1025 | |||
966 | return 0; | 1026 | return 0; |
967 | } | 1027 | } |
968 | 1028 | ||
1029 | #ifdef CONFIG_PM | ||
1030 | |||
1031 | static int p54u_suspend(struct usb_interface *intf, pm_message_t message) | ||
1032 | { | ||
1033 | return p54u_pre_reset(intf); | ||
1034 | } | ||
1035 | |||
1036 | #endif /* CONFIG_PM */ | ||
1037 | |||
969 | static struct usb_driver p54u_driver = { | 1038 | static struct usb_driver p54u_driver = { |
970 | .name = "p54usb", | 1039 | .name = "p54usb", |
971 | .id_table = p54u_table, | 1040 | .id_table = p54u_table, |
@@ -973,6 +1042,11 @@ static struct usb_driver p54u_driver = { | |||
973 | .disconnect = p54u_disconnect, | 1042 | .disconnect = p54u_disconnect, |
974 | .pre_reset = p54u_pre_reset, | 1043 | .pre_reset = p54u_pre_reset, |
975 | .post_reset = p54u_post_reset, | 1044 | .post_reset = p54u_post_reset, |
1045 | #ifdef CONFIG_PM | ||
1046 | .suspend = p54u_suspend, | ||
1047 | .resume = p54u_resume, | ||
1048 | .reset_resume = p54u_resume, | ||
1049 | #endif /* CONFIG_PM */ | ||
976 | .soft_unbind = 1, | 1050 | .soft_unbind = 1, |
977 | }; | 1051 | }; |
978 | 1052 | ||