Commit 38b60834 authored by Linus Torvalds's avatar Linus Torvalds

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

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 0820be61 ca65e31f
......@@ -1320,7 +1320,7 @@ static void urb_unlink (struct urb *urb)
list_del_init (&urb->urb_list);
dev = urb->dev;
urb->dev = NULL;
usb_dec_dev_use (dev);
usb_put_dev (dev);
spin_unlock_irqrestore (&hcd_data_lock, flags);
}
......@@ -1516,7 +1516,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
spin_lock_irqsave (&hcd_data_lock, flags);
if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) {
usb_inc_dev_use (urb->dev);
usb_get_dev (urb->dev);
list_add (&urb->urb_list, &dev->urb_list);
status = 0;
} else {
......@@ -1732,7 +1732,8 @@ static int hcd_free_dev (struct usb_device *udev)
return -EINVAL;
}
hcd->driver->free_config (hcd, udev);
if (hcd->driver->free_config)
hcd->driver->free_config (hcd, udev);
spin_lock_irqsave (&hcd_data_lock, flags);
list_del (&dev->dev_list);
......
......@@ -182,9 +182,6 @@ extern int usb_hcd_pci_resume (struct pci_dev *dev);
/* -------------------------------------------------------------------------- */
/* Enumeration is only for the hub driver, or HCD virtual root hubs */
extern struct usb_device *usb_alloc_dev(struct usb_device *parent,
struct usb_bus *);
extern void usb_free_dev(struct usb_device *);
extern int usb_new_device(struct usb_device *dev);
extern void usb_connect(struct usb_device *dev);
extern void usb_disconnect(struct usb_device **);
......
......@@ -149,6 +149,98 @@ static void hub_irq(struct urb *urb)
spin_unlock_irqrestore(&hub_event_lock, flags);
}
/* USB 2.0 spec Section 11.24.2.3 */
static inline int
hub_clear_tt_buffer (struct usb_device *hub, u16 devinfo, u16 tt)
{
return usb_control_msg (hub, usb_rcvctrlpipe (hub, 0),
HUB_CLEAR_TT_BUFFER, USB_DIR_IN | USB_RECIP_OTHER,
devinfo, tt, 0, 0, HZ);
}
/*
* enumeration blocks khubd for a long time. we use keventd instead, since
* long blocking there is the exception, not the rule. accordingly, HCDs
* talking to TTs must queue control transfers (not just bulk and iso), so
* both can talk to the same hub concurrently.
*/
static void hub_tt_kevent (void *arg)
{
struct usb_hub *hub = arg;
unsigned long flags;
spin_lock_irqsave (&hub->tt.lock, flags);
while (!list_empty (&hub->tt.clear_list)) {
struct list_head *temp;
struct usb_tt_clear *clear;
int status;
temp = hub->tt.clear_list.next;
clear = list_entry (temp, struct usb_tt_clear, clear_list);
list_del (&clear->clear_list);
/* drop lock so HCD can concurrently report other TT errors */
spin_unlock_irqrestore (&hub->tt.lock, flags);
status = hub_clear_tt_buffer (hub->dev,
clear->devinfo, clear->tt);
spin_lock_irqsave (&hub->tt.lock, flags);
if (status)
err ("usb-%s-%s clear tt %d (%04x) error %d",
hub->dev->bus->bus_name, hub->dev->devpath,
clear->tt, clear->devinfo, status);
kfree (clear);
}
spin_unlock_irqrestore (&hub->tt.lock, flags);
}
/**
* usb_hub_tt_clear_buffer - clear control/bulk TT state in high speed hub
* @dev: the device whose split transaction failed
* @pipe: identifies the endpoint of the failed transaction
*
* High speed HCDs use this to tell the hub driver that some split control or
* bulk transaction failed in a way that requires clearing internal state of
* a transaction translator. This is normally detected (and reported) from
* interrupt context.
*
* It may not be possible for that hub to handle additional full (or low)
* speed transactions until that state is fully cleared out.
*/
void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe)
{
struct usb_tt *tt = dev->tt;
unsigned long flags;
struct usb_tt_clear *clear;
/* we've got to cope with an arbitrary number of pending TT clears,
* since each TT has "at least two" buffers that can need it (and
* there can be many TTs per hub). even if they're uncommon.
*/
if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == 0) {
err ("can't save CLEAR_TT_BUFFER state for hub at usb-%s-%s",
dev->bus->bus_name, tt->hub->devpath);
/* FIXME recover somehow ... RESET_TT? */
return;
}
/* info that CLEAR_TT_BUFFER needs */
clear->tt = tt->multi ? dev->ttport : 1;
clear->devinfo = usb_pipeendpoint (pipe);
clear->devinfo |= dev->devnum << 4;
clear->devinfo |= usb_pipecontrol (pipe)
? (USB_ENDPOINT_XFER_CONTROL << 11)
: (USB_ENDPOINT_XFER_BULK << 11);
if (usb_pipein (pipe))
clear->devinfo |= 1 << 15;
/* tell keventd to clear state for this TT */
spin_lock_irqsave (&tt->lock, flags);
list_add_tail (&clear->clear_list, &tt->clear_list);
schedule_task (&tt->kevent);
spin_unlock_irqrestore (&tt->lock, flags);
}
static void usb_hub_power_on(struct usb_hub *hub)
{
int i;
......@@ -231,6 +323,9 @@ static int usb_hub_configure(struct usb_hub *hub,
break;
}
spin_lock_init (&hub->tt.lock);
INIT_LIST_HEAD (&hub->tt.clear_list);
INIT_TQUEUE (&hub->tt.kevent, hub_tt_kevent, hub);
switch (dev->descriptor.bDeviceProtocol) {
case 0:
break;
......@@ -432,6 +527,10 @@ static void hub_disconnect(struct usb_device *dev, void *ptr)
down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */
up(&hub->khubd_sem);
/* assuming we used keventd, it must quiesce too */
if (hub->tt.hub)
flush_scheduled_tasks ();
if (hub->urb) {
usb_unlink_urb(hub->urb);
usb_free_urb(hub->urb);
......
......@@ -136,6 +136,34 @@ struct usb_hub_descriptor {
struct usb_device;
/*
* As of USB 2.0, full/low speed devices are segregated into trees.
* One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
* The other type grows from high speed hubs when they connect to
* full/low speed devices using "Transaction Translators" (TTs).
*
* TTs should only be known to the hub driver, and high speed bus
* drivers (only EHCI for now). They affect periodic scheduling and
* sometimes control/bulk error recovery.
*/
struct usb_tt {
struct usb_device *hub; /* upstream highspeed hub */
int multi; /* true means one TT per port */
/* for control/bulk error recovery (CLEAR_TT_BUFFER) */
spinlock_t lock;
struct list_head clear_list; /* of usb_tt_clear */
struct tq_struct kevent;
};
struct usb_tt_clear {
struct list_head clear_list;
unsigned tt;
u16 devinfo;
};
extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe);
struct usb_hub {
struct usb_device *dev; /* the "real" device */
struct urb *urb; /* for interrupt polling pipe */
......
......@@ -962,35 +962,54 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
init_MUTEX(&dev->serialize);
dev->bus->op->allocate(dev);
if (dev->bus->op->allocate)
dev->bus->op->allocate(dev);
return dev;
}
/**
* usb_free_dev - free a usb device structure (usbcore-internal)
* usb_get_dev - increments the reference count of the device
* @dev: the device being referenced
*
* Each live reference to a device should be refcounted.
*
* Drivers for USB interfaces should normally record such references in
* their probe() methods, when they bind to an interface, and release
* them by calling usb_put_dev(), in their disconnect() methods.
*
* A pointer to the device with the incremented reference counter is returned.
*/
struct usb_device *usb_get_dev (struct usb_device *dev)
{
if (dev) {
atomic_inc (&dev->refcnt);
return dev;
}
return NULL;
}
/**
* usb_free_dev - free a usb device structure when all users of it are finished.
* @dev: device that's been disconnected
* Context: !in_interrupt ()
*
* Must be called when a user of a device is finished with it. When the last
* user of the device calls this function, the memory of the device is freed.
*
* Used by hub and virtual root hub drivers. The device is completely
* gone, everything is cleaned up, so it's time to get rid of these last
* records of this device.
*/
void usb_free_dev(struct usb_device *dev)
{
if (in_interrupt ())
BUG ();
if (!atomic_dec_and_test (&dev->refcnt)) {
/* MUST go to zero here, else someone's hanging on to
* a device that's supposed to have been cleaned up!!
*/
BUG ();
if (atomic_dec_and_test(&dev->refcnt)) {
if (dev->bus->op->deallocate)
dev->bus->op->deallocate(dev);
usb_destroy_configuration (dev);
usb_bus_put (dev->bus);
kfree (dev);
}
dev->bus->op->deallocate (dev);
usb_destroy_configuration (dev);
usb_bus_put (dev->bus);
kfree (dev);
}
/**
......@@ -1046,7 +1065,7 @@ void usb_free_urb(struct urb *urb)
}
/**
* usb_get_urb - incrementes the reference count of the urb
* usb_get_urb - increments the reference count of the urb
* @urb: pointer to the urb to modify
*
* This must be called whenever a urb is transfered from a device driver to a
......@@ -1162,10 +1181,15 @@ struct urb * usb_get_urb(struct urb *urb)
*/
int usb_submit_urb(struct urb *urb, int mem_flags)
{
if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op) {
if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) <= 0) {
err("%s: pipe %x has invalid size (<= 0)", __FUNCTION__, urb->pipe);
return -EMSGSIZE;
}
return urb->dev->bus->op->submit_urb(urb, mem_flags);
else
return -ENODEV;
}
return -ENODEV;
}
/*-------------------------------------------------------------------*/
......@@ -1928,8 +1952,9 @@ void usb_disconnect(struct usb_device **pdev)
put_device(&dev->dev);
}
/* Free up the device itself */
usb_free_dev(dev);
/* Decrement the reference count, it'll auto free everything when */
/* it hits 0 which could very well be now */
usb_put_dev(dev);
}
/**
......@@ -2558,9 +2583,13 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
*/
#define NEW_DEVICE_RETRYS 2
#define SET_ADDRESS_RETRYS 2
int usb_new_device(struct usb_device *dev)
{
int err;
int err = 0;
int i;
int j;
/* USB v1.1 5.5.3 */
/* We read the first 8 bytes from the device descriptor to get to */
......@@ -2569,18 +2598,30 @@ int usb_new_device(struct usb_device *dev)
dev->epmaxpacketin [0] = 8;
dev->epmaxpacketout[0] = 8;
err = usb_set_address(dev);
if (err < 0) {
err("USB device not accepting new address=%d (error=%d)",
dev->devnum, err);
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
return 1;
}
for (i = 0; i < NEW_DEVICE_RETRYS; ++i) {
wait_ms(10); /* Let the SET_ADDRESS settle */
for (j = 0; j < SET_ADDRESS_RETRYS; ++j) {
err = usb_set_address(dev);
if (err >= 0)
break;
wait_ms(200);
}
if (err < 0) {
err("USB device not accepting new address=%d (error=%d)",
dev->devnum, err);
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
return 1;
}
wait_ms(10); /* Let the SET_ADDRESS settle */
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
if (err >= 8)
break;
wait_ms(100);
}
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
if (err < 8) {
if (err < 0)
err("USB device not responding, giving up (error=%d)", err);
......@@ -2743,9 +2784,8 @@ module_exit(usb_exit);
/*
* USB may be built into the kernel or be built as modules.
* If the USB core [and maybe a host controller driver] is built
* into the kernel, and other device drivers are built as modules,
* then these symbols need to be exported for the modules to use.
* These symbols are exported for device (or host controller)
* driver modules to use.
*/
EXPORT_SYMBOL(usb_ifnum_to_ifpos);
EXPORT_SYMBOL(usb_ifnum_to_if);
......@@ -2762,6 +2802,8 @@ EXPORT_SYMBOL(usb_deregister_dev);
EXPORT_SYMBOL(usb_alloc_dev);
EXPORT_SYMBOL(usb_free_dev);
EXPORT_SYMBOL(usb_get_dev);
EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
EXPORT_SYMBOL(usb_find_interface_driver_for_ifnum);
EXPORT_SYMBOL(usb_driver_claim_interface);
......@@ -2799,6 +2841,5 @@ EXPORT_SYMBOL(usb_clear_halt);
EXPORT_SYMBOL(usb_set_configuration);
EXPORT_SYMBOL(usb_set_interface);
EXPORT_SYMBOL(usb_make_path);
EXPORT_SYMBOL(usb_devfs_handle);
MODULE_LICENSE("GPL");
......@@ -4,7 +4,12 @@
comment 'USB Host Controller Drivers'
dep_tristate ' EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate ' OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
# dep_tristate ' UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
if [ "$CONFIG_USB_UHCI_HCD_ALT" != "y" ]; then
dep_tristate ' UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
fi
if [ "$CONFIG_USB_UHCI_HCD" != "y" ]; then
dep_tristate ' UHCI HCD Alternate (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD_ALT $CONFIG_USB $CONFIG_EXPERIMENTAL
fi
if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
fi
......@@ -13,4 +18,4 @@ if [ "$CONFIG_USB_UHCI" != "y" ]; then
else
define_bool CONFIG_USB_UHCI_ALT n
fi
dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
#dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
......@@ -7,7 +7,8 @@ O_TARGET := host.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
# obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += usb-uhci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD_ALT) += uhci-hcd.o
obj-$(CONFIG_USB_UHCI) += usb-uhci.o
obj-$(CONFIG_USB_UHCI_ALT) += uhci.o
......
......@@ -46,8 +46,6 @@
#include <asm/system.h>
#include <asm/unaligned.h>
//#undef KERN_DEBUG
//#define KERN_DEBUG ""
/*-------------------------------------------------------------------------*/
......@@ -55,21 +53,20 @@
* EHCI hc_driver implementation ... experimental, incomplete.
* Based on the final 1.0 register interface specification.
*
* There are lots of things to help out with here ... notably
* everything "periodic", and of course testing with all sorts
* of usb 2.0 devices and configurations.
*
* USB 2.0 shows up in upcoming www.pcmcia.org technology.
* First was PCMCIA, like ISA; then CardBus, which is PCI.
* Next comes "CardBay", using USB 2.0 signals.
*
* Contains additional contributions by:
* Brad Hards
* Rory Bolt
* ...
* Contains additional contributions by: Brad Hards, Rory Bolt, ...
*
* Special thanks to Intel and VIA for providing host controllers to
* test this driver on, and Cypress (including In-System Design) for
* providing early devices for those host controllers to talk to!
*
* HISTORY:
*
* 2002-05-11 Clear TT errors for FS/LS ctrl/bulk. Fill in some other
* missing pieces: enabling 64bit dma, handoff from BIOS/SMM.
* 2002-05-07 Some error path cleanups to report better errors; wmb();
* use non-CVS version id; better iso bandwidth claim.
* 2002-04-19 Control/bulk/interrupt submit no longer uses giveback() on
......@@ -85,7 +82,7 @@
* 2001-June Works with usb-storage and NEC EHCI on 2.4
*/
#define DRIVER_VERSION "2002-May-07"
#define DRIVER_VERSION "2002-May-11"
#define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
......@@ -165,6 +162,34 @@ static void ehci_ready (struct ehci_hcd *ehci)
static void ehci_tasklet (unsigned long param);
/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
* off the controller (maybe it can boot from highspeed USB disks).
*/
static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
{
if (cap & (1 << 16)) {
int msec = 500;
/* request handoff to OS */
cap &= 1 << 24;
pci_write_config_dword (ehci->hcd.pdev, where, cap);
/* and wait a while for it to happen */
do {
wait_ms (10);
msec -= 10;
pci_read_config_dword (ehci->hcd.pdev, where, &cap);
} while ((cap & (1 << 16)) && msec);
if (cap & (1 << 16)) {
info ("BIOS handoff failed (%d, %04x)", where, cap);
return 1;
}
dbg ("BIOS handoff succeeded");
} else
dbg ("BIOS handoff not needed");
return 0;
}
/* called by khubd or root hub init threads */
static int ehci_start (struct usb_hcd *hcd)
......@@ -176,10 +201,6 @@ static int ehci_start (struct usb_hcd *hcd)
u32 hcc_params;
u8 tempbyte;
// FIXME: given EHCI 0.96 or later, and a controller with
// the USBLEGSUP/USBLEGCTLSTS extended capability, make sure
// the BIOS doesn't still own this controller.
spin_lock_init (&ehci->lock);
ehci->caps = (struct ehci_caps *) hcd->regs;
......@@ -187,6 +208,30 @@ static int ehci_start (struct usb_hcd *hcd)
dbg_hcs_params (ehci, "ehci_start");
dbg_hcc_params (ehci, "ehci_start");
hcc_params = readl (&ehci->caps->hcc_params);
/* EHCI 0.96 and later may have "extended capabilities" */
temp = HCC_EXT_CAPS (hcc_params);
while (temp) {
u32 cap;
pci_read_config_dword (ehci->hcd.pdev, temp, &cap);
dbg ("capability %04x at %02x", cap, temp);
switch (cap & 0xff) {
case 1: /* BIOS/SMM/... handoff */
if (bios_handoff (ehci, temp, cap) != 0)
return -EOPNOTSUPP;
break;
case 0: /* illegal reserved capability */
warn ("illegal capability!");
cap = 0;
/* FALLTHROUGH */
default: /* unknown */
break;
}
temp = (cap >> 8) & 0xff;
}
/* cache this readonly data; minimize PCI reads */
ehci->hcs_params = readl (&ehci->caps->hcs_params);
......@@ -197,7 +242,6 @@ static int ehci_start (struct usb_hcd *hcd)
ehci->periodic_size = DEFAULT_I_TDPS;
if ((retval = ehci_mem_init (ehci, SLAB_KERNEL)) < 0)
return retval;
hcc_params = readl (&ehci->caps->hcc_params);
/* controllers may cache some of the periodic schedule ... */
if (HCC_ISOC_CACHE (hcc_params)) // full frame cache
......@@ -221,23 +265,24 @@ static int ehci_start (struct usb_hcd *hcd)
* hcc_params controls whether ehci->regs->segment must (!!!)
* be used; it constrains QH/ITD/SITD and QTD locations.
* pci_pool consistent memory always uses segment zero.
* streaming mappings for I/O buffers, like pci_map_single(),
* can return segments above 4GB, if the device allows.
*
* NOTE: layered drivers can't yet tell when we enable that,
* so they can't pass this info along (like NETIF_F_HIGHDMA)
*/
if (HCC_64BIT_ADDR (hcc_params)) {
writel (0, &ehci->regs->segment);
/*
* FIXME Enlarge pci_set_dma_mask() when possible. The DMA
* mapping API spec now says that'll affect only single shot
* mappings, and the pci_pool data will stay safe in seg 0.
* That's what we want: no extra copies for USB transfers.
*/
info ("restricting 64bit DMA mappings to segment 0 ...");
if (!pci_set_dma_mask (ehci->hcd.pdev, 0xffffffffffffffffULL))
info ("enabled 64bit PCI DMA (DAC)");
}
/* clear interrupt enables, set irq latency */
temp = readl (&ehci->regs->command) & 0xff;
if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
log2_irq_thresh = 0;
log2_irq_thresh = 0;
temp |= 1 << (16 + log2_irq_thresh);
// if hc can park (ehci >= 0.96), default is 3 packets per async QH
// keeping default periodic framelist size
temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE),
// Philips, Intel, and maybe others need CMD_RUN before the
......@@ -433,10 +478,6 @@ static void ehci_tasklet (unsigned long param)
scan_async (ehci);
if (ehci->next_uframe != -1)
scan_periodic (ehci);
// FIXME: when nothing is connected to the root hub,
// turn off the RUN bit so the host can enter C3 "sleep" power
// saving mode; make root hub code scan memory less often.
}
/*-------------------------------------------------------------------------*/
......
......@@ -144,13 +144,12 @@ static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token)
usb_pipeendpoint (pipe),
usb_pipeout (pipe));
if (urb->dev->tt && !usb_pipeint (pipe)) {
err ("must CLEAR_TT_BUFFER, hub port %d%s addr %d ep %d",
urb->dev->ttport, /* devpath */
urb->dev->tt->multi ? "" : " (all-ports TT)",
urb->dev->devnum, usb_pipeendpoint (urb->pipe));
// FIXME something (khubd?) should make the hub
// CLEAR_TT_BUFFER ASAP, it's blocking other
// fs/ls requests... hub_tt_clear_buffer() ?
struct usb_device *tt = urb->dev->tt->hub;
dbg ("clear tt %s-%s p%d buffer, a%d ep%d",
tt->bus->bus_name, tt->devpath,
urb->dev->ttport, urb->dev->devnum,
usb_pipeendpoint (pipe));
usb_hub_tt_clear_buffer (urb->dev, pipe);
}
}
}
......@@ -817,9 +816,9 @@ submit_async (
} else {
// dbg_qh ("empty qh", ehci, qh);
// FIXME: how handle usb_clear_halt() for an EP with queued URBs?
// usbcore may not let us handle that cleanly...
// likely must cancel them all first!
/* NOTE: we already canceled any queued URBs
* when the endpoint halted.
*/
/* usb_clear_halt() means qh data toggle gets reset */
if (usb_pipebulk (urb->pipe)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* Universal Host Controller Interface driver for USB.
*
* Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
*
* (C) Copyright 1999 Linus Torvalds
* (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
* (C) Copyright 1999 Randy Dunlap
* (C) Copyright 1999 Georg Acher, acher@in.tum.de
* (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
* (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
*/
static __u8 root_hub_hub_des[] =
{
0x09, /* __u8 bLength; */
0x29, /* __u8 bDescriptorType; Hub-descriptor */
0x02, /* __u8 bNbrPorts; */
0x00, /* __u16 wHubCharacteristics; */
0x00,
0x01, /* __u8 bPwrOn2pwrGood; 2ms */
0x00, /* __u8 bHubContrCurrent; 0 mA */
0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */
0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
};
static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned int io_addr = uhci->io_addr;
int i, len = 1;
*buf = 0;
for (i = 0; i < uhci->rh_numports; i++) {
*buf |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
len = (i + 1) / 8 + 1;
}
return !!*buf;
}
#define OK(x) len = (x); break
#define CLR_RH_PORTSTAT(x) \
status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
status = (status & 0xfff5) & ~(x); \
outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
#define SET_RH_PORTSTAT(x) \
status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
status = (status & 0xfff5) | (x); \
outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
// FIXME: Shouldn't this return the length of the data too?
static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int i, status, retval = 0, len = 0;
unsigned int io_addr = uhci->io_addr;
__u16 cstatus;
char c_p_r[8];
for (i = 0; i < 8; i++)
c_p_r[i] = 0;
switch (typeReq) {
/* Request Destination:
without flags: Device,
RH_INTERFACE: interface,
RH_ENDPOINT: endpoint,
RH_CLASS means HUB here,
RH_OTHER | RH_CLASS almost ever means HUB_PORT here
*/
case GetHubStatus:
*(__u32 *)buf = cpu_to_le32(0);
OK(4); /* hub power */
case GetPortStatus:
status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1));
cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
((status & USBPORTSC_PEC) >> (3 - 1)) |
(c_p_r[wIndex - 1] << (0 + 4));
status = (status & USBPORTSC_CCS) |
((status & USBPORTSC_PE) >> (2 - 1)) |
((status & USBPORTSC_SUSP) >> (12 - 2)) |
((status & USBPORTSC_PR) >> (9 - 4)) |
(1 << 8) | /* power on */
((status & USBPORTSC_LSDA) << (-8 + 9));
*(__u16 *)buf = cpu_to_le16(status);
*(__u16 *)(buf + 2) = cpu_to_le16(cstatus);
OK(4);
case SetHubFeature:
switch (wValue) {
case C_HUB_OVER_CURRENT:
case C_HUB_LOCAL_POWER:
break;
default:
goto err;
}
break;
case ClearHubFeature:
switch (wValue) {
case C_HUB_OVER_CURRENT:
OK(0); /* hub power over current */
default:
goto err;
}
break;
case SetPortFeature:
if (!wIndex || wIndex > uhci->rh_numports)
goto err;
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
SET_RH_PORTSTAT(USBPORTSC_SUSP);
OK(0);
case USB_PORT_FEAT_RESET:
SET_RH_PORTSTAT(USBPORTSC_PR);
mdelay(50); /* USB v1.1 7.1.7.3 */
c_p_r[wIndex - 1] = 1;
CLR_RH_PORTSTAT(USBPORTSC_PR);
udelay(10);
SET_RH_PORTSTAT(USBPORTSC_PE);
mdelay(10);
SET_RH_PORTSTAT(0xa);
OK(0);
case USB_PORT_FEAT_POWER:
OK(0); /* port power ** */
case USB_PORT_FEAT_ENABLE:
SET_RH_PORTSTAT(USBPORTSC_PE);
OK(0);
default:
goto err;
}
break;
case ClearPortFeature:
if (!wIndex || wIndex > uhci->rh_numports)
goto err;
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
CLR_RH_PORTSTAT(USBPORTSC_PE);
OK(0);
case USB_PORT_FEAT_C_ENABLE:
SET_RH_PORTSTAT(USBPORTSC_PEC);
OK(0);
case USB_PORT_FEAT_SUSPEND:
CLR_RH_PORTSTAT(USBPORTSC_SUSP);
OK(0);
case USB_PORT_FEAT_C_SUSPEND:
/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
OK(0);
case USB_PORT_FEAT_POWER:
OK(0); /* port power */
case USB_PORT_FEAT_C_CONNECTION:
SET_RH_PORTSTAT(USBPORTSC_CSC);
OK(0);
case USB_PORT_FEAT_C_OVER_CURRENT:
OK(0); /* port power over current */
case USB_PORT_FEAT_C_RESET:
c_p_r[wIndex - 1] = 0;
OK(0);
default:
goto err;
}
break;
case GetHubDescriptor:
len = min_t(unsigned int, wLength,
min_t(unsigned int, sizeof(root_hub_hub_des), wLength));
memcpy(buf, root_hub_hub_des, len);
if (len > 2)
buf[2] = uhci->rh_numports;
OK(len);
default:
err:
retval = -EPIPE;
}
return retval;
}
......@@ -101,27 +101,27 @@ static void wakeup_hc(struct uhci *uhci);
#define IDLE_TIMEOUT (HZ / 20) /* 50 ms */
#define FSBR_DELAY (HZ / 20) /* 50 ms */
/* When we timeout an idle transfer for FSBR, we'll switch it over to */
/* depth first traversal. We'll do it in groups of this number of TD's */
/* to make sure it doesn't hog all of the bandwidth */
#define DEPTH_INTERVAL 5
#define MAX_URB_LOOP 2048 /* Maximum number of linked URB's */
/*
* Only the USB core should call uhci_alloc_dev and uhci_free_dev
* Technically, updating td->status here is a race, but it's not really a
* problem. The worst that can happen is that we set the IOC bit again
* generating a spurios interrupt. We could fix this by creating another
* QH and leaving the IOC bit always set, but then we would have to play
* games with the FSBR code to make sure we get the correct order in all
* the cases. I don't think it's worth the effort
*/
static int uhci_alloc_dev(struct usb_device *dev)
{
return 0;
}
static int uhci_free_dev(struct usb_device *dev)
{
return 0;
}
static inline void uhci_set_next_interrupt(struct uhci *uhci)
{
unsigned long flags;
spin_lock_irqsave(&uhci->frame_list_lock, flags);
set_bit(TD_CTRL_IOC_BIT, &uhci->skel_term_td->status);
uhci->skel_term_td->status |= TD_CTRL_IOC;
spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
}
......@@ -130,7 +130,7 @@ static inline void uhci_clear_next_interrupt(struct uhci *uhci)
unsigned long flags;
spin_lock_irqsave(&uhci->frame_list_lock, flags);
clear_bit(TD_CTRL_IOC_BIT, &uhci->skel_term_td->status);
uhci->skel_term_td->status &= ~TD_CTRL_IOC;
spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
}
......@@ -165,7 +165,7 @@ static struct uhci_td *uhci_alloc_td(struct uhci *uhci, struct usb_device *dev)
INIT_LIST_HEAD(&td->list);
INIT_LIST_HEAD(&td->fl_list);
usb_inc_dev_use(dev);
usb_get_dev(dev);
return td;
}
......@@ -317,7 +317,7 @@ static void uhci_free_td(struct uhci *uhci, struct uhci_td *td)
dbg("td is still in URB list!");
if (td->dev)
usb_dec_dev_use(td->dev);
usb_put_dev(td->dev);
pci_pool_free(uhci->td_pool, td, td->dma_handle);
}
......@@ -342,7 +342,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci *uhci, struct usb_device *dev)
INIT_LIST_HEAD(&qh->list);
INIT_LIST_HEAD(&qh->remove_list);
usb_inc_dev_use(dev);
usb_get_dev(dev);
return qh;
}
......@@ -355,7 +355,7 @@ static void uhci_free_qh(struct uhci *uhci, struct uhci_qh *qh)
dbg("qh still in remove_list!");
if (qh->dev)
usb_dec_dev_use(qh->dev);
usb_put_dev(qh->dev);
pci_pool_free(uhci->qh_pool, qh, qh->dma_handle);
}
......@@ -475,9 +475,9 @@ static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
tmp = tmp->next;
if (toggle)
set_bit(TD_TOKEN_TOGGLE, &td->info);
td->info |= TD_TOKEN_TOGGLE;
else
clear_bit(TD_TOKEN_TOGGLE, &td->info);
td->info &= ~TD_TOKEN_TOGGLE;
toggle ^= 1;
}
......@@ -860,7 +860,7 @@ static int uhci_submit_control(struct urb *urb)
return -ENOMEM;
/* Alternate Data0/1 (start with Data1) */
destination ^= 1 << TD_TOKEN_TOGGLE;
destination ^= TD_TOKEN_TOGGLE;
uhci_add_td_to_urb(urb, td);
uhci_fill_td(td, status, destination | ((pktsze - 1) << 21),
......@@ -887,7 +887,7 @@ static int uhci_submit_control(struct urb *urb)
else
destination |= USB_PID_OUT;
destination |= 1 << TD_TOKEN_TOGGLE; /* End in Data1 */
destination |= TD_TOKEN_TOGGLE; /* End in Data1 */
status &= ~TD_CTRL_SPD;
......@@ -956,14 +956,6 @@ static int uhci_result_control(struct urb *urb)
tmp = tmp->next;
if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) &&
!(td->status & TD_CTRL_ACTIVE)) {
uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
urbp->fsbr_timeout = 0;
urbp->fsbrtime = jiffies;
clear_bit(TD_CTRL_IOC_BIT, &td->status);
}
status = uhci_status_bits(td->status);
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
......@@ -1102,7 +1094,7 @@ static int uhci_submit_interrupt(struct urb *urb)
if (!td)
return -ENOMEM;
destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
destination |= ((urb->transfer_buffer_length - 1) << 21);
usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
......@@ -1132,14 +1124,6 @@ static int uhci_result_interrupt(struct urb *urb)
tmp = tmp->next;
if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) &&
!(td->status & TD_CTRL_ACTIVE)) {
uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
urbp->fsbr_timeout = 0;
urbp->fsbrtime = jiffies;
clear_bit(TD_CTRL_IOC_BIT, &td->status);
}
status = uhci_status_bits(td->status);
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
......@@ -1203,8 +1187,8 @@ static void uhci_reset_interrupt(struct urb *urb)
td = list_entry(urbp->td_list.next, struct uhci_td, list);
td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
td->info &= ~(1 << TD_TOKEN_TOGGLE);
td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
td->info &= ~TD_TOKEN_TOGGLE;
td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
out:
......@@ -1260,7 +1244,7 @@ static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
uhci_fill_td(td, status, destination |
(((pktsze - 1) & UHCI_NULL_DATA_SIZE) << 21) |
(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
data);
data += pktsze;
......@@ -1288,7 +1272,7 @@ static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
uhci_fill_td(td, status, destination |
(UHCI_NULL_DATA_SIZE << 21) |
(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
data);
usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
......@@ -1508,7 +1492,7 @@ static int uhci_submit_urb(struct urb *urb, int mem_flags)
uhci = (struct uhci *)urb->dev->bus->hcpriv;
INIT_LIST_HEAD(&urb->urb_list);
usb_inc_dev_use(urb->dev);
usb_get_dev(urb->dev);
spin_lock_irqsave(&uhci->urb_list_lock, flags);
spin_lock(&urb->lock);
......@@ -1519,7 +1503,7 @@ static int uhci_submit_urb(struct urb *urb, int mem_flags)
/* Since we can have problems on the out path */
spin_unlock(&urb->lock);
spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
usb_dec_dev_use(urb->dev);
usb_put_dev(urb->dev);
usb_put_urb(urb);
return ret;
......@@ -1839,11 +1823,18 @@ static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb)
{
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct list_head *head, *tmp;
int count = 0;
uhci_dec_fsbr(uhci, urb);
urbp->fsbr_timeout = 1;
/*
* Ideally we would want to fix qh->element as well, but it's
* read/write by the HC, so that can introduce a race. It's not
* really worth the hassle
*/
head = &urbp->td_list;
tmp = head->next;
while (tmp != head) {
......@@ -1851,10 +1842,15 @@ static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb)
tmp = tmp->next;
if (td->status & TD_CTRL_ACTIVE) {
set_bit(TD_CTRL_IOC_BIT, &td->status);
break;
}
/*
* Make sure we don't do the last one (since it'll have the
* TERM bit set) as well as we skip every so many TD's to
* make sure it doesn't hog the bandwidth
*/
if (tmp != head && (count % DEPTH_INTERVAL) == (DEPTH_INTERVAL - 1))
td->link |= UHCI_PTR_DEPTH;
count++;
}
return 0;
......@@ -1873,8 +1869,6 @@ static int uhci_get_current_frame_number(struct usb_device *dev)
}
struct usb_operations uhci_device_operations = {
allocate: uhci_alloc_dev,
deallocate: uhci_free_dev,
get_frame_number: uhci_get_current_frame_number,
submit_urb: uhci_submit_urb,
unlink_urb: uhci_unlink_urb,
......@@ -2382,7 +2376,7 @@ static void uhci_call_completion(struct urb *urb)
} else {
/* We decrement the usage count after we're done */
/* with everything */
usb_dec_dev_use(dev);
usb_put_dev(dev);
usb_put_urb(urb);
}
}
......
......@@ -100,7 +100,6 @@ struct uhci_qh {
#define TD_CTRL_C_ERR_SHIFT 27
#define TD_CTRL_LS (1 << 26) /* Low Speed Device */
#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */
#define TD_CTRL_IOC_BIT 24
#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */
#define TD_CTRL_ACTIVE (1 << 23) /* TD Active */
#define TD_CTRL_STALLED (1 << 22) /* TD Stalled */
......@@ -120,13 +119,14 @@ struct uhci_qh {
/*
* for TD <info>: (a.k.a. Token)
*/
#define TD_TOKEN_TOGGLE 19
#define TD_TOKEN_TOGGLE_SHIFT 19
#define TD_TOKEN_TOGGLE (1 << 19)
#define TD_TOKEN_PID_MASK 0xFF
#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n - 1 */
#define uhci_maxlen(token) ((token) >> 21)
#define uhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */
#define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE) & 1)
#define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1)
#define uhci_endpoint(token) (((token) >> 15) & 0xf)
#define uhci_devaddr(token) (((token) >> 8) & 0x7f)
#define uhci_devep(token) (((token) >> 8) & 0x7ff)
......
......@@ -210,7 +210,7 @@ static void urb_rm_priv_locked (struct urb * urb)
}
urb_free_priv ((struct ohci *)urb->dev->bus->hcpriv, urb_priv);
usb_dec_dev_use (urb->dev);
usb_put_dev (urb->dev);
urb->dev = NULL;
usb_put_urb (urb);
}
......@@ -563,7 +563,7 @@ static int sohci_submit_urb (struct urb * urb, int mem_flags)
/* increment the reference count of the urb, as we now also control it */
urb = usb_get_urb (urb);
usb_inc_dev_use (urb->dev);
usb_get_dev (urb->dev);
ohci = (ohci_t *) urb->dev->bus->hcpriv;
#ifdef DEBUG
......@@ -577,14 +577,14 @@ static int sohci_submit_urb (struct urb * urb, int mem_flags)
/* when controller's hung, permit only roothub cleanup attempts
* such as powering down ports */
if (ohci->disabled) {
usb_dec_dev_use (urb->dev);
usb_put_dev (urb->dev);
usb_put_urb (urb);
return -ESHUTDOWN;
}
/* every endpoint has a ed, locate and fill it */
if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) {
usb_dec_dev_use (urb->dev);
usb_put_dev (urb->dev);
usb_put_urb (urb);
return -ENOMEM;
}
......@@ -606,7 +606,7 @@ static int sohci_submit_urb (struct urb * urb, int mem_flags)
case PIPE_ISOCHRONOUS: /* number of packets from URB */
size = urb->number_of_packets;
if (size <= 0) {
usb_dec_dev_use (urb->dev);
usb_put_dev (urb->dev);
usb_put_urb (urb);
return -EINVAL;
}
......@@ -627,7 +627,7 @@ static int sohci_submit_urb (struct urb * urb, int mem_flags)
/* allocate the private part of the URB */
urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), mem_flags);
if (!urb_priv) {
usb_dec_dev_use (urb->dev);
usb_put_dev (urb->dev);
usb_put_urb (urb);
return -ENOMEM;
}
......@@ -645,7 +645,7 @@ static int sohci_submit_urb (struct urb * urb, int mem_flags)
urb_priv->length = i;
urb_free_priv (ohci, urb_priv);
spin_unlock_irqrestore (&usb_ed_lock, flags);
usb_dec_dev_use (urb->dev);
usb_put_dev (urb->dev);
usb_put_urb (urb);
return -ENOMEM;
}
......@@ -654,7 +654,7 @@ static int sohci_submit_urb (struct urb * urb, int mem_flags)
if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
urb_free_priv (ohci, urb_priv);
spin_unlock_irqrestore (&usb_ed_lock, flags);
usb_dec_dev_use (urb->dev);
usb_put_dev (urb->dev);
usb_put_urb (urb);
return -EINVAL;
}
......@@ -677,7 +677,7 @@ static int sohci_submit_urb (struct urb * urb, int mem_flags)
if (bustime < 0) {
urb_free_priv (ohci, urb_priv);
spin_unlock_irqrestore (&usb_ed_lock, flags);
usb_dec_dev_use (urb->dev);
usb_put_dev (urb->dev);
usb_put_urb (urb);
return bustime;
}
......@@ -802,7 +802,7 @@ static int sohci_unlink_urb (struct urb * urb)
return -ETIMEDOUT;
}
} else {
/* usb_dec_dev_use done in dl_del_list() */
/* usb_put_dev done in dl_del_list() */
urb->status = -EINPROGRESS;
spin_unlock_irqrestore (&usb_ed_lock, flags);
return -EINPROGRESS;
......@@ -2109,7 +2109,7 @@ static int rh_submit_urb (struct urb * urb)
#endif
urb->hcpriv = NULL;
usb_dec_dev_use (usb_dev);
usb_put_dev (usb_dev);
urb->dev = NULL;
if (urb->complete)
urb->complete (urb);
......@@ -2129,7 +2129,7 @@ static int rh_unlink_urb (struct urb * urb)
ohci->rh.urb = NULL;
urb->hcpriv = NULL;
usb_dec_dev_use(urb->dev);
usb_put_dev (urb->dev);
urb->dev = NULL;
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
urb->status = -ECONNRESET;
......
/*
UHCI HCD (Host Controller Driver) for USB, debugging calls
(c) 1999-2002
Georg Acher + Deti Fliegl + Thomas Sailer
georg@acher.org deti@fliegl.de sailer@ife.ee.ethz.ch
$Id: usb-uhci-dbg.c,v 1.1 2002/05/14 20:36:57 acher Exp $
*/
#ifdef DEBUG
static void __attribute__((__unused__)) uhci_show_qh (puhci_desc_t qh)
{
if (qh->type != QH_TYPE) {
dbg("qh has not QH_TYPE");
return;
}
dbg("QH @ %p/%08llX:", qh, (unsigned long long)qh->dma_addr);
if (qh->hw.qh.head & UHCI_PTR_TERM)
dbg(" Head Terminate");
else
dbg(" Head: %s @ %08X",
(qh->hw.qh.head & UHCI_PTR_QH?"QH":"TD"),
qh->hw.qh.head & ~UHCI_PTR_BITS);
if (qh->hw.qh.element & UHCI_PTR_TERM)
dbg(" Element Terminate");
else
dbg(" Element: %s @ %08X",
(qh->hw.qh.element & UHCI_PTR_QH?"QH":"TD"),
qh->hw.qh.element & ~UHCI_PTR_BITS);
}
#endif
#if 0
static void uhci_show_td (puhci_desc_t td)
{
char *spid;
switch (td->hw.td.info & 0xff) {
case USB_PID_SETUP:
spid = "SETUP";
break;
case USB_PID_OUT:
spid = " OUT ";
break;
case USB_PID_IN:
spid = " IN ";
break;
default:
spid = " ? ";
break;
}
warn(" TD @ %p/%08X, MaxLen=%02x DT%d EP=%x Dev=%x PID=(%s) buf=%08x",
td, td->dma_addr,
td->hw.td.info >> 21,
((td->hw.td.info >> 19) & 1),
(td->hw.td.info >> 15) & 15,
(td->hw.td.info >> 8) & 127,
spid,
td->hw.td.buffer);
warn(" Len=%02x e%d %s%s%s%s%s%s%s%s%s%s",
td->hw.td.status & 0x7ff,
((td->hw.td.status >> 27) & 3),
(td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "",
(td->hw.td.status & TD_CTRL_LS) ? "LS " : "",
(td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "",
(td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "",
(td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "",
(td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
(td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "",
(td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "",
(td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
(td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : ""
);
if (td->hw.td.link & UHCI_PTR_TERM)
warn(" TD Link Terminate");
else
warn(" Link points to %s @ %08x, %s",
(td->hw.td.link & UHCI_PTR_QH?"QH":"TD"),
td->hw.td.link & ~UHCI_PTR_BITS,
(td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : "Breadth first"));
}
#endif
#ifdef DEBUG
static void __attribute__((__unused__)) uhci_show_sc (int port, unsigned short status)
{
dbg(" stat%d = %04x %s%s%s%s%s%s%s%s",
port,
status,
(status & USBPORTSC_SUSP) ? "PortSuspend " : "",
(status & USBPORTSC_PR) ? "PortReset " : "",
(status & USBPORTSC_LSDA) ? "LowSpeed " : "",
(status & USBPORTSC_RD) ? "ResumeDetect " : "",
(status & USBPORTSC_PEC) ? "EnableChange " : "",
(status & USBPORTSC_PE) ? "PortEnabled " : "",
(status & USBPORTSC_CSC) ? "ConnectChange " : "",
(status & USBPORTSC_CCS) ? "PortConnected " : "");
}
void uhci_show_status (struct uhci_hcd *uhci)
{
unsigned int io_addr = (int)uhci->hcd.regs;
unsigned short usbcmd, usbstat, usbint, usbfrnum;
unsigned int flbaseadd;
unsigned char sof;
unsigned short portsc1, portsc2;
usbcmd = inw (io_addr + 0);
usbstat = inw (io_addr + 2);
usbint = inw (io_addr + 4);
usbfrnum = inw (io_addr + 6);
flbaseadd = inl (io_addr + 8);
sof = inb (io_addr + 12);
portsc1 = inw (io_addr + 16);
portsc2 = inw (io_addr + 18);
dbg(" usbcmd = %04x %s%s%s%s%s%s%s%s",
usbcmd,
(usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
(usbcmd & USBCMD_CF) ? "CF " : "",
(usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
(usbcmd & USBCMD_FGR) ? "FGR " : "",
(usbcmd & USBCMD_EGSM) ? "EGSM " : "",
(usbcmd & USBCMD_GRESET) ? "GRESET " : "",
(usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
(usbcmd & USBCMD_RS) ? "RS " : "");
dbg(" usbstat = %04x %s%s%s%s%s%s",
usbstat,
(usbstat & USBSTS_HCH) ? "HCHalted " : "",
(usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
(usbstat & USBSTS_HSE) ? "HostSystemError " : "",
(usbstat & USBSTS_RD) ? "ResumeDetect " : "",
(usbstat & USBSTS_ERROR) ? "USBError " : "",
(usbstat & USBSTS_USBINT) ? "USBINT " : "");
dbg(" usbint = %04x", usbint);
dbg(" usbfrnum = (%d)%03x", (usbfrnum >> 10) & 1,
0xfff & (4 * (unsigned int) usbfrnum));
dbg(" flbaseadd = %08x", flbaseadd);
dbg(" sof = %02x", sof);
uhci_show_sc (1, portsc1);
uhci_show_sc (2, portsc2);
}
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -1217,7 +1217,7 @@ _static int uhci_unlink_urb_sync (uhci_t *s, struct urb *urb)
urb->dev = NULL;
urb->complete ((struct urb *) urb);
}
usb_dec_dev_use (usb_dev);
usb_put_dev (usb_dev);
usb_put_urb (urb);
}
else
......@@ -1301,7 +1301,7 @@ _static void uhci_cleanup_unlink(uhci_t *s, int force)
uhci_urb_dma_unmap(s, urb, urb_priv);
usb_dec_dev_use (dev);
usb_put_dev (dev);
#ifdef DEBUG_SLAB
kmem_cache_free (urb_priv_kmem, urb_priv);
#else
......@@ -1655,7 +1655,7 @@ _static int uhci_submit_urb (struct urb *urb, int mem_flags)
/* increment the reference count of the urb, as we now also control it */
urb = usb_get_urb (urb);
usb_inc_dev_use (urb->dev);
usb_get_dev (urb->dev);
spin_lock_irqsave (&s->urb_list_lock, flags);
......@@ -1669,7 +1669,7 @@ _static int uhci_submit_urb (struct urb *urb, int mem_flags)
((type == PIPE_BULK) &&
(!(urb->transfer_flags & USB_QUEUE_BULK) || !(queued_urb->transfer_flags & USB_QUEUE_BULK)))) {
spin_unlock_irqrestore (&s->urb_list_lock, flags);
usb_dec_dev_use (urb->dev);
usb_put_dev (urb->dev);
usb_put_urb (urb);
err("ENXIO %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,queued_urb);
return -ENXIO; // urb already queued
......@@ -1682,7 +1682,7 @@ _static int uhci_submit_urb (struct urb *urb, int mem_flags)
urb_priv = kmalloc (sizeof (urb_priv_t), mem_flags);
#endif
if (!urb_priv) {
usb_dec_dev_use (urb->dev);
usb_put_dev (urb->dev);
spin_unlock_irqrestore (&s->urb_list_lock, flags);
usb_put_urb (urb);
return -ENOMEM;
......@@ -1767,7 +1767,7 @@ _static int uhci_submit_urb (struct urb *urb, int mem_flags)
if (ret != 0) {
uhci_urb_dma_unmap(s, urb, urb_priv);
usb_dec_dev_use (urb->dev);
usb_put_dev (urb->dev);
#ifdef DEBUG_SLAB
kmem_cache_free(urb_priv_kmem, urb_priv);
#else
......@@ -2737,7 +2737,7 @@ _static int process_urb (uhci_t *s, struct list_head *p)
spin_lock(&s->urb_list_lock);
}
usb_dec_dev_use (usb_dev);
usb_put_dev (usb_dev);
usb_put_urb (urb);
}
}
......
......@@ -970,7 +970,7 @@ static void usbvideo_Disconnect(struct usb_device *dev, void *ptr)
for (i=0; i < USBVIDEO_NUMSBUF; i++)
usb_free_urb(uvd->sbuf[i].urb);
usb_dec_dev_use(uvd->dev);
usb_put_dev(uvd->dev);
uvd->dev = NULL; /* USB device is no more */
video_unregister_device(&uvd->vdev);
......@@ -1176,7 +1176,7 @@ int usbvideo_RegisterVideoDevice(uvd_t *uvd)
}
#endif
usb_inc_dev_use(uvd->dev);
usb_get_dev(uvd->dev);
return 0;
}
......
......@@ -1256,7 +1256,7 @@ static void * CDCEther_probe( struct usb_device *usb, unsigned int ifnum,
ether_dev );
// Does this REALLY do anything???
usb_inc_dev_use( usb );
usb_get_dev( usb );
// TODO - last minute HACK
ether_dev->comm_ep_in = 5;
......@@ -1298,7 +1298,7 @@ static void CDCEther_disconnect( struct usb_device *usb, void *ptr )
ether_dev->net = NULL;
// I ask again, does this do anything???
usb_dec_dev_use( usb );
usb_put_dev( usb );
// We are done with this interface
usb_driver_release_interface( &CDCEther_driver,
......
......@@ -981,7 +981,7 @@ static void *pegasus_probe(struct usb_device *dev, unsigned int ifnum,
return NULL;
}
usb_inc_dev_use(dev);
usb_get_dev(dev);
memset(pegasus, 0, sizeof(struct pegasus));
pegasus->dev_index = dev_index;
init_waitqueue_head(&pegasus->ctrl_wait);
......@@ -1086,7 +1086,7 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr)
pegasus->flags |= PEGASUS_UNPLUG;
unregister_netdev(pegasus->net);
usb_dec_dev_use(dev);
usb_put_dev(dev);
usb_unlink_urb(pegasus->intr_urb);
usb_unlink_urb(pegasus->tx_urb);
usb_unlink_urb(pegasus->rx_urb);
......
This diff is collapsed.
......@@ -40,3 +40,7 @@ CONFIG_USB_STORAGE_SDDR09
Say Y here to include additional code to support the Sandisk SDDR-09
SmartMedia reader in the USB Mass Storage driver.
Also works for the Microtech Zio! SmartMedia reader.
CONFIG_USB_STORAGE_SDDR55
Say Y here to include additional code to support the Sandisk SDDR-55
SmartMedia reader in the USB Mass Storage driver.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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