diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 49 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.h | 2 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hub.c | 4 |
3 files changed, 29 insertions, 26 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index dc9ed29c6175..025b969f95e8 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -110,17 +110,23 @@ static void finish_reset(struct uhci_hcd *uhci) | |||
110 | uhci->is_stopped = UHCI_IS_STOPPED; | 110 | uhci->is_stopped = UHCI_IS_STOPPED; |
111 | uhci_to_hcd(uhci)->state = HC_STATE_HALT; | 111 | uhci_to_hcd(uhci)->state = HC_STATE_HALT; |
112 | uhci_to_hcd(uhci)->poll_rh = 0; | 112 | uhci_to_hcd(uhci)->poll_rh = 0; |
113 | |||
114 | uhci->dead = 0; /* Full reset resurrects the controller */ | ||
113 | } | 115 | } |
114 | 116 | ||
115 | /* | 117 | /* |
116 | * Last rites for a defunct/nonfunctional controller | 118 | * Last rites for a defunct/nonfunctional controller |
117 | * or one we don't want to use any more. | 119 | * or one we don't want to use any more. |
118 | */ | 120 | */ |
119 | static void hc_died(struct uhci_hcd *uhci) | 121 | static void uhci_hc_died(struct uhci_hcd *uhci) |
120 | { | 122 | { |
123 | uhci_get_current_frame_number(uhci); | ||
121 | uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr); | 124 | uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr); |
122 | finish_reset(uhci); | 125 | finish_reset(uhci); |
123 | uhci->hc_inaccessible = 1; | 126 | uhci->dead = 1; |
127 | |||
128 | /* The current frame may already be partway finished */ | ||
129 | ++uhci->frame_number; | ||
124 | } | 130 | } |
125 | 131 | ||
126 | /* | 132 | /* |
@@ -234,7 +240,7 @@ __acquires(uhci->lock) | |||
234 | spin_unlock_irq(&uhci->lock); | 240 | spin_unlock_irq(&uhci->lock); |
235 | msleep(1); | 241 | msleep(1); |
236 | spin_lock_irq(&uhci->lock); | 242 | spin_lock_irq(&uhci->lock); |
237 | if (uhci->hc_inaccessible) /* Died */ | 243 | if (uhci->dead) |
238 | return; | 244 | return; |
239 | } | 245 | } |
240 | if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) | 246 | if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) |
@@ -287,7 +293,7 @@ __acquires(uhci->lock) | |||
287 | spin_unlock_irq(&uhci->lock); | 293 | spin_unlock_irq(&uhci->lock); |
288 | msleep(20); | 294 | msleep(20); |
289 | spin_lock_irq(&uhci->lock); | 295 | spin_lock_irq(&uhci->lock); |
290 | if (uhci->hc_inaccessible) /* Died */ | 296 | if (uhci->dead) |
291 | return; | 297 | return; |
292 | 298 | ||
293 | /* End Global Resume and wait for EOP to be sent */ | 299 | /* End Global Resume and wait for EOP to be sent */ |
@@ -339,7 +345,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) | |||
339 | errbuf, ERRBUF_LEN); | 345 | errbuf, ERRBUF_LEN); |
340 | lprintk(errbuf); | 346 | lprintk(errbuf); |
341 | } | 347 | } |
342 | hc_died(uhci); | 348 | uhci_hc_died(uhci); |
343 | 349 | ||
344 | /* Force a callback in case there are | 350 | /* Force a callback in case there are |
345 | * pending unlinks */ | 351 | * pending unlinks */ |
@@ -462,7 +468,7 @@ static void uhci_shutdown(struct pci_dev *pdev) | |||
462 | { | 468 | { |
463 | struct usb_hcd *hcd = (struct usb_hcd *) pci_get_drvdata(pdev); | 469 | struct usb_hcd *hcd = (struct usb_hcd *) pci_get_drvdata(pdev); |
464 | 470 | ||
465 | hc_died(hcd_to_uhci(hcd)); | 471 | uhci_hc_died(hcd_to_uhci(hcd)); |
466 | } | 472 | } |
467 | 473 | ||
468 | /* | 474 | /* |
@@ -664,8 +670,8 @@ static void uhci_stop(struct usb_hcd *hcd) | |||
664 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 670 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
665 | 671 | ||
666 | spin_lock_irq(&uhci->lock); | 672 | spin_lock_irq(&uhci->lock); |
667 | if (!uhci->hc_inaccessible) | 673 | if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && !uhci->dead) |
668 | hc_died(uhci); | 674 | uhci_hc_died(uhci); |
669 | uhci_scan_schedule(uhci, NULL); | 675 | uhci_scan_schedule(uhci, NULL); |
670 | spin_unlock_irq(&uhci->lock); | 676 | spin_unlock_irq(&uhci->lock); |
671 | 677 | ||
@@ -681,7 +687,7 @@ static int uhci_rh_suspend(struct usb_hcd *hcd) | |||
681 | spin_lock_irq(&uhci->lock); | 687 | spin_lock_irq(&uhci->lock); |
682 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) | 688 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) |
683 | rc = -ESHUTDOWN; | 689 | rc = -ESHUTDOWN; |
684 | else if (!uhci->hc_inaccessible) | 690 | else if (!uhci->dead) |
685 | suspend_rh(uhci, UHCI_RH_SUSPENDED); | 691 | suspend_rh(uhci, UHCI_RH_SUSPENDED); |
686 | spin_unlock_irq(&uhci->lock); | 692 | spin_unlock_irq(&uhci->lock); |
687 | return rc; | 693 | return rc; |
@@ -696,7 +702,7 @@ static int uhci_rh_resume(struct usb_hcd *hcd) | |||
696 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { | 702 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { |
697 | dev_warn(&hcd->self.root_hub->dev, "HC isn't running!\n"); | 703 | dev_warn(&hcd->self.root_hub->dev, "HC isn't running!\n"); |
698 | rc = -ESHUTDOWN; | 704 | rc = -ESHUTDOWN; |
699 | } else if (!uhci->hc_inaccessible) | 705 | } else if (!uhci->dead) |
700 | wakeup_rh(uhci); | 706 | wakeup_rh(uhci); |
701 | spin_unlock_irq(&uhci->lock); | 707 | spin_unlock_irq(&uhci->lock); |
702 | return rc; | 708 | return rc; |
@@ -710,8 +716,8 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) | |||
710 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); | 716 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); |
711 | 717 | ||
712 | spin_lock_irq(&uhci->lock); | 718 | spin_lock_irq(&uhci->lock); |
713 | if (uhci->hc_inaccessible) /* Dead or already suspended */ | 719 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead) |
714 | goto done; | 720 | goto done_okay; /* Already suspended or dead */ |
715 | 721 | ||
716 | if (uhci->rh_state > UHCI_RH_SUSPENDED) { | 722 | if (uhci->rh_state > UHCI_RH_SUSPENDED) { |
717 | dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); | 723 | dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); |
@@ -724,12 +730,12 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) | |||
724 | */ | 730 | */ |
725 | pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); | 731 | pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); |
726 | mb(); | 732 | mb(); |
727 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
728 | uhci->hc_inaccessible = 1; | ||
729 | hcd->poll_rh = 0; | 733 | hcd->poll_rh = 0; |
730 | 734 | ||
731 | /* FIXME: Enable non-PME# remote wakeup? */ | 735 | /* FIXME: Enable non-PME# remote wakeup? */ |
732 | 736 | ||
737 | done_okay: | ||
738 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
733 | done: | 739 | done: |
734 | spin_unlock_irq(&uhci->lock); | 740 | spin_unlock_irq(&uhci->lock); |
735 | return rc; | 741 | return rc; |
@@ -742,25 +748,22 @@ static int uhci_resume(struct usb_hcd *hcd) | |||
742 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); | 748 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); |
743 | 749 | ||
744 | /* Since we aren't in D3 any more, it's safe to set this flag | 750 | /* Since we aren't in D3 any more, it's safe to set this flag |
745 | * even if the controller was dead. It might not even be dead | 751 | * even if the controller was dead. |
746 | * any more, if the firmware or quirks code has reset it. | ||
747 | */ | 752 | */ |
748 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | 753 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
749 | mb(); | 754 | mb(); |
750 | 755 | ||
751 | if (uhci->rh_state == UHCI_RH_RESET) /* Dead */ | ||
752 | return 0; | ||
753 | |||
754 | spin_lock_irq(&uhci->lock); | 756 | spin_lock_irq(&uhci->lock); |
755 | 757 | ||
756 | /* FIXME: Disable non-PME# remote wakeup? */ | 758 | /* FIXME: Disable non-PME# remote wakeup? */ |
757 | 759 | ||
758 | uhci->hc_inaccessible = 0; | 760 | /* The firmware or a boot kernel may have changed the controller |
759 | 761 | * settings during a system wakeup. Check it and reconfigure | |
760 | /* The BIOS may have changed the controller settings during a | 762 | * to avoid problems. |
761 | * system wakeup. Check it and reconfigure to avoid problems. | ||
762 | */ | 763 | */ |
763 | check_and_reset_hc(uhci); | 764 | check_and_reset_hc(uhci); |
765 | |||
766 | /* If the controller was dead before, it's back alive now */ | ||
764 | configure_hc(uhci); | 767 | configure_hc(uhci); |
765 | 768 | ||
766 | if (uhci->rh_state == UHCI_RH_RESET) { | 769 | if (uhci->rh_state == UHCI_RH_RESET) { |
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 469b4268b850..619d704f4e8f 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h | |||
@@ -395,7 +395,7 @@ struct uhci_hcd { | |||
395 | 395 | ||
396 | unsigned int scan_in_progress:1; /* Schedule scan is running */ | 396 | unsigned int scan_in_progress:1; /* Schedule scan is running */ |
397 | unsigned int need_rescan:1; /* Redo the schedule scan */ | 397 | unsigned int need_rescan:1; /* Redo the schedule scan */ |
398 | unsigned int hc_inaccessible:1; /* HC is suspended or dead */ | 398 | unsigned int dead:1; /* Controller has died */ |
399 | unsigned int working_RD:1; /* Suspended root hub doesn't | 399 | unsigned int working_RD:1; /* Suspended root hub doesn't |
400 | need to be polled */ | 400 | need to be polled */ |
401 | unsigned int is_initialized:1; /* Data structure is usable */ | 401 | unsigned int is_initialized:1; /* Data structure is usable */ |
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index f53c116e0dfd..c545ef92fe29 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c | |||
@@ -171,7 +171,7 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
171 | spin_lock_irqsave(&uhci->lock, flags); | 171 | spin_lock_irqsave(&uhci->lock, flags); |
172 | 172 | ||
173 | uhci_scan_schedule(uhci, NULL); | 173 | uhci_scan_schedule(uhci, NULL); |
174 | if (uhci->hc_inaccessible) | 174 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead) |
175 | goto done; | 175 | goto done; |
176 | uhci_check_ports(uhci); | 176 | uhci_check_ports(uhci); |
177 | 177 | ||
@@ -227,7 +227,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
227 | u16 wPortChange, wPortStatus; | 227 | u16 wPortChange, wPortStatus; |
228 | unsigned long flags; | 228 | unsigned long flags; |
229 | 229 | ||
230 | if (uhci->hc_inaccessible) | 230 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead) |
231 | return -ETIMEDOUT; | 231 | return -ETIMEDOUT; |
232 | 232 | ||
233 | spin_lock_irqsave(&uhci->lock, flags); | 233 | spin_lock_irqsave(&uhci->lock, flags); |