diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 86 |
1 files changed, 65 insertions, 21 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 730ba3a621ae..82e608a4bbd0 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -13,18 +13,13 @@ | |||
13 | * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface | 13 | * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface |
14 | * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). | 14 | * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). |
15 | * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) | 15 | * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) |
16 | * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu | 16 | * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu |
17 | * | 17 | * |
18 | * Intel documents this fairly well, and as far as I know there | 18 | * Intel documents this fairly well, and as far as I know there |
19 | * are no royalties or anything like that, but even so there are | 19 | * are no royalties or anything like that, but even so there are |
20 | * people who decided that they want to do the same thing in a | 20 | * people who decided that they want to do the same thing in a |
21 | * completely different way. | 21 | * completely different way. |
22 | * | 22 | * |
23 | * WARNING! The USB documentation is downright evil. Most of it | ||
24 | * is just crap, written by a committee. You're better off ignoring | ||
25 | * most of it, the important stuff is: | ||
26 | * - the low-level protocol (fairly simple but lots of small details) | ||
27 | * - working around the horridness of the rest | ||
28 | */ | 23 | */ |
29 | 24 | ||
30 | #include <linux/config.h> | 25 | #include <linux/config.h> |
@@ -147,6 +142,15 @@ static void reset_hc(struct uhci_hcd *uhci) | |||
147 | } | 142 | } |
148 | 143 | ||
149 | /* | 144 | /* |
145 | * Last rites for a defunct/nonfunctional controller | ||
146 | */ | ||
147 | static void hc_died(struct uhci_hcd *uhci) | ||
148 | { | ||
149 | reset_hc(uhci); | ||
150 | uhci->hc_inaccessible = 1; | ||
151 | } | ||
152 | |||
153 | /* | ||
150 | * Initialize a controller that was newly discovered or has just been | 154 | * Initialize a controller that was newly discovered or has just been |
151 | * resumed. In either case we can't be sure of its previous state. | 155 | * resumed. In either case we can't be sure of its previous state. |
152 | */ | 156 | */ |
@@ -287,6 +291,8 @@ __acquires(uhci->lock) | |||
287 | spin_unlock_irq(&uhci->lock); | 291 | spin_unlock_irq(&uhci->lock); |
288 | msleep(1); | 292 | msleep(1); |
289 | spin_lock_irq(&uhci->lock); | 293 | spin_lock_irq(&uhci->lock); |
294 | if (uhci->hc_inaccessible) /* Died */ | ||
295 | return; | ||
290 | } | 296 | } |
291 | if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) | 297 | if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) |
292 | dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n"); | 298 | dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n"); |
@@ -335,6 +341,8 @@ __acquires(uhci->lock) | |||
335 | spin_unlock_irq(&uhci->lock); | 341 | spin_unlock_irq(&uhci->lock); |
336 | msleep(20); | 342 | msleep(20); |
337 | spin_lock_irq(&uhci->lock); | 343 | spin_lock_irq(&uhci->lock); |
344 | if (uhci->hc_inaccessible) /* Died */ | ||
345 | return; | ||
338 | 346 | ||
339 | /* End Global Resume and wait for EOP to be sent */ | 347 | /* End Global Resume and wait for EOP to be sent */ |
340 | outw(USBCMD_CF, uhci->io_addr + USBCMD); | 348 | outw(USBCMD_CF, uhci->io_addr + USBCMD); |
@@ -387,9 +395,11 @@ static void stall_callback(unsigned long _uhci) | |||
387 | check_fsbr(uhci); | 395 | check_fsbr(uhci); |
388 | 396 | ||
389 | /* Poll for and perform state transitions */ | 397 | /* Poll for and perform state transitions */ |
390 | rh_state_transitions(uhci); | 398 | if (!uhci->hc_inaccessible) { |
391 | if (uhci->suspended_ports && !uhci->hc_inaccessible) | 399 | rh_state_transitions(uhci); |
392 | uhci_check_ports(uhci); | 400 | if (uhci->suspended_ports) |
401 | uhci_check_ports(uhci); | ||
402 | } | ||
393 | 403 | ||
394 | restart_timer(uhci); | 404 | restart_timer(uhci); |
395 | spin_unlock_irqrestore(&uhci->lock, flags); | 405 | spin_unlock_irqrestore(&uhci->lock, flags); |
@@ -399,6 +409,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) | |||
399 | { | 409 | { |
400 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 410 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
401 | unsigned short status; | 411 | unsigned short status; |
412 | unsigned long flags; | ||
402 | 413 | ||
403 | /* | 414 | /* |
404 | * Read the interrupt status, and write it back to clear the | 415 | * Read the interrupt status, and write it back to clear the |
@@ -417,20 +428,26 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) | |||
417 | if (status & USBSTS_HCPE) | 428 | if (status & USBSTS_HCPE) |
418 | dev_err(uhci_dev(uhci), "host controller process " | 429 | dev_err(uhci_dev(uhci), "host controller process " |
419 | "error, something bad happened!\n"); | 430 | "error, something bad happened!\n"); |
420 | if ((status & USBSTS_HCH) && | 431 | if (status & USBSTS_HCH) { |
421 | uhci->rh_state >= UHCI_RH_RUNNING) { | 432 | spin_lock_irqsave(&uhci->lock, flags); |
422 | dev_err(uhci_dev(uhci), "host controller halted, " | 433 | if (uhci->rh_state >= UHCI_RH_RUNNING) { |
434 | dev_err(uhci_dev(uhci), | ||
435 | "host controller halted, " | ||
423 | "very bad!\n"); | 436 | "very bad!\n"); |
424 | /* FIXME: Reset the controller, fix the offending TD */ | 437 | hc_died(uhci); |
438 | spin_unlock_irqrestore(&uhci->lock, flags); | ||
439 | return IRQ_HANDLED; | ||
440 | } | ||
441 | spin_unlock_irqrestore(&uhci->lock, flags); | ||
425 | } | 442 | } |
426 | } | 443 | } |
427 | 444 | ||
428 | if (status & USBSTS_RD) | 445 | if (status & USBSTS_RD) |
429 | uhci->resume_detect = 1; | 446 | uhci->resume_detect = 1; |
430 | 447 | ||
431 | spin_lock(&uhci->lock); | 448 | spin_lock_irqsave(&uhci->lock, flags); |
432 | uhci_scan_schedule(uhci, regs); | 449 | uhci_scan_schedule(uhci, regs); |
433 | spin_unlock(&uhci->lock); | 450 | spin_unlock_irqrestore(&uhci->lock, flags); |
434 | 451 | ||
435 | return IRQ_HANDLED; | 452 | return IRQ_HANDLED; |
436 | } | 453 | } |
@@ -525,10 +542,15 @@ static int uhci_start(struct usb_hcd *hcd) | |||
525 | struct dentry *dentry; | 542 | struct dentry *dentry; |
526 | 543 | ||
527 | io_size = (unsigned) hcd->rsrc_len; | 544 | io_size = (unsigned) hcd->rsrc_len; |
545 | if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM)) | ||
546 | hcd->can_wakeup = 1; /* Assume it supports PME# */ | ||
528 | 547 | ||
529 | dentry = debugfs_create_file(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, &uhci_debug_operations); | 548 | dentry = debugfs_create_file(hcd->self.bus_name, |
549 | S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, | ||
550 | &uhci_debug_operations); | ||
530 | if (!dentry) { | 551 | if (!dentry) { |
531 | dev_err(uhci_dev(uhci), "couldn't create uhci debugfs entry\n"); | 552 | dev_err(uhci_dev(uhci), |
553 | "couldn't create uhci debugfs entry\n"); | ||
532 | retval = -ENOMEM; | 554 | retval = -ENOMEM; |
533 | goto err_create_debug_entry; | 555 | goto err_create_debug_entry; |
534 | } | 556 | } |
@@ -765,7 +787,8 @@ static int uhci_rh_suspend(struct usb_hcd *hcd) | |||
765 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 787 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
766 | 788 | ||
767 | spin_lock_irq(&uhci->lock); | 789 | spin_lock_irq(&uhci->lock); |
768 | suspend_rh(uhci, UHCI_RH_SUSPENDED); | 790 | if (!uhci->hc_inaccessible) /* Not dead */ |
791 | suspend_rh(uhci, UHCI_RH_SUSPENDED); | ||
769 | spin_unlock_irq(&uhci->lock); | 792 | spin_unlock_irq(&uhci->lock); |
770 | return 0; | 793 | return 0; |
771 | } | 794 | } |
@@ -773,26 +796,44 @@ static int uhci_rh_suspend(struct usb_hcd *hcd) | |||
773 | static int uhci_rh_resume(struct usb_hcd *hcd) | 796 | static int uhci_rh_resume(struct usb_hcd *hcd) |
774 | { | 797 | { |
775 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 798 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
799 | int rc = 0; | ||
776 | 800 | ||
777 | spin_lock_irq(&uhci->lock); | 801 | spin_lock_irq(&uhci->lock); |
778 | wakeup_rh(uhci); | 802 | if (uhci->hc_inaccessible) { |
803 | if (uhci->rh_state == UHCI_RH_SUSPENDED) { | ||
804 | dev_warn(uhci_dev(uhci), "HC isn't running!\n"); | ||
805 | rc = -ENODEV; | ||
806 | } | ||
807 | /* Otherwise the HC is dead */ | ||
808 | } else | ||
809 | wakeup_rh(uhci); | ||
779 | spin_unlock_irq(&uhci->lock); | 810 | spin_unlock_irq(&uhci->lock); |
780 | return 0; | 811 | return rc; |
781 | } | 812 | } |
782 | 813 | ||
783 | static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) | 814 | static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) |
784 | { | 815 | { |
785 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 816 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
817 | int rc = 0; | ||
786 | 818 | ||
787 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); | 819 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); |
788 | 820 | ||
789 | spin_lock_irq(&uhci->lock); | 821 | spin_lock_irq(&uhci->lock); |
822 | if (uhci->hc_inaccessible) /* Dead or already suspended */ | ||
823 | goto done; | ||
790 | 824 | ||
791 | #ifndef CONFIG_USB_SUSPEND | 825 | #ifndef CONFIG_USB_SUSPEND |
792 | /* Otherwise this would never happen */ | 826 | /* Otherwise this would never happen */ |
793 | suspend_rh(uhci, UHCI_RH_SUSPENDED); | 827 | suspend_rh(uhci, UHCI_RH_SUSPENDED); |
794 | #endif | 828 | #endif |
795 | 829 | ||
830 | if (uhci->rh_state > UHCI_RH_SUSPENDED) { | ||
831 | dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); | ||
832 | hcd->state = HC_STATE_RUNNING; | ||
833 | rc = -EBUSY; | ||
834 | goto done; | ||
835 | }; | ||
836 | |||
796 | /* All PCI host controllers are required to disable IRQ generation | 837 | /* All PCI host controllers are required to disable IRQ generation |
797 | * at the source, so we must turn off PIRQ. | 838 | * at the source, so we must turn off PIRQ. |
798 | */ | 839 | */ |
@@ -801,8 +842,9 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) | |||
801 | 842 | ||
802 | /* FIXME: Enable non-PME# remote wakeup? */ | 843 | /* FIXME: Enable non-PME# remote wakeup? */ |
803 | 844 | ||
845 | done: | ||
804 | spin_unlock_irq(&uhci->lock); | 846 | spin_unlock_irq(&uhci->lock); |
805 | return 0; | 847 | return rc; |
806 | } | 848 | } |
807 | 849 | ||
808 | static int uhci_resume(struct usb_hcd *hcd) | 850 | static int uhci_resume(struct usb_hcd *hcd) |
@@ -811,6 +853,8 @@ static int uhci_resume(struct usb_hcd *hcd) | |||
811 | 853 | ||
812 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); | 854 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); |
813 | 855 | ||
856 | if (uhci->rh_state == UHCI_RH_RESET) /* Dead */ | ||
857 | return 0; | ||
814 | spin_lock_irq(&uhci->lock); | 858 | spin_lock_irq(&uhci->lock); |
815 | 859 | ||
816 | /* FIXME: Disable non-PME# remote wakeup? */ | 860 | /* FIXME: Disable non-PME# remote wakeup? */ |