diff options
| -rw-r--r-- | drivers/usb/Config.in | 8 | ||||
| -rw-r--r-- | drivers/usb/Makefile | 2 | ||||
| -rw-r--r-- | drivers/usb/host/Config.in | 1 | ||||
| -rw-r--r-- | drivers/usb/host/Makefile | 5 | ||||
| -rw-r--r-- | drivers/usb/host/usb-ohci-pci.c | 445 | ||||
| -rw-r--r-- | drivers/usb/host/usb-ohci-sa1111.c | 130 | ||||
| -rw-r--r-- | drivers/usb/host/usb-ohci.c | 478 | ||||
| -rw-r--r-- | drivers/usb/host/usb-ohci.h | 15 | ||||
| -rw-r--r-- | drivers/usb/storage/freecom.c | 133 | ||||
| -rw-r--r-- | drivers/usb/storage/scsiglue.c | 6 | ||||
| -rw-r--r-- | drivers/usb/storage/transport.c | 81 |
11 files changed, 714 insertions, 590 deletions
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index a65593c97aeb..ba75a67a2d75 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -4,7 +4,13 @@ mainmenu_option next_comment comment 'USB support' -dep_tristate 'Support for USB' CONFIG_USB $CONFIG_PCI +# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. +if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SA1111" = "y" ]; then + tristate 'Support for USB' CONFIG_USB +else + define_bool CONFIG_USB n +fi + if [ "$CONFIG_USB" = "y" -o "$CONFIG_USB" = "m" ]; then source drivers/usb/core/Config.in diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index d1fe96b74c97..2965c6ca6965 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -6,9 +6,11 @@ mod-subdirs := serial obj-$(CONFIG_USB) += core/ + obj-$(CONFIG_USB_EHCI_HCD) += host/ obj-$(CONFIG_USB_OHCI_HCD) += host/ obj-$(CONFIG_USB_OHCI) += host/ +obj-$(CONFIG_USB_OHCI_SA1111) += host/ obj-$(CONFIG_USB_SL811HS) += host/ obj-$(CONFIG_USB_UHCI_ALT) += host/ obj-$(CONFIG_USB_UHCI_HCD_ALT) += host/ diff --git a/drivers/usb/host/Config.in b/drivers/usb/host/Config.in index 2afce8e137d8..806495da5726 100644 --- a/drivers/usb/host/Config.in +++ b/drivers/usb/host/Config.in @@ -20,5 +20,6 @@ fi #fi #dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB if [ "$CONFIG_ARM" = "y" ]; then + dep_tristate ' SA1111 OHCI-compatible host interface support' CONFIG_USB_OHCI_SA1111 $CONFIG_USB dep_tristate ' SL811HS support' CONFIG_USB_SL811HS $CONFIG_USB fi diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 4eb4a16e123f..459006376b9c 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -3,6 +3,8 @@ # framework and drivers # +export-objs := usb-ohci.o + obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o obj-$(CONFIG_USB_UHCI_HCD) += usb-uhci-hcd.o @@ -10,7 +12,8 @@ obj-$(CONFIG_USB_UHCI_HCD_ALT) += uhci-hcd.o obj-$(CONFIG_USB_UHCI) += usb-uhci.o obj-$(CONFIG_USB_UHCI_ALT) += uhci.o -obj-$(CONFIG_USB_OHCI) += usb-ohci.o +obj-$(CONFIG_USB_OHCI) += usb-ohci.o usb-ohci-pci.o +obj-$(CONFIG_USB_OHCI_SA1111) += usb-ohci.o usb-ohci-sa1111.o obj-$(CONFIG_USB_SL811HS) += hc_sl811.o include $(TOPDIR)/Rules.make diff --git a/drivers/usb/host/usb-ohci-pci.c b/drivers/usb/host/usb-ohci-pci.c new file mode 100644 index 000000000000..508d7f689480 --- /dev/null +++ b/drivers/usb/host/usb-ohci-pci.c @@ -0,0 +1,445 @@ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/interrupt.h> /* for in_interrupt() */ +#undef DEBUG +#include <linux/usb.h> + +#include "../core/hcd.h" +#include "usb-ohci.h" + +#ifdef CONFIG_PMAC_PBOOK +#include <asm/machdep.h> +#include <asm/pmac_feature.h> +#include <asm/pci-bridge.h> +#ifndef CONFIG_PM +#define CONFIG_PM +#endif +#endif + + +/*-------------------------------------------------------------------------*/ + +/* Increment the module usage count, start the control thread and + * return success. */ + +static struct pci_driver ohci_pci_driver; + +static int __devinit +hc_found_ohci (struct pci_dev *dev, int irq, + void *mem_base, const struct pci_device_id *id) +{ + u8 latency, limit; + ohci_t * ohci; + int ret; + + printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name); + + /* bad pci latencies can contribute to overruns */ + pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); + if (latency) { + pci_read_config_byte (dev, PCI_MAX_LAT, &limit); + if (limit && limit < latency) { + dbg ("PCI latency reduced to max %d", limit); + pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit); + latency = limit; + } + } + + ret = hc_add_ohci(dev, irq, mem_base, id->driver_data, + &ohci, ohci_pci_driver.name, dev->slot_name); + + if (ret == 0) { + ohci->pci_latency = latency; + + if (hc_start (ohci, &ohci->ohci_dev->dev) < 0) { + err ("can't start usb-%s", ohci->slot_name); + hc_remove_ohci(ohci); + return -EBUSY; + } + +#ifdef DEBUG + ohci_dump (ohci, 1); +#endif + } + + return ret; +} + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_PM + +/* controller died; cleanup debris, then restart */ +/* must not be called from interrupt context */ + +static void hc_restart (ohci_t *ohci) +{ + int temp; + int i; + + if (ohci->pci_latency) + pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency); + + ohci->disabled = 1; + ohci->sleeping = 0; + if (ohci->bus->root_hub) + usb_disconnect (&ohci->bus->root_hub); + + /* empty the interrupt branches */ + for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0; + for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table[i] = 0; + + /* no EDs to remove */ + ohci->ed_rm_list [0] = NULL; + ohci->ed_rm_list [1] = NULL; + + /* empty control and bulk lists */ + ohci->ed_isotail = NULL; + ohci->ed_controltail = NULL; + ohci->ed_bulktail = NULL; + + if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) { + err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp); + } else + dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name); +} + +#endif /* CONFIG_PM */ + +/*-------------------------------------------------------------------------*/ + +/* configured so that an OHCI device is always provided */ +/* always called with process context; sleeping is OK */ + +static int __devinit +ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) +{ + unsigned long mem_resource, mem_len; + void *mem_base; + int status; + + if (pci_enable_device(dev) < 0) + return -ENODEV; + + if (!dev->irq) { + err("found OHCI device with no IRQ assigned. check BIOS settings!"); + pci_disable_device (dev); + return -ENODEV; + } + + /* we read its hardware registers as memory */ + mem_resource = pci_resource_start(dev, 0); + mem_len = pci_resource_len(dev, 0); + if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) { + dbg ("controller already in use"); + pci_disable_device (dev); + return -EBUSY; + } + + mem_base = ioremap_nocache (mem_resource, mem_len); + if (!mem_base) { + err("Error mapping OHCI memory"); + release_mem_region(mem_resource, mem_len); + pci_disable_device (dev); + return -EFAULT; + } + + /* controller writes into our memory */ + pci_set_master (dev); + + status = hc_found_ohci (dev, dev->irq, mem_base, id); + if (status < 0) { + iounmap (mem_base); + release_mem_region(mem_resource, mem_len); + pci_disable_device (dev); + } + return status; +} + +/*-------------------------------------------------------------------------*/ + +/* may be called from interrupt context [interface spec] */ +/* may be called without controller present */ +/* may be called with controller, bus, and devices active */ + +static void __devexit +ohci_pci_remove (struct pci_dev *dev) +{ + ohci_t *ohci = (ohci_t *) pci_get_drvdata(dev); + + dbg ("remove %s controller usb-%s%s%s", + hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), + dev->slot_name, + ohci->disabled ? " (disabled)" : "", + in_interrupt () ? " in interrupt" : "" + ); + + hc_remove_ohci(ohci); + + release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0)); +} + + +#ifdef CONFIG_PM + +/*-------------------------------------------------------------------------*/ + +static int +ohci_pci_suspend (struct pci_dev *dev, u32 state) +{ + ohci_t *ohci = (ohci_t *) pci_get_drvdata(dev); + unsigned long flags; + u16 cmd; + + if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) { + dbg ("can't suspend usb-%s (state is %s)", dev->slot_name, + hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS)); + return -EIO; + } + + /* act as if usb suspend can always be used */ + info ("USB suspend: usb-%s", dev->slot_name); + ohci->sleeping = 1; + + /* First stop processing */ + spin_lock_irqsave (&usb_ed_lock, flags); + ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE); + writel (ohci->hc_control, &ohci->regs->control); + writel (OHCI_INTR_SF, &ohci->regs->intrstatus); + (void) readl (&ohci->regs->intrstatus); + spin_unlock_irqrestore (&usb_ed_lock, flags); + + /* Wait a frame or two */ + mdelay(1); + if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF) + mdelay (1); + +#ifdef CONFIG_PMAC_PBOOK + if (_machine == _MACH_Pmac) + disable_irq (ohci->irq); + /* else, 2.4 assumes shared irqs -- don't disable */ +#endif + /* Enable remote wakeup */ + writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable); + + /* Suspend chip and let things settle down a bit */ + ohci->hc_control = OHCI_USB_SUSPEND; + writel (ohci->hc_control, &ohci->regs->control); + (void) readl (&ohci->regs->control); + mdelay (500); /* No schedule here ! */ + switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) { + case OHCI_USB_RESET: + dbg("Bus in reset phase ???"); + break; + case OHCI_USB_RESUME: + dbg("Bus in resume phase ???"); + break; + case OHCI_USB_OPER: + dbg("Bus in operational phase ???"); + break; + case OHCI_USB_SUSPEND: + dbg("Bus suspended"); + break; + } + /* In some rare situations, Apple's OHCI have happily trashed + * memory during sleep. We disable it's bus master bit during + * suspend + */ + pci_read_config_word (dev, PCI_COMMAND, &cmd); + cmd &= ~PCI_COMMAND_MASTER; + pci_write_config_word (dev, PCI_COMMAND, cmd); +#ifdef CONFIG_PMAC_PBOOK + { + struct device_node *of_node; + + /* Disable USB PAD & cell clock */ + of_node = pci_device_to_OF_node (ohci->ohci_dev); + if (of_node && _machine == _MACH_Pmac) + pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); + } +#endif + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static int +ohci_pci_resume (struct pci_dev *dev) +{ + ohci_t *ohci = (ohci_t *) pci_get_drvdata(dev); + int temp; + unsigned long flags; + + /* guard against multiple resumes */ + atomic_inc (&ohci->resume_count); + if (atomic_read (&ohci->resume_count) != 1) { + err ("concurrent PCI resumes for usb-%s", dev->slot_name); + atomic_dec (&ohci->resume_count); + return 0; + } + +#ifdef CONFIG_PMAC_PBOOK + { + struct device_node *of_node; + + /* Re-enable USB PAD & cell clock */ + of_node = pci_device_to_OF_node (ohci->ohci_dev); + if (of_node && _machine == _MACH_Pmac) + pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1); + } +#endif + + /* did we suspend, or were we powered off? */ + ohci->hc_control = readl (&ohci->regs->control); + temp = ohci->hc_control & OHCI_CTRL_HCFS; + +#ifdef DEBUG + /* the registers may look crazy here */ + ohci_dump_status (ohci); +#endif + + /* Re-enable bus mastering */ + pci_set_master(ohci->ohci_dev); + + switch (temp) { + + case OHCI_USB_RESET: // lost power + info ("USB restart: usb-%s", dev->slot_name); + hc_restart (ohci); + break; + + case OHCI_USB_SUSPEND: // host wakeup + case OHCI_USB_RESUME: // remote wakeup + info ("USB continue: usb-%s from %s wakeup", dev->slot_name, + (temp == OHCI_USB_SUSPEND) + ? "host" : "remote"); + ohci->hc_control = OHCI_USB_RESUME; + writel (ohci->hc_control, &ohci->regs->control); + (void) readl (&ohci->regs->control); + mdelay (20); /* no schedule here ! */ + /* Some controllers (lucent) need a longer delay here */ + mdelay (15); + temp = readl (&ohci->regs->control); + temp = ohci->hc_control & OHCI_CTRL_HCFS; + if (temp != OHCI_USB_RESUME) { + err ("controller usb-%s won't resume", dev->slot_name); + ohci->disabled = 1; + return -EIO; + } + + /* Some chips likes being resumed first */ + writel (OHCI_USB_OPER, &ohci->regs->control); + (void) readl (&ohci->regs->control); + mdelay (3); + + /* Then re-enable operations */ + spin_lock_irqsave (&usb_ed_lock, flags); + ohci->disabled = 0; + ohci->sleeping = 0; + ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; + if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) { + if (ohci->ed_controltail) + ohci->hc_control |= OHCI_CTRL_CLE; + if (ohci->ed_bulktail) + ohci->hc_control |= OHCI_CTRL_BLE; + } + writel (ohci->hc_control, &ohci->regs->control); + writel (OHCI_INTR_SF, &ohci->regs->intrstatus); + writel (OHCI_INTR_SF, &ohci->regs->intrenable); + /* Check for a pending done list */ + writel (OHCI_INTR_WDH, &ohci->regs->intrdisable); + (void) readl (&ohci->regs->intrdisable); + spin_unlock_irqrestore (&usb_ed_lock, flags); +#ifdef CONFIG_PMAC_PBOOK + if (_machine == _MACH_Pmac) + enable_irq (ohci->irq); +#endif + if (ohci->hcca->done_head) + dl_done_list (ohci, dl_reverse_done_list (ohci)); + writel (OHCI_INTR_WDH, &ohci->regs->intrenable); + writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ + writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ + break; + + default: + warn ("odd PCI resume for usb-%s", dev->slot_name); + } + + /* controller is operational, extra resumes are harmless */ + atomic_dec (&ohci->resume_count); + + return 0; +} + +#endif /* CONFIG_PM */ + + +/*-------------------------------------------------------------------------*/ + +static const struct pci_device_id __devinitdata ohci_pci_ids [] = { { + + /* + * AMD-756 [Viper] USB has a serious erratum when used with + * lowspeed devices like mice. + */ + vendor: 0x1022, + device: 0x740c, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + + driver_data: OHCI_QUIRK_AMD756, + +} , { + + /* handle any USB OHCI controller */ + class: ((PCI_CLASS_SERIAL_USB << 8) | 0x10), + class_mask: ~0, + + /* no matter who makes it */ + vendor: PCI_ANY_ID, + device: PCI_ANY_ID, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + + }, { /* end: all zeroes */ } +}; + +MODULE_DEVICE_TABLE (pci, ohci_pci_ids); + +static struct pci_driver ohci_pci_driver = { + name: "usb-ohci", + id_table: &ohci_pci_ids [0], + + probe: ohci_pci_probe, + remove: __devexit_p(ohci_pci_remove), + +#ifdef CONFIG_PM + suspend: ohci_pci_suspend, + resume: ohci_pci_resume, +#endif /* PM */ +}; + + +/*-------------------------------------------------------------------------*/ + +static int __init ohci_hcd_init (void) +{ + return pci_module_init (&ohci_pci_driver); +} + +/*-------------------------------------------------------------------------*/ + +static void __exit ohci_hcd_cleanup (void) +{ + pci_unregister_driver (&ohci_pci_driver); +} + +module_init (ohci_hcd_init); +module_exit (ohci_hcd_cleanup); + +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/usb-ohci-sa1111.c b/drivers/usb/host/usb-ohci-sa1111.c new file mode 100644 index 000000000000..ad3d00b07df3 --- /dev/null +++ b/drivers/usb/host/usb-ohci-sa1111.c @@ -0,0 +1,130 @@ +/* + * linux/drivers/usb/usb-ohci-sa1111.c + * + * The outline of this code was taken from Brad Parkers <brad@heeltoe.com> + * original OHCI driver modifications, and reworked into a cleaner form + * by Russell King <rmk@arm.linux.org.uk>. + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/errno.h> + +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/arch/assabet.h> +#include <asm/arch/badge4.h> +#include <asm/hardware/sa1111.h> + +#include "usb-ohci.h" + +int __devinit +hc_add_ohci(struct pci_dev *dev, int irq, void *membase, unsigned long flags, + ohci_t **ohci, const char *name, const char *slot_name); +extern void hc_remove_ohci(ohci_t *ohci); + +static ohci_t *sa1111_ohci; + +static void __init sa1111_ohci_configure(void) +{ + unsigned int usb_rst = 0; + + if (machine_is_xp860() || + machine_has_neponset() || + machine_is_pfs168() || + machine_is_badge4()) + usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW; + + /* + * Configure the power sense and control lines. Place the USB + * host controller in reset. + */ + USB_RESET = usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET; + + /* + * Now, carefully enable the USB clock, and take + * the USB host controller out of reset. + */ + SKPCR |= SKPCR_UCLKEN; + udelay(11); + USB_RESET = usb_rst; +} + +static int __init sa1111_ohci_init(void) +{ + int ret; + + if (!sa1111) + return -ENODEV; + + /* + * Request memory resources. + */ +// if (!request_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT, "usb-ohci")) +// return -EBUSY; + + sa1111_ohci_configure(); + + /* + * Initialise the generic OHCI driver. + */ + ret = hc_add_ohci((struct pci_dev *)1, NIRQHCIM, + (void *)&USB_OHCI_OP_BASE, 0, &sa1111_ohci, + "usb-ohci", "sa1111"); + + if (ret == 0) { + if (hc_start (sa1111_ohci, &sa1111->dev) < 0) { + err ("can't start usb-%s", sa1111_ohci->slot_name); + hc_remove_ohci (sa1111_ohci); + return -EBUSY; + } + +#ifdef DEBUG + ohci_dump (ohci, 1); +#endif +#ifdef CONFIG_SA1100_BADGE4 + if (machine_is_badge4()) { + /* found the controller, so now power the bus */ + badge4_set_5V(BADGE4_5V_USB, 1); + } +#endif + } +// else +// release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT); + + return ret; +} + +static void __exit sa1111_ohci_exit(void) +{ + hc_remove_ohci(sa1111_ohci); + + /* + * Put the USB host controller into reset. + */ + USB_RESET |= USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET; + + /* + * Stop the USB clock. + */ + SKPCR &= ~SKPCR_UCLKEN; + + /* + * Release memory resources. + */ +// release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT); + +#ifdef CONFIG_SA1100_BADGE4 + if (machine_is_badge4()) { + badge4_set_5V(BADGE4_5V_USB, 0); + } +#endif +} + +module_init(sa1111_ohci_init); +module_exit(sa1111_ohci_exit); diff --git a/drivers/usb/host/usb-ohci.c b/drivers/usb/host/usb-ohci.c index 6a95ef5f23aa..f291c0ba32c9 100644 --- a/drivers/usb/host/usb-ohci.c +++ b/drivers/usb/host/usb-ohci.c @@ -82,16 +82,6 @@ #include "usb-ohci.h" -#ifdef CONFIG_PMAC_PBOOK -#include <asm/machdep.h> -#include <asm/pmac_feature.h> -#include <asm/pci-bridge.h> -#ifndef CONFIG_PM -#define CONFIG_PM -#endif -#endif - - /* * Version Information */ @@ -99,14 +89,10 @@ #define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell" #define DRIVER_DESC "USB OHCI Host Controller Driver" -/* For initializing controller (mask in an HCFS mode too) */ -#define OHCI_CONTROL_INIT \ - (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE - #define OHCI_UNLINK_TIMEOUT (HZ / 10) static LIST_HEAD (ohci_hcd_list); -static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; +spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; /*-------------------------------------------------------------------------*/ @@ -443,7 +429,7 @@ static void ohci_dump_roothub (ohci_t *controller, int verbose) static void ohci_dump (ohci_t *controller, int verbose) { - dbg ("OHCI controller usb-%s state", controller->ohci_dev->slot_name); + dbg ("OHCI controller usb-%s state", controller->slot_name); // dumps some of the state we know about ohci_dump_status (controller); @@ -465,7 +451,7 @@ static void ohci_dump (ohci_t *controller, int verbose) static int sohci_return_urb (struct ohci *hc, struct urb * urb) { urb_priv_t * urb_priv = urb->hcpriv; - struct urb * urbt; + struct urb * urbt = NULL; unsigned long flags; int i; @@ -499,7 +485,7 @@ static int sohci_return_urb (struct ohci *hc, struct urb * urb) break; case PIPE_ISOCHRONOUS: - for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next); + // for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next); if (urbt) { /* send the reply and requeue URB */ pci_unmap_single (hc->ohci_dev, urb_priv->td [0]->data_dma, @@ -865,7 +851,7 @@ static int sohci_free_dev (struct usb_device * usb_dev) if (ed->state == ED_OPER) { /* driver on that interface didn't unlink an urb */ dbg ("driver usb-%s dev %d ed 0x%x unfreed URB", - ohci->ohci_dev->slot_name, usb_dev->devnum, i); + ohci->slot_name, usb_dev->devnum, i); ep_unlink (ohci, ed); } ep_rm_ed (usb_dev, ed); @@ -910,7 +896,7 @@ static int sohci_free_dev (struct usb_device * usb_dev) } else { /* likely some interface's driver has a refcount bug */ err ("bus %s devnum %d deletion in interrupt", - ohci->ohci_dev->slot_name, usb_dev->devnum); + ohci->slot_name, usb_dev->devnum); BUG (); } } @@ -1529,7 +1515,7 @@ static void dl_del_urb (struct urb * urb) /* replies to the request have to be on a FIFO basis so * we reverse the reversed done-list */ -static td_t * dl_reverse_done_list (ohci_t * ohci) +td_t * dl_reverse_done_list (ohci_t * ohci) { __u32 td_list_hc; td_t * td_rev = NULL; @@ -1677,7 +1663,7 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame) /* td done list */ -static void dl_done_list (ohci_t * ohci, td_t * td_list) +void dl_done_list (ohci_t * ohci, td_t * td_list) { td_t * td_list_next = NULL; ed_t * ed; @@ -1822,7 +1808,7 @@ static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len) num_ports = roothub_a (ohci) & RH_A_NDP; if (num_ports > MAX_ROOT_PORTS) { err ("bogus NDP=%d for OHCI usb-%s", num_ports, - ohci->ohci_dev->slot_name); + ohci->slot_name); err ("rereads as NDP=%d", readl (&ohci->regs->roothub.a) & RH_A_NDP); /* retry later; "should not happen" */ @@ -2148,7 +2134,7 @@ static int rh_unlink_urb (struct urb * urb) /* reset the HC and BUS */ -static int hc_reset (ohci_t * ohci) +int hc_reset (ohci_t * ohci) { int timeout = 30; int smm_timeout = 50; /* 0,5 sec */ @@ -2169,7 +2155,7 @@ static int hc_reset (ohci_t * ohci) writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); dbg("USB HC reset_hc usb-%s: ctrl = 0x%x ;", - ohci->ohci_dev->slot_name, + ohci->slot_name, readl (&ohci->regs->control)); /* Reset USB (needed by some controllers) */ @@ -2193,7 +2179,7 @@ static int hc_reset (ohci_t * ohci) * enable interrupts * connect the virtual root hub */ -static int hc_start (ohci_t * ohci) +int hc_start (ohci_t * ohci, struct device *parent_dev) { __u32 mask; unsigned int fminterval; @@ -2247,7 +2233,7 @@ static int hc_start (ohci_t * ohci) dev = usb_to_ohci (usb_dev); ohci->bus->root_hub = usb_dev; usb_connect (usb_dev); - if (usb_register_root_hub (usb_dev, &ohci->ohci_dev->dev) != 0) { + if (usb_register_root_hub (usb_dev, parent_dev) != 0) { usb_free_dev (usb_dev); ohci->disabled = 1; return -ENODEV; @@ -2308,7 +2294,7 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r) if (ints & OHCI_INTR_UE) { ohci->disabled++; err ("OHCI Unrecoverable Error, controller usb-%s disabled", - ohci->ohci_dev->slot_name); + ohci->slot_name); // e.g. due to PCI Master/Target Abort #ifdef DEBUG @@ -2385,7 +2371,9 @@ static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base) ohci->regs = mem_base; ohci->ohci_dev = dev; +#ifdef CONFIG_PCI pci_set_drvdata(dev, ohci); +#endif INIT_LIST_HEAD (&ohci->ohci_hcd_list); list_add (&ohci->ohci_hcd_list, &ohci_hcd_list); @@ -2394,7 +2382,9 @@ static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base) ohci->bus = usb_alloc_bus (&sohci_device_operations); if (!ohci->bus) { +#ifdef CONFIG_PCI pci_set_drvdata (dev, NULL); +#endif pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca, ohci->hcca, ohci->hcca_dma); kfree (ohci); @@ -2413,7 +2403,7 @@ static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base) static void hc_release_ohci (ohci_t * ohci) { - dbg ("USB HC release ohci usb-%s", ohci->ohci_dev->slot_name); + dbg ("USB HC release ohci usb-%s", ohci->slot_name); /* disconnect all devices */ if (ohci->bus->root_hub) @@ -2426,7 +2416,9 @@ static void hc_release_ohci (ohci_t * ohci) free_irq (ohci->irq, ohci); ohci->irq = -1; } +#ifdef CONFIG_PCI pci_set_drvdata(ohci->ohci_dev, NULL); +#endif if (ohci->bus) { if (ohci->bus->busnum) usb_deregister_bus (ohci->bus); @@ -2448,18 +2440,15 @@ static void hc_release_ohci (ohci_t * ohci) /*-------------------------------------------------------------------------*/ -/* Increment the module usage count, start the control thread and - * return success. */ - -static struct pci_driver ohci_pci_driver; - -static int __devinit -hc_found_ohci (struct pci_dev *dev, int irq, - void *mem_base, const struct pci_device_id *id) +/* + * Host bus independent add one OHCI host controller. + */ +int +hc_add_ohci(struct pci_dev *dev, int irq, void *mem_base, unsigned long flags, + ohci_t **ohcip, const char *name, const char *slot_name) { - ohci_t * ohci; - u8 latency, limit; char buf[8], *bufp = buf; + ohci_t * ohci; int ret; #ifndef __sparc__ @@ -2469,34 +2458,20 @@ hc_found_ohci (struct pci_dev *dev, int irq, #endif printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n", (unsigned long) mem_base, bufp); - printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name); ohci = hc_alloc_ohci (dev, mem_base); if (!ohci) { return -ENOMEM; } + ohci->slot_name = slot_name; if ((ret = ohci_mem_init (ohci)) < 0) { hc_release_ohci (ohci); return ret; } - ohci->flags = id->driver_data; + ohci->flags = flags; if (ohci->flags & OHCI_QUIRK_AMD756) printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n"); - /* bad pci latencies can contribute to overruns */ - pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); - if (latency) { - pci_read_config_byte (dev, PCI_MAX_LAT, &limit); - if (limit && limit < latency) { - dbg ("PCI latency reduced to max %d", limit); - pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit); - ohci->pci_latency = limit; - } else { - /* it might already have been reduced */ - ohci->pci_latency = latency; - } - } - if (hc_reset (ohci) < 0) { hc_release_ohci (ohci); return -ENODEV; @@ -2508,134 +2483,23 @@ hc_found_ohci (struct pci_dev *dev, int irq, usb_register_bus (ohci->bus); - if (request_irq (irq, hc_interrupt, SA_SHIRQ, - ohci_pci_driver.name, ohci) != 0) { + if (request_irq (irq, hc_interrupt, SA_SHIRQ, name, ohci) != 0) { err ("request interrupt %s failed", bufp); hc_release_ohci (ohci); return -EBUSY; } ohci->irq = irq; - if (hc_start (ohci) < 0) { - err ("can't start usb-%s", dev->slot_name); - hc_release_ohci (ohci); - return -EBUSY; - } + *ohcip = ohci; -#ifdef DEBUG - ohci_dump (ohci, 1); -#endif return 0; } -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_PM - -/* controller died; cleanup debris, then restart */ -/* must not be called from interrupt context */ - -static void hc_restart (ohci_t *ohci) -{ - int temp; - int i; - - if (ohci->pci_latency) - pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency); - - ohci->disabled = 1; - ohci->sleeping = 0; - if (ohci->bus->root_hub) - usb_disconnect (&ohci->bus->root_hub); - - /* empty the interrupt branches */ - for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0; - for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table[i] = 0; - - /* no EDs to remove */ - ohci->ed_rm_list [0] = NULL; - ohci->ed_rm_list [1] = NULL; - - /* empty control and bulk lists */ - ohci->ed_isotail = NULL; - ohci->ed_controltail = NULL; - ohci->ed_bulktail = NULL; - - if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) { - err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp); - } else - dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name); -} - -#endif /* CONFIG_PM */ - -/*-------------------------------------------------------------------------*/ - -/* configured so that an OHCI device is always provided */ -/* always called with process context; sleeping is OK */ - -static int __devinit -ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) -{ - unsigned long mem_resource, mem_len; - void *mem_base; - int status; - - if (pci_enable_device(dev) < 0) - return -ENODEV; - - if (!dev->irq) { - err("found OHCI device with no IRQ assigned. check BIOS settings!"); - pci_disable_device (dev); - return -ENODEV; - } - - /* we read its hardware registers as memory */ - mem_resource = pci_resource_start(dev, 0); - mem_len = pci_resource_len(dev, 0); - if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) { - dbg ("controller already in use"); - pci_disable_device (dev); - return -EBUSY; - } - - mem_base = ioremap_nocache (mem_resource, mem_len); - if (!mem_base) { - err("Error mapping OHCI memory"); - release_mem_region (mem_resource, mem_len); - pci_disable_device (dev); - return -EFAULT; - } - - /* controller writes into our memory */ - pci_set_master (dev); - - status = hc_found_ohci (dev, dev->irq, mem_base, id); - if (status < 0) { - iounmap (mem_base); - release_mem_region (mem_resource, mem_len); - pci_disable_device (dev); - } - return status; -} - -/*-------------------------------------------------------------------------*/ - -/* may be called from interrupt context [interface spec] */ -/* may be called without controller present */ -/* may be called with controller, bus, and devices active */ - -static void __devexit -ohci_pci_remove (struct pci_dev *dev) +/* + * Host bus independent remove one OHCI host controller. + */ +void hc_remove_ohci(ohci_t *ohci) { - ohci_t *ohci = pci_get_drvdata(dev); - - dbg ("remove %s controller usb-%s%s%s", - hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), - dev->slot_name, - ohci->disabled ? " (disabled)" : "", - in_interrupt () ? " in interrupt" : "" - ); #ifdef DEBUG ohci_dump (ohci, 1); #endif @@ -2652,270 +2516,16 @@ ohci_pci_remove (struct pci_dev *dev) &ohci->regs->control); hc_release_ohci (ohci); - - release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0)); - pci_disable_device (dev); } - -#ifdef CONFIG_PM - -/*-------------------------------------------------------------------------*/ - -static int -ohci_pci_suspend (struct pci_dev *dev, u32 state) -{ - ohci_t *ohci = pci_get_drvdata(dev); - unsigned long flags; - u16 cmd; - - if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) { - dbg ("can't suspend usb-%s (state is %s)", dev->slot_name, - hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS)); - return -EIO; - } - - /* act as if usb suspend can always be used */ - info ("USB suspend: usb-%s", dev->slot_name); - ohci->sleeping = 1; - - /* First stop processing */ - spin_lock_irqsave (&usb_ed_lock, flags); - ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE); - writel (ohci->hc_control, &ohci->regs->control); - writel (OHCI_INTR_SF, &ohci->regs->intrstatus); - (void) readl (&ohci->regs->intrstatus); - spin_unlock_irqrestore (&usb_ed_lock, flags); - - /* Wait a frame or two */ - mdelay(1); - if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF) - mdelay (1); - -#ifdef CONFIG_PMAC_PBOOK - if (_machine == _MACH_Pmac) - disable_irq (ohci->irq); - /* else, 2.4 assumes shared irqs -- don't disable */ -#endif - /* Enable remote wakeup */ - writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable); - - /* Suspend chip and let things settle down a bit */ - ohci->hc_control = OHCI_USB_SUSPEND; - writel (ohci->hc_control, &ohci->regs->control); - (void) readl (&ohci->regs->control); - mdelay (500); /* No schedule here ! */ - switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) { - case OHCI_USB_RESET: - dbg("Bus in reset phase ???"); - break; - case OHCI_USB_RESUME: - dbg("Bus in resume phase ???"); - break; - case OHCI_USB_OPER: - dbg("Bus in operational phase ???"); - break; - case OHCI_USB_SUSPEND: - dbg("Bus suspended"); - break; - } - /* In some rare situations, Apple's OHCI have happily trashed - * memory during sleep. We disable it's bus master bit during - * suspend - */ - pci_read_config_word (dev, PCI_COMMAND, &cmd); - cmd &= ~PCI_COMMAND_MASTER; - pci_write_config_word (dev, PCI_COMMAND, cmd); -#ifdef CONFIG_PMAC_PBOOK - { - struct device_node *of_node; - - /* Disable USB PAD & cell clock */ - of_node = pci_device_to_OF_node (ohci->ohci_dev); - if (of_node) - pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); - } -#endif - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static int -ohci_pci_resume (struct pci_dev *dev) -{ - ohci_t *ohci = pci_get_drvdata(dev); - int temp; - unsigned long flags; - - /* guard against multiple resumes */ - atomic_inc (&ohci->resume_count); - if (atomic_read (&ohci->resume_count) != 1) { - err ("concurrent PCI resumes for usb-%s", dev->slot_name); - atomic_dec (&ohci->resume_count); - return 0; - } - -#ifdef CONFIG_PMAC_PBOOK - { - struct device_node *of_node; - - /* Re-enable USB PAD & cell clock */ - of_node = pci_device_to_OF_node (ohci->ohci_dev); - if (of_node) - pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1); - } -#endif - - /* did we suspend, or were we powered off? */ - ohci->hc_control = readl (&ohci->regs->control); - temp = ohci->hc_control & OHCI_CTRL_HCFS; - -#ifdef DEBUG - /* the registers may look crazy here */ - ohci_dump_status (ohci); -#endif - - /* Re-enable bus mastering */ - pci_set_master(ohci->ohci_dev); - - switch (temp) { - - case OHCI_USB_RESET: // lost power - info ("USB restart: usb-%s", dev->slot_name); - hc_restart (ohci); - break; - - case OHCI_USB_SUSPEND: // host wakeup - case OHCI_USB_RESUME: // remote wakeup - info ("USB continue: usb-%s from %s wakeup", dev->slot_name, - (temp == OHCI_USB_SUSPEND) - ? "host" : "remote"); - ohci->hc_control = OHCI_USB_RESUME; - writel (ohci->hc_control, &ohci->regs->control); - (void) readl (&ohci->regs->control); - mdelay (20); /* no schedule here ! */ - /* Some controllers (lucent) need a longer delay here */ - mdelay (15); - temp = readl (&ohci->regs->control); - temp = ohci->hc_control & OHCI_CTRL_HCFS; - if (temp != OHCI_USB_RESUME) { - err ("controller usb-%s won't resume", dev->slot_name); - ohci->disabled = 1; - return -EIO; - } - - /* Some chips likes being resumed first */ - writel (OHCI_USB_OPER, &ohci->regs->control); - (void) readl (&ohci->regs->control); - mdelay (3); - - /* Then re-enable operations */ - spin_lock_irqsave (&usb_ed_lock, flags); - ohci->disabled = 0; - ohci->sleeping = 0; - ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; - if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) { - if (ohci->ed_controltail) - ohci->hc_control |= OHCI_CTRL_CLE; - if (ohci->ed_bulktail) - ohci->hc_control |= OHCI_CTRL_BLE; - } - writel (ohci->hc_control, &ohci->regs->control); - writel (OHCI_INTR_SF, &ohci->regs->intrstatus); - writel (OHCI_INTR_SF, &ohci->regs->intrenable); - /* Check for a pending done list */ - writel (OHCI_INTR_WDH, &ohci->regs->intrdisable); - (void) readl (&ohci->regs->intrdisable); - spin_unlock_irqrestore (&usb_ed_lock, flags); -#ifdef CONFIG_PMAC_PBOOK - if (_machine == _MACH_Pmac) - enable_irq (ohci->irq); -#endif - if (ohci->hcca->done_head) - dl_done_list (ohci, dl_reverse_done_list (ohci)); - writel (OHCI_INTR_WDH, &ohci->regs->intrenable); - writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ - writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ - break; - - default: - warn ("odd PCI resume for usb-%s", dev->slot_name); - } - - /* controller is operational, extra resumes are harmless */ - atomic_dec (&ohci->resume_count); - - return 0; -} - -#endif /* CONFIG_PM */ - - -/*-------------------------------------------------------------------------*/ - -static const struct pci_device_id __devinitdata ohci_pci_ids [] = { { - - /* - * AMD-756 [Viper] USB has a serious erratum when used with - * lowspeed devices like mice. - */ - vendor: 0x1022, - device: 0x740c, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, - - driver_data: OHCI_QUIRK_AMD756, - -} , { - - /* handle any USB OHCI controller */ - class: ((PCI_CLASS_SERIAL_USB << 8) | 0x10), - class_mask: ~0, - - /* no matter who makes it */ - vendor: PCI_ANY_ID, - device: PCI_ANY_ID, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, - - }, { /* end: all zeroes */ } -}; - -MODULE_DEVICE_TABLE (pci, ohci_pci_ids); - -static struct pci_driver ohci_pci_driver = { - name: "usb-ohci", - id_table: &ohci_pci_ids [0], - - probe: ohci_pci_probe, - remove: __devexit_p(ohci_pci_remove), - -#ifdef CONFIG_PM - suspend: ohci_pci_suspend, - resume: ohci_pci_resume, -#endif /* PM */ -}; - - -/*-------------------------------------------------------------------------*/ - -static int __init ohci_hcd_init (void) -{ - return pci_module_init (&ohci_pci_driver); -} - -/*-------------------------------------------------------------------------*/ - -static void __exit ohci_hcd_cleanup (void) -{ - pci_unregister_driver (&ohci_pci_driver); -} - -module_init (ohci_hcd_init); -module_exit (ohci_hcd_cleanup); - - MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(hc_add_ohci); +EXPORT_SYMBOL(hc_remove_ohci); +EXPORT_SYMBOL(hc_start); +EXPORT_SYMBOL(hc_reset); +EXPORT_SYMBOL(dl_done_list); +EXPORT_SYMBOL(dl_reverse_done_list); +EXPORT_SYMBOL(usb_ed_lock); diff --git a/drivers/usb/host/usb-ohci.h b/drivers/usb/host/usb-ohci.h index 99a20358452d..c04bb49a003f 100644 --- a/drivers/usb/host/usb-ohci.h +++ b/drivers/usb/host/usb-ohci.h @@ -403,6 +403,7 @@ typedef struct ohci { /* PCI device handle, settings, ... */ struct pci_dev *ohci_dev; + const char *slot_name; u8 pci_latency; struct pci_pool *td_cache; struct pci_pool *dev_cache; @@ -423,6 +424,10 @@ struct ohci_device { // #define ohci_to_usb(ohci) ((ohci)->usb) #define usb_to_ohci(usb) ((struct ohci_device *)(usb)->hcpriv) +/* For initializing controller (mask in an HCFS mode too) */ +#define OHCI_CONTROL_INIT \ + (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE + /* hcd */ /* endpoint */ static int ep_link(ohci_t * ohci, ed_t * ed); @@ -447,11 +452,6 @@ static int rh_init_int_timer(struct urb * urb); # define OHCI_MEM_FLAGS 0 #endif -#ifndef CONFIG_PCI -# error "usb-ohci currently requires PCI-based controllers" - /* to support non-PCI OHCIs, you need custom bus/mem/... glue */ -#endif - /* Recover a TD/ED using its collision chain */ static void * @@ -641,3 +641,8 @@ dev_free (struct ohci *hc, struct ohci_device *dev) pci_pool_free (hc->dev_cache, dev, dev->dma); } +extern spinlock_t usb_ed_lock; +extern void dl_done_list (ohci_t * ohci, td_t * td_list); +extern td_t * dl_reverse_done_list (ohci_t * ohci); + + diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index 1b763e6608dd..a5a2d59be9ca 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -167,108 +167,6 @@ static void us_transfer_freecom(Scsi_Cmnd *srb, struct us_data* us, int transfer srb->result = result; } -#if 0 -/* Write a value to an ide register. */ -static int -freecom_ide_write (struct us_data *us, int reg, int value) -{ - freecom_udata_t extra = (freecom_udata_t) us->extra; - struct freecom_ide_out *ideout = - (struct freecom_ide_out *) extra->buffer; - int opipe; - int result, partial; - - US_DEBUGP("IDE out 0x%02x <- 0x%02x\n", reg, value); - - /* Get handles for both transports. */ - opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out); - - if (reg < 0 || reg > 8) - return USB_STOR_TRANSPORT_ERROR; - if (reg < 8) - reg |= 0x20; - else - reg = 0x0e; - - ideout->Type = FCM_PACKET_IDE_WRITE | reg; - ideout->Pad = 0; - ideout->Value = cpu_to_le16 (value); - memset (ideout->Pad2, 0, sizeof (ideout->Pad2)); - - result = usb_stor_bulk_msg (us, ideout, opipe, - FCM_PACKET_LENGTH, &partial); - if (result != 0) { - if (result == -ENOENT) - return US_BULK_TRANSFER_ABORTED; - else - return USB_STOR_TRANSPORT_ERROR; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -/* Read a value from an ide register. */ -static int -freecom_ide_read (struct us_data *us, int reg, int *value) -{ - freecom_udata_t extra = (freecom_udata_t) us->extra; - struct freecom_ide_in *idein = - (struct freecom_ide_in *) extra->buffer; - __u8 *buffer = extra->buffer; - int ipipe, opipe; - int result, partial; - int desired_length; - - /* Get handles for both transports. */ - opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out); - ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in); - - if (reg < 0 || reg > 8) - return USB_STOR_TRANSPORT_ERROR; - if (reg < 8) - reg |= 0x10; - else - reg = 0x0e; - - US_DEBUGP("IDE in request for register 0x%02x\n", reg); - - idein->Type = FCM_PACKET_IDE_READ | reg; - memset (idein->Pad, 0, sizeof (idein->Pad)); - - result = usb_stor_bulk_msg (us, idein, opipe, - FCM_PACKET_LENGTH, &partial); - if (result != 0) { - if (result == -ENOENT) - return US_BULK_TRANSFER_ABORTED; - else - return USB_STOR_TRANSPORT_ERROR; - } - - desired_length = 1; - if (reg == 0x10) - desired_length = 2; - - result = usb_stor_bulk_msg (us, buffer, ipipe, - desired_length, &partial); - if (result != 0) { - if (result == -ENOENT) - return US_BULK_TRANSFER_ABORTED; - else - return USB_STOR_TRANSPORT_ERROR; - } - US_DEBUGP("IDE in partial is %d\n", partial); - - if (desired_length == 1) - *value = buffer[0]; - else - *value = le16_to_cpu (*(__u16 *) buffer); - - US_DEBUGP("IDE in 0x%02x -> 0x%02x\n", reg, *value); - - return USB_STOR_TRANSPORT_GOOD; -} -#endif - static int freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, int ipipe, int opipe, int count) @@ -292,8 +190,8 @@ freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, US_DEBUGP ("Freecom readdata xpot failure: r=%d, p=%d\n", result, partial); - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { + /* has the current command been aborted? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { US_DEBUGP("freecom_readdata(): transfer aborted\n"); return US_BULK_TRANSFER_ABORTED; } @@ -333,8 +231,8 @@ freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, US_DEBUGP ("Freecom writedata xpot failure: r=%d, p=%d\n", result, partial); - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { + /* has the current command been aborted? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { US_DEBUGP("freecom_writedata(): transfer aborted\n"); return US_BULK_TRANSFER_ABORTED; } @@ -396,8 +294,8 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) US_DEBUGP ("freecom xport failure: r=%d, p=%d\n", result, partial); - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { + /* we canceled this transfer */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { US_DEBUGP("freecom_transport(): transfer aborted\n"); return US_BULK_TRANSFER_ABORTED; } @@ -410,8 +308,9 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) result = usb_stor_bulk_msg (us, fst, ipipe, FCM_PACKET_LENGTH, &partial); US_DEBUGP("foo Status result %d %d\n", result, partial); - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { + + /* we canceled this transfer */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { US_DEBUGP("freecom_transport(): transfer aborted\n"); return US_BULK_TRANSFER_ABORTED; } @@ -448,8 +347,8 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) US_DEBUGP ("freecom xport failure: r=%d, p=%d\n", result, partial); - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { + /* we canceled this transfer */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { US_DEBUGP("freecom_transport(): transfer aborted\n"); return US_BULK_TRANSFER_ABORTED; } @@ -463,8 +362,8 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) US_DEBUGP("bar Status result %d %d\n", result, partial); - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { + /* we canceled this transfer */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { US_DEBUGP("freecom_transport(): transfer aborted\n"); return US_BULK_TRANSFER_ABORTED; } @@ -524,7 +423,8 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) result = usb_stor_bulk_msg (us, fst, ipipe, FCM_PACKET_LENGTH, &partial); US_DEBUG(pdump ((void *) fst, partial)); - if (result == -ENOENT) { + + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { US_DEBUGP ("freecom_transport: transfer aborted\n"); return US_BULK_TRANSFER_ABORTED; } @@ -552,7 +452,8 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) US_DEBUGP("FCM: Waiting for status\n"); result = usb_stor_bulk_msg (us, fst, ipipe, FCM_PACKET_LENGTH, &partial); - if (result == -ENOENT) { + + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { US_DEBUGP ("freecom_transport: transfer aborted\n"); return US_BULK_TRANSFER_ABORTED; } diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index b7ddec789416..17e861fcae9f 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -386,9 +386,9 @@ Scsi_Host_Template usb_stor_host_template = { unsigned char usb_stor_sense_notready[18] = { [0] = 0x70, /* current error */ [2] = 0x02, /* not ready */ - [5] = 0x0a, /* additional length */ - [10] = 0x04, /* not ready */ - [11] = 0x03 /* manual intervention */ + [7] = 0x0a, /* additional length */ + [12] = 0x04, /* not ready */ + [13] = 0x03 /* manual intervention */ }; #define USB_STOR_SCSI_SENSE_HDRSZ 4 diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index ec0f11d3b38e..bcf22f6c2d9f 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -986,9 +986,11 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) clear_bit(IP_WANTED, &us->bitflags); } - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_control_msg(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } /* STALL must be cleared when it is detected */ if (result == -EPIPE) { @@ -996,9 +998,12 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) result = usb_stor_clear_halt(us, usb_sndctrlpipe(us->pusb_dev, 0)); - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_control_msg(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } + return USB_STOR_TRANSPORT_FAILED; } @@ -1098,9 +1103,11 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) /* check the return code for the command */ US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); if (result < 0) { - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } /* a stall is a fatal condition from the device */ if (result == -EPIPE) { @@ -1108,9 +1115,11 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) result = usb_stor_clear_halt(us, usb_sndctrlpipe(us->pusb_dev, 0)); - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } return USB_STOR_TRANSPORT_FAILED; } @@ -1215,18 +1224,22 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) &partial); US_DEBUGP("Bulk command transfer result=%d\n", result); - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); result = usb_stor_clear_halt(us, pipe); - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } result = -EPIPE; } else if (result) { /* unknown error -- we've got a problem */ @@ -1259,36 +1272,44 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, &partial); - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); result = usb_stor_clear_halt(us, pipe); - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, &partial); - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); result = usb_stor_clear_halt(us, pipe); - /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } return USB_STOR_TRANSPORT_ERROR; } } |
