diff options
Diffstat (limited to 'drivers/usb/host/ohci-hcd.c')
| -rw-r--r-- | drivers/usb/host/ohci-hcd.c | 517 |
1 files changed, 340 insertions, 177 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 33f1c1c32ed..f98d03f3144 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1,5 +1,7 @@ /* - * OHCI HCD (Host Controller Driver) for USB. + * Open Host Controller Interface (OHCI) driver for USB. + * + * Maintainer: Alan Stern <stern@rowland.harvard.edu> * * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net> @@ -32,28 +34,23 @@ #include <linux/list.h> #include <linux/usb.h> #include <linux/usb/otg.h> +#include <linux/usb/hcd.h> #include <linux/dma-mapping.h> #include <linux/dmapool.h> -#include <linux/reboot.h> #include <linux/workqueue.h> #include <linux/debugfs.h> #include <asm/io.h> #include <asm/irq.h> -#include <asm/system.h> #include <asm/unaligned.h> #include <asm/byteorder.h> -#include "../core/hcd.h" -#define DRIVER_VERSION "2006 August 04" #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" /*-------------------------------------------------------------------------*/ -#undef OHCI_VERBOSE_DEBUG /* not always helpful */ - /* For initializing controller (mask in an HCFS mode too) */ #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR #define OHCI_INTR_INIT \ @@ -77,15 +74,11 @@ static const char hcd_name [] = "ohci_hcd"; #define STATECHANGE_DELAY msecs_to_jiffies(300) #include "ohci.h" +#include "pci-quirks.h" static void ohci_dump (struct ohci_hcd *ohci, int verbose); -static int ohci_init (struct ohci_hcd *ohci); static void ohci_stop (struct usb_hcd *hcd); -#if defined(CONFIG_PM) || defined(CONFIG_PCI) -static int ohci_restart (struct ohci_hcd *ohci); -#endif - #include "ohci-hub.c" #include "ohci-dbg.c" #include "ohci-mem.c" @@ -104,13 +97,13 @@ static int ohci_restart (struct ohci_hcd *ohci); /* Some boards misreport power switching/overcurrent */ -static int distrust_firmware = 1; +static bool distrust_firmware = 1; module_param (distrust_firmware, bool, 0); MODULE_PARM_DESC (distrust_firmware, "true to distrust firmware power/overcurrent setup"); /* Some boards leave IR set wrongly, since they fail BIOS/SMM handshakes */ -static int no_handshake = 0; +static bool no_handshake = 0; module_param (no_handshake, bool, 0); MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake"); @@ -132,10 +125,6 @@ static int ohci_urb_enqueue ( unsigned long flags; int retval = 0; -#ifdef OHCI_VERBOSE_DEBUG - urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS); -#endif - /* every endpoint has a ed, locate and maybe (re)initialize it */ if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval))) return -ENOMEM; @@ -153,7 +142,7 @@ static int ohci_urb_enqueue ( // case PIPE_INTERRUPT: // case PIPE_BULK: default: - /* one TD for every 4096 Bytes (can be upto 8K) */ + /* one TD for every 4096 Bytes (can be up to 8K) */ size += urb->transfer_buffer_length / 4096; /* ... and for any remaining bytes ... */ if ((urb->transfer_buffer_length % 4096) != 0) @@ -194,11 +183,11 @@ static int ohci_urb_enqueue ( spin_lock_irqsave (&ohci->lock, flags); /* don't submit to a dead HC */ - if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + if (!HCD_HW_ACCESSIBLE(hcd)) { retval = -ENODEV; goto fail; } - if (!HC_IS_RUNNING(hcd->state)) { + if (ohci->rh_state != OHCI_RH_RUNNING) { retval = -ENODEV; goto fail; } @@ -221,13 +210,47 @@ static int ohci_urb_enqueue ( frame &= ~(ed->interval - 1); frame |= ed->branch; urb->start_frame = frame; - - /* yes, only URB_ISO_ASAP is supported, and - * urb->start_frame is never used as input. + ed->last_iso = frame + ed->interval * (size - 1); + } + } else if (ed->type == PIPE_ISOCHRONOUS) { + u16 next = ohci_frame_no(ohci) + 1; + u16 frame = ed->last_iso + ed->interval; + u16 length = ed->interval * (size - 1); + + /* Behind the scheduling threshold? */ + if (unlikely(tick_before(frame, next))) { + + /* URB_ISO_ASAP: Round up to the first available slot */ + if (urb->transfer_flags & URB_ISO_ASAP) { + frame += (next - frame + ed->interval - 1) & + -ed->interval; + + /* + * Not ASAP: Use the next slot in the stream, + * no matter what. */ + } else { + /* + * Some OHCI hardware doesn't handle late TDs + * correctly. After retiring them it proceeds + * to the next ED instead of the next TD. + * Therefore we have to omit the late TDs + * entirely. + */ + urb_priv->td_cnt = DIV_ROUND_UP( + (u16) (next - frame), + ed->interval); + if (urb_priv->td_cnt >= urb_priv->length) { + ++urb_priv->td_cnt; /* Mark it */ + ohci_dbg(ohci, "iso underrun %p (%u+%u < %u)\n", + urb, frame, length, + next); + } + } } - } else if (ed->type == PIPE_ISOCHRONOUS) - urb->start_frame = ed->last_iso + ed->interval; + urb->start_frame = frame; + ed->last_iso = frame + length; + } /* fill the TDs and link them to the ed; and * enable that part of the schedule, if needed @@ -255,15 +278,11 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) unsigned long flags; int rc; -#ifdef OHCI_VERBOSE_DEBUG - urb_print(urb, "UNLINK", 1, status); -#endif - spin_lock_irqsave (&ohci->lock, flags); rc = usb_hcd_check_unlink_urb(hcd, urb, status); if (rc) { ; /* Do nothing */ - } else if (HC_IS_RUNNING(hcd->state)) { + } else if (ohci->rh_state == OHCI_RH_RUNNING) { urb_priv_t *urb_priv; /* Unless an IRQ completed the unlink while it was being @@ -310,7 +329,7 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) rescan: spin_lock_irqsave (&ohci->lock, flags); - if (!HC_IS_RUNNING (hcd->state)) { + if (ohci->rh_state != OHCI_RH_RUNNING) { sanitize: ed->state = ED_IDLE; if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) @@ -352,7 +371,6 @@ sanitize: } ep->hcpriv = NULL; spin_unlock_irqrestore (&ohci->lock, flags); - return; } static int ohci_get_frame (struct usb_hcd *hcd) @@ -367,6 +385,7 @@ static void ohci_usb_reset (struct ohci_hcd *ohci) ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); ohci->hc_control &= OHCI_CTRL_RWC; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); + ohci->rh_state = OHCI_RH_HALTED; } /* ohci_shutdown forcibly disables IRQs and DMA, helping kexec and @@ -379,10 +398,14 @@ ohci_shutdown (struct usb_hcd *hcd) struct ohci_hcd *ohci; ohci = hcd_to_ohci (hcd); - ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - ohci_usb_reset (ohci); - /* flush the writes */ - (void) ohci_readl (ohci, &ohci->regs->control); + ohci_writel(ohci, (u32) ~0, &ohci->regs->intrdisable); + + /* Software reset, after which the controller goes into SUSPEND */ + ohci_writel(ohci, OHCI_HCR, &ohci->regs->cmdstatus); + ohci_readl(ohci, &ohci->regs->cmdstatus); /* flush the writes */ + udelay(10); + + ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval); } static int check_ed(struct ohci_hcd *ohci, struct ed *ed) @@ -483,7 +506,10 @@ static int ohci_init (struct ohci_hcd *ohci) int ret; struct usb_hcd *hcd = ohci_to_hcd(ohci); - disable (ohci); + if (distrust_firmware) + ohci->flags |= OHCI_QUIRK_HUB_POWER; + + ohci->rh_state = OHCI_RH_HALTED; ohci->regs = hcd->regs; /* REVISIT this BIOS handshake is now moved into PCI "quirks", and @@ -554,17 +580,17 @@ static int ohci_init (struct ohci_hcd *ohci) */ static int ohci_run (struct ohci_hcd *ohci) { - u32 mask, temp; + u32 mask, val; int first = ohci->fminterval == 0; struct usb_hcd *hcd = ohci_to_hcd(ohci); - disable (ohci); + ohci->rh_state = OHCI_RH_HALTED; /* boot firmware should have set this up (5.1.1.3.1) */ if (first) { - temp = ohci_readl (ohci, &ohci->regs->fminterval); - ohci->fminterval = temp & 0x3fff; + val = ohci_readl (ohci, &ohci->regs->fminterval); + ohci->fminterval = val & 0x3fff; if (ohci->fminterval != FI) ohci_dbg (ohci, "fminterval delta %d\n", ohci->fminterval - FI); @@ -572,36 +598,36 @@ static int ohci_run (struct ohci_hcd *ohci) /* also: power/overcurrent flags in roothub.a */ } - /* Reset USB nearly "by the book". RemoteWakeupConnected was - * saved if boot firmware (BIOS/SMM/...) told us it's connected, - * or if bus glue did the same (e.g. for PCI add-in cards with - * PCI PM support). + /* Reset USB nearly "by the book". RemoteWakeupConnected has + * to be checked in case boot firmware (BIOS/SMM/...) has set up + * wakeup in a way the bus isn't aware of (e.g., legacy PCI PM). + * If the bus glue detected wakeup capability then it should + * already be enabled; if so we'll just enable it again. */ - if ((ohci->hc_control & OHCI_CTRL_RWC) != 0 - && !device_may_wakeup(hcd->self.controller)) - device_init_wakeup(hcd->self.controller, 1); + if ((ohci->hc_control & OHCI_CTRL_RWC) != 0) + device_set_wakeup_capable(hcd->self.controller, 1); switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_OPER: - temp = 0; + val = 0; break; case OHCI_USB_SUSPEND: case OHCI_USB_RESUME: ohci->hc_control &= OHCI_CTRL_RWC; ohci->hc_control |= OHCI_USB_RESUME; - temp = 10 /* msec wait */; + val = 10 /* msec wait */; break; // case OHCI_USB_RESET: default: ohci->hc_control &= OHCI_CTRL_RWC; ohci->hc_control |= OHCI_USB_RESET; - temp = 50 /* msec wait */; + val = 50 /* msec wait */; break; } ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); // flush the writes (void) ohci_readl (ohci, &ohci->regs->control); - msleep(temp); + msleep(val); memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); @@ -611,9 +637,9 @@ static int ohci_run (struct ohci_hcd *ohci) retry: /* HC Reset requires max 10 us delay */ ohci_writel (ohci, OHCI_HCR, &ohci->regs->cmdstatus); - temp = 30; /* ... allow extra time */ + val = 30; /* ... allow extra time */ while ((ohci_readl (ohci, &ohci->regs->cmdstatus) & OHCI_HCR) != 0) { - if (--temp == 0) { + if (--val == 0) { spin_unlock_irq (&ohci->lock); ohci_err (ohci, "USB HC reset timed out!\n"); return -1; @@ -664,14 +690,14 @@ retry: } /* use rhsc irqs after khubd is fully initialized */ - hcd->poll_rh = 1; + set_bit(HCD_FLAG_POLL_RH, &hcd->flags); hcd->uses_new_polling = 1; /* start controller operations */ ohci->hc_control &= OHCI_CTRL_RWC; ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - hcd->state = HC_STATE_RUNNING; + ohci->rh_state = OHCI_RH_RUNNING; /* wake on ConnectStatusChange, matching external hubs */ ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status); @@ -682,22 +708,23 @@ retry: ohci_writel (ohci, mask, &ohci->regs->intrenable); /* handle root hub init quirks ... */ - temp = roothub_a (ohci); - temp &= ~(RH_A_PSM | RH_A_OCPM); + val = roothub_a (ohci); + val &= ~(RH_A_PSM | RH_A_OCPM); if (ohci->flags & OHCI_QUIRK_SUPERIO) { /* NSC 87560 and maybe others */ - temp |= RH_A_NOCP; - temp &= ~(RH_A_POTPGT | RH_A_NPS); - ohci_writel (ohci, temp, &ohci->regs->roothub.a); - } else if ((ohci->flags & OHCI_QUIRK_AMD756) || distrust_firmware) { + val |= RH_A_NOCP; + val &= ~(RH_A_POTPGT | RH_A_NPS); + ohci_writel (ohci, val, &ohci->regs->roothub.a); + } else if ((ohci->flags & OHCI_QUIRK_AMD756) || + (ohci->flags & OHCI_QUIRK_HUB_POWER)) { /* hub power always on; required for AMD-756 and some * Mac platforms. ganged overcurrent reporting, if any. */ - temp |= RH_A_NPS; - ohci_writel (ohci, temp, &ohci->regs->roothub.a); + val |= RH_A_NPS; + ohci_writel (ohci, val, &ohci->regs->roothub.a); } ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status); - ohci_writel (ohci, (temp & RH_A_NPS) ? 0 : RH_B_PPCM, + ohci_writel (ohci, (val & RH_A_NPS) ? 0 : RH_B_PPCM, &ohci->regs->roothub.b); // flush those writes (void) ohci_readl (ohci, &ohci->regs->control); @@ -706,8 +733,7 @@ retry: spin_unlock_irq (&ohci->lock); // POTPGT delay is bits 24-31, in 2 ms units. - mdelay ((temp >> 23) & 0x1fe); - hcd->state = HC_STATE_RUNNING; + mdelay ((val >> 23) & 0x1fe); if (quirk_zfmicro(ohci)) { /* Create timer to watch for bad queue state on ZF Micro */ @@ -723,6 +749,32 @@ retry: return 0; } +/* ohci_setup routine for generic controller initialization */ + +int ohci_setup(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + ohci_hcd_init(ohci); + + return ohci_init(ohci); +} +EXPORT_SYMBOL_GPL(ohci_setup); + +/* ohci_start routine for generic controller start of all OHCI bus glue */ +static int ohci_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + ret = ohci_run(ohci); + if (ret < 0) { + ohci_err(ohci, "can't start\n"); + ohci_stop(hcd); + } + return ret; +} + /*-------------------------------------------------------------------------*/ /* an interrupt happens */ @@ -743,8 +795,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) * of dead, unclocked, or unplugged (CardBus...) devices */ if (ints == ~(u32)0) { - disable (ohci); + ohci->rh_state = OHCI_RH_HALTED; ohci_dbg (ohci, "device removed!\n"); + usb_hc_died(hcd); return IRQ_HANDLED; } @@ -752,7 +805,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) ints &= ohci_readl(ohci, ®s->intrenable); /* interrupt for some other device? */ - if (ints == 0) + if (ints == 0 || unlikely(ohci->rh_state == OHCI_RH_HALTED)) return IRQ_NOTMINE; if (ints & OHCI_INTR_UE) { @@ -767,8 +820,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) schedule_work (&ohci->nec_work); } else { - disable (ohci); ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n"); + ohci->rh_state = OHCI_RH_HALTED; + usb_hc_died(hcd); } ohci_dump (ohci, 1); @@ -776,7 +830,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) } if (ints & OHCI_INTR_RHSC) { - ohci_vdbg(ohci, "rhsc\n"); + ohci_dbg(ohci, "rhsc\n"); ohci->next_statechange = jiffies + STATECHANGE_DELAY; ohci_writel(ohci, OHCI_INTR_RD | OHCI_INTR_RHSC, ®s->intrstatus); @@ -798,9 +852,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) * this might not happen. */ else if (ints & OHCI_INTR_RD) { - ohci_vdbg(ohci, "resume detect\n"); + ohci_dbg(ohci, "resume detect\n"); ohci_writel(ohci, OHCI_INTR_RD, ®s->intrstatus); - hcd->poll_rh = 1; + set_bit(HCD_FLAG_POLL_RH, &hcd->flags); if (ohci->autostop) { spin_lock (&ohci->lock); ohci_rh_resume (ohci); @@ -851,11 +905,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list && !ohci->ed_to_check - && HC_IS_RUNNING(hcd->state)) + && ohci->rh_state == OHCI_RH_RUNNING) ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); spin_unlock (&ohci->lock); - if (HC_IS_RUNNING(hcd->state)) { + if (ohci->rh_state == OHCI_RH_RUNNING) { ohci_writel (ohci, ints, ®s->intrstatus); ohci_writel (ohci, OHCI_INTR_MIE, ®s->intrenable); // flush those writes @@ -873,15 +927,18 @@ static void ohci_stop (struct usb_hcd *hcd) ohci_dump (ohci, 1); - flush_scheduled_work(); + if (quirk_nec(ohci)) + flush_work(&ohci->nec_work); - ohci_usb_reset (ohci); ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + ohci_usb_reset(ohci); free_irq(hcd->irq, hcd); - hcd->irq = -1; + hcd->irq = 0; if (quirk_zfmicro(ohci)) del_timer(&ohci->unlink_watchdog); + if (quirk_amdiso(ohci)) + usb_amd_dev_put(); remove_debug_files (ohci); ohci_mem_cleanup (ohci); @@ -899,14 +956,15 @@ static void ohci_stop (struct usb_hcd *hcd) #if defined(CONFIG_PM) || defined(CONFIG_PCI) /* must not be called from interrupt context */ -static int ohci_restart (struct ohci_hcd *ohci) +int ohci_restart(struct ohci_hcd *ohci) { int temp; int i; struct urb_priv *priv; + ohci_init(ohci); spin_lock_irq(&ohci->lock); - disable (ohci); + ohci->rh_state = OHCI_RH_HALTED; /* Recycle any "live" eds/tds (and urbs). */ if (!list_empty (&ohci->pending)) @@ -958,84 +1016,172 @@ static int ohci_restart (struct ohci_hcd *ohci) ohci_dbg(ohci, "restart complete\n"); return 0; } +EXPORT_SYMBOL_GPL(ohci_restart); #endif -/*-------------------------------------------------------------------------*/ +#ifdef CONFIG_PM -#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC +int ohci_suspend(struct usb_hcd *hcd, bool do_wakeup) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + unsigned long flags; + int rc = 0; -MODULE_AUTHOR (DRIVER_AUTHOR); -MODULE_DESCRIPTION (DRIVER_INFO); -MODULE_LICENSE ("GPL"); + /* Disable irq emission and mark HW unaccessible. Use + * the spinlock to properly synchronize with possible pending + * RH suspend or resume activity. + */ + spin_lock_irqsave (&ohci->lock, flags); + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + (void)ohci_readl(ohci, &ohci->regs->intrdisable); -#ifdef CONFIG_PCI -#include "ohci-pci.c" -#define PCI_DRIVER ohci_pci_driver -#endif + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + spin_unlock_irqrestore (&ohci->lock, flags); -#ifdef CONFIG_SA1111 -#include "ohci-sa1111.c" -#define SA1111_DRIVER ohci_hcd_sa1111_driver -#endif + synchronize_irq(hcd->irq); -#ifdef CONFIG_ARCH_S3C2410 -#include "ohci-s3c2410.c" -#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver -#endif + if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) { + ohci_resume(hcd, false); + rc = -EBUSY; + } + return rc; +} +EXPORT_SYMBOL_GPL(ohci_suspend); -#ifdef CONFIG_ARCH_OMAP -#include "ohci-omap.c" -#define PLATFORM_DRIVER ohci_hcd_omap_driver -#endif -#ifdef CONFIG_ARCH_LH7A404 -#include "ohci-lh7a404.c" -#define PLATFORM_DRIVER ohci_hcd_lh7a404_driver -#endif +int ohci_resume(struct usb_hcd *hcd, bool hibernated) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int port; + bool need_reinit = false; -#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) -#include "ohci-pxa27x.c" -#define PLATFORM_DRIVER ohci_hcd_pxa27x_driver -#endif + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); -#ifdef CONFIG_ARCH_EP93XX -#include "ohci-ep93xx.c" -#define PLATFORM_DRIVER ohci_hcd_ep93xx_driver -#endif + /* Make sure resume from hibernation re-enumerates everything */ + if (hibernated) + ohci_usb_reset(ohci); -#ifdef CONFIG_SOC_AU1X00 -#include "ohci-au1xxx.c" -#define PLATFORM_DRIVER ohci_hcd_au1xxx_driver -#endif + /* See if the controller is already running or has been reset */ + ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); + if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { + need_reinit = true; + } else { + switch (ohci->hc_control & OHCI_CTRL_HCFS) { + case OHCI_USB_OPER: + case OHCI_USB_RESET: + need_reinit = true; + } + } -#ifdef CONFIG_PNX8550 -#include "ohci-pnx8550.c" -#define PLATFORM_DRIVER ohci_hcd_pnx8550_driver -#endif + /* If needed, reinitialize and suspend the root hub */ + if (need_reinit) { + spin_lock_irq(&ohci->lock); + ohci_rh_resume(ohci); + ohci_rh_suspend(ohci, 0); + spin_unlock_irq(&ohci->lock); + } -#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC -#include "ohci-ppc-soc.c" -#define PLATFORM_DRIVER ohci_hcd_ppc_soc_driver -#endif + /* Normally just turn on port power and enable interrupts */ + else { + ohci_dbg(ohci, "powerup ports\n"); + for (port = 0; port < ohci->num_ports; port++) + ohci_writel(ohci, RH_PS_PPS, + &ohci->regs->roothub.portstatus[port]); + + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrenable); + ohci_readl(ohci, &ohci->regs->intrenable); + msleep(20); + } + + usb_hcd_resume_root_hub(hcd); + + return 0; +} +EXPORT_SYMBOL_GPL(ohci_resume); -#ifdef CONFIG_ARCH_AT91 -#include "ohci-at91.c" -#define PLATFORM_DRIVER ohci_hcd_at91_driver #endif -#ifdef CONFIG_ARCH_PNX4008 -#include "ohci-pnx4008.c" -#define PLATFORM_DRIVER usb_hcd_pnx4008_driver +/*-------------------------------------------------------------------------*/ + +/* + * Generic structure: This gets copied for platform drivers so that + * individual entries can be overridden as needed. + */ + +static const struct hc_driver ohci_hc_driver = { + .description = hcd_name, + .product_desc = "OHCI Host Controller", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_MEMORY | HCD_USB11, + + /* + * basic lifecycle operations + */ + .reset = ohci_setup, + .start = ohci_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif + .start_port_reset = ohci_start_port_reset, +}; + +void ohci_init_driver(struct hc_driver *drv, + const struct ohci_driver_overrides *over) +{ + /* Copy the generic table to drv and then apply the overrides */ + *drv = ohci_hc_driver; + + if (over) { + drv->product_desc = over->product_desc; + drv->hcd_priv_size += over->extra_priv_size; + if (over->reset) + drv->reset = over->reset; + } +} +EXPORT_SYMBOL_GPL(ohci_init_driver); -#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \ - defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_CPU_SUBTYPE_SH7763) -#include "ohci-sh.c" -#define PLATFORM_DRIVER ohci_hcd_sh_driver +/*-------------------------------------------------------------------------*/ + +MODULE_AUTHOR (DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE ("GPL"); + +#if defined(CONFIG_ARCH_SA1100) && defined(CONFIG_SA1111) +#include "ohci-sa1111.c" +#define SA1111_DRIVER ohci_hcd_sa1111_driver #endif +#ifdef CONFIG_USB_OHCI_HCD_DAVINCI +#include "ohci-da8xx.c" +#define DAVINCI_PLATFORM_DRIVER ohci_hcd_da8xx_driver +#endif #ifdef CONFIG_USB_OHCI_HCD_PPC_OF #include "ohci-ppc-of.c" @@ -1047,23 +1193,29 @@ MODULE_LICENSE ("GPL"); #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver #endif -#ifdef CONFIG_USB_OHCI_HCD_SSB -#include "ohci-ssb.c" -#define SSB_OHCI_DRIVER ssb_ohci_driver -#endif - #ifdef CONFIG_MFD_SM501 #include "ohci-sm501.c" -#define PLATFORM_DRIVER ohci_hcd_sm501_driver +#define SM501_OHCI_DRIVER ohci_hcd_sm501_driver +#endif + +#ifdef CONFIG_MFD_TC6393XB +#include "ohci-tmio.c" +#define TMIO_OHCI_DRIVER ohci_hcd_tmio_driver +#endif + +#ifdef CONFIG_MACH_JZ4740 +#include "ohci-jz4740.c" +#define PLATFORM_DRIVER ohci_hcd_jz4740_driver #endif -#if !defined(PCI_DRIVER) && \ - !defined(PLATFORM_DRIVER) && \ - !defined(OF_PLATFORM_DRIVER) && \ - !defined(SA1111_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) && \ - !defined(SSB_OHCI_DRIVER) -#error "missing bus glue for ohci-hcd" +#ifdef CONFIG_USB_OCTEON_OHCI +#include "ohci-octeon.c" +#define PLATFORM_DRIVER ohci_octeon_driver +#endif + +#ifdef CONFIG_TILE_USB +#include "ohci-tilegx.c" +#define PLATFORM_DRIVER ohci_hcd_tilegx_driver #endif static int __init ohci_hcd_mod_init(void) @@ -1073,17 +1225,16 @@ static int __init ohci_hcd_mod_init(void) if (usb_disabled()) return -ENODEV; - printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name); + printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name); pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, sizeof (struct ed), sizeof (struct td)); + set_bit(USB_OHCI_LOADED, &usb_hcds_loaded); -#ifdef DEBUG - ohci_debug_root = debugfs_create_dir("ohci", NULL); + ohci_debug_root = debugfs_create_dir("ohci", usb_debug_root); if (!ohci_debug_root) { retval = -ENOENT; goto error_debug; } -#endif #ifdef PS3_SYSTEM_BUS_DRIVER retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER); @@ -1098,7 +1249,7 @@ static int __init ohci_hcd_mod_init(void) #endif #ifdef OF_PLATFORM_DRIVER - retval = of_register_platform_driver(&OF_PLATFORM_DRIVER); + retval = platform_driver_register(&OF_PLATFORM_DRIVER); if (retval < 0) goto error_of_platform; #endif @@ -1109,34 +1260,45 @@ static int __init ohci_hcd_mod_init(void) goto error_sa1111; #endif -#ifdef PCI_DRIVER - retval = pci_register_driver(&PCI_DRIVER); +#ifdef SM501_OHCI_DRIVER + retval = platform_driver_register(&SM501_OHCI_DRIVER); if (retval < 0) - goto error_pci; + goto error_sm501; #endif -#ifdef SSB_OHCI_DRIVER - retval = ssb_driver_register(&SSB_OHCI_DRIVER); - if (retval) - goto error_ssb; +#ifdef TMIO_OHCI_DRIVER + retval = platform_driver_register(&TMIO_OHCI_DRIVER); + if (retval < 0) + goto error_tmio; +#endif + +#ifdef DAVINCI_PLATFORM_DRIVER + retval = platform_driver_register(&DAVINCI_PLATFORM_DRIVER); + if (retval < 0) + goto error_davinci; #endif return retval; /* Error path */ -#ifdef SSB_OHCI_DRIVER - error_ssb: +#ifdef DAVINCI_PLATFORM_DRIVER + platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER); + error_davinci: +#endif +#ifdef TMIO_OHCI_DRIVER + platform_driver_unregister(&TMIO_OHCI_DRIVER); + error_tmio: #endif -#ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); - error_pci: +#ifdef SM501_OHCI_DRIVER + platform_driver_unregister(&SM501_OHCI_DRIVER); + error_sm501: #endif #ifdef SA1111_DRIVER sa1111_driver_unregister(&SA1111_DRIVER); error_sa1111: #endif #ifdef OF_PLATFORM_DRIVER - of_unregister_platform_driver(&OF_PLATFORM_DRIVER); + platform_driver_unregister(&OF_PLATFORM_DRIVER); error_of_platform: #endif #ifdef PLATFORM_DRIVER @@ -1147,29 +1309,31 @@ static int __init ohci_hcd_mod_init(void) ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); error_ps3: #endif -#ifdef DEBUG debugfs_remove(ohci_debug_root); ohci_debug_root = NULL; error_debug: -#endif + clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded); return retval; } module_init(ohci_hcd_mod_init); static void __exit ohci_hcd_mod_exit(void) { -#ifdef SSB_OHCI_DRIVER - ssb_driver_unregister(&SSB_OHCI_DRIVER); +#ifdef DAVINCI_PLATFORM_DRIVER + platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER); +#endif +#ifdef TMIO_OHCI_DRIVER + platform_driver_unregister(&TMIO_OHCI_DRIVER); #endif -#ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); +#ifdef SM501_OHCI_DRIVER + platform_driver_unregister(&SM501_OHCI_DRIVER); #endif #ifdef SA1111_DRIVER sa1111_driver_unregister(&SA1111_DRIVER); #endif #ifdef OF_PLATFORM_DRIVER - of_unregister_platform_driver(&OF_PLATFORM_DRIVER); + platform_driver_unregister(&OF_PLATFORM_DRIVER); #endif #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); @@ -1177,9 +1341,8 @@ static void __exit ohci_hcd_mod_exit(void) #ifdef PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif -#ifdef DEBUG debugfs_remove(ohci_debug_root); -#endif + clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded); } module_exit(ohci_hcd_mod_exit); |
