Commit 42294085 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linuxusb.bkbits.net/linus-2.5

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents cdf24f56 c1f4224e
......@@ -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
......
......@@ -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/
......
......@@ -904,7 +904,8 @@ static void usb_find_drivers(struct usb_device *dev)
/* register this interface with driverfs */
interface->dev.parent = &dev->dev;
sprintf (&interface->dev.bus_id[0], "%03d", ifnum);
interface->dev.bus = &usb_bus_type;
sprintf (&interface->dev.bus_id[0], "%03d%03d", dev->devnum,ifnum);
sprintf (&interface->dev.name[0], "figure out some name...");
device_register (&interface->dev);
......@@ -2757,12 +2758,16 @@ struct list_head *usb_bus_get_list(void)
}
#endif
struct bus_type usb_bus_type = {
name: "usb",
};
/*
* Init
*/
static int __init usb_init(void)
{
bus_register(&usb_bus_type);
usb_major_init();
usbfs_init();
usb_hub_init();
......@@ -2775,6 +2780,7 @@ static int __init usb_init(void)
*/
static void __exit usb_exit(void)
{
put_bus(&usb_bus_type);
usb_major_cleanup();
usbfs_cleanup();
usb_hub_cleanup();
......
......@@ -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
......@@ -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
#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");
/*
* 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);
......@@ -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);
......@@ -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);
......@@ -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;
}
......
......@@ -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
......
......@@ -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;
}
}
......
......@@ -713,6 +713,8 @@ struct usb_driver {
/* void (*resume)(struct usb_device *dev); */
};
extern struct bus_type usb_bus_type;
/*
* use these in module_init()/module_exit()
* and don't forget MODULE_DEVICE_TABLE(usb, ...)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment