diff options
Diffstat (limited to 'drivers/usb/host/ohci-hcd.c')
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 234 |
1 files changed, 180 insertions, 54 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 6edf4097d2d2..240c7f507541 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
@@ -81,7 +81,6 @@ static void ohci_dump (struct ohci_hcd *ohci, int verbose); | |||
81 | static int ohci_init (struct ohci_hcd *ohci); | 81 | static int ohci_init (struct ohci_hcd *ohci); |
82 | static void ohci_stop (struct usb_hcd *hcd); | 82 | static void ohci_stop (struct usb_hcd *hcd); |
83 | static int ohci_restart (struct ohci_hcd *ohci); | 83 | static int ohci_restart (struct ohci_hcd *ohci); |
84 | static void ohci_quirk_nec_worker (struct work_struct *work); | ||
85 | 84 | ||
86 | #include "ohci-hub.c" | 85 | #include "ohci-hub.c" |
87 | #include "ohci-dbg.c" | 86 | #include "ohci-dbg.c" |
@@ -118,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake"); | |||
118 | */ | 117 | */ |
119 | static int ohci_urb_enqueue ( | 118 | static int ohci_urb_enqueue ( |
120 | struct usb_hcd *hcd, | 119 | struct usb_hcd *hcd, |
121 | struct usb_host_endpoint *ep, | ||
122 | struct urb *urb, | 120 | struct urb *urb, |
123 | gfp_t mem_flags | 121 | gfp_t mem_flags |
124 | ) { | 122 | ) { |
@@ -131,11 +129,11 @@ static int ohci_urb_enqueue ( | |||
131 | int retval = 0; | 129 | int retval = 0; |
132 | 130 | ||
133 | #ifdef OHCI_VERBOSE_DEBUG | 131 | #ifdef OHCI_VERBOSE_DEBUG |
134 | urb_print (urb, "SUB", usb_pipein (pipe)); | 132 | urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS); |
135 | #endif | 133 | #endif |
136 | 134 | ||
137 | /* every endpoint has a ed, locate and maybe (re)initialize it */ | 135 | /* every endpoint has a ed, locate and maybe (re)initialize it */ |
138 | if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval))) | 136 | if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval))) |
139 | return -ENOMEM; | 137 | return -ENOMEM; |
140 | 138 | ||
141 | /* for the private part of the URB we need the number of TDs (size) */ | 139 | /* for the private part of the URB we need the number of TDs (size) */ |
@@ -200,22 +198,17 @@ static int ohci_urb_enqueue ( | |||
200 | retval = -ENODEV; | 198 | retval = -ENODEV; |
201 | goto fail; | 199 | goto fail; |
202 | } | 200 | } |
203 | 201 | retval = usb_hcd_link_urb_to_ep(hcd, urb); | |
204 | /* in case of unlink-during-submit */ | 202 | if (retval) |
205 | spin_lock (&urb->lock); | ||
206 | if (urb->status != -EINPROGRESS) { | ||
207 | spin_unlock (&urb->lock); | ||
208 | urb->hcpriv = urb_priv; | ||
209 | finish_urb (ohci, urb); | ||
210 | retval = 0; | ||
211 | goto fail; | 203 | goto fail; |
212 | } | ||
213 | 204 | ||
214 | /* schedule the ed if needed */ | 205 | /* schedule the ed if needed */ |
215 | if (ed->state == ED_IDLE) { | 206 | if (ed->state == ED_IDLE) { |
216 | retval = ed_schedule (ohci, ed); | 207 | retval = ed_schedule (ohci, ed); |
217 | if (retval < 0) | 208 | if (retval < 0) { |
218 | goto fail0; | 209 | usb_hcd_unlink_urb_from_ep(hcd, urb); |
210 | goto fail; | ||
211 | } | ||
219 | if (ed->type == PIPE_ISOCHRONOUS) { | 212 | if (ed->type == PIPE_ISOCHRONOUS) { |
220 | u16 frame = ohci_frame_no(ohci); | 213 | u16 frame = ohci_frame_no(ohci); |
221 | 214 | ||
@@ -239,8 +232,6 @@ static int ohci_urb_enqueue ( | |||
239 | urb->hcpriv = urb_priv; | 232 | urb->hcpriv = urb_priv; |
240 | td_submit_urb (ohci, urb); | 233 | td_submit_urb (ohci, urb); |
241 | 234 | ||
242 | fail0: | ||
243 | spin_unlock (&urb->lock); | ||
244 | fail: | 235 | fail: |
245 | if (retval) | 236 | if (retval) |
246 | urb_free_priv (ohci, urb_priv); | 237 | urb_free_priv (ohci, urb_priv); |
@@ -249,22 +240,26 @@ fail: | |||
249 | } | 240 | } |
250 | 241 | ||
251 | /* | 242 | /* |
252 | * decouple the URB from the HC queues (TDs, urb_priv); it's | 243 | * decouple the URB from the HC queues (TDs, urb_priv). |
253 | * already marked using urb->status. reporting is always done | 244 | * reporting is always done |
254 | * asynchronously, and we might be dealing with an urb that's | 245 | * asynchronously, and we might be dealing with an urb that's |
255 | * partially transferred, or an ED with other urbs being unlinked. | 246 | * partially transferred, or an ED with other urbs being unlinked. |
256 | */ | 247 | */ |
257 | static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) | 248 | static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) |
258 | { | 249 | { |
259 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 250 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
260 | unsigned long flags; | 251 | unsigned long flags; |
252 | int rc; | ||
261 | 253 | ||
262 | #ifdef OHCI_VERBOSE_DEBUG | 254 | #ifdef OHCI_VERBOSE_DEBUG |
263 | urb_print (urb, "UNLINK", 1); | 255 | urb_print(urb, "UNLINK", 1, status); |
264 | #endif | 256 | #endif |
265 | 257 | ||
266 | spin_lock_irqsave (&ohci->lock, flags); | 258 | spin_lock_irqsave (&ohci->lock, flags); |
267 | if (HC_IS_RUNNING(hcd->state)) { | 259 | rc = usb_hcd_check_unlink_urb(hcd, urb, status); |
260 | if (rc) { | ||
261 | ; /* Do nothing */ | ||
262 | } else if (HC_IS_RUNNING(hcd->state)) { | ||
268 | urb_priv_t *urb_priv; | 263 | urb_priv_t *urb_priv; |
269 | 264 | ||
270 | /* Unless an IRQ completed the unlink while it was being | 265 | /* Unless an IRQ completed the unlink while it was being |
@@ -282,10 +277,10 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) | |||
282 | * any more ... just clean up every urb's memory. | 277 | * any more ... just clean up every urb's memory. |
283 | */ | 278 | */ |
284 | if (urb->hcpriv) | 279 | if (urb->hcpriv) |
285 | finish_urb (ohci, urb); | 280 | finish_urb(ohci, urb, status); |
286 | } | 281 | } |
287 | spin_unlock_irqrestore (&ohci->lock, flags); | 282 | spin_unlock_irqrestore (&ohci->lock, flags); |
288 | return 0; | 283 | return rc; |
289 | } | 284 | } |
290 | 285 | ||
291 | /*-------------------------------------------------------------------------*/ | 286 | /*-------------------------------------------------------------------------*/ |
@@ -314,6 +309,8 @@ rescan: | |||
314 | if (!HC_IS_RUNNING (hcd->state)) { | 309 | if (!HC_IS_RUNNING (hcd->state)) { |
315 | sanitize: | 310 | sanitize: |
316 | ed->state = ED_IDLE; | 311 | ed->state = ED_IDLE; |
312 | if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) | ||
313 | ohci->eds_scheduled--; | ||
317 | finish_unlinks (ohci, 0); | 314 | finish_unlinks (ohci, 0); |
318 | } | 315 | } |
319 | 316 | ||
@@ -321,7 +318,12 @@ sanitize: | |||
321 | case ED_UNLINK: /* wait for hw to finish? */ | 318 | case ED_UNLINK: /* wait for hw to finish? */ |
322 | /* major IRQ delivery trouble loses INTR_SF too... */ | 319 | /* major IRQ delivery trouble loses INTR_SF too... */ |
323 | if (limit-- == 0) { | 320 | if (limit-- == 0) { |
324 | ohci_warn (ohci, "IRQ INTR_SF lossage\n"); | 321 | ohci_warn(ohci, "ED unlink timeout\n"); |
322 | if (quirk_zfmicro(ohci)) { | ||
323 | ohci_warn(ohci, "Attempting ZF TD recovery\n"); | ||
324 | ohci->ed_to_check = ed; | ||
325 | ohci->zf_delay = 2; | ||
326 | } | ||
325 | goto sanitize; | 327 | goto sanitize; |
326 | } | 328 | } |
327 | spin_unlock_irqrestore (&ohci->lock, flags); | 329 | spin_unlock_irqrestore (&ohci->lock, flags); |
@@ -379,6 +381,93 @@ ohci_shutdown (struct usb_hcd *hcd) | |||
379 | (void) ohci_readl (ohci, &ohci->regs->control); | 381 | (void) ohci_readl (ohci, &ohci->regs->control); |
380 | } | 382 | } |
381 | 383 | ||
384 | static int check_ed(struct ohci_hcd *ohci, struct ed *ed) | ||
385 | { | ||
386 | return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0 | ||
387 | && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK) | ||
388 | == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK) | ||
389 | && !list_empty(&ed->td_list); | ||
390 | } | ||
391 | |||
392 | /* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes | ||
393 | * an interrupt TD but neglects to add it to the donelist. On systems with | ||
394 | * this chipset, we need to periodically check the state of the queues to look | ||
395 | * for such "lost" TDs. | ||
396 | */ | ||
397 | static void unlink_watchdog_func(unsigned long _ohci) | ||
398 | { | ||
399 | long flags; | ||
400 | unsigned max; | ||
401 | unsigned seen_count = 0; | ||
402 | unsigned i; | ||
403 | struct ed **seen = NULL; | ||
404 | struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci; | ||
405 | |||
406 | spin_lock_irqsave(&ohci->lock, flags); | ||
407 | max = ohci->eds_scheduled; | ||
408 | if (!max) | ||
409 | goto done; | ||
410 | |||
411 | if (ohci->ed_to_check) | ||
412 | goto out; | ||
413 | |||
414 | seen = kcalloc(max, sizeof *seen, GFP_ATOMIC); | ||
415 | if (!seen) | ||
416 | goto out; | ||
417 | |||
418 | for (i = 0; i < NUM_INTS; i++) { | ||
419 | struct ed *ed = ohci->periodic[i]; | ||
420 | |||
421 | while (ed) { | ||
422 | unsigned temp; | ||
423 | |||
424 | /* scan this branch of the periodic schedule tree */ | ||
425 | for (temp = 0; temp < seen_count; temp++) { | ||
426 | if (seen[temp] == ed) { | ||
427 | /* we've checked it and what's after */ | ||
428 | ed = NULL; | ||
429 | break; | ||
430 | } | ||
431 | } | ||
432 | if (!ed) | ||
433 | break; | ||
434 | seen[seen_count++] = ed; | ||
435 | if (!check_ed(ohci, ed)) { | ||
436 | ed = ed->ed_next; | ||
437 | continue; | ||
438 | } | ||
439 | |||
440 | /* HC's TD list is empty, but HCD sees at least one | ||
441 | * TD that's not been sent through the donelist. | ||
442 | */ | ||
443 | ohci->ed_to_check = ed; | ||
444 | ohci->zf_delay = 2; | ||
445 | |||
446 | /* The HC may wait until the next frame to report the | ||
447 | * TD as done through the donelist and INTR_WDH. (We | ||
448 | * just *assume* it's not a multi-TD interrupt URB; | ||
449 | * those could defer the IRQ more than one frame, using | ||
450 | * DI...) Check again after the next INTR_SF. | ||
451 | */ | ||
452 | ohci_writel(ohci, OHCI_INTR_SF, | ||
453 | &ohci->regs->intrstatus); | ||
454 | ohci_writel(ohci, OHCI_INTR_SF, | ||
455 | &ohci->regs->intrenable); | ||
456 | |||
457 | /* flush those writes */ | ||
458 | (void) ohci_readl(ohci, &ohci->regs->control); | ||
459 | |||
460 | goto out; | ||
461 | } | ||
462 | } | ||
463 | out: | ||
464 | kfree(seen); | ||
465 | if (ohci->eds_scheduled) | ||
466 | mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ)); | ||
467 | done: | ||
468 | spin_unlock_irqrestore(&ohci->lock, flags); | ||
469 | } | ||
470 | |||
382 | /*-------------------------------------------------------------------------* | 471 | /*-------------------------------------------------------------------------* |
383 | * HC functions | 472 | * HC functions |
384 | *-------------------------------------------------------------------------*/ | 473 | *-------------------------------------------------------------------------*/ |
@@ -616,6 +705,15 @@ retry: | |||
616 | mdelay ((temp >> 23) & 0x1fe); | 705 | mdelay ((temp >> 23) & 0x1fe); |
617 | hcd->state = HC_STATE_RUNNING; | 706 | hcd->state = HC_STATE_RUNNING; |
618 | 707 | ||
708 | if (quirk_zfmicro(ohci)) { | ||
709 | /* Create timer to watch for bad queue state on ZF Micro */ | ||
710 | setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func, | ||
711 | (unsigned long) ohci); | ||
712 | |||
713 | ohci->eds_scheduled = 0; | ||
714 | ohci->ed_to_check = NULL; | ||
715 | } | ||
716 | |||
619 | ohci_dump (ohci, 1); | 717 | ohci_dump (ohci, 1); |
620 | 718 | ||
621 | return 0; | 719 | return 0; |
@@ -629,10 +727,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
629 | { | 727 | { |
630 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 728 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
631 | struct ohci_regs __iomem *regs = ohci->regs; | 729 | struct ohci_regs __iomem *regs = ohci->regs; |
632 | int ints; | 730 | int ints; |
633 | 731 | ||
634 | /* we can eliminate a (slow) ohci_readl() | 732 | /* we can eliminate a (slow) ohci_readl() |
635 | if _only_ WDH caused this irq */ | 733 | * if _only_ WDH caused this irq |
734 | */ | ||
636 | if ((ohci->hcca->done_head != 0) | 735 | if ((ohci->hcca->done_head != 0) |
637 | && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head) | 736 | && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head) |
638 | & 0x01)) { | 737 | & 0x01)) { |
@@ -651,7 +750,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
651 | 750 | ||
652 | if (ints & OHCI_INTR_UE) { | 751 | if (ints & OHCI_INTR_UE) { |
653 | // e.g. due to PCI Master/Target Abort | 752 | // e.g. due to PCI Master/Target Abort |
654 | if (ohci->flags & OHCI_QUIRK_NEC) { | 753 | if (quirk_nec(ohci)) { |
655 | /* Workaround for a silicon bug in some NEC chips used | 754 | /* Workaround for a silicon bug in some NEC chips used |
656 | * in Apple's PowerBooks. Adapted from Darwin code. | 755 | * in Apple's PowerBooks. Adapted from Darwin code. |
657 | */ | 756 | */ |
@@ -713,6 +812,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
713 | ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); | 812 | ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); |
714 | } | 813 | } |
715 | 814 | ||
815 | if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) { | ||
816 | spin_lock(&ohci->lock); | ||
817 | if (ohci->ed_to_check) { | ||
818 | struct ed *ed = ohci->ed_to_check; | ||
819 | |||
820 | if (check_ed(ohci, ed)) { | ||
821 | /* HC thinks the TD list is empty; HCD knows | ||
822 | * at least one TD is outstanding | ||
823 | */ | ||
824 | if (--ohci->zf_delay == 0) { | ||
825 | struct td *td = list_entry( | ||
826 | ed->td_list.next, | ||
827 | struct td, td_list); | ||
828 | ohci_warn(ohci, | ||
829 | "Reclaiming orphan TD %p\n", | ||
830 | td); | ||
831 | takeback_td(ohci, td); | ||
832 | ohci->ed_to_check = NULL; | ||
833 | } | ||
834 | } else | ||
835 | ohci->ed_to_check = NULL; | ||
836 | } | ||
837 | spin_unlock(&ohci->lock); | ||
838 | } | ||
839 | |||
716 | /* could track INTR_SO to reduce available PCI/... bandwidth */ | 840 | /* could track INTR_SO to reduce available PCI/... bandwidth */ |
717 | 841 | ||
718 | /* handle any pending URB/ED unlinks, leaving INTR_SF enabled | 842 | /* handle any pending URB/ED unlinks, leaving INTR_SF enabled |
@@ -721,7 +845,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
721 | spin_lock (&ohci->lock); | 845 | spin_lock (&ohci->lock); |
722 | if (ohci->ed_rm_list) | 846 | if (ohci->ed_rm_list) |
723 | finish_unlinks (ohci, ohci_frame_no(ohci)); | 847 | finish_unlinks (ohci, ohci_frame_no(ohci)); |
724 | if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list | 848 | if ((ints & OHCI_INTR_SF) != 0 |
849 | && !ohci->ed_rm_list | ||
850 | && !ohci->ed_to_check | ||
725 | && HC_IS_RUNNING(hcd->state)) | 851 | && HC_IS_RUNNING(hcd->state)) |
726 | ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); | 852 | ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); |
727 | spin_unlock (&ohci->lock); | 853 | spin_unlock (&ohci->lock); |
@@ -751,6 +877,9 @@ static void ohci_stop (struct usb_hcd *hcd) | |||
751 | free_irq(hcd->irq, hcd); | 877 | free_irq(hcd->irq, hcd); |
752 | hcd->irq = -1; | 878 | hcd->irq = -1; |
753 | 879 | ||
880 | if (quirk_zfmicro(ohci)) | ||
881 | del_timer(&ohci->unlink_watchdog); | ||
882 | |||
754 | remove_debug_files (ohci); | 883 | remove_debug_files (ohci); |
755 | ohci_mem_cleanup (ohci); | 884 | ohci_mem_cleanup (ohci); |
756 | if (ohci->hcca) { | 885 | if (ohci->hcca) { |
@@ -798,9 +927,8 @@ static int ohci_restart (struct ohci_hcd *ohci) | |||
798 | ed, ed->state); | 927 | ed, ed->state); |
799 | } | 928 | } |
800 | 929 | ||
801 | spin_lock (&urb->lock); | 930 | if (!urb->unlinked) |
802 | urb->status = -ESHUTDOWN; | 931 | urb->unlinked = -ESHUTDOWN; |
803 | spin_unlock (&urb->lock); | ||
804 | } | 932 | } |
805 | finish_unlinks (ohci, 0); | 933 | finish_unlinks (ohci, 0); |
806 | spin_unlock_irq(&ohci->lock); | 934 | spin_unlock_irq(&ohci->lock); |
@@ -828,27 +956,6 @@ static int ohci_restart (struct ohci_hcd *ohci) | |||
828 | 956 | ||
829 | /*-------------------------------------------------------------------------*/ | 957 | /*-------------------------------------------------------------------------*/ |
830 | 958 | ||
831 | /* NEC workaround */ | ||
832 | static void ohci_quirk_nec_worker(struct work_struct *work) | ||
833 | { | ||
834 | struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); | ||
835 | int status; | ||
836 | |||
837 | status = ohci_init(ohci); | ||
838 | if (status != 0) { | ||
839 | ohci_err(ohci, "Restarting NEC controller failed " | ||
840 | "in ohci_init, %d\n", status); | ||
841 | return; | ||
842 | } | ||
843 | |||
844 | status = ohci_restart(ohci); | ||
845 | if (status != 0) | ||
846 | ohci_err(ohci, "Restarting NEC controller failed " | ||
847 | "in ohci_restart, %d\n", status); | ||
848 | } | ||
849 | |||
850 | /*-------------------------------------------------------------------------*/ | ||
851 | |||
852 | #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC | 959 | #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC |
853 | 960 | ||
854 | MODULE_AUTHOR (DRIVER_AUTHOR); | 961 | MODULE_AUTHOR (DRIVER_AUTHOR); |
@@ -926,11 +1033,17 @@ MODULE_LICENSE ("GPL"); | |||
926 | #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver | 1033 | #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver |
927 | #endif | 1034 | #endif |
928 | 1035 | ||
1036 | #ifdef CONFIG_USB_OHCI_HCD_SSB | ||
1037 | #include "ohci-ssb.c" | ||
1038 | #define SSB_OHCI_DRIVER ssb_ohci_driver | ||
1039 | #endif | ||
1040 | |||
929 | #if !defined(PCI_DRIVER) && \ | 1041 | #if !defined(PCI_DRIVER) && \ |
930 | !defined(PLATFORM_DRIVER) && \ | 1042 | !defined(PLATFORM_DRIVER) && \ |
931 | !defined(OF_PLATFORM_DRIVER) && \ | 1043 | !defined(OF_PLATFORM_DRIVER) && \ |
932 | !defined(SA1111_DRIVER) && \ | 1044 | !defined(SA1111_DRIVER) && \ |
933 | !defined(PS3_SYSTEM_BUS_DRIVER) | 1045 | !defined(PS3_SYSTEM_BUS_DRIVER) && \ |
1046 | !defined(SSB_OHCI_DRIVER) | ||
934 | #error "missing bus glue for ohci-hcd" | 1047 | #error "missing bus glue for ohci-hcd" |
935 | #endif | 1048 | #endif |
936 | 1049 | ||
@@ -975,10 +1088,20 @@ static int __init ohci_hcd_mod_init(void) | |||
975 | goto error_pci; | 1088 | goto error_pci; |
976 | #endif | 1089 | #endif |
977 | 1090 | ||
1091 | #ifdef SSB_OHCI_DRIVER | ||
1092 | retval = ssb_driver_register(&SSB_OHCI_DRIVER); | ||
1093 | if (retval) | ||
1094 | goto error_ssb; | ||
1095 | #endif | ||
1096 | |||
978 | return retval; | 1097 | return retval; |
979 | 1098 | ||
980 | /* Error path */ | 1099 | /* Error path */ |
1100 | #ifdef SSB_OHCI_DRIVER | ||
1101 | error_ssb: | ||
1102 | #endif | ||
981 | #ifdef PCI_DRIVER | 1103 | #ifdef PCI_DRIVER |
1104 | pci_unregister_driver(&PCI_DRIVER); | ||
982 | error_pci: | 1105 | error_pci: |
983 | #endif | 1106 | #endif |
984 | #ifdef SA1111_DRIVER | 1107 | #ifdef SA1111_DRIVER |
@@ -1003,6 +1126,9 @@ module_init(ohci_hcd_mod_init); | |||
1003 | 1126 | ||
1004 | static void __exit ohci_hcd_mod_exit(void) | 1127 | static void __exit ohci_hcd_mod_exit(void) |
1005 | { | 1128 | { |
1129 | #ifdef SSB_OHCI_DRIVER | ||
1130 | ssb_driver_unregister(&SSB_OHCI_DRIVER); | ||
1131 | #endif | ||
1006 | #ifdef PCI_DRIVER | 1132 | #ifdef PCI_DRIVER |
1007 | pci_unregister_driver(&PCI_DRIVER); | 1133 | pci_unregister_driver(&PCI_DRIVER); |
1008 | #endif | 1134 | #endif |