Commit 4a5f1de1 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 e6101d76 bdf0fc9d
...@@ -8,13 +8,8 @@ obj-$(CONFIG_USB) += core/ ...@@ -8,13 +8,8 @@ obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_EHCI_HCD) += host/ obj-$(CONFIG_USB_EHCI_HCD) += host/
obj-$(CONFIG_USB_OHCI_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/
obj-$(CONFIG_USB_UHCI_HCD) += host/ obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_UHCI) += host/ obj-$(CONFIG_USB_SL811HS) += host/
obj-$(CONFIG_USB_ACM) += class/ obj-$(CONFIG_USB_ACM) += class/
obj-$(CONFIG_USB_AUDIO) += class/ obj-$(CONFIG_USB_AUDIO) += class/
......
...@@ -20,14 +20,16 @@ config USB_BLUETOOTH_TTY ...@@ -20,14 +20,16 @@ config USB_BLUETOOTH_TTY
tristate "USB Bluetooth TTY support" tristate "USB Bluetooth TTY support"
depends on USB depends on USB
---help--- ---help---
Say Y here if you want to connect a USB Bluetooth device to your This driver implements a nonstandard tty interface to a Bluetooth
computer's USB port. You will need the Bluetooth stack (available device that can be used only by specialized Bluetooth HCI software.
at <http://developer.axis.com/software/index.shtml>) to fully use
the device. Say Y here if you want to use OpenBT Bluetooth stack (available
at <http://developer.axis.com/software/index.shtml>), or other TTY
This driver implements a tty inteface to a Bluetooth device. If based Bluetooth stacks, and want to connect a USB Bluetooth device
you want to use a socket based Bluetooth stack (like the BlueZ to your computer's USB port.
stack), do not use this driver.
Do *not* enable this driver if you want to use generic Linux
Bluetooth support.
If in doubt, say N here. If in doubt, say N here.
......
/* /*
* usblp.c Version 0.12 * usblp.c Version 0.13
* *
* Copyright (c) 1999 Michael Gee <michael@linuxspecific.com> * Copyright (c) 1999 Michael Gee <michael@linuxspecific.com>
* Copyright (c) 1999 Pavel Machek <pavel@suse.cz> * Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
* Copyright (c) 2000 Randy Dunlap <randy.dunlap@intel.com> * Copyright (c) 2000 Randy Dunlap <rddunlap@osdl.org>
* Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
# Copyright (c) 2001 Pete Zaitcev <zaitcev@redhat.com> # Copyright (c) 2001 Pete Zaitcev <zaitcev@redhat.com>
# Copyright (c) 2001 David Paschal <paschal@rcsis.com> # Copyright (c) 2001 David Paschal <paschal@rcsis.com>
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
* v0.10- remove sleep_on, fix error on oom (oliver@neukum.org) * v0.10- remove sleep_on, fix error on oom (oliver@neukum.org)
* v0.11 - add proto_bias option (Pete Zaitcev) * v0.11 - add proto_bias option (Pete Zaitcev)
* v0.12 - add hpoj.sourceforge.net ioctls (David Paschal) * v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
* v0.13 - alloc space for statusbuf (<status> not on stack);
* use usb_buffer_alloc() for read buf & write buf;
*/ */
/* /*
...@@ -59,7 +61,7 @@ ...@@ -59,7 +61,7 @@
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v0.12" #define DRIVER_VERSION "v0.13"
#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal" #define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
#define DRIVER_DESC "USB Printer Device Class driver" #define DRIVER_DESC "USB Printer Device Class driver"
...@@ -120,11 +122,19 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H ...@@ -120,11 +122,19 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
#define USBLP_LAST_PROTOCOL 3 #define USBLP_LAST_PROTOCOL 3
#define USBLP_MAX_PROTOCOLS (USBLP_LAST_PROTOCOL+1) #define USBLP_MAX_PROTOCOLS (USBLP_LAST_PROTOCOL+1)
/*
* some arbitrary status buffer size;
* need a status buffer that is allocated via kmalloc(), not on stack
*/
#define STATUS_BUF_SIZE 8
struct usblp { struct usblp {
struct usb_device *dev; /* USB device */ struct usb_device *dev; /* USB device */
devfs_handle_t devfs; /* devfs device */ devfs_handle_t devfs; /* devfs device */
struct semaphore sem; /* locks this struct, especially "dev" */ struct semaphore sem; /* locks this struct, especially "dev" */
char *buf; /* writeurb->transfer_buffer */ char *writebuf; /* write transfer_buffer */
char *readbuf; /* read transfer_buffer */
char *statusbuf; /* status transfer_buffer */
struct urb *readurb, *writeurb; /* The urbs */ struct urb *readurb, *writeurb; /* The urbs */
wait_queue_head_t wait; /* Zzzzz ... */ wait_queue_head_t wait; /* Zzzzz ... */
int readcount; /* Counter for reads */ int readcount; /* Counter for reads */
...@@ -289,13 +299,14 @@ static int usblp_check_status(struct usblp *usblp, int err) ...@@ -289,13 +299,14 @@ static int usblp_check_status(struct usblp *usblp, int err)
unsigned char status, newerr = 0; unsigned char status, newerr = 0;
int error; int error;
error = usblp_read_status (usblp, &status); error = usblp_read_status (usblp, usblp->statusbuf);
if (error < 0) { if (error < 0) {
err("usblp%d: error %d reading printer status", err("usblp%d: error %d reading printer status",
usblp->minor, error); usblp->minor, error);
return 0; return 0;
} }
status = *usblp->statusbuf;
if (~status & LP_PERRORP) { if (~status & LP_PERRORP) {
newerr = 3; newerr = 3;
if (status & LP_POUTPA) newerr = 1; if (status & LP_POUTPA) newerr = 1;
...@@ -375,8 +386,12 @@ static void usblp_cleanup (struct usblp *usblp) ...@@ -375,8 +386,12 @@ static void usblp_cleanup (struct usblp *usblp)
usb_deregister_dev (1, usblp->minor); usb_deregister_dev (1, usblp->minor);
info("usblp%d: removed", usblp->minor); info("usblp%d: removed", usblp->minor);
kfree (usblp->writeurb->transfer_buffer); usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
usblp->writebuf, usblp->writeurb->transfer_dma);
usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
usblp->readbuf, usblp->writeurb->transfer_dma);
kfree (usblp->device_id_string); kfree (usblp->device_id_string);
kfree (usblp->statusbuf);
usb_free_urb(usblp->writeurb); usb_free_urb(usblp->writeurb);
usb_free_urb(usblp->readurb); usb_free_urb(usblp->readurb);
kfree (usblp); kfree (usblp);
...@@ -841,11 +856,27 @@ static int usblp_probe(struct usb_interface *intf, ...@@ -841,11 +856,27 @@ static int usblp_probe(struct usb_interface *intf,
goto abort_minor; goto abort_minor;
} }
/* Malloc write/read buffers in one chunk. We somewhat wastefully usblp->writebuf = usblp->readbuf = NULL;
usblp->writeurb->transfer_flags = URB_NO_DMA_MAP;
usblp->readurb->transfer_flags = URB_NO_DMA_MAP;
/* Malloc write & read buffers. We somewhat wastefully
* malloc both regardless of bidirectionality, because the * malloc both regardless of bidirectionality, because the
* alternate setting can be changed later via an ioctl. */ * alternate setting can be changed later via an ioctl. */
if (!(usblp->buf = kmalloc(2 * USBLP_BUF_SIZE, GFP_KERNEL))) { if (!(usblp->writebuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
err("out of memory for buf"); GFP_KERNEL, &usblp->writeurb->transfer_dma))) {
err("out of memory for write buf");
goto abort_minor;
}
if (!(usblp->readbuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
GFP_KERNEL, &usblp->readurb->transfer_dma))) {
err("out of memory for read buf");
goto abort_minor;
}
/* Allocate buffer for printer status */
usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
if (!usblp->statusbuf) {
err("out of memory for statusbuf");
goto abort_minor; goto abort_minor;
} }
...@@ -900,10 +931,16 @@ static int usblp_probe(struct usb_interface *intf, ...@@ -900,10 +931,16 @@ static int usblp_probe(struct usb_interface *intf,
usb_deregister_dev (1, usblp->minor); usb_deregister_dev (1, usblp->minor);
abort: abort:
if (usblp) { if (usblp) {
if (usblp->writebuf)
usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
usblp->writebuf, usblp->writeurb->transfer_dma);
if (usblp->readbuf)
usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
usblp->readbuf, usblp->writeurb->transfer_dma);
if (usblp->statusbuf) kfree(usblp->statusbuf);
if (usblp->device_id_string) kfree(usblp->device_id_string);
usb_free_urb(usblp->writeurb); usb_free_urb(usblp->writeurb);
usb_free_urb(usblp->readurb); usb_free_urb(usblp->readurb);
if (usblp->buf) kfree(usblp->buf);
if (usblp->device_id_string) kfree(usblp->device_id_string);
kfree(usblp); kfree(usblp);
} }
return -EIO; return -EIO;
...@@ -1020,16 +1057,16 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol) ...@@ -1020,16 +1057,16 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol)
usb_fill_bulk_urb(usblp->writeurb, usblp->dev, usb_fill_bulk_urb(usblp->writeurb, usblp->dev,
usb_sndbulkpipe(usblp->dev, usb_sndbulkpipe(usblp->dev,
usblp->protocol[protocol].epwrite->bEndpointAddress), usblp->protocol[protocol].epwrite->bEndpointAddress),
usblp->buf, 0, usblp->writebuf, 0,
usblp_bulk_write, usblp); usblp_bulk_write, usblp);
usblp->bidir = (usblp->protocol[protocol].epread != 0); usblp->bidir = (usblp->protocol[protocol].epread != 0);
if (usblp->bidir) if (usblp->bidir)
usb_fill_bulk_urb(usblp->readurb, usblp->dev, usb_fill_bulk_urb(usblp->readurb, usblp->dev,
usb_rcvbulkpipe(usblp->dev, usb_rcvbulkpipe(usblp->dev,
usblp->protocol[protocol].epread->bEndpointAddress), usblp->protocol[protocol].epread->bEndpointAddress),
usblp->buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp->readbuf, USBLP_BUF_SIZE,
usblp_bulk_read, usblp); usblp_bulk_read, usblp);
usblp->current_protocol = protocol; usblp->current_protocol = protocol;
......
...@@ -148,23 +148,31 @@ usb_descriptor_attr (bcdDevice, "%04x\n") ...@@ -148,23 +148,31 @@ usb_descriptor_attr (bcdDevice, "%04x\n")
usb_descriptor_attr (bDeviceClass, "%02x\n") usb_descriptor_attr (bDeviceClass, "%02x\n")
usb_descriptor_attr (bDeviceSubClass, "%02x\n") usb_descriptor_attr (bDeviceSubClass, "%02x\n")
usb_descriptor_attr (bDeviceProtocol, "%02x\n") usb_descriptor_attr (bDeviceProtocol, "%02x\n")
usb_descriptor_attr (bNumConfigurations, "%d\n")
void usb_create_driverfs_dev_files (struct usb_device *udev) void usb_create_driverfs_dev_files (struct usb_device *udev)
{ {
struct device *dev = &udev->dev; struct device *dev = &udev->dev;
/* current configuration's attributes */
device_create_file (dev, &dev_attr_bNumInterfaces); device_create_file (dev, &dev_attr_bNumInterfaces);
device_create_file (dev, &dev_attr_bConfigurationValue); device_create_file (dev, &dev_attr_bConfigurationValue);
device_create_file (dev, &dev_attr_bmAttributes); device_create_file (dev, &dev_attr_bmAttributes);
device_create_file (dev, &dev_attr_bMaxPower); device_create_file (dev, &dev_attr_bMaxPower);
/* device attributes */
device_create_file (dev, &dev_attr_idVendor); device_create_file (dev, &dev_attr_idVendor);
device_create_file (dev, &dev_attr_idProduct); device_create_file (dev, &dev_attr_idProduct);
device_create_file (dev, &dev_attr_bcdDevice); device_create_file (dev, &dev_attr_bcdDevice);
device_create_file (dev, &dev_attr_bDeviceClass); device_create_file (dev, &dev_attr_bDeviceClass);
device_create_file (dev, &dev_attr_bDeviceSubClass); device_create_file (dev, &dev_attr_bDeviceSubClass);
device_create_file (dev, &dev_attr_bDeviceProtocol); device_create_file (dev, &dev_attr_bDeviceProtocol);
device_create_file (dev, &dev_attr_bNumConfigurations);
/* speed varies depending on how you connect the device */
device_create_file (dev, &dev_attr_speed); device_create_file (dev, &dev_attr_speed);
// FIXME iff there are other speed configs, show how many
if (udev->descriptor.iManufacturer) if (udev->descriptor.iManufacturer)
device_create_file (dev, &dev_attr_manufacturer); device_create_file (dev, &dev_attr_manufacturer);
......
...@@ -138,6 +138,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -138,6 +138,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
hcd->pdev = dev; hcd->pdev = dev;
hcd->self.bus_name = dev->slot_name; hcd->self.bus_name = dev->slot_name;
hcd->product_desc = dev->name; hcd->product_desc = dev->name;
hcd->controller = &dev->dev;
if ((retval = hcd_buffer_create (hcd)) != 0) { if ((retval = hcd_buffer_create (hcd)) != 0) {
clean_3: clean_3:
......
...@@ -23,6 +23,11 @@ ...@@ -23,6 +23,11 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#endif
#include <linux/module.h> #include <linux/module.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -32,13 +37,6 @@ ...@@ -32,13 +37,6 @@
#include <linux/pci.h> /* for hcd->pdev and dma addressing */ #include <linux/pci.h> /* for hcd->pdev and dma addressing */
#include <asm/byteorder.h> #include <asm/byteorder.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/usb.h> #include <linux/usb.h>
#include "hcd.h" #include "hcd.h"
...@@ -1090,6 +1088,7 @@ static int hcd_unlink_urb (struct urb *urb) ...@@ -1090,6 +1088,7 @@ static int hcd_unlink_urb (struct urb *urb)
{ {
struct hcd_dev *dev; struct hcd_dev *dev;
struct usb_hcd *hcd = 0; struct usb_hcd *hcd = 0;
struct device *sys = 0;
unsigned long flags; unsigned long flags;
struct completion_splice splice; struct completion_splice splice;
int retval; int retval;
...@@ -1110,38 +1109,31 @@ static int hcd_unlink_urb (struct urb *urb) ...@@ -1110,38 +1109,31 @@ static int hcd_unlink_urb (struct urb *urb)
*/ */
spin_lock_irqsave (&urb->lock, flags); spin_lock_irqsave (&urb->lock, flags);
spin_lock (&hcd_data_lock); spin_lock (&hcd_data_lock);
if (!urb->hcpriv || urb->transfer_flags & URB_TIMEOUT_KILLED) {
retval = -EINVAL;
goto done;
}
if (!urb->dev || !urb->dev->bus) { if (!urb->dev || !urb->dev->bus) {
retval = -ENODEV; retval = -ENODEV;
goto done; goto done;
} }
/* giveback clears dev; non-null means it's linked at this level */
dev = urb->dev->hcpriv; dev = urb->dev->hcpriv;
sys = &urb->dev->dev;
hcd = urb->dev->bus->hcpriv; hcd = urb->dev->bus->hcpriv;
if (!dev || !hcd) { if (!dev || !hcd) {
retval = -ENODEV; retval = -ENODEV;
goto done; goto done;
} }
/* Except for interrupt transfers, any status except -EINPROGRESS if (!urb->hcpriv) {
* means the HCD already started to unlink this URB from the hardware. retval = -EINVAL;
* So there's no more work to do. goto done;
* }
* For interrupt transfers, this is the only way to trigger unlinking
* from the hardware. Since we (currently) overload urb->status to /* Any status except -EINPROGRESS means something already started to
* tell the driver to unlink, error status might get clobbered ... * unlink this URB from the hardware. So there's no more work to do.
* unless that transfer hasn't yet restarted. One such case is when
* the URB gets unlinked from its completion handler.
* *
* FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED * FIXME use better explicit urb state
*/ */
if (urb->status != -EINPROGRESS if (urb->status != -EINPROGRESS) {
&& usb_pipetype (urb->pipe) != PIPE_INTERRUPT) {
retval = -EINVAL; retval = -EINVAL;
goto done; goto done;
} }
...@@ -1150,9 +1142,7 @@ static int hcd_unlink_urb (struct urb *urb) ...@@ -1150,9 +1142,7 @@ static int hcd_unlink_urb (struct urb *urb)
* lower level hcd code is always async, locking on urb->status * lower level hcd code is always async, locking on urb->status
* updates; an intercepted completion unblocks us. * updates; an intercepted completion unblocks us.
*/ */
if ((urb->transfer_flags & URB_TIMEOUT_KILLED)) if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
urb->status = -ETIMEDOUT;
else if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
if (in_interrupt ()) { if (in_interrupt ()) {
dbg ("non-async unlink in_interrupt"); dbg ("non-async unlink in_interrupt");
retval = -EWOULDBLOCK; retval = -EWOULDBLOCK;
...@@ -1177,29 +1167,34 @@ static int hcd_unlink_urb (struct urb *urb) ...@@ -1177,29 +1167,34 @@ static int hcd_unlink_urb (struct urb *urb)
retval = 0; retval = 0;
} else { } else {
retval = hcd->driver->urb_dequeue (hcd, urb); retval = hcd->driver->urb_dequeue (hcd, urb);
// FIXME: if retval and we tried to splice, whoa!!
if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval); /* hcds shouldn't really fail these calls, but... */
if (retval) {
dev_dbg (*sys, "dequeue %p --> %d\n", urb, retval);
if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
spin_lock_irqsave (&urb->lock, flags);
urb->complete = splice.complete;
urb->context = splice.context;
spin_unlock_irqrestore (&urb->lock, flags);
}
goto bye;
}
} }
/* block till giveback, if needed */ /* block till giveback, if needed */
if (!(urb->transfer_flags & (URB_ASYNC_UNLINK|URB_TIMEOUT_KILLED)) if (urb->transfer_flags & URB_ASYNC_UNLINK)
&& HCD_IS_RUNNING (hcd->state)
&& !retval) {
dbg ("%s: wait for giveback urb %p",
hcd->self.bus_name, urb);
wait_for_completion (&splice.done);
} else if ((urb->transfer_flags & URB_ASYNC_UNLINK) && retval == 0) {
return -EINPROGRESS; return -EINPROGRESS;
}
goto bye; dev_dbg (*sys, "wait for giveback urb %p\n", urb);
wait_for_completion (&splice.done);
return 0;
done: done:
spin_unlock (&hcd_data_lock); spin_unlock (&hcd_data_lock);
spin_unlock_irqrestore (&urb->lock, flags); spin_unlock_irqrestore (&urb->lock, flags);
bye: bye:
if (retval) if (retval && sys)
dbg ("%s: hcd_unlink_urb fail %d", dev_dbg (*sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
hcd ? hcd->self.bus_name : "(no bus?)",
retval);
return retval; return retval;
} }
......
...@@ -74,10 +74,10 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ ...@@ -74,10 +74,10 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
struct hc_driver *driver; /* hw-specific hooks */ struct hc_driver *driver; /* hw-specific hooks */
int irq; /* irq allocated */ int irq; /* irq allocated */
void *regs; /* device memory/io */ void *regs; /* device memory/io */
struct device *controller; /* handle to hardware */
/* a few non-PCI controllers exist, mostly for OHCI */ /* a few non-PCI controllers exist, mostly for OHCI */
struct pci_dev *pdev; /* pci is typical */ struct pci_dev *pdev; /* pci is typical */
struct device *parent; /* parent device driver */
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
int region; /* pci region for regs */ int region; /* pci region for regs */
u32 pci_state [16]; /* for PM state save */ u32 pci_state [16]; /* for PM state save */
......
...@@ -67,7 +67,7 @@ static void generic_release (struct device_driver * drv) ...@@ -67,7 +67,7 @@ static void generic_release (struct device_driver * drv)
} }
static struct device_driver usb_generic_driver = { static struct device_driver usb_generic_driver = {
.name = "generic", .name = "usb",
.bus = &usb_bus_type, .bus = &usb_bus_type,
.probe = generic_probe, .probe = generic_probe,
.remove = generic_remove, .remove = generic_remove,
...@@ -514,17 +514,10 @@ static int usb_device_match (struct device *dev, struct device_driver *drv) ...@@ -514,17 +514,10 @@ static int usb_device_match (struct device *dev, struct device_driver *drv)
* or other modules, configure the device, and more. Drivers can provide * or other modules, configure the device, and more. Drivers can provide
* a MODULE_DEVICE_TABLE to help with module loading subtasks. * a MODULE_DEVICE_TABLE to help with module loading subtasks.
* *
* Some synchronization is important: removes can't start processing * We're called either from khubd (the typical case) or from root hub
* before the add-device processing completes, and vice versa. That keeps * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
* a stack of USB-related identifiers stable while they're in use. If we * delays in event delivery. Use sysfs (and DEVPATH) to make sure the
* know that agents won't complete after they return (such as by forking * device (and this configuration!) are still present.
* a process that completes later), it's enough to just waitpid() for the
* agent -- as is currently done.
*
* The reason: we know we're called either from khubd (the typical case)
* or from root hub initialization (init, kapmd, modprobe, etc). In both
* cases, we know no other thread can recycle our address, since we must
* already have been serialized enough to prevent that.
*/ */
static int usb_hotplug (struct device *dev, char **envp, int num_envp, static int usb_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size) char *buffer, int buffer_size)
...@@ -579,7 +572,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, ...@@ -579,7 +572,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
scratch += length; scratch += length;
#endif #endif
/* per-device configuration hacks are common */ /* per-device configurations are common */
envp [i++] = scratch; envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x", length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",
usb_dev->descriptor.idVendor, usb_dev->descriptor.idVendor,
...@@ -604,10 +597,9 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, ...@@ -604,10 +597,9 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
if (usb_dev->descriptor.bDeviceClass == 0) { if (usb_dev->descriptor.bDeviceClass == 0) {
int alt = intf->act_altsetting; int alt = intf->act_altsetting;
/* a simple/common case: one config, one interface, one driver /* 2.4 only exposed interface zero. in 2.5, hotplug
* with current altsetting being a reasonable setting. * agents are called for all interfaces, and can use
* everything needs a smart agent and usbfs; or can rely on * $DEVPATH/bInterfaceNumber if necessary.
* device-specific binding policies.
*/ */
envp [i++] = scratch; envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length, length += snprintf (scratch, buffer_size - length,
...@@ -949,6 +941,24 @@ int usb_new_device(struct usb_device *dev, struct device *parent) ...@@ -949,6 +941,24 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
int i; int i;
int j; int j;
/*
* Set the driver for the usb device to point to the "generic" driver.
* This prevents the main usb device from being sent to the usb bus
* probe function. Yes, it's a hack, but a nice one :)
*
* Do it asap, so more driver model stuff (like the device.h message
* utilities) can be used in hcd submit/unlink code paths.
*/
usb_generic_driver.bus = &usb_bus_type;
dev->dev.parent = parent;
dev->dev.driver = &usb_generic_driver;
dev->dev.bus = &usb_bus_type;
if (dev->dev.bus_id[0] == 0)
sprintf (&dev->dev.bus_id[0], "%d-%s",
dev->bus->busnum, dev->devpath);
/* USB device state == default ... it's not usable yet */
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices. * it's fixed size except for full speed devices.
*/ */
...@@ -1010,6 +1020,8 @@ int usb_new_device(struct usb_device *dev, struct device *parent) ...@@ -1010,6 +1020,8 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
} }
/* USB device state == addressed ... still not usable */
err = usb_get_device_descriptor(dev); err = usb_get_device_descriptor(dev);
if (err < (signed)sizeof(dev->descriptor)) { if (err < (signed)sizeof(dev->descriptor)) {
if (err < 0) if (err < 0)
...@@ -1042,6 +1054,8 @@ int usb_new_device(struct usb_device *dev, struct device *parent) ...@@ -1042,6 +1054,8 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
return 1; return 1;
} }
/* USB device state == configured ... tell the world! */
dbg("new device strings: Mfr=%d, Product=%d, SerialNumber=%d", dbg("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber); dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
set_device_description (dev); set_device_description (dev);
...@@ -1051,23 +1065,10 @@ int usb_new_device(struct usb_device *dev, struct device *parent) ...@@ -1051,23 +1065,10 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
#endif #endif
/* /* put into sysfs, with device and config specific files */
* Set the driver for the usb device to point to the "generic" driver.
* This prevents the main usb device from being sent to the usb bus
* probe function. Yes, it's a hack, but a nice one :)
*/
usb_generic_driver.bus = &usb_bus_type;
dev->dev.parent = parent;
dev->dev.driver = &usb_generic_driver;
dev->dev.bus = &usb_bus_type;
if (dev->dev.bus_id[0] == 0)
sprintf (&dev->dev.bus_id[0], "%d-%s",
dev->bus->busnum, dev->devpath);
err = device_register (&dev->dev); err = device_register (&dev->dev);
if (err) if (err)
return err; return err;
/* add the USB device specific driverfs files */
usb_create_driverfs_dev_files (dev); usb_create_driverfs_dev_files (dev);
/* Register all of the interfaces for this device with the driver core. /* Register all of the interfaces for this device with the driver core.
......
...@@ -49,7 +49,7 @@ config USB_OHCI_HCD ...@@ -49,7 +49,7 @@ config USB_OHCI_HCD
The module will be called ohci-hcd.o. If you want to compile it The module will be called ohci-hcd.o. If you want to compile it
as a module, say M here and read <file:Documentation/modules.txt>. as a module, say M here and read <file:Documentation/modules.txt>.
config USB_UHCI_HCD_ALT config USB_UHCI_HCD
tristate "UHCI HCD (most Intel and VIA) support" tristate "UHCI HCD (most Intel and VIA) support"
depends on USB depends on USB
---help--- ---help---
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD_ALT) += uhci-hcd.o obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_SL811HS) += hc_sl811.o obj-$(CONFIG_USB_SL811HS) += hc_sl811.o
......
...@@ -272,6 +272,7 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { } ...@@ -272,6 +272,7 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep) static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep)
{ {
u32 scratch; u32 scratch;
u32 hw_curr;
struct list_head *entry; struct list_head *entry;
struct ehci_qtd *td; struct ehci_qtd *td;
unsigned temp; unsigned temp;
...@@ -279,20 +280,22 @@ static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep) ...@@ -279,20 +280,22 @@ static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep)
char *next = *nextp; char *next = *nextp;
scratch = cpu_to_le32p (&qh->hw_info1); scratch = cpu_to_le32p (&qh->hw_info1);
temp = snprintf (next, size, "qh/%p dev%d %cs ep%d %08x %08x", hw_curr = cpu_to_le32p (&qh->hw_current);
temp = snprintf (next, size, "qh/%p dev%d %cs ep%d %08x %08x (%08x %08x)",
qh, scratch & 0x007f, qh, scratch & 0x007f,
speed_char (scratch), speed_char (scratch),
(scratch >> 8) & 0x000f, (scratch >> 8) & 0x000f,
scratch, cpu_to_le32p (&qh->hw_info2)); scratch, cpu_to_le32p (&qh->hw_info2),
hw_curr, cpu_to_le32p (&qh->hw_token));
size -= temp; size -= temp;
next += temp; next += temp;
list_for_each (entry, &qh->qtd_list) { list_for_each (entry, &qh->qtd_list) {
td = list_entry (entry, struct ehci_qtd, td = list_entry (entry, struct ehci_qtd, qtd_list);
qtd_list);
scratch = cpu_to_le32p (&td->hw_token); scratch = cpu_to_le32p (&td->hw_token);
temp = snprintf (next, size, temp = snprintf (next, size,
"\n\ttd/%p %s len=%d %08x urb %p", "\n\t%std/%p %s len=%d %08x urb %p",
(hw_curr == td->qtd_dma) ? "*" : "",
td, ({ char *tmp; td, ({ char *tmp;
switch ((scratch>>8)&0x03) { switch ((scratch>>8)&0x03) {
case 0: tmp = "out"; break; case 0: tmp = "out"; break;
...@@ -552,8 +555,8 @@ show_registers (struct device *dev, char *buf, size_t count, loff_t off) ...@@ -552,8 +555,8 @@ show_registers (struct device *dev, char *buf, size_t count, loff_t off)
size -= temp; size -= temp;
next += temp; next += temp;
temp = snprintf (next, size, "complete %ld unlink %ld qpatch %ld\n", temp = snprintf (next, size, "complete %ld unlink %ld\n",
ehci->stats.complete, ehci->stats.unlink, ehci->stats.qpatch); ehci->stats.complete, ehci->stats.unlink);
size -= temp; size -= temp;
next += temp; next += temp;
#endif #endif
......
...@@ -494,8 +494,8 @@ static void ehci_stop (struct usb_hcd *hcd) ...@@ -494,8 +494,8 @@ static void ehci_stop (struct usb_hcd *hcd)
#ifdef EHCI_STATS #ifdef EHCI_STATS
dbg ("irq normal %ld err %ld reclaim %ld", dbg ("irq normal %ld err %ld reclaim %ld",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim); ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim);
dbg ("complete %ld unlink %ld qpatch %ld", dbg ("complete %ld unlink %ld",
ehci->stats.complete, ehci->stats.unlink, ehci->stats.qpatch); ehci->stats.complete, ehci->stats.unlink);
#endif #endif
dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status)); dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
......
...@@ -58,19 +58,23 @@ static void ehci_hcd_free (struct usb_hcd *hcd) ...@@ -58,19 +58,23 @@ static void ehci_hcd_free (struct usb_hcd *hcd)
/* Allocate the key transfer structures from the previously allocated pool */ /* Allocate the key transfer structures from the previously allocated pool */
static void ehci_qtd_init (struct ehci_qtd *qtd, dma_addr_t dma)
{
memset (qtd, 0, sizeof *qtd);
qtd->qtd_dma = dma;
qtd->hw_next = EHCI_LIST_END;
qtd->hw_alt_next = EHCI_LIST_END;
INIT_LIST_HEAD (&qtd->qtd_list);
}
static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags) static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags)
{ {
struct ehci_qtd *qtd; struct ehci_qtd *qtd;
dma_addr_t dma; dma_addr_t dma;
qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma); qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma);
if (qtd != 0) { if (qtd != 0)
memset (qtd, 0, sizeof *qtd); ehci_qtd_init (qtd, dma);
qtd->qtd_dma = dma;
qtd->hw_next = EHCI_LIST_END;
qtd->hw_alt_next = EHCI_LIST_END;
INIT_LIST_HEAD (&qtd->qtd_list);
}
return qtd; return qtd;
} }
...@@ -87,12 +91,21 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) ...@@ -87,12 +91,21 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
qh = (struct ehci_qh *) qh = (struct ehci_qh *)
pci_pool_alloc (ehci->qh_pool, flags, &dma); pci_pool_alloc (ehci->qh_pool, flags, &dma);
if (qh) { if (!qh)
memset (qh, 0, sizeof *qh); return qh;
atomic_set (&qh->refcount, 1);
qh->qh_dma = dma; memset (qh, 0, sizeof *qh);
// INIT_LIST_HEAD (&qh->qh_list); atomic_set (&qh->refcount, 1);
INIT_LIST_HEAD (&qh->qtd_list); qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD (&qh->qtd_list);
/* dummy td enables safe urb queuing */
qh->dummy = ehci_qtd_alloc (ehci, flags);
if (qh->dummy == 0) {
dbg ("no dummy td");
pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
qh = 0;
} }
return qh; return qh;
} }
...@@ -115,6 +128,8 @@ static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -115,6 +128,8 @@ static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh)
dbg ("unused qh not empty!"); dbg ("unused qh not empty!");
BUG (); BUG ();
} }
if (qh->dummy)
ehci_qtd_free (ehci, qh->dummy);
pci_pool_free (ehci->qh_pool, qh, qh->qh_dma); pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
} }
......
...@@ -85,7 +85,7 @@ qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token) ...@@ -85,7 +85,7 @@ qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token)
/* update halted (but potentially linked) qh */ /* update halted (but potentially linked) qh */
static inline void qh_update (struct ehci_qh *qh, struct ehci_qtd *qtd) static void qh_update (struct ehci_qh *qh, struct ehci_qtd *qtd)
{ {
qh->hw_current = 0; qh->hw_current = 0;
qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma); qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
...@@ -221,17 +221,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -221,17 +221,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
struct urb *urb = qtd->urb; struct urb *urb = qtd->urb;
u32 token = 0; u32 token = 0;
/* hc's on-chip qh overlay cache can overwrite our idea of
* next qtd ptrs, if we appended a qtd while the queue was
* advancing. (because we don't use dummy qtds.)
*/
if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current
&& qtd->hw_next != qh->hw_qtd_next) {
qh->hw_alt_next = qtd->hw_alt_next;
qh->hw_qtd_next = qtd->hw_next;
COUNT (ehci->stats.qpatch);
}
/* clean up any state from previous QTD ...*/ /* clean up any state from previous QTD ...*/
if (last) { if (last) {
if (likely (last->urb != urb)) { if (likely (last->urb != urb)) {
...@@ -495,8 +484,7 @@ qh_urb_transaction ( ...@@ -495,8 +484,7 @@ qh_urb_transaction (
} }
/* by default, enable interrupt on urb completion */ /* by default, enable interrupt on urb completion */
// ... do it always, unless we switch over to dummy qtds if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
// if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC); qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
return head; return head;
...@@ -661,8 +649,15 @@ ehci_qh_make ( ...@@ -661,8 +649,15 @@ ehci_qh_make (
/* initialize sw and hw queues with these qtds */ /* initialize sw and hw queues with these qtds */
if (!list_empty (qtd_list)) { if (!list_empty (qtd_list)) {
struct ehci_qtd *qtd;
/* hc's list view ends with dummy td; we might update it */
qtd = list_entry (qtd_list->prev, struct ehci_qtd, qtd_list);
qtd->hw_next = QTD_NEXT (qh->dummy->qtd_dma);
list_splice (qtd_list, &qh->qtd_list); list_splice (qtd_list, &qh->qtd_list);
qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list)); qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
qh_update (qh, qtd);
} else { } else {
qh->hw_qtd_next = qh->hw_alt_next = EHCI_LIST_END; qh->hw_qtd_next = qh->hw_alt_next = EHCI_LIST_END;
} }
...@@ -767,39 +762,48 @@ static struct ehci_qh *qh_append_tds ( ...@@ -767,39 +762,48 @@ static struct ehci_qh *qh_append_tds (
/* append to tds already queued to this qh? */ /* append to tds already queued to this qh? */
if (unlikely (!list_empty (&qh->qtd_list) && qtd)) { if (unlikely (!list_empty (&qh->qtd_list) && qtd)) {
struct ehci_qtd *last_qtd; struct ehci_qtd *dummy;
u32 hw_next; dma_addr_t dma;
u32 token;
/* update the last qtd's "next" pointer */
// dbg_qh ("non-empty qh", ehci, qh); /* to avoid racing the HC, use the dummy td instead of
last_qtd = list_entry (qh->qtd_list.prev, * the first td of our list (becomes new dummy). both
* tds stay deactivated until we're done, when the
* HC is allowed to fetch the old dummy (4.10.2).
*/
token = qtd->hw_token;
qtd->hw_token = 0;
dummy = qh->dummy;
// dbg ("swap td %p with dummy %p", qtd, dummy);
dma = dummy->qtd_dma;
*dummy = *qtd;
dummy->qtd_dma = dma;
list_del (&qtd->qtd_list);
list_add (&dummy->qtd_list, qtd_list);
ehci_qtd_init (qtd, qtd->qtd_dma);
qh->dummy = qtd;
/* hc must see the new dummy at list end */
qtd = list_entry (qh->qtd_list.prev,
struct ehci_qtd, qtd_list); struct ehci_qtd, qtd_list);
hw_next = QTD_NEXT (qtd->qtd_dma); qtd->hw_next = QTD_NEXT (dma);
last_qtd->hw_next = hw_next;
/* previous urb allows short rx? maybe optimize. */
if (!(last_qtd->urb->transfer_flags & URB_SHORT_NOT_OK)
&& (epnum & 0x10)) {
// only the last QTD for now
last_qtd->hw_alt_next = hw_next;
}
/* qh_completions() may need to patch the qh overlay if /* let the hc process these next qtds */
* the hc was advancing this queue while we appended.
* we know it can: last_qtd->hw_token has IOC set.
*
* or: use a dummy td (so the overlay gets the next td
* only when we set its active bit); fewer irqs.
*/
wmb (); wmb ();
dummy->hw_token = token;
/* no URB queued */ /* no URB queued */
} else { } else {
// dbg_qh ("empty qh", ehci, qh); struct ehci_qtd *last_qtd;
/* NOTE: we already canceled any queued URBs /* make sure hc sees current dummy at the end */
* when the endpoint halted. last_qtd = list_entry (qtd_list->prev,
*/ struct ehci_qtd, qtd_list);
last_qtd->hw_next = QTD_NEXT (qh->dummy->qtd_dma);
// dbg_qh ("empty qh", ehci, qh);
/* usb_clear_halt() means qh data toggle gets reset */ /* usb_clear_halt() means qh data toggle gets reset */
if (unlikely (!usb_gettoggle (urb->dev, if (unlikely (!usb_gettoggle (urb->dev,
......
...@@ -31,11 +31,6 @@ struct ehci_stats { ...@@ -31,11 +31,6 @@ struct ehci_stats {
/* termination of urbs from core */ /* termination of urbs from core */
unsigned long complete; unsigned long complete;
unsigned long unlink; unsigned long unlink;
/* qhs patched to recover from td queueing race
* (can avoid by using 'dummy td', allowing fewer irqs)
*/
unsigned long qpatch;
}; };
/* ehci_hcd->lock guards shared data against other CPUs: /* ehci_hcd->lock guards shared data against other CPUs:
...@@ -311,6 +306,7 @@ struct ehci_qh { ...@@ -311,6 +306,7 @@ struct ehci_qh {
dma_addr_t qh_dma; /* address of qh */ dma_addr_t qh_dma; /* address of qh */
union ehci_shadow qh_next; /* ptr to qh; or periodic */ union ehci_shadow qh_next; /* ptr to qh; or periodic */
struct list_head qtd_list; /* sw qtd list */ struct list_head qtd_list; /* sw qtd list */
struct ehci_qtd *dummy;
atomic_t refcount; atomic_t refcount;
......
...@@ -24,7 +24,8 @@ ...@@ -24,7 +24,8 @@
/* debug| print the main components of an URB /* debug| print the main components of an URB
* small: 0) header + data packets 1) just header * small: 0) header + data packets 1) just header
*/ */
static void urb_print (struct urb * urb, char * str, int small) static void __attribute__((unused))
urb_print (struct urb * urb, char * str, int small)
{ {
unsigned int pipe= urb->pipe; unsigned int pipe= urb->pipe;
...@@ -204,10 +205,6 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose) ...@@ -204,10 +205,6 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose)
// dumps some of the state we know about // dumps some of the state we know about
ohci_dump_status (controller); ohci_dump_status (controller);
#ifdef OHCI_VERBOSE_DEBUG
if (verbose)
ohci_dump_periodic (controller, "hcca");
#endif
if (controller->hcca) if (controller->hcca)
dbg ("hcca frame #%04x", controller->hcca->frame_no); dbg ("hcca frame #%04x", controller->hcca->frame_no);
ohci_dump_roothub (controller, 1); ohci_dump_roothub (controller, 1);
...@@ -510,16 +507,16 @@ static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL); ...@@ -510,16 +507,16 @@ static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
static inline void create_debug_files (struct ohci_hcd *bus) static inline void create_debug_files (struct ohci_hcd *bus)
{ {
device_create_file (bus->hcd.parent, &dev_attr_async); device_create_file (bus->hcd.controller, &dev_attr_async);
device_create_file (bus->hcd.parent, &dev_attr_periodic); device_create_file (bus->hcd.controller, &dev_attr_periodic);
// registers // registers
dbg ("%s: created debug files", bus->hcd.self.bus_name); dbg ("%s: created debug files", bus->hcd.self.bus_name);
} }
static inline void remove_debug_files (struct ohci_hcd *bus) static inline void remove_debug_files (struct ohci_hcd *bus)
{ {
device_remove_file (bus->hcd.parent, &dev_attr_async); device_remove_file (bus->hcd.controller, &dev_attr_async);
device_remove_file (bus->hcd.parent, &dev_attr_periodic); device_remove_file (bus->hcd.controller, &dev_attr_periodic);
} }
#else /* empty stubs for creating those files */ #else /* empty stubs for creating those files */
......
...@@ -271,7 +271,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) ...@@ -271,7 +271,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags; unsigned long flags;
#ifdef DEBUG #ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "UNLINK", 1); urb_print (urb, "UNLINK", 1);
#endif #endif
...@@ -514,7 +514,7 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -514,7 +514,7 @@ static int hc_start (struct ohci_hcd *ohci)
usb_connect (udev); usb_connect (udev);
udev->speed = USB_SPEED_FULL; udev->speed = USB_SPEED_FULL;
if (usb_register_root_hub (udev, ohci->parent_dev) != 0) { if (usb_register_root_hub (udev, ohci->hcd.controller) != 0) {
usb_free_dev (udev); usb_free_dev (udev);
ohci->hcd.self.root_hub = NULL; ohci->hcd.self.root_hub = NULL;
disable (ohci); disable (ohci);
......
...@@ -80,8 +80,6 @@ ohci_pci_start (struct usb_hcd *hcd) ...@@ -80,8 +80,6 @@ ohci_pci_start (struct usb_hcd *hcd)
} }
ohci->regs = hcd->regs; ohci->regs = hcd->regs;
ohci->parent_dev = &ohci->hcd.pdev->dev;
if (hc_reset (ohci) < 0) { if (hc_reset (ohci) < 0) {
ohci_stop (hcd); ohci_stop (hcd);
return -ENODEV; return -ENODEV;
......
...@@ -110,10 +110,12 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) ...@@ -110,10 +110,12 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
{ {
unsigned i; unsigned i;
#ifdef OHCI_VERBOSE_DEBUG
dbg ("%s: link %sed %p branch %d [%dus.], interval %d", dbg ("%s: link %sed %p branch %d [%dus.], interval %d",
ohci->hcd.self.bus_name, ohci->hcd.self.bus_name,
(ed->hwINFO & ED_ISO) ? "iso " : "", (ed->hwINFO & ED_ISO) ? "iso " : "",
ed, ed->branch, ed->load, ed->interval); ed, ed->branch, ed->load, ed->interval);
#endif
for (i = ed->branch; i < NUM_INTS; i += ed->interval) { for (i = ed->branch; i < NUM_INTS; i += ed->interval) {
struct ed **prev = &ohci->periodic [i]; struct ed **prev = &ohci->periodic [i];
...@@ -244,10 +246,12 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) ...@@ -244,10 +246,12 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
} }
ohci->hcd.self.bandwidth_allocated -= ed->load / ed->interval; ohci->hcd.self.bandwidth_allocated -= ed->load / ed->interval;
#ifdef OHCI_VERBOSE_DEBUG
dbg ("%s: unlink %sed %p branch %d [%dus.], interval %d", dbg ("%s: unlink %sed %p branch %d [%dus.], interval %d",
ohci->hcd.self.bus_name, ohci->hcd.self.bus_name,
(ed->hwINFO & ED_ISO) ? "iso " : "", (ed->hwINFO & ED_ISO) ? "iso " : "",
ed, ed->branch, ed->load, ed->interval); ed, ed->branch, ed->load, ed->interval);
#endif
} }
/* unlink an ed from one of the HC chains. /* unlink an ed from one of the HC chains.
...@@ -414,7 +418,6 @@ static struct ed *ed_get ( ...@@ -414,7 +418,6 @@ static struct ed *ed_get (
} }
} }
ed->hwINFO = info; ed->hwINFO = info;
} }
done: done:
......
...@@ -176,7 +176,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, ...@@ -176,7 +176,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver,
hcd->irq = dev->irq[1]; hcd->irq = dev->irq[1];
hcd->regs = dev->mapbase; hcd->regs = dev->mapbase;
hcd->pdev = SA1111_FAKE_PCIDEV; hcd->pdev = SA1111_FAKE_PCIDEV;
hcd->parent = &dev->dev; hcd->controller = &dev->dev;
retval = hcd_buffer_create (hcd); retval = hcd_buffer_create (hcd);
if (retval != 0) { if (retval != 0) {
...@@ -292,8 +292,6 @@ ohci_sa1111_start (struct usb_hcd *hcd) ...@@ -292,8 +292,6 @@ ohci_sa1111_start (struct usb_hcd *hcd)
} }
ohci->regs = hcd->regs; ohci->regs = hcd->regs;
ohci->parent_dev = hcd->parent;
if (hc_reset (ohci) < 0) { if (hc_reset (ohci) < 0) {
ohci_stop (hcd); ohci_stop (hcd);
return -ENODEV; return -ENODEV;
......
...@@ -349,11 +349,6 @@ struct hash_list_t { ...@@ -349,11 +349,6 @@ struct hash_list_t {
struct ohci_hcd { struct ohci_hcd {
spinlock_t lock; spinlock_t lock;
/*
* parent device
*/
struct device *parent_dev;
/* /*
* I/O memory used to communicate with the HC (dma-consistent) * I/O memory used to communicate with the HC (dma-consistent)
*/ */
......
...@@ -840,7 +840,7 @@ probe_scanner(struct usb_interface *intf, ...@@ -840,7 +840,7 @@ probe_scanner(struct usb_interface *intf,
struct usb_device *dev = interface_to_usbdev (intf); struct usb_device *dev = interface_to_usbdev (intf);
struct scn_usb_data *scn; struct scn_usb_data *scn;
struct usb_host_interface *interface; struct usb_host_interface *interface;
struct usb_host_endpoint *endpoint; struct usb_endpoint_descriptor *endpoint;
int ep_cnt; int ep_cnt;
int ix; int ix;
...@@ -911,7 +911,6 @@ probe_scanner(struct usb_interface *intf, ...@@ -911,7 +911,6 @@ probe_scanner(struct usb_interface *intf,
} }
interface = intf->altsetting; interface = intf->altsetting;
endpoint = &interface->endpoint[0];
/* /*
* Start checking for two bulk endpoints OR two bulk endpoints *and* one * Start checking for two bulk endpoints OR two bulk endpoints *and* one
...@@ -929,22 +928,23 @@ probe_scanner(struct usb_interface *intf, ...@@ -929,22 +928,23 @@ probe_scanner(struct usb_interface *intf,
ep_cnt = have_bulk_in = have_bulk_out = have_intr = 0; ep_cnt = have_bulk_in = have_bulk_out = have_intr = 0;
while (ep_cnt < interface->desc.bNumEndpoints) { while (ep_cnt < interface->desc.bNumEndpoints) {
endpoint = &interface->endpoint[ep_cnt].desc;
if (!have_bulk_in && IS_EP_BULK_IN(endpoint[ep_cnt])) { if (!have_bulk_in && IS_EP_BULK_IN(endpoint)) {
ep_cnt++; ep_cnt++;
have_bulk_in = ep_cnt; have_bulk_in = ep_cnt;
dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in); dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in);
continue; continue;
} }
if (!have_bulk_out && IS_EP_BULK_OUT(endpoint[ep_cnt])) { if (!have_bulk_out && IS_EP_BULK_OUT(endpoint)) {
ep_cnt++; ep_cnt++;
have_bulk_out = ep_cnt; have_bulk_out = ep_cnt;
dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out); dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out);
continue; continue;
} }
if (!have_intr && IS_EP_INTR(endpoint[ep_cnt])) { if (!have_intr && IS_EP_INTR(endpoint)) {
ep_cnt++; ep_cnt++;
have_intr = ep_cnt; have_intr = ep_cnt;
dbg("probe_scanner: intr_ep:%d", have_intr); dbg("probe_scanner: intr_ep:%d", have_intr);
......
...@@ -211,10 +211,10 @@ static struct usb_device_id scanner_device_ids [] = { ...@@ -211,10 +211,10 @@ static struct usb_device_id scanner_device_ids [] = {
MODULE_DEVICE_TABLE (usb, scanner_device_ids); MODULE_DEVICE_TABLE (usb, scanner_device_ids);
#define IS_EP_BULK(ep) ((ep).desc.bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0) #define IS_EP_BULK(ep) ((ep)->bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0)
#define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep).desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) #define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep)->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) #define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep)->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
#define IS_EP_INTR(ep) ((ep).desc.bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0) #define IS_EP_INTR(ep) ((ep)->bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0)
#define USB_SCN_MINOR(X) minor((X)->i_rdev) - SCN_BASE_MNR #define USB_SCN_MINOR(X) minor((X)->i_rdev) - SCN_BASE_MNR
......
...@@ -1572,7 +1572,8 @@ static int hid_probe (struct usb_interface *intf, const struct usb_device_id *id ...@@ -1572,7 +1572,8 @@ static int hid_probe (struct usb_interface *intf, const struct usb_device_id *id
int i; int i;
char *c; char *c;
dbg("HID probe called for ifnum %d", intf->ifnum); dbg("HID probe called for ifnum %d",
intf->altsetting->desc.bInterfaceNumber);
if (!(hid = usb_hid_configure(intf))) if (!(hid = usb_hid_configure(intf)))
return -EIO; return -EIO;
...@@ -1590,6 +1591,7 @@ static int hid_probe (struct usb_interface *intf, const struct usb_device_id *id ...@@ -1590,6 +1591,7 @@ static int hid_probe (struct usb_interface *intf, const struct usb_device_id *id
dev_set_drvdata(&intf->dev, hid); dev_set_drvdata(&intf->dev, hid);
if (!hid->claimed) { if (!hid->claimed) {
printk ("HID device not claimed by input or hiddev\n");
hid_disconnect(intf); hid_disconnect(intf);
return -EIO; return -EIO;
} }
......
...@@ -33,7 +33,7 @@ struct hid_usage_entry { ...@@ -33,7 +33,7 @@ struct hid_usage_entry {
char *description; char *description;
}; };
static struct hid_usage_entry hid_usage_table[] = { static const struct hid_usage_entry hid_usage_table[] = {
{ 0, 0, "Undefined" }, { 0, 0, "Undefined" },
{ 1, 0, "GenericDesktop" }, { 1, 0, "GenericDesktop" },
{0, 0x01, "Pointer"}, {0, 0x01, "Pointer"},
...@@ -218,11 +218,95 @@ static struct hid_usage_entry hid_usage_table[] = { ...@@ -218,11 +218,95 @@ static struct hid_usage_entry hid_usage_table[] = {
{0, 0xAA, "Shared_Parameter_Blocks"}, {0, 0xAA, "Shared_Parameter_Blocks"},
{0, 0xAB, "Create_New_Effect_Report"}, {0, 0xAB, "Create_New_Effect_Report"},
{0, 0xAC, "RAM_Pool_Available"}, {0, 0xAC, "RAM_Pool_Available"},
{ 0x84, 0, "Power Device" },
{ 0x84, 0x02, "PresentStatus" },
{ 0x84, 0x03, "ChangeStatus" },
{ 0x84, 0x04, "UPS" },
{ 0x84, 0x05, "PowerSupply" },
{ 0x84, 0x10, "BatterySystem" },
{ 0x84, 0x11, "BatterySystemID" },
{ 0x84, 0x12, "Battery" },
{ 0x84, 0x13, "BatteryID" },
{ 0x84, 0x14, "Charger" },
{ 0x84, 0x15, "ChargerID" },
{ 0x84, 0x16, "PowerConverter" },
{ 0x84, 0x17, "PowerConverterID" },
{ 0x84, 0x18, "OutletSystem" },
{ 0x84, 0x19, "OutletSystemID" },
{ 0x84, 0x1a, "Input" },
{ 0x84, 0x1b, "InputID" },
{ 0x84, 0x1c, "Output" },
{ 0x84, 0x1d, "OutputID" },
{ 0x84, 0x1e, "Flow" },
{ 0x84, 0x1f, "FlowID" },
{ 0x84, 0x20, "Outlet" },
{ 0x84, 0x21, "OutletID" },
{ 0x84, 0x22, "Gang" },
{ 0x84, 0x24, "PowerSummary" },
{ 0x84, 0x25, "PowerSummaryID" },
{ 0x84, 0x30, "Voltage" },
{ 0x84, 0x31, "Current" },
{ 0x84, 0x32, "Frequency" },
{ 0x84, 0x33, "ApparentPower" },
{ 0x84, 0x35, "PercentLoad" },
{ 0x84, 0x40, "ConfigVoltage" },
{ 0x84, 0x41, "ConfigCurrent" },
{ 0x84, 0x43, "ConfigApparentPower" },
{ 0x84, 0x53, "LowVoltageTransfer" },
{ 0x84, 0x54, "HighVoltageTransfer" },
{ 0x84, 0x56, "DelayBeforeStartup" },
{ 0x84, 0x57, "DelayBeforeShutdown" },
{ 0x84, 0x58, "Test" },
{ 0x84, 0x5a, "AudibleAlarmControl" },
{ 0x84, 0x60, "Present" },
{ 0x84, 0x61, "Good" },
{ 0x84, 0x62, "InternalFailure" },
{ 0x84, 0x65, "Overload" },
{ 0x84, 0x66, "OverCharged" },
{ 0x84, 0x67, "OverTemperature" },
{ 0x84, 0x68, "ShutdownRequested" },
{ 0x84, 0x69, "ShutdownImminent" },
{ 0x84, 0x6b, "SwitchOn/Off" },
{ 0x84, 0x6c, "Switchable" },
{ 0x84, 0x6d, "Used" },
{ 0x84, 0x6e, "Boost" },
{ 0x84, 0x73, "CommunicationLost" },
{ 0x84, 0xfd, "iManufacturer" },
{ 0x84, 0xfe, "iProduct" },
{ 0x84, 0xff, "iSerialNumber" },
{ 0x85, 0, "Battery System" },
{ 0x85, 0x01, "SMBBatteryMode" },
{ 0x85, 0x02, "SMBBatteryStatus" },
{ 0x85, 0x03, "SMBAlarmWarning" },
{ 0x85, 0x04, "SMBChargerMode" },
{ 0x85, 0x05, "SMBChargerStatus" },
{ 0x85, 0x06, "SMBChargerSpecInfo" },
{ 0x85, 0x07, "SMBSelectorState" },
{ 0x85, 0x08, "SMBSelectorPresets" },
{ 0x85, 0x09, "SMBSelectorInfo" },
{ 0x85, 0x29, "RemainingCapacityLimit" },
{ 0x85, 0x2c, "CapacityMode" },
{ 0x85, 0x42, "BelowRemainingCapacityLimit" },
{ 0x85, 0x44, "Charging" },
{ 0x85, 0x45, "Discharging" },
{ 0x85, 0x4b, "NeedReplacement" },
{ 0x85, 0x66, "RemainingCapacity" },
{ 0x85, 0x68, "RunTimeToEmpty" },
{ 0x85, 0x6a, "AverageTimeToFull" },
{ 0x85, 0x83, "DesignCapacity" },
{ 0x85, 0x85, "ManufacturerDate" },
{ 0x85, 0x89, "iDeviceChemistry" },
{ 0x85, 0x8b, "Rechargable" },
{ 0x85, 0x8f, "iOEMInformation" },
{ 0x85, 0x8d, "CapacityGranularity1" },
{ 0x85, 0xd0, "ACPresent" },
/* pages 0xff00 to 0xffff are vendor-specific */
{ 0xffff, 0, "Vendor-specific-FF" },
{ 0, 0, NULL } { 0, 0, NULL }
}; };
static void resolv_usage_page(unsigned page) { static void resolv_usage_page(unsigned page) {
struct hid_usage_entry *p; const struct hid_usage_entry *p;
for (p = hid_usage_table; p->description; p++) for (p = hid_usage_table; p->description; p++)
if (p->page == page) { if (p->page == page) {
...@@ -233,13 +317,13 @@ static void resolv_usage_page(unsigned page) { ...@@ -233,13 +317,13 @@ static void resolv_usage_page(unsigned page) {
} }
static void resolv_usage(unsigned usage) { static void resolv_usage(unsigned usage) {
struct hid_usage_entry *p; const struct hid_usage_entry *p;
resolv_usage_page(usage >> 16); resolv_usage_page(usage >> 16);
printk("."); printk(".");
for (p = hid_usage_table; p->description; p++) for (p = hid_usage_table; p->description; p++)
if (p->page == (usage >> 16)) { if (p->page == (usage >> 16)) {
for(++p; p->description && p->page == 0; p++) for(++p; p->description && p->page != 0; p++)
if (p->usage == (usage & 0xffff)) { if (p->usage == (usage & 0xffff)) {
printk("%s", p->description); printk("%s", p->description);
return; return;
......
...@@ -306,7 +306,7 @@ struct hid_report_enum { ...@@ -306,7 +306,7 @@ struct hid_report_enum {
#define HID_REPORT_TYPES 3 #define HID_REPORT_TYPES 3
#define HID_BUFFER_SIZE 32 #define HID_BUFFER_SIZE 32
#define HID_CONTROL_FIFO_SIZE 64 #define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */
#define HID_OUTPUT_FIFO_SIZE 64 #define HID_OUTPUT_FIFO_SIZE 64
struct hid_control_fifo { struct hid_control_fifo {
......
...@@ -652,6 +652,15 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -652,6 +652,15 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return copy_to_user((char *) arg, hid->name, len) ? return copy_to_user((char *) arg, hid->name, len) ?
-EFAULT : len; -EFAULT : len;
} }
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
int len;
if (!hid->phys) return 0;
len = strlen(hid->phys) + 1;
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, hid->phys, len) ?
-EFAULT : len;
}
} }
return -EINVAL; return -EINVAL;
} }
......
...@@ -1214,7 +1214,6 @@ static struct video_device vicam_template = { ...@@ -1214,7 +1214,6 @@ static struct video_device vicam_template = {
.type = VID_TYPE_CAPTURE, .type = VID_TYPE_CAPTURE,
.hardware = VID_HARDWARE_VICAM, .hardware = VID_HARDWARE_VICAM,
.fops = &vicam_fops, .fops = &vicam_fops,
// .initialize = vicam_video_init,
.minor = -1, .minor = -1,
}; };
......
...@@ -550,6 +550,74 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -550,6 +550,74 @@ static int ch9_postconfig (struct usbtest_dev *dev)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static void unlink1_callback (struct urb *urb)
{
int status = urb->status;
// we "know" -EPIPE (stall) never happens
if (!status)
status = usb_submit_urb (urb, SLAB_ATOMIC);
if (status) {
if (status == -ECONNRESET || status == -ENOENT)
status = 0;
urb->status = status;
complete ((struct completion *) urb->context);
}
}
static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async)
{
struct urb *urb;
struct completion completion;
int retval = 0;
init_completion (&completion);
urb = simple_alloc_urb (testdev_to_usbdev (dev), pipe, size);
if (async)
urb->transfer_flags |= URB_ASYNC_UNLINK;
urb->context = &completion;
urb->complete = unlink1_callback;
/* keep the endpoint busy. there are lots of hc/hcd-internal
* states, and testing should get to all of them over time.
*
* FIXME want additional tests for when endpoint is STALLing
* due to errors, or is just NAKing requests.
*/
if ((retval = usb_submit_urb (urb, SLAB_KERNEL)) != 0) {
dbg ("submit/unlink fail %d", retval);
return retval;
}
/* unlinking that should always work. variable delay tests more
* hcd states and code paths, even with little other system load.
*/
wait_ms (jiffies % (2 * INTERRUPT_RATE));
retval = usb_unlink_urb (urb);
if (!(retval == 0 || retval == -EINPROGRESS)) {
dbg ("submit/unlink fail %d", retval);
return retval;
}
wait_for_completion (&completion);
retval = urb->status;
simple_free_urb (urb);
return retval;
}
static int unlink_simple (struct usbtest_dev *dev, int pipe, int len)
{
int retval = 0;
/* test sync and async paths */
retval = unlink1 (dev, pipe, len, 1);
if (!retval)
retval = unlink1 (dev, pipe, len, 0);
return retval;
}
/*-------------------------------------------------------------------------*/
/* We only have this one interface to user space, through usbfs. /* We only have this one interface to user space, through usbfs.
* User mode code can scan usbfs to find N different devices (maybe on * User mode code can scan usbfs to find N different devices (maybe on
* different busses) to use when testing, and allocate one thread per * different busses) to use when testing, and allocate one thread per
...@@ -560,7 +628,8 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -560,7 +628,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
* video capture, and so on. Run different tests at different times, in * video capture, and so on. Run different tests at different times, in
* different sequences. Nothing here should interact with other devices, * different sequences. Nothing here should interact with other devices,
* except indirectly by consuming USB bandwidth and CPU resources for test * except indirectly by consuming USB bandwidth and CPU resources for test
* threads and request completion. * threads and request completion. But the only way to know that for sure
* is to test when HC queues are in use by many devices.
*/ */
static int static int
...@@ -761,13 +830,35 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) ...@@ -761,13 +830,35 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
dbg ("ch9 subset failed, iterations left %d", i); dbg ("ch9 subset failed, iterations left %d", i);
break; break;
/* test cases for the unlink/cancel codepaths need a thread to // case 10: queued control
* usb_unlink_urb() or usg_sg_cancel(), and a way to check if
* the urb/sg_request was properly canceled. /* simple non-queued unlinks (ring with one urb) */
* case 11:
* for the unlink-queued cases, the usb_sg_*() code uses/tests if (dev->in_pipe == 0 || !param->length)
* the "streamed" cleanup mode, not the "packet" one break;
*/ retval = 0;
dbg ("%s TEST 11: unlink %d reads of %d",
dev->id, param->iterations, param->length);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = unlink_simple (dev, dev->in_pipe, param->length);
if (retval)
dbg ("unlink reads failed, iterations left %d", i);
break;
case 12:
if (dev->out_pipe == 0 || !param->length)
break;
retval = 0;
dbg ("%s TEST 12: unlink %d writes of %d",
dev->id, param->iterations, param->length);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = unlink_simple (dev, dev->out_pipe, param->length);
if (retval)
dbg ("unlink writes failed, iterations left %d", i);
break;
// FIXME unlink from queue (ring with N urbs)
// FIXME scatterlist cancel (needs helper thread)
} }
do_gettimeofday (&param->duration); do_gettimeofday (&param->duration);
......
...@@ -124,20 +124,23 @@ config USB_RTL8150 ...@@ -124,20 +124,23 @@ config USB_RTL8150
module, say M here and read <file:Documentation/modules.txt>. module, say M here and read <file:Documentation/modules.txt>.
config USB_USBNET config USB_USBNET
tristate "USB-to-USB Networking cable device support" tristate "USB-to-USB Networking for cables, PDAs and other devices"
depends on USB && NET depends on USB && NET
---help--- ---help---
This driver supports network links over USB with USB "Network" This driver supports network links over USB with USB "Network"
or "data transfer" cables, often used to network laptops to PCs. or "data transfer" cables, often used to network laptops to PCs.
Such cables have chips from suppliers such as Belkin/eTEK, GeneSys Such cables have chips from suppliers such as Belkin/eTEK, GeneSys
(GeneLink), NetChip and Prolific. Intelligent USB devices could also (GeneLink), NetChip and Prolific. Some motherboards with USB PC2PC
use this approach to provide Internet access, using standard USB support include such chips.
cabling. You can find these chips also on some motherboards with
USB PC2PC support. Intelligent USB devices, such as PDAs running Linux (like Yopy
and Zaurus, or iPaqs after upgrading to Linux) can use the same
approach to provide Internet access.
These links will have names like "usb0", "usb1", etc. They act These links will have names like "usb0", "usb1", etc. They act
like two-node Ethernets, so you can use 802.1d Ethernet Bridging like two-node Ethernets, so you can use 802.1d Ethernet Bridging
(CONFIG_BRIDGE) to simplify your network routing. (CONFIG_BRIDGE) to simplify your network routing. For more
information see <http://www.linux-usb.org/usbnet/>.
This code is also available as a kernel module (code which can be This code is also available as a kernel module (code which can be
inserted in and removed from the running kernel whenever you want). inserted in and removed from the running kernel whenever you want).
......
...@@ -128,15 +128,8 @@ freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, ...@@ -128,15 +128,8 @@ freecom_readdata (Scsi_Cmnd *srb, struct us_data *us,
result = usb_stor_bulk_msg (us, fxfr, opipe, result = usb_stor_bulk_msg (us, fxfr, opipe,
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, &partial);
if (result != USB_STOR_XFER_GOOD) { if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("Freecom readdata xpot failure: r=%d, p=%d\n", US_DEBUGP ("Freecom readdata xport failure: r=%d, p=%d\n",
result, partial); result, partial);
/* has the current command been aborted? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_readdata(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
US_DEBUGP("Done issuing read request: %d %d\n", result, partial); US_DEBUGP("Done issuing read request: %d %d\n", result, partial);
...@@ -171,15 +164,8 @@ freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, ...@@ -171,15 +164,8 @@ freecom_writedata (Scsi_Cmnd *srb, struct us_data *us,
result = usb_stor_bulk_msg (us, fxfr, opipe, result = usb_stor_bulk_msg (us, fxfr, opipe,
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, &partial);
if (result != USB_STOR_XFER_GOOD) { if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("Freecom writedata xpot failure: r=%d, p=%d\n", US_DEBUGP ("Freecom writedata xport failure: r=%d, p=%d\n",
result, partial); result, partial);
/* has the current command been aborted? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_writedata(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
US_DEBUGP("Done issuing write request: %d %d\n", US_DEBUGP("Done issuing write request: %d %d\n",
...@@ -238,13 +224,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -238,13 +224,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
if (result != USB_STOR_XFER_GOOD) { if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("freecom xport failure: r=%d, p=%d\n", US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
result, partial); result, partial);
/* we canceled this transfer */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
...@@ -253,12 +232,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -253,12 +232,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_msg (us, fst, ipipe, result = usb_stor_bulk_msg (us, fst, ipipe,
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, &partial);
US_DEBUGP("foo Status result %d %d\n", result, partial); US_DEBUGP("foo Status result %d %d\n", result, partial);
/* we canceled this transfer */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (result != USB_STOR_XFER_GOOD) if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
...@@ -293,13 +266,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -293,13 +266,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
if (result != USB_STOR_XFER_GOOD) { if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("freecom xport failure: r=%d, p=%d\n", US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
result, partial); result, partial);
/* we canceled this transfer */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
...@@ -308,12 +274,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -308,12 +274,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, &partial);
US_DEBUGP("bar Status result %d %d\n", result, partial); US_DEBUGP("bar Status result %d %d\n", result, partial);
/* we canceled this transfer */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (result > USB_STOR_XFER_SHORT) if (result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
...@@ -372,10 +332,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -372,10 +332,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, &partial);
US_DEBUG(pdump ((void *) fst, partial)); US_DEBUG(pdump ((void *) fst, partial));
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP ("freecom_transport: transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (partial != 4 || result > USB_STOR_XFER_SHORT) if (partial != 4 || result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
if ((fst->Status & ERR_STAT) != 0) { if ((fst->Status & ERR_STAT) != 0) {
...@@ -401,10 +357,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -401,10 +357,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_msg (us, fst, ipipe, result = usb_stor_bulk_msg (us, fst, ipipe,
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, &partial);
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP ("freecom_transport: transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (partial != 4 || result > USB_STOR_XFER_SHORT) if (partial != 4 || result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
if ((fst->Status & ERR_STAT) != 0) { if ((fst->Status & ERR_STAT) != 0) {
......
...@@ -130,8 +130,6 @@ ...@@ -130,8 +130,6 @@
#define ISD200_TRANSPORT_GOOD 0 /* Transport good, command good */ #define ISD200_TRANSPORT_GOOD 0 /* Transport good, command good */
#define ISD200_TRANSPORT_FAILED 1 /* Transport good, command failed */ #define ISD200_TRANSPORT_FAILED 1 /* Transport good, command failed */
#define ISD200_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */ #define ISD200_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */
#define ISD200_TRANSPORT_ABORTED 3 /* Transport aborted */
#define ISD200_TRANSPORT_SHORT 4 /* Transport short */
/* driver action codes */ /* driver action codes */
#define ACTION_READ_STATUS 0 #define ACTION_READ_STATUS 0
...@@ -394,138 +392,6 @@ void isd200_build_sense(struct us_data *us, Scsi_Cmnd *srb) ...@@ -394,138 +392,6 @@ void isd200_build_sense(struct us_data *us, Scsi_Cmnd *srb)
***********************************************************************/ ***********************************************************************/
/**************************************************************************
* ISD200 Bulk Transport
*
* Note: This routine was copied from the usb_stor_Bulk_transport routine
* located in the transport.c source file. The scsi command is limited to
* only 12 bytes while the CDB for the ISD200 must be 16 bytes.
*/
int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,
union ata_cdb *AtaCdb, unsigned char AtaCdbLength )
{
struct bulk_cb_wrap bcb;
struct bulk_cs_wrap bcs;
int result;
unsigned int transfer_length;
int dir = srb->sc_data_direction;
srb->sc_data_direction = SCSI_DATA_WRITE;
transfer_length = usb_stor_transfer_length(srb);
srb->sc_data_direction = dir;
/* set up the command wrapper */
bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb.DataTransferLength = cpu_to_le32(transfer_length);
bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
bcb.Tag = srb->serial_number;
bcb.Lun = srb->cmnd[1] >> 5;
if (us->flags & US_FL_SCM_MULT_TARG)
bcb.Lun |= srb->target << 4;
bcb.Length = AtaCdbLength;
/* copy the command payload */
memset(bcb.CDB, 0, sizeof(bcb.CDB));
memcpy(bcb.CDB, AtaCdb, bcb.Length);
/* send it to out endpoint */
US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
le32_to_cpu(bcb.Signature), bcb.Tag,
(bcb.Lun >> 4), (bcb.Lun & 0x0F),
le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length);
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
(char *) &bcb, US_BULK_CB_WRAP_LEN, NULL);
US_DEBUGP("Bulk command transfer result=%d\n", result);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
return ISD200_TRANSPORT_ABORTED;
}
if (result != USB_STOR_XFER_GOOD)
return ISD200_TRANSPORT_ERROR;
/* if the command transfered well, then we go to the data stage */
if (transfer_length) {
unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ?
us->recv_bulk_pipe : us->send_bulk_pipe;
result = usb_stor_bulk_transfer_srb(us, pipe, srb,
transfer_length);
US_DEBUGP("Bulk data transfer result 0x%x\n", result);
/* if it was aborted, we need to indicate that */
if (result == USB_STOR_XFER_ABORTED)
return ISD200_TRANSPORT_ABORTED;
if (result == USB_STOR_XFER_ERROR)
return ISD200_TRANSPORT_ERROR;
}
/* See flow chart on pg 15 of the Bulk Only Transport spec for
* an explanation of how this code works.
*/
/* get CSW for device status */
US_DEBUGP("Attempting to get CSW...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
return ISD200_TRANSPORT_ABORTED;
}
/* did the attempt to read the CSW fail? */
if (result == USB_STOR_XFER_STALLED) {
/* get the status again */
US_DEBUGP("Attempting to get CSW (2nd try)...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
/* if the command was aborted, indicate that */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
return ISD200_TRANSPORT_ABORTED;
}
}
/* if we still have a failure at this point, we're in trouble */
US_DEBUGP("Bulk status result = %d\n", result);
if (result != USB_STOR_XFER_GOOD)
return ISD200_TRANSPORT_ERROR;
/* check bulk status */
US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",
le32_to_cpu(bcs.Signature), bcs.Tag,
bcs.Residue, bcs.Status);
if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) ||
bcs.Tag != bcb.Tag ||
bcs.Status > US_BULK_STAT_PHASE) {
US_DEBUGP("Bulk logical error\n");
return ISD200_TRANSPORT_ERROR;
}
/* based on the status code, we report good or bad */
switch (bcs.Status) {
case US_BULK_STAT_OK:
/* command good -- note that we could be short on data */
if (srb->resid > 0)
return ISD200_TRANSPORT_SHORT;
return ISD200_TRANSPORT_GOOD;
case US_BULK_STAT_FAIL:
/* command failed */
return ISD200_TRANSPORT_FAILED;
case US_BULK_STAT_PHASE:
/* phase error */
usb_stor_Bulk_reset(us);
return ISD200_TRANSPORT_ERROR;
}
/* we should never get here, but if we do, we're in trouble */
return ISD200_TRANSPORT_ERROR;
}
/************************************************************************** /**************************************************************************
* isd200_action * isd200_action
* *
...@@ -612,9 +478,11 @@ static int isd200_action( struct us_data *us, int action, ...@@ -612,9 +478,11 @@ static int isd200_action( struct us_data *us, int action,
break; break;
} }
status = isd200_Bulk_transport(us, &srb, &ata, sizeof(ata.generic)); memcpy(srb.cmnd, &ata, sizeof(ata.generic));
if (status != ISD200_TRANSPORT_GOOD && status = usb_stor_Bulk_transport(&srb, us);
status != ISD200_TRANSPORT_SHORT) { if (status == USB_STOR_TRANSPORT_GOOD)
status = ISD200_GOOD;
else {
US_DEBUGP(" isd200_action(0x%02x) error: %d\n",action,status); US_DEBUGP(" isd200_action(0x%02x) error: %d\n",action,status);
status = ISD200_ERROR; status = ISD200_ERROR;
/* need to reset device here */ /* need to reset device here */
...@@ -669,8 +537,8 @@ void isd200_invoke_transport( struct us_data *us, ...@@ -669,8 +537,8 @@ void isd200_invoke_transport( struct us_data *us,
/* send the command to the transport layer */ /* send the command to the transport layer */
srb->resid = 0; srb->resid = 0;
transferStatus = isd200_Bulk_transport(us, srb, ataCdb, memcpy(srb->cmnd, ataCdb, sizeof(ataCdb->generic));
sizeof(ataCdb->generic)); transferStatus = usb_stor_Bulk_transport(srb, us);
/* if the command gets aborted by the higher layers, we need to /* if the command gets aborted by the higher layers, we need to
* short-circuit all other processing * short-circuit all other processing
...@@ -683,45 +551,37 @@ void isd200_invoke_transport( struct us_data *us, ...@@ -683,45 +551,37 @@ void isd200_invoke_transport( struct us_data *us,
switch (transferStatus) { switch (transferStatus) {
case ISD200_TRANSPORT_GOOD: case USB_STOR_TRANSPORT_GOOD:
/* Indicate a good result */ /* Indicate a good result */
srb->result = GOOD << 1; srb->result = GOOD << 1;
break; break;
case ISD200_TRANSPORT_ABORTED: case USB_STOR_TRANSPORT_FAILED:
/* if the command gets aborted by the higher layers, we need to
* short-circuit all other processing
*/
US_DEBUGP("-- transport indicates command was aborted\n");
srb->result = DID_ABORT << 16;
break;
case ISD200_TRANSPORT_FAILED:
US_DEBUGP("-- transport indicates command failure\n"); US_DEBUGP("-- transport indicates command failure\n");
need_auto_sense = 1; need_auto_sense = 1;
break; break;
case ISD200_TRANSPORT_ERROR: case USB_STOR_TRANSPORT_ERROR:
US_DEBUGP("-- transport indicates transport failure\n"); US_DEBUGP("-- transport indicates transport error\n");
srb->result = DID_ERROR << 16; srb->result = DID_ERROR << 16;
break; /* Need reset here */
return;
case ISD200_TRANSPORT_SHORT:
srb->result = GOOD << 1;
if (!((srb->cmnd[0] == REQUEST_SENSE) ||
(srb->cmnd[0] == INQUIRY) ||
(srb->cmnd[0] == MODE_SENSE) ||
(srb->cmnd[0] == LOG_SENSE) ||
(srb->cmnd[0] == MODE_SENSE_10))) {
US_DEBUGP("-- unexpectedly short transfer\n");
need_auto_sense = 1;
}
break;
default: default:
US_DEBUGP("-- transport indicates unknown failure\n"); US_DEBUGP("-- transport indicates unknown error\n");
srb->result = DID_ERROR << 16; srb->result = DID_ERROR << 16;
/* Need reset here */
return;
}
if ((srb->resid > 0) &&
!((srb->cmnd[0] == REQUEST_SENSE) ||
(srb->cmnd[0] == INQUIRY) ||
(srb->cmnd[0] == MODE_SENSE) ||
(srb->cmnd[0] == LOG_SENSE) ||
(srb->cmnd[0] == MODE_SENSE_10))) {
US_DEBUGP("-- unexpectedly short transfer\n");
need_auto_sense = 1;
} }
if (need_auto_sense) { if (need_auto_sense) {
...@@ -729,14 +589,23 @@ void isd200_invoke_transport( struct us_data *us, ...@@ -729,14 +589,23 @@ void isd200_invoke_transport( struct us_data *us,
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("-- auto-sense aborted\n"); US_DEBUGP("-- auto-sense aborted\n");
srb->result = DID_ABORT << 16; srb->result = DID_ABORT << 16;
} else if (result == ISD200_GOOD) return;
}
if (result == ISD200_GOOD) {
isd200_build_sense(us, srb); isd200_build_sense(us, srb);
srb->result = CHECK_CONDITION << 1;
/* If things are really okay, then let's show that */
if ((srb->sense_buffer[2] & 0xf) == 0x0)
srb->result = GOOD << 1;
} else
srb->result = DID_ERROR << 16;
} }
/* Regardless of auto-sense, if we _know_ we have an error /* Regardless of auto-sense, if we _know_ we have an error
* condition, show that in the result code * condition, show that in the result code
*/ */
if (transferStatus == ISD200_TRANSPORT_FAILED) if (transferStatus == USB_STOR_TRANSPORT_FAILED)
srb->result = CHECK_CONDITION << 1; srb->result = CHECK_CONDITION << 1;
} }
......
/* /*
* Common routines for a handful of drivers. * Common routines for a handful of drivers.
* Unrelated to CF/SM - just USB stuff. * Unrelated to CF/SM - just scatter-gather stuff.
*
* This is mostly a thin layer on top of transport.c.
* It converts routines that return values like -EPIPE
* into routines that return USB_STOR_TRANSPORT_ABORTED etc.
*
* There is also some debug printing here.
*/ */
#include "debug.h" #include "usb.h"
#include "transport.h"
#include "raw_bulk.h" #include "raw_bulk.h"
/* /*
......
...@@ -103,7 +103,7 @@ static int detect(struct SHT *sht) ...@@ -103,7 +103,7 @@ static int detect(struct SHT *sht)
* *
* NOTE: There is no contention here, because we're already deregistered * NOTE: There is no contention here, because we're already deregistered
* the driver and we're doing each virtual host in turn, not in parallel * the driver and we're doing each virtual host in turn, not in parallel
* Synchronization: BLK, no spinlock. * Synchronization: BKL, no spinlock.
*/ */
static int release(struct Scsi_Host *psh) static int release(struct Scsi_Host *psh)
{ {
......
...@@ -562,12 +562,6 @@ int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, ...@@ -562,12 +562,6 @@ int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
value, index, data, size); value, index, data, size);
US_DEBUGP("usb_stor_control_msg returned %d\n", result); US_DEBUGP("usb_stor_control_msg returned %d\n", result);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("-- transfer aborted\n");
return USB_STOR_XFER_ABORTED;
}
/* a stall indicates a protocol error */ /* a stall indicates a protocol error */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("-- stall on control pipe\n"); US_DEBUGP("-- stall on control pipe\n");
...@@ -624,12 +618,6 @@ int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, ...@@ -624,12 +618,6 @@ int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
return USB_STOR_XFER_STALLED; return USB_STOR_XFER_STALLED;
} }
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("-- transfer aborted\n");
return USB_STOR_XFER_ABORTED;
}
/* NAK - that means we've retried a few times already */ /* NAK - that means we've retried a few times already */
if (result == -ETIMEDOUT) { if (result == -ETIMEDOUT) {
US_DEBUGP("-- device NAKed\n"); US_DEBUGP("-- device NAKed\n");
...@@ -669,7 +657,7 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, ...@@ -669,7 +657,7 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
/* initialize the scatter-gather request block */ /* initialize the scatter-gather request block */
US_DEBUGP("usb_stor_bulk_transfer_sglist(): xfer %d bytes, " US_DEBUGP("usb_stor_bulk_transfer_sglist(): xfer %d bytes, "
"%d entires\n", length, num_sg); "%d entries\n", length, num_sg);
result = usb_sg_init(us->current_sg, us->pusb_dev, pipe, 0, result = usb_sg_init(us->current_sg, us->pusb_dev, pipe, 0,
sg, num_sg, length, SLAB_NOIO); sg, num_sg, length, SLAB_NOIO);
if (result) { if (result) {
...@@ -691,26 +679,27 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, ...@@ -691,26 +679,27 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
} }
} }
/* wait for the completion of the transfer */
usb_sg_wait(us->current_sg); usb_sg_wait(us->current_sg);
clear_bit(US_FLIDX_CANCEL_SG, &us->flags); clear_bit(US_FLIDX_CANCEL_SG, &us->flags);
result = us->current_sg->status; result = us->current_sg->status;
partial = us->current_sg->bytes; partial = us->current_sg->bytes;
US_DEBUGP("usb_sg_wait() returned %d xferrerd %d/%d\n", US_DEBUGP("usb_sg_wait() returned %d xferred %d/%d\n",
result, partial, length); result, partial, length);
if (act_len) if (act_len)
*act_len = partial; *act_len = partial;
/* if we stall, we need to clear it before we go on */ /* if we stall, we need to clear it before we go on */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x," US_DEBUGP("clearing endpoint halt for pipe 0x%x, "
"stalled at %d bytes\n", pipe, partial); "stalled at %d bytes\n", pipe, partial);
if (usb_stor_clear_halt(us, pipe) < 0) if (usb_stor_clear_halt(us, pipe) < 0)
return USB_STOR_XFER_ERROR; return USB_STOR_XFER_ERROR;
return USB_STOR_XFER_STALLED; return USB_STOR_XFER_STALLED;
} }
/* NAK - that means we've tried this a few times already */ /* NAK - that means we've retried this a few times already */
if (result == -ETIMEDOUT) { if (result == -ETIMEDOUT) {
US_DEBUGP("-- device NAKed\n"); US_DEBUGP("-- device NAKed\n");
return USB_STOR_XFER_ERROR; return USB_STOR_XFER_ERROR;
...@@ -738,10 +727,10 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, ...@@ -738,10 +727,10 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
* Transfer an entire SCSI command's worth of data payload over the bulk * Transfer an entire SCSI command's worth of data payload over the bulk
* pipe. * pipe.
* *
* Nore that this uses the usb_stor_bulk_transfer_buf() and * Nore that this uses usb_stor_bulk_transfer_buf() and
* usb_stor_bulk_transfer_sglist() to achieve its goals -- * usb_stor_bulk_transfer_sglist() to achieve its goals --
* this function simply determines whether we're going to use * this function simply determines whether we're going to use
* scatter-gather or not, and acts apropriately. * scatter-gather or not, and acts appropriately.
*/ */
int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe, int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,
char *buf, unsigned int length_left, int use_sg, int *residual) char *buf, unsigned int length_left, int use_sg, int *residual)
...@@ -1116,15 +1105,6 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1116,15 +1105,6 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
if (result != USB_STOR_XFER_GOOD) { if (result != USB_STOR_XFER_GOOD) {
/* Reset flag for status notification */ /* Reset flag for status notification */
clear_bit(US_FLIDX_IP_WANTED, &us->flags); clear_bit(US_FLIDX_IP_WANTED, &us->flags);
}
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_control_msg(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (result != USB_STOR_XFER_GOOD) {
/* Uh oh... serious problem here */ /* Uh oh... serious problem here */
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
...@@ -1137,12 +1117,6 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1137,12 +1117,6 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_transfer_srb(us, pipe, srb, result = usb_stor_bulk_transfer_srb(us, pipe, srb,
transfer_length); transfer_length);
US_DEBUGP("CBI data stage result is 0x%x\n", result); US_DEBUGP("CBI data stage result is 0x%x\n", result);
/* report any errors */
if (result == USB_STOR_XFER_ABORTED) {
clear_bit(US_FLIDX_IP_WANTED, &us->flags);
return USB_STOR_TRANSPORT_ABORTED;
}
if (result == USB_STOR_XFER_ERROR) { if (result == USB_STOR_XFER_ERROR) {
clear_bit(US_FLIDX_IP_WANTED, &us->flags); clear_bit(US_FLIDX_IP_WANTED, &us->flags);
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
...@@ -1157,7 +1131,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1157,7 +1131,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* has the current command been aborted? */ /* has the current command been aborted? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("CBI interrupt aborted\n"); US_DEBUGP("CBI interrupt aborted\n");
return USB_STOR_TRANSPORT_ABORTED; return USB_STOR_TRANSPORT_ERROR;
} }
US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n",
...@@ -1222,13 +1196,6 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1222,13 +1196,6 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
/* check the return code for the command */ /* check the return code for the command */
US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result); US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (result != USB_STOR_XFER_GOOD) { if (result != USB_STOR_XFER_GOOD) {
/* Uh oh... serious problem here */ /* Uh oh... serious problem here */
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
...@@ -1242,14 +1209,8 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1242,14 +1209,8 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_transfer_srb(us, pipe, srb, result = usb_stor_bulk_transfer_srb(us, pipe, srb,
transfer_length); transfer_length);
US_DEBUGP("CB data stage result is 0x%x\n", result); US_DEBUGP("CB data stage result is 0x%x\n", result);
if (result == USB_STOR_XFER_ERROR)
/* report any errors */
if (result == USB_STOR_XFER_ABORTED) {
return USB_STOR_TRANSPORT_ABORTED;
}
if (result == USB_STOR_XFER_ERROR) {
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
}
} }
/* STATUS STAGE */ /* STATUS STAGE */
...@@ -1319,12 +1280,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1319,12 +1280,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
(char *) &bcb, US_BULK_CB_WRAP_LEN, NULL); (char *) &bcb, US_BULK_CB_WRAP_LEN, NULL);
US_DEBUGP("Bulk command transfer result=%d\n", result); US_DEBUGP("Bulk command transfer result=%d\n", result);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (result != USB_STOR_XFER_GOOD) if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
...@@ -1336,10 +1291,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1336,10 +1291,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_transfer_srb(us, pipe, srb, result = usb_stor_bulk_transfer_srb(us, pipe, srb,
transfer_length); transfer_length);
US_DEBUGP("Bulk data transfer result 0x%x\n", result); US_DEBUGP("Bulk data transfer result 0x%x\n", result);
/* if it was aborted, we need to indicate that */
if (result == USB_STOR_XFER_ABORTED)
return USB_STOR_TRANSPORT_ABORTED;
if (result == USB_STOR_XFER_ERROR) if (result == USB_STOR_XFER_ERROR)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
...@@ -1353,12 +1304,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1353,12 +1304,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL); (char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
/* did the attempt to read the CSW fail? */ /* did the attempt to read the CSW fail? */
if (result == USB_STOR_XFER_STALLED) { if (result == USB_STOR_XFER_STALLED) {
...@@ -1366,12 +1311,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1366,12 +1311,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("Attempting to get CSW (2nd try)...\n"); US_DEBUGP("Attempting to get CSW (2nd try)...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL); (char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
} }
/* if we still have a failure at this point, we're in trouble */ /* if we still have a failure at this point, we're in trouble */
......
...@@ -121,7 +121,6 @@ struct bulk_cs_wrap { ...@@ -121,7 +121,6 @@ struct bulk_cs_wrap {
#define USB_STOR_XFER_SHORT 1 /* transfered less than expected */ #define USB_STOR_XFER_SHORT 1 /* transfered less than expected */
#define USB_STOR_XFER_STALLED 2 /* endpoint stalled */ #define USB_STOR_XFER_STALLED 2 /* endpoint stalled */
#define USB_STOR_XFER_ERROR 3 /* transfer died in the middle */ #define USB_STOR_XFER_ERROR 3 /* transfer died in the middle */
#define USB_STOR_XFER_ABORTED 4 /* transfer canceled */
/* /*
* Transport return codes * Transport return codes
......
...@@ -437,41 +437,6 @@ static int usb_stor_control_thread(void * __us) ...@@ -437,41 +437,6 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = GOOD << 1; us->srb->result = GOOD << 1;
} }
/* Most USB devices can't handle START_STOP. But we
* need something for media-change, so we'll use TUR
* instead.
*
* We specifically allow this command through if either:
* (a) it's a load/eject command (cmnd[4] & 2)
* (b) it's a multi-target unit (i.e. legacy SCSI adaptor)
*/
else if (us->srb->cmnd[0] == START_STOP &&
!(us->srb->cmnd[4] & 2) &&
!(us->flags & US_FL_SCM_MULT_TARG)) {
unsigned char saved_cdb[16]; /* largest SCSI-III cmd */
__u8 old_cmd_len;
US_DEBUGP("Converting START_STOP to TUR\n");
/* save old command */
memcpy(saved_cdb, us->srb->cmnd, us->srb->cmd_len);
old_cmd_len = us->srb->cmd_len;
/* set up new command -- preserve LUN */
us->srb->cmd_len = 6;
memset(us->srb->cmnd, 0, us->srb->cmd_len);
us->srb->cmnd[0] = TEST_UNIT_READY;
us->srb->cmnd[1] = saved_cdb[1] & 0xE0;
/* do command */
US_DEBUG(usb_stor_show_command(us->srb));
us->proto_handler(us->srb, us);
/* restore original command */
us->srb->cmd_len = old_cmd_len;
memcpy(us->srb->cmnd, saved_cdb, us->srb->cmd_len);
}
/* we've got a command, let's do it! */ /* we've got a command, let's do it! */
else { else {
US_DEBUG(usb_stor_show_command(us->srb)); US_DEBUG(usb_stor_show_command(us->srb));
......
...@@ -443,19 +443,19 @@ extern void firmware_uregister(struct subsystem *); ...@@ -443,19 +443,19 @@ extern void firmware_uregister(struct subsystem *);
#ifdef DEBUG #ifdef DEBUG
#define dev_dbg(dev, format, arg...) \ #define dev_dbg(dev, format, arg...) \
printk (KERN_DEBUG "%s %s: " format , \ printk (KERN_DEBUG "%s %s: " format , \
dev.driver->name , dev.bus_id , ## arg) (dev).driver->name , (dev).bus_id , ## arg)
#else #else
#define dev_dbg(dev, format, arg...) do {} while (0) #define dev_dbg(dev, format, arg...) do {} while (0)
#endif #endif
#define dev_err(dev, format, arg...) \ #define dev_err(dev, format, arg...) \
printk (KERN_ERR "%s %s: " format , \ printk (KERN_ERR "%s %s: " format , \
dev.driver->name , dev.bus_id , ## arg) (dev).driver->name , (dev).bus_id , ## arg)
#define dev_info(dev, format, arg...) \ #define dev_info(dev, format, arg...) \
printk (KERN_INFO "%s %s: " format , \ printk (KERN_INFO "%s %s: " format , \
dev.driver->name , dev.bus_id , ## arg) (dev).driver->name , (dev).bus_id , ## arg)
#define dev_warn(dev, format, arg...) \ #define dev_warn(dev, format, arg...) \
printk (KERN_WARN "%s %s: " format , \ printk (KERN_WARNING "%s %s: " format , \
dev.driver->name , dev.bus_id , ## arg) (dev).driver->name , (dev).bus_id , ## arg)
#endif /* _DEVICE_H_ */ #endif /* _DEVICE_H_ */
...@@ -159,6 +159,7 @@ struct hiddev_usage_ref { ...@@ -159,6 +159,7 @@ struct hiddev_usage_ref {
#define HIDIOCSFLAG _IOW('H', 0x0F, int) #define HIDIOCSFLAG _IOW('H', 0x0F, int)
#define HIDIOCGCOLLECTIONINDEX _IOW('H', 0x10, struct hiddev_usage_ref) #define HIDIOCGCOLLECTIONINDEX _IOW('H', 0x10, struct hiddev_usage_ref)
#define HIDIOCGCOLLECTIONINFO _IOWR('H', 0x11, struct hiddev_collection_info) #define HIDIOCGCOLLECTIONINFO _IOWR('H', 0x11, struct hiddev_collection_info)
#define HIDIOCGPHYS(len) _IOC(_IOC_READ, 'H', 0x12, len)
/* /*
* Flags to be used in HIDIOCSFLAG * Flags to be used in HIDIOCSFLAG
......
...@@ -105,7 +105,7 @@ extern const char *print_tainted(void); ...@@ -105,7 +105,7 @@ extern const char *print_tainted(void);
extern void dump_stack(void); extern void dump_stack(void);
#if DEBUG #ifdef DEBUG
#define pr_debug(fmt,arg...) \ #define pr_debug(fmt,arg...) \
printk(KERN_DEBUG fmt,##arg) printk(KERN_DEBUG fmt,##arg)
#else #else
......
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