diff options
Diffstat (limited to 'drivers/usb/host/ohci-hcd.c')
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 58 |
1 files changed, 25 insertions, 33 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 1e27f10c159..13cd2177b55 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -95,12 +95,11 @@ #include <linux/init.h> #include <linux/timer.h> #include <linux/list.h> -#include <linux/interrupt.h> /* for in_interrupt () */ #include <linux/usb.h> #include <linux/usb_otg.h> -#include "../core/hcd.h" #include <linux/dma-mapping.h> -#include <linux/dmapool.h> /* needed by ohci-mem.c when no PCI */ +#include <linux/dmapool.h> +#include <linux/reboot.h> #include <asm/io.h> #include <asm/irq.h> @@ -108,8 +107,9 @@ #include <asm/unaligned.h> #include <asm/byteorder.h> +#include "../core/hcd.h" -#define DRIVER_VERSION "2004 Nov 08" +#define DRIVER_VERSION "2005 April 22" #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" @@ -141,6 +141,7 @@ static const char hcd_name [] = "ohci_hcd"; 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); +static int ohci_reboot (struct notifier_block *, unsigned long , void *); #include "ohci-hub.c" #include "ohci-dbg.c" @@ -420,6 +421,23 @@ static void ohci_usb_reset (struct ohci_hcd *ohci) ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); } +/* reboot notifier forcibly disables IRQs and DMA, helping kexec and + * other cases where the next software may expect clean state from the + * "firmware". this is bus-neutral, unlike shutdown() methods. + */ +static int +ohci_reboot (struct notifier_block *block, unsigned long code, void *null) +{ + struct ohci_hcd *ohci; + + ohci = container_of (block, struct ohci_hcd, reboot_notifier); + ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + ohci_usb_reset (ohci); + /* flush the writes */ + (void) ohci_readl (ohci, &ohci->regs->control); + return 0; +} + /*-------------------------------------------------------------------------* * HC functions *-------------------------------------------------------------------------*/ @@ -487,13 +505,10 @@ static int ohci_init (struct ohci_hcd *ohci) /* Start an OHCI controller, set the BUS operational * resets USB and controller * enable interrupts - * connect the virtual root hub */ static int ohci_run (struct ohci_hcd *ohci) { u32 mask, temp; - struct usb_device *udev; - struct usb_bus *bus; int first = ohci->fminterval == 0; disable (ohci); @@ -654,37 +669,13 @@ retry: // POTPGT delay is bits 24-31, in 2 ms units. mdelay ((temp >> 23) & 0x1fe); - bus = &ohci_to_hcd(ohci)->self; ohci_to_hcd(ohci)->state = HC_STATE_RUNNING; ohci_dump (ohci, 1); - udev = bus->root_hub; - if (udev) { - return 0; - } - - /* connect the virtual root hub */ - udev = usb_alloc_dev (NULL, bus, 0); - if (!udev) { - disable (ohci); - ohci->hc_control &= ~OHCI_CTRL_HCFS; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - return -ENOMEM; - } - - udev->speed = USB_SPEED_FULL; - if (usb_hcd_register_root_hub (udev, ohci_to_hcd(ohci)) != 0) { - usb_put_dev (udev); - disable (ohci); - ohci->hc_control &= ~OHCI_CTRL_HCFS; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - return -ENODEV; - } - if (ohci->power_budget) - hub_set_power_budget(udev, ohci->power_budget); + if (ohci_to_hcd(ohci)->self.root_hub == NULL) + create_debug_files (ohci); - create_debug_files (ohci); return 0; } @@ -781,6 +772,7 @@ static void ohci_stop (struct usb_hcd *hcd) ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); remove_debug_files (ohci); + unregister_reboot_notifier (&ohci->reboot_notifier); ohci_mem_cleanup (ohci); if (ohci->hcca) { dma_free_coherent (hcd->self.controller, |