Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@penguin.transmeta.com>2002-03-07 01:13:15 -0800
committerLinus Torvalds <torvalds@penguin.transmeta.com>2002-03-07 01:13:15 -0800
commit0a8d2a8630f00dfa82283d4caa140d4bb42bbfb0 (patch)
tree5651d22cd6a70aadb0db3274add70abbe711c516
parent8f706ce4d83d0cf3a39b00eafe31a4b824c990ab (diff)
parentab7e3d486ff0cf46b0be72ee0d9a002a8fb334b0 (diff)
Merge bk://linuxusb.bkbits.net/linus-2.5
into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
-rw-r--r--MAINTAINERS6
-rw-r--r--drivers/usb/Config.in154
-rw-r--r--drivers/usb/hcd.c80
-rw-r--r--drivers/usb/hcd.h2
-rw-r--r--drivers/usb/hcd/ehci-hcd.c59
-rw-r--r--drivers/usb/hcd/ehci-hub.c30
-rw-r--r--drivers/usb/hcd/ehci-q.c15
-rw-r--r--drivers/usb/hcd/ehci-sched.c858
-rw-r--r--drivers/usb/hcd/ehci.h14
-rw-r--r--drivers/usb/pegasus.c150
-rw-r--r--drivers/usb/pegasus.h14
-rw-r--r--drivers/usb/printer.c90
-rw-r--r--drivers/usb/serial/ir-usb.c39
13 files changed, 936 insertions, 575 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 2a366462e718..973c2fde7105 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1722,12 +1722,12 @@ L: linux-usb-devel@lists.sourceforge.net
S: Maintained
USB SERIAL KEYSPAN DRIVER
-P: Hugh Blemings
-M: hugh@misc.nu
+P: Greg Kroah-Hartman
+M: greg@kroah.com
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
+W: http://www.kroah.com/linux/
S: Maintained
-W: http://misc.nu/hugh/keyspan/
USB SUBSYSTEM
P: Greg Kroah-Hartman
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index a56f898170c4..07c4fee17cd0 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -8,7 +8,7 @@ dep_tristate 'Support for USB' CONFIG_USB $CONFIG_PCI
if [ "$CONFIG_USB" = "y" -o "$CONFIG_USB" = "m" ]; then
bool ' USB verbose debug messages' CONFIG_USB_DEBUG
-comment 'Miscellaneous USB options'
+ comment 'Miscellaneous USB options'
bool ' USB device filesystem' CONFIG_USB_DEVICEFS
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool ' Enforce USB bandwidth allocation (EXPERIMENTAL)' CONFIG_USB_BANDWIDTH
@@ -16,90 +16,90 @@ comment 'Miscellaneous USB options'
define_bool CONFIG_USB_BANDWIDTH n
fi
bool ' Long timeout for slow-responding devices (some MGE Ellipse UPSes)' CONFIG_USB_LONG_TIMEOUT
-fi
-comment 'USB Host Controller Drivers'
-source drivers/usb/hcd/Config.in
-if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
- dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
-fi
-if [ "$CONFIG_USB_UHCI" != "y" ]; then
- dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
-else
- define_bool CONFIG_USB_UHCI_ALT n
-fi
-dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
+ comment 'USB Host Controller Drivers'
+ source drivers/usb/hcd/Config.in
+ if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
+ dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
+ fi
+ if [ "$CONFIG_USB_UHCI" != "y" ]; then
+ dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
+ else
+ define_bool CONFIG_USB_UHCI_ALT n
+ fi
+ dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
-comment 'USB Device Class drivers'
-dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
-dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
-if [ "$CONFIG_SCSI" = "n" ]; then
- comment ' SCSI support is needed for USB Storage'
-fi
-dep_tristate ' USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
- dep_mbool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE
- dep_mbool ' Datafab MDCFE-B Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
- dep_mbool ' Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM $CONFIG_USB_STORAGE
- dep_mbool ' ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200 $CONFIG_USB_STORAGE
- dep_mbool ' Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM $CONFIG_USB_STORAGE
- dep_mbool ' HP CD-Writer 82xx support' CONFIG_USB_STORAGE_HP8200e $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
- dep_mbool ' SanDisk SDDR-09 (and other SmartMedia) support' CONFIG_USB_STORAGE_SDDR09 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
- dep_mbool ' Lexar Jumpshot Compact Flash Reader' CONFIG_USB_STORAGE_JUMPSHOT $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
-dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
-dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
+ comment 'USB Device Class drivers'
+ dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
+ dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
+ if [ "$CONFIG_SCSI" = "n" ]; then
+ comment ' SCSI support is needed for USB Storage'
+ fi
+ dep_tristate ' USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
+ dep_mbool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE
+ dep_mbool ' Datafab MDCFE-B Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+ dep_mbool ' Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM $CONFIG_USB_STORAGE
+ dep_mbool ' ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200 $CONFIG_USB_STORAGE
+ dep_mbool ' Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM $CONFIG_USB_STORAGE
+ dep_mbool ' HP CD-Writer 82xx support' CONFIG_USB_STORAGE_HP8200e $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+ dep_mbool ' SanDisk SDDR-09 (and other SmartMedia) support' CONFIG_USB_STORAGE_SDDR09 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+ dep_mbool ' Lexar Jumpshot Compact Flash Reader' CONFIG_USB_STORAGE_JUMPSHOT $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
+ dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
-comment 'USB Human Interface Devices (HID)'
-if [ "$CONFIG_INPUT" = "n" ]; then
- comment ' Input core support is needed for USB HID'
-else
- dep_tristate ' USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB $CONFIG_INPUT
- dep_mbool ' /dev/hiddev raw HID device support (EXPERIMENTAL)' CONFIG_USB_HIDDEV $CONFIG_USB_HID
- if [ "$CONFIG_USB_HID" != "y" ]; then
- dep_tristate ' USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT
- dep_tristate ' USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT
+ comment 'USB Human Interface Devices (HID)'
+ if [ "$CONFIG_INPUT" = "n" ]; then
+ comment ' Input core support is needed for USB HID'
+ else
+ dep_tristate ' USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB $CONFIG_INPUT
+ dep_mbool ' /dev/hiddev raw HID device support (EXPERIMENTAL)' CONFIG_USB_HIDDEV $CONFIG_USB_HID
+ if [ "$CONFIG_USB_HID" != "y" ]; then
+ dep_tristate ' USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT
+ dep_tristate ' USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT
+ fi
+ dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
fi
- dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
-fi
-comment 'USB Imaging devices'
-dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
-dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
-dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
-dep_tristate ' Microtek X6USB scanner support' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI
-dep_tristate ' HP53xx USB scanner support (EXPERIMENTAL)' CONFIG_USB_HPUSBSCSI $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
+ comment 'USB Imaging devices'
+ dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
+ dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
+ dep_tristate ' Microtek X6USB scanner support' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI
+ dep_tristate ' HP53xx USB scanner support (EXPERIMENTAL)' CONFIG_USB_HPUSBSCSI $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
-comment 'USB Multimedia devices'
-if [ "$CONFIG_VIDEO_DEV" = "n" ]; then
- comment ' Video4Linux support is needed for USB Multimedia device support'
-else
- dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
- dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
- dep_tristate ' USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
- dep_tristate ' USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
- dep_tristate ' USB STV680 (Pencam) Camera support' CONFIG_USB_STV680 $CONFIG_USB $CONFIG_VIDEO_DEV
- dep_tristate ' USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
- dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
- dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
- dep_tristate ' USB Konica Webcam support' CONFIG_USB_KONICAWC $CONFIG_USB $CONFIG_VIDEO_DEV
-fi
+ comment 'USB Multimedia devices'
+ if [ "$CONFIG_VIDEO_DEV" = "n" ]; then
+ comment ' Video4Linux support is needed for USB Multimedia device support'
+ else
+ dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
+ dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
+ dep_tristate ' USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
+ dep_tristate ' USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
+ dep_tristate ' USB STV680 (Pencam) Camera support' CONFIG_USB_STV680 $CONFIG_USB $CONFIG_VIDEO_DEV
+ dep_tristate ' USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
+ dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
+ dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
+ dep_tristate ' USB Konica Webcam support' CONFIG_USB_KONICAWC $CONFIG_USB $CONFIG_VIDEO_DEV
+ fi
-comment 'USB Network adaptors'
-if [ "$CONFIG_NET" = "n" ]; then
- comment ' Networking support is needed for USB Networking device support'
-else
- dep_tristate ' USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
- dep_tristate ' USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
- dep_tristate ' USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
- dep_tristate ' USB Communication Class Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
- dep_tristate ' USB-to-USB Networking cable device support (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-fi
+ comment 'USB Network adaptors'
+ if [ "$CONFIG_NET" = "n" ]; then
+ comment ' Networking support is needed for USB Networking device support'
+ else
+ dep_tristate ' USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB Communication Class Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB-to-USB Networking cable device support (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+ fi
-comment 'USB port drivers'
-dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
-source drivers/usb/serial/Config.in
+ comment 'USB port drivers'
+ dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
+ source drivers/usb/serial/Config.in
-comment 'USB Miscellaneous drivers'
-dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
-dep_tristate ' USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL
+ comment 'USB Miscellaneous drivers'
+ dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
+ dep_tristate ' USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL
+fi
endmenu
diff --git a/drivers/usb/hcd.c b/drivers/usb/hcd.c
index 188d38a3e4a0..f947e7e13ec4 100644
--- a/drivers/usb/hcd.c
+++ b/drivers/usb/hcd.c
@@ -224,12 +224,12 @@ static const u8 rh_config_descriptor [] = {
* helper routine for returning string descriptors in UTF-16LE
* input can actually be ISO-8859-1; ASCII is its 7-bit subset
*/
-static int ascii2utf (char *ascii, u8 *utf, int utfmax)
+static int ascii2utf (char *s, u8 *utf, int utfmax)
{
int retval;
- for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
- *utf++ = *ascii++ & 0x7f;
+ for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
+ *utf++ = *s++;
*utf++ = 0;
}
return retval;
@@ -248,8 +248,7 @@ static int ascii2utf (char *ascii, u8 *utf, int utfmax)
*/
static int rh_string (
int id,
- struct pci_dev *pci_desc,
- char *type,
+ struct usb_hcd *hcd,
u8 *data,
int len
) {
@@ -263,15 +262,16 @@ static int rh_string (
// serial number
} else if (id == 1) {
- strcpy (buf, pci_desc->slot_name);
+ strcpy (buf, hcd->bus_name);
// product description
} else if (id == 2) {
- strcpy (buf, pci_desc->name);
+ strcpy (buf, hcd->product_desc);
// id 3 == vendor description
} else if (id == 3) {
- sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, type);
+ sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE,
+ hcd->description);
// unsupported IDs --> "protocol stall"
} else
@@ -338,9 +338,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
break;
case USB_DT_STRING << 8:
urb->actual_length = rh_string (
- wValue & 0xff,
- hcd->pdev,
- (char *) hcd->description,
+ wValue & 0xff, hcd,
ubuf, wLength);
break;
default:
@@ -1004,6 +1002,7 @@ clean_2:
hcd->self.hcpriv = (void *) hcd;
hcd->bus = &hcd->self;
hcd->bus_name = dev->slot_name;
+ hcd->product_desc = dev->name;
INIT_LIST_HEAD (&hcd->dev_list);
@@ -1266,7 +1265,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
struct usb_hcd *hcd;
struct hcd_dev *dev;
unsigned long flags;
- int pipe;
+ int pipe, temp;
if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
@@ -1286,6 +1285,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state))
return -ESHUTDOWN;
pipe = urb->pipe;
+ temp = usb_pipetype (urb->pipe);
if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe),
usb_pipeout (pipe)))
return -EPIPE;
@@ -1298,7 +1298,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
/* enforce simple/standard policy */
allowed = USB_ASYNC_UNLINK; // affects later unlinks
allowed |= USB_NO_FSBR; // only affects UHCI
- switch (usb_pipetype (pipe)) {
+ switch (temp) {
case PIPE_CONTROL:
allowed |= USB_DISABLE_SPD;
break;
@@ -1317,15 +1317,55 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
/* warn if submitter gave bogus flags */
if (urb->transfer_flags != orig_flags)
- warn ("BOGUS urb flags, %x --> %x",
+ err ("BOGUS urb flags, %x --> %x",
orig_flags, urb->transfer_flags);
}
#endif
/*
- * FIXME: alloc periodic bandwidth here, for interrupt and iso?
- * Need to look at the ring submit mechanism for iso tds ... they
- * aren't actually "periodic" in 2.4 kernels.
+ * Force periodic transfer intervals to be legal values that are
+ * a power of two (so HCDs don't need to).
*
+ * FIXME want bus->{intr,iso}_sched_horizon values here. Each HC
+ * supports different values... this uses EHCI/UHCI defaults (and
+ * EHCI can use smaller non-default values).
+ */
+ switch (temp) {
+ case PIPE_ISOCHRONOUS:
+ case PIPE_INTERRUPT:
+ /* too small? */
+ if (urb->interval <= 0)
+ return -EINVAL;
+ /* too big? */
+ switch (urb->dev->speed) {
+ case USB_SPEED_HIGH: /* units are microframes */
+ // NOTE usb handles 2^15
+ if (urb->interval > (1024 * 8))
+ urb->interval = 1024 * 8;
+ temp = 1024 * 8;
+ break;
+ case USB_SPEED_FULL: /* units are frames/msec */
+ case USB_SPEED_LOW:
+ if (temp == PIPE_INTERRUPT) {
+ if (urb->interval > 255)
+ return -EINVAL;
+ // NOTE ohci only handles up to 32
+ temp = 128;
+ } else {
+ if (urb->interval > 1024)
+ urb->interval = 1024;
+ // NOTE usb and ohci handle up to 2^15
+ temp = 1024;
+ }
+ default:
+ return -EINVAL;
+ }
+ /* power of two? */
+ while (temp > urb->interval)
+ temp >>= 1;
+ urb->interval = temp;
+ }
+
+ /*
* FIXME: make urb timeouts be generic, keeping the HCD cores
* as simple as possible.
*/
@@ -1589,6 +1629,9 @@ static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
struct usb_hcd *hcd = __hcd;
int start = hcd->state;
+ if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
+ return;
+
hcd->driver->irq (hcd);
if (hcd->state != start && hcd->state == USB_STATE_HALT)
hc_died (hcd);
@@ -1642,7 +1685,8 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
// hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev)
if (urb->status)
- dbg ("giveback urb %p status %d", urb, urb->status);
+ dbg ("giveback urb %p status %d len %d",
+ urb, urb->status, urb->actual_length);
/* if no error, make sure urb->next progresses */
else if (urb->next) {
diff --git a/drivers/usb/hcd.h b/drivers/usb/hcd.h
index 19698b04a6eb..acd83cdf0c3d 100644
--- a/drivers/usb/hcd.h
+++ b/drivers/usb/hcd.h
@@ -39,7 +39,7 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
struct usb_bus self; /* hcd is-a bus */
const char *bus_name;
-
+ const char *product_desc; /* product/vendor string */
const char *description; /* "ehci-hcd" etc */
struct timer_list rh_timer; /* drives root hub */
diff --git a/drivers/usb/hcd/ehci-hcd.c b/drivers/usb/hcd/ehci-hcd.c
index 2ab1e0c78c6f..42e0b4c25ee6 100644
--- a/drivers/usb/hcd/ehci-hcd.c
+++ b/drivers/usb/hcd/ehci-hcd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2001 by David Brownell
+ * Copyright (c) 2000-2002 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -31,10 +31,6 @@
#include <linux/list.h>
#include <linux/interrupt.h>
-#ifndef CONFIG_USB_DEBUG
- #define CONFIG_USB_DEBUG /* this is still experimental! */
-#endif
-
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
@@ -73,19 +69,25 @@
* ...
*
* HISTORY:
+ *
+ * 2002-03-05 Initial high-speed ISO support; reduce ITD memory; shift
+ * more checking to generic hcd framework (db). Make it work with
+ * Philips EHCI; reduce PCI traffic; shorten IRQ path (Rory Bolt).
* 2002-01-14 Minor cleanup; version synch.
* 2002-01-08 Fix roothub handoff of FS/LS to companion controllers.
* 2002-01-04 Control/Bulk queuing behaves.
+ *
* 2001-12-12 Initial patch version for Linux 2.5.1 kernel.
+ * 2001-June Works with usb-storage and NEC EHCI on 2.4
*/
-#define DRIVER_VERSION "$Revision: 0.26 $"
+#define DRIVER_VERSION "$Revision: 0.27 $"
#define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
// #define EHCI_VERBOSE_DEBUG
-// #define have_iso
+// #define have_split_iso
#ifdef CONFIG_DEBUG_SLAB
# define EHCI_SLAB_FLAGS (SLAB_POISON)
@@ -187,6 +189,9 @@ static int ehci_start (struct usb_hcd *hcd)
dbg_hcs_params (ehci, "ehci_start");
dbg_hcc_params (ehci, "ehci_start");
+ /* cache this readonly data; minimize PCI reads */
+ ehci->hcs_params = readl (&ehci->caps->hcs_params);
+
/*
* hw default: 1K periodic list heads, one per frame.
* periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -204,7 +209,7 @@ static int ehci_start (struct usb_hcd *hcd)
ehci->async = 0;
ehci->reclaim = 0;
- ehci->next_frame = -1;
+ ehci->next_uframe = -1;
/* controller state: unknown --> reset */
@@ -310,7 +315,7 @@ static void ehci_stop (struct usb_hcd *hcd)
// root hub is shut down separately (first, when possible)
scan_async (ehci);
- if (ehci->next_frame != -1)
+ if (ehci->next_uframe != -1)
scan_periodic (ehci);
ehci_mem_cleanup (ehci);
@@ -332,14 +337,12 @@ static int ehci_get_frame (struct usb_hcd *hcd)
static int ehci_suspend (struct usb_hcd *hcd, u32 state)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- u32 params;
int ports;
int i;
dbg ("%s: suspend to %d", hcd->bus_name, state);
- params = readl (&ehci->caps->hcs_params);
- ports = HCS_N_PORTS (params);
+ ports = HCS_N_PORTS (ehci->hcs_params);
// FIXME: This assumes what's probably a D3 level suspend...
@@ -375,14 +378,12 @@ dbg ("%s: suspend port %d", hcd->bus_name, i);
static int ehci_resume (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- u32 params;
int ports;
int i;
dbg ("%s: resume", hcd->bus_name);
- params = readl (&ehci->caps->hcs_params);
- ports = HCS_N_PORTS (params);
+ ports = HCS_N_PORTS (ehci->hcs_params);
// FIXME: if controller didn't retain state,
// return and let generic code clean it up
@@ -426,7 +427,7 @@ static void ehci_tasklet (unsigned long param)
if (ehci->reclaim_ready)
end_unlink_async (ehci);
scan_async (ehci);
- if (ehci->next_frame != -1)
+ if (ehci->next_uframe != -1)
scan_periodic (ehci);
// FIXME: when nothing is connected to the root hub,
@@ -440,20 +441,20 @@ static void ehci_irq (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 status = readl (&ehci->regs->status);
- int bh = 0;
+ int bh;
- /* clear (just) interrupts */
status &= INTR_MASK;
+ if (!status) /* irq sharing? */
+ return;
+
+ /* clear (just) interrupts */
writel (status, &ehci->regs->status);
readl (&ehci->regs->command); /* unblock posted write */
-
- if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
- return;
+ bh = 0;
#ifdef EHCI_VERBOSE_DEBUG
/* unrequested/ignored: Port Change Detect, Frame List Rollover */
- if (status & INTR_MASK)
- dbg_status (ehci, "irq", status);
+ dbg_status (ehci, "irq", status);
#endif
/* INT, ERR, and IAA interrupt rates can be throttled */
@@ -520,17 +521,15 @@ static int ehci_urb_enqueue (
return intr_submit (ehci, urb, &qtd_list, mem_flags);
case PIPE_ISOCHRONOUS:
-#ifdef have_iso
if (urb->dev->speed == USB_SPEED_HIGH)
- return itd_submit (ehci, urb);
+ return itd_submit (ehci, urb, mem_flags);
+#ifdef have_split_iso
else
- return sitd_submit (ehci, urb);
+ return sitd_submit (ehci, urb, mem_flags);
#else
- // FIXME highspeed iso stuff is written but never run/tested.
- // and the split iso support isn't even written yet.
- dbg ("no iso support yet");
+ dbg ("no split iso support yet");
return -ENOSYS;
-#endif /* have_iso */
+#endif /* have_split_iso */
}
return 0;
diff --git a/drivers/usb/hcd/ehci-hub.c b/drivers/usb/hcd/ehci-hub.c
index 798fd6066430..6720f8f888e5 100644
--- a/drivers/usb/hcd/ehci-hub.c
+++ b/drivers/usb/hcd/ehci-hub.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -68,8 +68,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
/* init status to no-changes */
buf [0] = 0;
- temp = readl (&ehci->caps->hcs_params);
- ports = HCS_N_PORTS (temp);
+ ports = HCS_N_PORTS (ehci->hcs_params);
if (ports > 7) {
buf [1] = 0;
retval++;
@@ -107,8 +106,7 @@ ehci_hub_descriptor (
struct ehci_hcd *ehci,
struct usb_hub_descriptor *desc
) {
- u32 params = readl (&ehci->caps->hcs_params);
- int ports = HCS_N_PORTS (params);
+ int ports = HCS_N_PORTS (ehci->hcs_params);
u16 temp;
desc->bDescriptorType = 0x29;
@@ -124,10 +122,10 @@ ehci_hub_descriptor (
memset (&desc->bitmap [temp], 0xff, temp);
temp = 0x0008; /* per-port overcurrent reporting */
- if (HCS_PPC (params)) /* per-port power control */
- temp |= 0x0001;
- if (HCS_INDICATOR (params)) /* per-port indicators (LEDs) */
- temp |= 0x0080;
+ if (HCS_PPC (ehci->hcs_params))
+ temp |= 0x0001; /* per-port power control */
+ if (HCS_INDICATOR (ehci->hcs_params))
+ temp |= 0x0080; /* per-port indicators (LEDs) */
desc->wHubCharacteristics = cpu_to_le16 (temp);
}
@@ -142,8 +140,7 @@ static int ehci_hub_control (
u16 wLength
) {
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- u32 params = readl (&ehci->caps->hcs_params);
- int ports = HCS_N_PORTS (params);
+ int ports = HCS_N_PORTS (ehci->hcs_params);
u32 temp;
unsigned long flags;
int retval = 0;
@@ -189,7 +186,7 @@ static int ehci_hub_control (
/* ? */
break;
case USB_PORT_FEAT_POWER:
- if (HCS_PPC (params))
+ if (HCS_PPC (ehci->hcs_params))
writel (temp & ~PORT_POWER,
&ehci->regs->port_status [wIndex]);
break;
@@ -300,7 +297,7 @@ static int ehci_hub_control (
&ehci->regs->port_status [wIndex]);
break;
case USB_PORT_FEAT_POWER:
- if (HCS_PPC (params))
+ if (HCS_PPC (ehci->hcs_params))
writel (temp | PORT_POWER,
&ehci->regs->port_status [wIndex]);
break;
@@ -312,6 +309,13 @@ static int ehci_hub_control (
hcd->bus_name, wIndex + 1);
temp |= PORT_OWNER;
} else {
+ /* Philips 1562 wants CMD_RUN to reset */
+ if (!HCD_IS_RUNNING(ehci->hcd.state)) {
+ u32 cmd = readl (&ehci->regs->command);
+ cmd |= CMD_RUN;
+ writel (cmd, &ehci->regs->command);
+ ehci->hcd.state = USB_STATE_RUNNING;
+ }
vdbg ("%s port %d reset",
hcd->bus_name, wIndex + 1);
temp |= PORT_RESET;
diff --git a/drivers/usb/hcd/ehci-q.c b/drivers/usb/hcd/ehci-q.c
index df6c07d3d6fe..d59d6039f593 100644
--- a/drivers/usb/hcd/ehci-q.c
+++ b/drivers/usb/hcd/ehci-q.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -643,12 +643,19 @@ ehci_qh_make (
if (usb_pipecontrol (urb->pipe)) {
info1 |= 64 << 16; /* usb2 fixed maxpacket */
info1 |= 1 << 14; /* toggle from qtd */
+ info2 |= (EHCI_TUNE_MULT_HS << 30);
} else if (usb_pipebulk (urb->pipe)) {
info1 |= 512 << 16; /* usb2 fixed maxpacket */
info2 |= (EHCI_TUNE_MULT_HS << 30);
- } else
- info1 |= usb_maxpacket (urb->dev, urb->pipe,
- usb_pipeout (urb->pipe)) << 16;
+ } else {
+ u32 temp;
+ temp = usb_maxpacket (urb->dev, urb->pipe,
+ usb_pipeout (urb->pipe));
+ info1 |= (temp & 0x3ff) << 16; /* maxpacket */
+ /* HS intr can be "high bandwidth" */
+ temp = 1 + ((temp >> 11) & 0x03);
+ info2 |= temp << 30; /* mult */
+ }
break;
default:
#ifdef DEBUG
diff --git a/drivers/usb/hcd/ehci-sched.c b/drivers/usb/hcd/ehci-sched.c
index 0e40057ebf07..83b6c229a93c 100644
--- a/drivers/usb/hcd/ehci-sched.c
+++ b/drivers/usb/hcd/ehci-sched.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -55,12 +55,12 @@ periodic_next_shadow (union ehci_shadow *periodic, int tag)
return &periodic->qh->qh_next;
case Q_TYPE_FSTN:
return &periodic->fstn->fstn_next;
-#ifdef have_iso
case Q_TYPE_ITD:
return &periodic->itd->itd_next;
+#ifdef have_split_iso
case Q_TYPE_SITD:
return &periodic->sitd->sitd_next;
-#endif /* have_iso */
+#endif /* have_split_iso */
}
dbg ("BAD shadow %p tag %d", periodic->ptr, tag);
// BUG ();
@@ -109,9 +109,6 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
u32 *hw_p = &ehci->periodic [frame];
union ehci_shadow *q = &ehci->pshadow [frame];
unsigned usecs = 0;
-#ifdef have_iso
- u32 temp = 0;
-#endif
while (q->ptr) {
switch (Q_NEXT_TYPE (*hw_p)) {
@@ -130,15 +127,13 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
}
q = &q->fstn->fstn_next;
break;
-#ifdef have_iso
case Q_TYPE_ITD:
- temp = le32_to_cpu (q->itd->transaction [uframe]);
- temp >>= 16;
- temp &= 0x0fff;
- if (temp)
- usecs += HS_USECS_ISO (temp);
+ /* NOTE the "one uframe per itd" policy */
+ if (q->itd->hw_transaction [uframe] != 0)
+ usecs += q->itd->usecs;
q = &q->itd->itd_next;
break;
+#ifdef have_split_iso
case Q_TYPE_SITD:
temp = q->sitd->hw_fullspeed_ep &
__constant_cpu_to_le32 (1 << 31);
@@ -163,7 +158,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
}
q = &q->sitd->sitd_next;
break;
-#endif /* have_iso */
+#endif /* have_split_iso */
default:
BUG ();
}
@@ -178,6 +173,45 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
/*-------------------------------------------------------------------------*/
+static void enable_periodic (struct ehci_hcd *ehci)
+{
+ u32 cmd;
+
+ /* did clearing PSE did take effect yet?
+ * takes effect only at frame boundaries...
+ */
+ while (readl (&ehci->regs->status) & STS_PSS)
+ udelay (20);
+
+ cmd = readl (&ehci->regs->command) | CMD_PSE;
+ writel (cmd, &ehci->regs->command);
+ /* posted write ... PSS happens later */
+ ehci->hcd.state = USB_STATE_RUNNING;
+
+ /* make sure tasklet scans these */
+ ehci->next_uframe = readl (&ehci->regs->frame_index)
+ % (ehci->periodic_size << 3);
+}
+
+static void disable_periodic (struct ehci_hcd *ehci)
+{
+ u32 cmd;
+
+ /* did setting PSE not take effect yet?
+ * takes effect only at frame boundaries...
+ */
+ while (!(readl (&ehci->regs->status) & STS_PSS))
+ udelay (20);
+
+ cmd = readl (&ehci->regs->command) & ~CMD_PSE;
+ writel (cmd, &ehci->regs->command);
+ /* posted write ... */
+
+ ehci->next_uframe = -1;
+}
+
+/*-------------------------------------------------------------------------*/
+
static void intr_deschedule (
struct ehci_hcd *ehci,
unsigned frame,
@@ -199,21 +233,9 @@ static void intr_deschedule (
ehci->periodic_urbs--;
/* maybe turn off periodic schedule */
- if (!ehci->periodic_urbs) {
- u32 cmd = readl (&ehci->regs->command);
-
- /* did setting PSE not take effect yet?
- * takes effect only at frame boundaries...
- */
- while (!(readl (&ehci->regs->status) & STS_PSS))
- udelay (20);
-
- cmd &= ~CMD_PSE;
- writel (cmd, &ehci->regs->command);
- /* posted write ... */
-
- ehci->next_frame = -1;
- } else
+ if (!ehci->periodic_urbs)
+ disable_periodic (ehci);
+ else
vdbg ("periodic schedule still enabled");
spin_unlock_irqrestore (&ehci->lock, flags);
@@ -242,7 +264,7 @@ static int intr_submit (
) {
unsigned epnum, period;
unsigned temp;
- unsigned short mult, usecs;
+ unsigned short usecs;
unsigned long flags;
struct ehci_qh *qh;
struct hcd_dev *dev;
@@ -255,12 +277,7 @@ static int intr_submit (
epnum |= 0x10;
} else
temp = urb->dev->epmaxpacketout [epnum];
- mult = 1;
- if (urb->dev->speed == USB_SPEED_HIGH) {
- /* high speed "high bandwidth" is coded in ep maxpacket */
- mult += (temp >> 11) & 0x03;
- temp &= 0x03ff;
- } else {
+ if (urb->dev->speed != USB_SPEED_HIGH) {
dbg ("no intr/tt scheduling yet");
status = -ENOSYS;
goto done;
@@ -279,21 +296,12 @@ static int intr_submit (
usecs = HS_USECS (urb->transfer_buffer_length);
- /*
- * force a power-of-two (frames) sized polling interval
- *
- * NOTE: endpoint->bInterval for highspeed is measured in uframes,
- * while for full/low speeds it's in frames. Here we "know" that
- * urb->interval doesn't give acccess to high interrupt rates.
- */
- period = ehci->periodic_size;
- temp = period;
- if (unlikely (urb->interval < 1))
- urb->interval = 1;
- while (temp > urb->interval)
- temp >>= 1;
- period = urb->interval = temp;
-
+ /* FIXME handle HS periods of less than 1 frame. */
+ if (urb->interval < 8)
+ period = 1;
+ else
+ period = urb->interval >> 8;
+
spin_lock_irqsave (&ehci->lock, flags);
/* get the qh (must be empty and idle) */
@@ -335,7 +343,6 @@ static int intr_submit (
unsigned frame = urb->interval;
qh->hw_next = EHCI_LIST_END;
- qh->hw_info2 |= cpu_to_le32 (mult << 30);
qh->usecs = usecs;
urb->hcpriv = qh_put (qh);
@@ -378,7 +385,7 @@ static int intr_submit (
/* stuff into the periodic schedule */
qh->qh_state = QH_STATE_LINKED;
- vdbg ("qh %p usecs %d period %d starting frame %d.%d",
+ vdbg ("qh %p usecs %d period %d starting %d.%d",
qh, qh->usecs, period, frame, uframe);
do {
if (unlikely (ehci->pshadow [frame].ptr != 0)) {
@@ -397,23 +404,8 @@ static int intr_submit (
usb_claim_bandwidth (urb->dev, urb, usecs, 0);
/* maybe enable periodic schedule processing */
- if (!ehci->periodic_urbs++) {
- u32 cmd;
-
- /* did clearing PSE did take effect yet?
- * takes effect only at frame boundaries...
- */
- while (readl (&ehci->regs->status) & STS_PSS)
- udelay (20);
-
- cmd = readl (&ehci->regs->command) | CMD_PSE;
- writel (cmd, &ehci->regs->command);
- /* posted write ... PSS happens later */
- ehci->hcd.state = USB_STATE_RUNNING;
-
- /* make sure tasklet scans these */
- ehci->next_frame = ehci_get_frame (&ehci->hcd);
- }
+ if (!ehci->periodic_urbs++)
+ enable_periodic (ehci);
break;
} while (frame);
@@ -489,53 +481,56 @@ intr_complete (
/*-------------------------------------------------------------------------*/
-#ifdef have_iso
-
-static inline void itd_free (struct ehci_hcd *ehci, struct ehci_itd *itd)
+static void
+itd_free_list (struct ehci_hcd *ehci, struct urb *urb)
{
- pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+ struct ehci_itd *first_itd = urb->hcpriv;
+
+ pci_unmap_single (ehci->hcd.pdev,
+ first_itd->buf_dma, urb->transfer_buffer_length,
+ usb_pipein (urb->pipe)
+ ? PCI_DMA_FROMDEVICE
+ : PCI_DMA_TODEVICE);
+ while (!list_empty (&first_itd->itd_list)) {
+ struct ehci_itd *itd;
+
+ itd = list_entry (
+ first_itd->itd_list.next,
+ struct ehci_itd, itd_list);
+ list_del (&itd->itd_list);
+ pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+ }
+ pci_pool_free (ehci->itd_pool, first_itd, first_itd->itd_dma);
+ urb->hcpriv = 0;
}
-/*
- * Create itd and allocate into uframes within specified frame.
- * Caller must update the resulting uframe links.
- */
-static struct ehci_itd *
-itd_make (
+static int
+itd_fill (
struct ehci_hcd *ehci,
+ struct ehci_itd *itd,
struct urb *urb,
unsigned index, // urb->iso_frame_desc [index]
- unsigned frame, // scheduled start
- dma_addr_t dma, // mapped transfer buffer
- int mem_flags
+ dma_addr_t dma // mapped transfer buffer
) {
- struct ehci_itd *itd;
u64 temp;
u32 buf1;
- unsigned epnum, maxp, multi, usecs;
+ unsigned i, epnum, maxp, multi;
unsigned length;
- unsigned i, bufnum;
-
- /* allocate itd, start to fill it */
- itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &dma);
- if (!itd)
- return itd;
itd->hw_next = EHCI_LIST_END;
itd->urb = urb;
itd->index = index;
- INIT_LIST_HEAD (&itd->itd_list);
- itd->uframe = (frame * 8) % ehci->periodic_size;
- /* tell itd about the buffer its transfers will consume */
+ /* tell itd about its transfer buffer, max 2 pages */
length = urb->iso_frame_desc [index].length;
dma += urb->iso_frame_desc [index].offset;
temp = dma & ~0x0fff;
- for (i = 0; i < 7; i++) {
+ for (i = 0; i < 2; i++) {
itd->hw_bufp [i] = cpu_to_le32 ((u32) temp);
itd->hw_bufp_hi [i] = cpu_to_le32 ((u32)(temp >> 32));
- temp += 0x0fff;
+ temp += 0x1000;
}
+ itd->buf_dma = dma;
/*
* this might be a "high bandwidth" highspeed endpoint,
@@ -544,282 +539,407 @@ itd_make (
epnum = usb_pipeendpoint (urb->pipe);
if (usb_pipein (urb->pipe)) {
maxp = urb->dev->epmaxpacketin [epnum];
- buf1 = (1 << 11) | maxp;
+ buf1 = (1 << 11);
} else {
maxp = urb->dev->epmaxpacketout [epnum];
- buf1 = maxp;
+ buf1 = 0;
}
+ buf1 |= (maxp & 0x03ff);
multi = 1;
- multi += (temp >> 11) & 0x03;
+ multi += (maxp >> 11) & 0x03;
maxp &= 0x03ff;
+ maxp *= multi;
+
+ /* transfer can't fit in any uframe? */
+ if (length < 0 || maxp < length) {
+ dbg ("BAD iso packet: %d bytes, max %d, urb %p [%d] (of %d)",
+ length, maxp, urb, index,
+ urb->iso_frame_desc [index].length);
+ return -ENOSPC;
+ }
+ itd->usecs = HS_USECS_ISO (length);
/* "plus" info in low order bits of buffer pointers */
itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum);
itd->hw_bufp [1] |= cpu_to_le32 (buf1);
itd->hw_bufp [2] |= cpu_to_le32 (multi);
- /* schedule as many uframes as needed */
- maxp *= multi;
- usecs = HS_USECS_ISO (maxp);
- bufnum = 0;
- for (i = 0; i < 8; i++) {
- unsigned t, offset, scratch;
+ /* figure hw_transaction[] value (it's scheduled later) */
+ itd->transaction = EHCI_ISOC_ACTIVE;
+ itd->transaction |= dma & 0x0fff; /* offset; buffer=0 */
+ if ((index + 1) == urb->number_of_packets)
+ itd->transaction |= EHCI_ITD_IOC; /* end-of-urb irq */
+ itd->transaction |= length << 16;
+ cpu_to_le32s (&itd->transaction);
- if (length <= 0) {
- itd->hw_transaction [i] = 0;
- continue;
- }
+ return 0;
+}
- /* don't commit more than 80% periodic == 100 usec */
- if ((periodic_usecs (ehci, itd->uframe, i) + usecs) > 100)
- continue;
+static int
+itd_urb_transaction (
+ struct ehci_hcd *ehci,
+ struct urb *urb,
+ int mem_flags
+) {
+ int frame_index;
+ struct ehci_itd *first_itd, *itd;
+ int status;
+ dma_addr_t buf_dma, itd_dma;
- /* we'll use this uframe; figure hw_transaction */
- t = EHCI_ISOC_ACTIVE;
- t |= bufnum << 12; // which buffer?
- offset = temp & 0x0fff; // offset therein
- t |= offset;
- if ((offset + maxp) >= 4096) // hc auto-wraps end-of-"page"
- bufnum++;
- if (length <= maxp) {
- // interrupt only needed at end-of-urb
- if ((index + 1) == urb->number_of_packets)
- t |= EHCI_ITD_IOC;
- scratch = length;
- } else
- scratch = maxp;
- t |= scratch << 16;
- t = cpu_to_le32 (t);
+ /* set up one dma mapping for this urb */
+ buf_dma = pci_map_single (ehci->hcd.pdev,
+ urb->transfer_buffer, urb->transfer_buffer_length,
+ usb_pipein (urb->pipe)
+ ? PCI_DMA_FROMDEVICE
+ : PCI_DMA_TODEVICE);
+ if (buf_dma == 0)
+ return -ENOMEM;
- itd->hw_transaction [i] = itd->transaction [i] = t;
- length -= scratch;
- }
- if (length > 0) {
- dbg ("iso frame too big, urb %p [%d], %d extra (of %d)",
- urb, index, length, urb->iso_frame_desc [index].length);
- itd_free (ehci, itd);
- itd = 0;
+ /* allocate/init ITDs */
+ for (frame_index = 0, first_itd = 0;
+ frame_index < urb->number_of_packets;
+ frame_index++) {
+ itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &itd_dma);
+ if (!itd) {
+ status = -ENOMEM;
+ goto fail;
+ }
+ memset (itd, 0, sizeof *itd);
+ itd->itd_dma = itd_dma;
+
+ status = itd_fill (ehci, itd, urb, frame_index, buf_dma);
+ if (status != 0)
+ goto fail;
+
+ if (first_itd)
+ list_add_tail (&itd->itd_list,
+ &first_itd->itd_list);
+ else {
+ INIT_LIST_HEAD (&itd->itd_list);
+ urb->hcpriv = first_itd = itd;
+ }
}
- return itd;
+ urb->error_count = 0;
+ return 0;
+
+fail:
+ if (urb->hcpriv)
+ itd_free_list (ehci, urb);
+ return status;
}
+/*-------------------------------------------------------------------------*/
+
static inline void
itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
{
- u32 ptr;
+ /* always prepend ITD/SITD ... only QH tree is order-sensitive */
+ itd->itd_next = ehci->pshadow [frame];
+ itd->hw_next = ehci->periodic [frame];
+ ehci->pshadow [frame].itd = itd;
+ ehci->periodic [frame] = cpu_to_le32 (itd->itd_dma) | Q_TYPE_ITD;
+}
- ptr = cpu_to_le32 (itd->itd_dma); // type 0 == itd
- if (ehci->pshadow [frame].ptr) {
- if (!itd->itd_next.ptr) {
- itd->itd_next = ehci->pshadow [frame];
- itd->hw_next = ehci->periodic [frame];
- } else if (itd->itd_next.ptr != ehci->pshadow [frame].ptr) {
- dbg ("frame %d itd link goof", frame);
- BUG ();
+/*
+ * return zero on success, else -errno
+ * - start holds first uframe to start scheduling into
+ * - max is the first uframe it's NOT (!) OK to start scheduling into
+ * math to be done modulo "mod" (ehci->periodic_size << 3)
+ */
+static int get_iso_range (
+ struct ehci_hcd *ehci,
+ struct urb *urb,
+ unsigned *start,
+ unsigned *max,
+ unsigned mod
+) {
+ struct list_head *lh;
+ struct hcd_dev *dev = urb->dev->hcpriv;
+ int last = -1;
+ unsigned now, span, end;
+
+ span = urb->interval * urb->number_of_packets;
+
+ /* first see if we know when the next transfer SHOULD happen */
+ list_for_each (lh, &dev->urb_list) {
+ struct urb *u;
+ struct ehci_itd *itd;
+ unsigned s;
+
+ u = list_entry (lh, struct urb, urb_list);
+ if (u == urb || u->pipe != urb->pipe)
+ continue;
+ if (u->interval != urb->interval) { /* must not change! */
+ dbg ("urb %p interval %d ... != %p interval %d",
+ u, u->interval, urb, urb->interval);
+ return -EINVAL;
+ }
+
+ /* URB for this endpoint... covers through when? */
+ itd = urb->hcpriv;
+ s = itd->uframe + u->interval * u->number_of_packets;
+ if (last < 0)
+ last = s;
+ else {
+ /*
+ * So far we can only queue two ISO URBs...
+ *
+ * FIXME do interval math, figure out whether
+ * this URB is "before" or not ... also, handle
+ * the case where the URB might have completed,
+ * but hasn't yet been processed.
+ */
+ dbg ("NYET: queue >2 URBs per ISO endpoint");
+ return -EDOM;
}
}
- ehci->pshadow [frame].itd = itd;
- ehci->periodic [frame] = ptr;
-}
-#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
+ /* calculate the legal range [start,max) */
+ now = readl (&ehci->regs->frame_index) + 1; /* next uframe */
+ if (!ehci->periodic_urbs)
+ now += 8; /* startup delay */
+ now %= mod;
+ end = now + mod;
+ if (last < 0) {
+ *start = now + ehci->i_thresh + /* paranoia */ 1;
+ *max = end - span;
+ if (*max < *start + 1)
+ *max = *start + 1;
+ } else {
+ *start = last % mod;
+ *max = (last + 1) % mod;
+ }
-static unsigned long
-itd_complete (struct ehci_hcd *ehci, struct ehci_itd *itd, unsigned long flags)
+ /* explicit start frame? */
+ if (!(urb->transfer_flags & USB_ISO_ASAP)) {
+ unsigned temp;
+
+ /* sanity check: must be in range */
+ urb->start_frame %= ehci->periodic_size;
+ temp = urb->start_frame << 3;
+ if (temp < *start)
+ temp += mod;
+ if (temp > *max)
+ return -EDOM;
+
+ /* use that explicit start frame */
+ *start = urb->start_frame << 3;
+ temp += 8;
+ if (temp < *max)
+ *max = temp;
+ }
+
+ // FIXME minimize wraparound to "now" ... insist max+span
+ // (and start+span) remains a few frames short of "end"
+
+ *max %= ehci->periodic_size;
+ if ((*start + span) < end)
+ return 0;
+ return -EFBIG;
+}
+
+static int
+itd_schedule (struct ehci_hcd *ehci, struct urb *urb)
{
- struct urb *urb = itd->urb;
+ unsigned start, max, i;
+ int status;
+ unsigned mod = ehci->periodic_size << 3;
- /* if not unlinking: */
- if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
- && ehci->hcd.state != USB_STATE_HALT) {
- int i;
- struct usb_iso_packet_descriptor *desc;
- struct ehci_itd *first_itd = urb->hcpriv;
+ for (i = 0; i < urb->number_of_packets; i++) {
+ urb->iso_frame_desc [i].status = -EINPROGRESS;
+ urb->iso_frame_desc [i].actual_length = 0;
+ }
- /* update status for this frame's transfers */
- desc = &urb->iso_frame_desc [itd->index];
- desc->status = 0;
- desc->actual_length = 0;
- for (i = 0; i < 8; i++) {
- u32 t = itd->hw_transaction [i];
- if (t & (ISO_ERRS | EHCI_ISOC_ACTIVE)) {
- if (t & EHCI_ISOC_ACTIVE)
- desc->status = -EXDEV;
- else if (t & EHCI_ISOC_BUF_ERR)
- desc->status = usb_pipein (urb->pipe)
- ? -ENOSR /* couldn't read */
- : -ECOMM; /* couldn't write */
- else if (t & EHCI_ISOC_BABBLE)
- desc->status = -EOVERFLOW;
- else /* (t & EHCI_ISOC_XACTERR) */
- desc->status = -EPROTO;
+ if ((status = get_iso_range (ehci, urb, &start, &max, mod)) != 0)
+ return status;
+
+ do {
+ unsigned uframe;
+ unsigned usecs;
+ struct ehci_itd *itd;
+
+ /* check schedule: enough space? */
+ itd = urb->hcpriv;
+ uframe = start;
+ for (i = 0, uframe = start;
+ i < urb->number_of_packets;
+ i++, uframe += urb->interval) {
+ uframe %= mod;
+
+ /* can't commit more than 80% periodic == 100 usec */
+ if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
+ > (100 - itd->usecs)) {
+ itd = 0;
break;
}
- desc->actual_length += EHCI_ITD_LENGTH (t);
+ itd = list_entry (itd->itd_list.next,
+ struct ehci_itd, itd_list);
+ }
+ if (!itd)
+ continue;
+
+ /* that's where we'll schedule this! */
+ itd = urb->hcpriv;
+ urb->start_frame = start >> 3;
+ vdbg ("ISO urb %p (%d packets period %d) starting %d.%d",
+ urb, urb->number_of_packets, urb->interval,
+ urb->start_frame, start & 0x7);
+ for (i = 0, uframe = start, usecs = 0;
+ i < urb->number_of_packets;
+ i++, uframe += urb->interval) {
+ uframe %= mod;
+
+ itd->uframe = uframe;
+ itd->hw_transaction [uframe & 0x07] = itd->transaction;
+ itd_link (ehci, (uframe >> 3) % ehci->periodic_size,
+ itd);
+ usecs += itd->usecs;
+
+ itd = list_entry (itd->itd_list.next,
+ struct ehci_itd, itd_list);
}
- /* handle completion now? */
- if ((itd->index + 1) != urb->number_of_packets)
- return flags;
+ /* update bandwidth utilization records (for usbfs) */
+ /* FIXME usbcore expects per-frame average, which isn't
+ * most accurate model... this provides the total claim,
+ * and expects the average to be computed only display.
+ */
+ usb_claim_bandwidth (urb->dev, urb, usecs, 1);
- i = usb_pipein (urb->pipe);
- if (i)
- pci_dma_sync_single (ehci->hcd.pdev,
- first_itd->buf_dma,
- urb->transfer_buffer_length,
- PCI_DMA_FROMDEVICE);
-
- /* call completion with no locks; it can unlink ... */
- spin_unlock_irqrestore (&ehci->lock, flags);
- urb->complete (urb);
- spin_lock_irqsave (&ehci->lock, flags);
-
- /* re-activate this URB? or unlink? */
- if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
- && ehci->hcd.state != USB_STATE_HALT) {
- if (!i)
- pci_dma_sync_single (ehci->hcd.pdev,
- first_itd->buf_dma,
- urb->transfer_buffer_length,
- PCI_DMA_TODEVICE);
-
- itd = urb->hcpriv;
- do {
- for (i = 0; i < 8; i++)
- itd->hw_transaction [i]
- = itd->transaction [i];
- itd = list_entry (itd->itd_list.next,
- struct ehci_itd, itd_list);
- } while (itd != urb->hcpriv);
- return flags;
- }
+ /* maybe enable periodic schedule processing */
+ if (!ehci->periodic_urbs++)
+ enable_periodic (ehci);
+
+ return 0;
- /* unlink done only on the last itd */
- } else if ((itd->index + 1) != urb->number_of_packets)
+ } while ((start = ++start % mod) != max);
+
+ /* no room in the schedule */
+ dbg ("urb %p, CAN'T SCHEDULE", urb);
+ return -ENOSPC;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
+
+static unsigned long
+itd_complete (
+ struct ehci_hcd *ehci,
+ struct ehci_itd *itd,
+ unsigned uframe,
+ unsigned long flags
+) {
+ struct urb *urb = itd->urb;
+ struct usb_iso_packet_descriptor *desc;
+ u32 t;
+
+ /* update status for this uframe's transfers */
+ desc = &urb->iso_frame_desc [itd->index];
+
+ t = itd->hw_transaction [uframe];
+ itd->hw_transaction [uframe] = 0;
+ if (t & EHCI_ISOC_ACTIVE)
+ desc->status = -EXDEV;
+ else if (t & ISO_ERRS) {
+ urb->error_count++;
+ if (t & EHCI_ISOC_BUF_ERR)
+ desc->status = usb_pipein (urb->pipe)
+ ? -ENOSR /* couldn't read */
+ : -ECOMM; /* couldn't write */
+ else if (t & EHCI_ISOC_BABBLE)
+ desc->status = -EOVERFLOW;
+ else /* (t & EHCI_ISOC_XACTERR) */
+ desc->status = -EPROTO;
+
+ /* HC need not update length with this error */
+ if (!(t & EHCI_ISOC_BABBLE))
+ desc->actual_length += EHCI_ITD_LENGTH (t);
+ } else {
+ desc->status = 0;
+ desc->actual_length += EHCI_ITD_LENGTH (t);
+ }
+
+ vdbg ("itd %p urb %p packet %d/%d trans %x status %d len %d",
+ itd, urb, itd->index + 1, urb->number_of_packets,
+ t, desc->status, desc->actual_length);
+
+ /* handle completion now? */
+ if ((itd->index + 1) != urb->number_of_packets)
return flags;
- /* we're unlinking ... */
+ /*
+ * For now, always give the urb back to the driver ... expect it
+ * to submit a new urb (or resubmit this), and to have another
+ * already queued when un-interrupted transfers are needed.
+ * No, that's not what OHCI or UHCI are now doing.
+ *
+ * FIXME Revisit the ISO URB model. It's cleaner not to have all
+ * the special case magic, but it'd be faster to reuse existing
+ * ITD/DMA setup and schedule state. Easy to dma_sync/complete(),
+ * then either reschedule or, if unlinking, free and giveback().
+ * But we can't overcommit like the full and low speed HCs do, and
+ * there's no clean way to report an error when rescheduling...
+ *
+ * NOTE that for now we don't accelerate ISO unlinks; they just
+ * happen according to the current schedule. Means a delay of
+ * up to about a second (max).
+ */
+ itd_free_list (ehci, urb);
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
- /* decouple urb from the hcd */
spin_unlock_irqrestore (&ehci->lock, flags);
- if (ehci->hcd.state == USB_STATE_HALT)
- urb->status = -ESHUTDOWN;
- itd = urb->hcpriv;
- urb->hcpriv = 0;
- ehci_urb_done (ehci, itd->buf_dma, urb);
+ usb_hcd_giveback_urb (&ehci->hcd, urb);
spin_lock_irqsave (&ehci->lock, flags);
- /* take itds out of the hc's periodic schedule */
- list_entry (itd->itd_list.prev, struct ehci_itd, itd_list)
- ->itd_list.next = 0;
- do {
- struct ehci_itd *next;
-
- if (itd->itd_list.next)
- next = list_entry (itd->itd_list.next,
- struct ehci_itd, itd_list);
- else
- next = 0;
-
- // FIXME: hc WILL (!) lap us here, if we get behind
- // by 128 msec (or less, with smaller periodic_size).
- // Reading/caching these itds will cause trouble...
+ /* defer stopping schedule; completion can submit */
+ ehci->periodic_urbs--;
+ if (!ehci->periodic_urbs)
+ disable_periodic (ehci);
- periodic_unlink (ehci, itd->uframe, itd);
- itd_free (ehci, itd);
- itd = next;
- } while (itd);
return flags;
}
/*-------------------------------------------------------------------------*/
-static int itd_submit (struct ehci_hcd *ehci, struct urb *urb)
+static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
{
- struct ehci_itd *first_itd = 0, *itd;
- unsigned frame_index;
- dma_addr_t dma;
- unsigned long flags;
-
- dbg ("itd_submit");
+ int status;
+ unsigned long flags;
- /* set up one dma mapping for this urb */
- dma = pci_map_single (ehci->hcd.pdev,
- urb->transfer_buffer, urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
- ? PCI_DMA_FROMDEVICE
- : PCI_DMA_TODEVICE);
- if (dma == 0)
- return -ENOMEM;
+ dbg ("itd_submit urb %p", urb);
+ /* NOTE DMA mapping assumes this ... */
+ if (urb->iso_frame_desc [0].offset != 0)
+ return -EINVAL;
+
/*
- * Schedule as needed. This is VERY optimistic about free
- * bandwidth! But the API assumes drivers can pick frames
- * intelligently (how?), so there's no other good option.
- *
- * FIXME this doesn't handle urb->next rings, or try to
- * use the iso periodicity.
+ * NOTE doing this for now, anticipating periodic URB models
+ * get updated to be "explicit resubmit".
*/
- if (urb->transfer_flags & USB_ISO_ASAP) {
- urb->start_frame = ehci_get_frame (&ehci->hcd);
- urb->start_frame++;
- }
- urb->start_frame %= ehci->periodic_size;
-
- /* create and populate itds (doing uframe scheduling) */
- spin_lock_irqsave (&ehci->lock, flags);
- for (frame_index = 0;
- frame_index < urb->number_of_packets;
- frame_index++) {
- itd = itd_make (ehci, urb, frame_index,
- urb->start_frame + frame_index,
- dma, SLAB_ATOMIC);
- if (itd) {
- if (first_itd)
- list_add_tail (&itd->itd_list,
- &first_itd->itd_list);
- else
- first_itd = itd;
- } else {
- spin_unlock_irqrestore (&ehci->lock, flags);
- if (first_itd) {
- while (!list_empty (&first_itd->itd_list)) {
- itd = list_entry (
- first_itd->itd_list.next,
- struct ehci_itd, itd_list);
- list_del (&itd->itd_list);
- itd_free (ehci, itd);
- }
- itd_free (ehci, first_itd);
- }
- pci_unmap_single (ehci->hcd.pdev,
- dma, urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
- ? PCI_DMA_FROMDEVICE
- : PCI_DMA_TODEVICE);
- return -ENOMEM;
- }
+ if (urb->next) {
+ dbg ("use explicit resubmit for ISO");
+ return -EINVAL;
}
- /* stuff into the schedule */
- itd = first_itd;
- do {
- unsigned i;
-
- for (i = 0; i < 8; i++) {
- if (!itd->hw_transaction [i])
- continue;
- itd_link (ehci, itd->uframe + i, itd);
- }
- itd = list_entry (itd->itd_list.next,
- struct ehci_itd, itd_list);
- } while (itd != first_itd);
- urb->hcpriv = first_itd;
+ /* allocate ITDs w/o locking anything */
+ status = itd_urb_transaction (ehci, urb, mem_flags);
+ if (status < 0)
+ return status;
+ /* schedule ... need to lock */
+ spin_lock_irqsave (&ehci->lock, flags);
+ status = itd_schedule (ehci, urb);
spin_unlock_irqrestore (&ehci->lock, flags);
- return 0;
+ if (status < 0)
+ itd_free_list (ehci, urb);
+
+ return status;
}
+#ifdef have_split_iso
+
/*-------------------------------------------------------------------------*/
/*
@@ -827,7 +947,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb)
* the TTs in USB 2.0 hubs.
*/
-static inline void
+static void
sitd_free (struct ehci_hcd *ehci, struct ehci_sitd *sitd)
{
pci_pool_free (ehci->sitd_pool, sitd, sitd->sitd_dma);
@@ -861,7 +981,7 @@ sitd_make (
}
-static inline void
+static void
sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
{
u32 ptr;
@@ -894,12 +1014,11 @@ sitd_complete (
/*-------------------------------------------------------------------------*/
-static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb)
+static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
{
// struct ehci_sitd *first_sitd = 0;
unsigned frame_index;
dma_addr_t dma;
- int mem_flags;
dbg ("NYI -- sitd_submit");
@@ -908,8 +1027,6 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb)
// FIXME: setup one big dma mapping
dma = 0;
- mem_flags = SLAB_ATOMIC;
-
for (frame_index = 0;
frame_index < urb->number_of_packets;
frame_index++) {
@@ -941,53 +1058,62 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb)
return -ENOSYS;
}
-
-#endif /* have_iso */
+#endif /* have_split_iso */
/*-------------------------------------------------------------------------*/
static void scan_periodic (struct ehci_hcd *ehci)
{
- unsigned frame;
- unsigned clock;
+ unsigned frame, clock, now_uframe, mod;
unsigned long flags;
+ mod = ehci->periodic_size << 3;
spin_lock_irqsave (&ehci->lock, flags);
/*
* When running, scan from last scan point up to "now"
+ * else clean up by scanning everything that's left.
* Touches as few pages as possible: cache-friendly.
- * It's safe to scan entries more than once, though.
+ * Don't scan ISO entries more than once, though.
*/
- if (HCD_IS_RUNNING (ehci->hcd.state)) {
- frame = ehci->next_frame;
- clock = ehci_get_frame (&ehci->hcd);
+ frame = ehci->next_uframe >> 3;
+ if (HCD_IS_RUNNING (ehci->hcd.state))
+ now_uframe = readl (&ehci->regs->frame_index);
+ else
+ now_uframe = (frame << 3) - 1;
+ now_uframe %= mod;
+ clock = now_uframe >> 3;
- /* when shutting down, scan everything for thoroughness */
- } else {
- frame = 0;
- clock = ehci->periodic_size - 1;
- }
for (;;) {
- union ehci_shadow q;
- u32 type;
+ union ehci_shadow q, *q_p;
+ u32 type, *hw_p;
+ unsigned uframes;
restart:
- q.ptr = ehci->pshadow [frame].ptr;
- type = Q_NEXT_TYPE (ehci->periodic [frame]);
+ /* scan schedule to _before_ current frame index */
+ if (frame == clock)
+ uframes = now_uframe & 0x07;
+ else
+ uframes = 8;
+
+ q_p = &ehci->pshadow [frame];
+ hw_p = &ehci->periodic [frame];
+ q.ptr = q_p->ptr;
+ type = Q_NEXT_TYPE (*hw_p);
/* scan each element in frame's queue for completions */
while (q.ptr != 0) {
int last;
+ unsigned uf;
union ehci_shadow temp;
switch (type) {
case Q_TYPE_QH:
last = (q.qh->hw_next == EHCI_LIST_END);
+ temp = q.qh->qh_next;
+ type = Q_NEXT_TYPE (q.qh->hw_next);
flags = intr_complete (ehci, frame,
qh_put (q.qh), flags);
- type = Q_NEXT_TYPE (q.qh->hw_next);
- temp = q.qh->qh_next;
qh_unput (ehci, q.qh);
q = temp;
break;
@@ -1000,22 +1126,49 @@ restart:
dbg ("ignoring completions from FSTNs");
}
type = Q_NEXT_TYPE (q.fstn->hw_next);
- temp = q.fstn->fstn_next;
+ q = q.fstn->fstn_next;
break;
-#ifdef have_iso
case Q_TYPE_ITD:
last = (q.itd->hw_next == EHCI_LIST_END);
- flags = itd_complete (ehci, q.itd, flags);
- type = Q_NEXT_TYPE (q.itd->hw_next);
- q = q.itd->itd_next;
+
+ /* Unlink each (S)ITD we see, since the ISO
+ * URB model forces constant rescheduling.
+ * That complicates sharing uframes in ITDs,
+ * and means we need to skip uframes the HC
+ * hasn't yet processed.
+ */
+ for (uf = 0; uf < uframes; uf++) {
+ if (q.itd->hw_transaction [uf] != 0) {
+ temp = q;
+ *q_p = q.itd->itd_next;
+ *hw_p = q.itd->hw_next;
+ type = Q_NEXT_TYPE (*hw_p);
+
+ /* might free q.itd ... */
+ flags = itd_complete (ehci,
+ temp.itd, uf, flags);
+ break;
+ }
+ }
+ /* we might skip this ITD's uframe ... */
+ if (uf == uframes) {
+ q_p = &q.itd->itd_next;
+ hw_p = &q.itd->hw_next;
+ type = Q_NEXT_TYPE (q.itd->hw_next);
+ }
+
+ q = *q_p;
break;
+#ifdef have_split_iso
case Q_TYPE_SITD:
last = (q.sitd->hw_next == EHCI_LIST_END);
flags = sitd_complete (ehci, q.sitd, flags);
type = Q_NEXT_TYPE (q.sitd->hw_next);
+
+ // FIXME unlink SITD after split completes
q = q.sitd->sitd_next;
break;
-#endif /* have_iso */
+#endif /* have_split_iso */
default:
dbg ("corrupt type %d frame %d shadow %p",
type, frame, q.ptr);
@@ -1044,13 +1197,16 @@ restart:
if (!HCD_IS_RUNNING (ehci->hcd.state))
break;
- ehci->next_frame = clock;
- now = ehci_get_frame (&ehci->hcd);
- if (clock == now)
+ ehci->next_uframe = now_uframe;
+ now = readl (&ehci->regs->frame_index) % mod;
+ if (now_uframe == now)
break;
- clock = now;
- } else if (++frame >= ehci->periodic_size)
- frame = 0;
+
+ /* rescan the rest of this frame, then ... */
+ now_uframe = now;
+ clock = now_uframe >> 3;
+ } else
+ frame = (frame + 1) % ehci->periodic_size;
}
spin_unlock_irqrestore (&ehci->lock, flags);
- }
+}
diff --git a/drivers/usb/hcd/ehci.h b/drivers/usb/hcd/ehci.h
index eda91299c73a..701dc60d7fd5 100644
--- a/drivers/usb/hcd/ehci.h
+++ b/drivers/usb/hcd/ehci.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -49,7 +49,7 @@ struct ehci_hcd { /* one per controller */
unsigned i_thresh; /* uframes HC might cache */
union ehci_shadow *pshadow; /* mirror hw periodic table */
- int next_frame; /* scan periodic, start here */
+ int next_uframe; /* scan periodic, start here */
unsigned periodic_urbs; /* how many urbs scheduled? */
/* deferred work from IRQ, etc */
@@ -62,6 +62,7 @@ struct ehci_hcd { /* one per controller */
struct usb_hcd hcd;
struct ehci_caps *caps;
struct ehci_regs *regs;
+ u32 hcs_params; /* cached register copy */
/* per-HC memory pools (could be per-PCI-bus, but ...) */
struct pci_pool *qh_pool; /* qh per active urb */
@@ -324,13 +325,14 @@ struct ehci_itd {
union ehci_shadow itd_next; /* ptr to periodic q entry */
struct urb *urb;
- unsigned index; /* in urb->iso_frame_desc */
struct list_head itd_list; /* list of urb frames' itds */
dma_addr_t buf_dma; /* frame's buffer address */
- unsigned uframe; /* in periodic schedule */
- u32 transaction [8]; /* copy of hw_transaction */
-
+ /* for now, only one hw_transaction per itd */
+ u32 transaction;
+ u16 index; /* in urb->iso_frame_desc */
+ u16 uframe; /* in periodic schedule */
+ u16 usecs;
} __attribute__ ((aligned (32)));
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
index 58682c6f5594..cd5ab8c129c3 100644
--- a/drivers/usb/pegasus.c
+++ b/drivers/usb/pegasus.c
@@ -1,7 +1,7 @@
/*
** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
**
-** Copyright (c) 1999-2001 Petko Manolov (pmanolov@lnxw.com)
+** Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
**
**
** ChangeLog:
@@ -21,6 +21,8 @@
** TODO: suppressing HCD warnings spewage on disconnect.
** v0.4.13 Ethernet address is now set at probe(), not at open()
** time as this seems to break dhcpd.
+** v0.5.0 branch to 2.5.x kernels
+** v0.5.1 ethtool support added
*/
/*
@@ -46,20 +48,25 @@
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/module.h>
#include <asm/byteorder.h>
+#include <asm/uaccess.h>
#include "pegasus.h"
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.4.23 (2002/02/01)"
-#define DRIVER_AUTHOR "Petko Manolov <pmanolov@lnxw.com>"
+#define DRIVER_VERSION "v0.5.1 (2002/03/06)"
+#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
#define PEGASUS_USE_INTR
#define PEGASUS_WRITE_EEPROM
+#define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
+ BMSR_100FULL | BMSR_ANEGCAPABLE)
static int loopback = 0;
static int mii_mode = 0;
@@ -461,8 +468,8 @@ static inline int reset_mac( pegasus_t *pegasus )
usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK ) {
__u16 auxmode;
- read_mii_word( pegasus, 0, 0x1b, &auxmode );
- write_mii_word( pegasus, 0, 0x1b, auxmode | 4 );
+ read_mii_word( pegasus, 0, MII_TPISTATUS, &auxmode );
+ write_mii_word( pegasus, 0, MII_TPISTATUS, auxmode | 4 );
}
return 0;
@@ -481,16 +488,16 @@ static int enable_net_traffic( struct net_device *dev, struct usb_device *usb )
if ( !(bmsr & 0x20) && !loopback )
warn( "%s: link NOT established (0x%x) - check the cable.",
dev->name, bmsr );
- if ( read_mii_word(pegasus, pegasus->phy, MII_ANLPA, &linkpart) )
+ if ( read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart) )
return 2;
if ( !(linkpart & 1) )
warn( "link partner stat %x", linkpart );
data[0] = 0xc9;
data[1] = 0;
- if ( linkpart & (ANLPA_100TX_FD | ANLPA_10T_FD) )
+ if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL) )
data[1] |= 0x20; /* set full duplex */
- if ( linkpart & (ANLPA_100TX_FD | ANLPA_100TX_HD) )
+ if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF) )
data[1] |= 0x10; /* set 100 Mbps */
if ( mii_mode )
data[1] = 0;
@@ -710,15 +717,26 @@ static inline void get_interrupt_interval( pegasus_t *pegasus )
}
+static void set_carrier(struct net_device *net)
+{
+ pegasus_t *pegasus;
+ short tmp;
+
+ pegasus = net->priv;
+ read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp);
+ if (tmp & BMSR_LSTATUS)
+ netif_carrier_on(net);
+ else
+ netif_carrier_off(net);
+
+}
+
+
static int pegasus_open(struct net_device *net)
{
pegasus_t *pegasus = (pegasus_t *)net->priv;
int res;
- if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
- err("can't enable_net_traffic() - %d", res);
- return -EIO;
- }
FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
pegasus->rx_buff, PEGASUS_MAX_MTU,
@@ -735,6 +753,11 @@ static int pegasus_open(struct net_device *net)
#endif
netif_start_queue( net );
pegasus->flags |= PEGASUS_RUNNING;
+ if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
+ err("can't enable_net_traffic() - %d", res);
+ return -EIO;
+ }
+ set_carrier(net);
return 0;
}
@@ -760,24 +783,103 @@ static int pegasus_close( struct net_device *net )
}
+static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
+{
+ pegasus_t *pegasus;
+ int cmd;
+ char tmp[128];
+
+ pegasus = net->priv;
+ if (get_user(cmd, (int *)uaddr))
+ return -EFAULT;
+ switch (cmd) {
+ case ETHTOOL_GDRVINFO: {
+ struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+ strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
+ strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
+ sprintf(tmp, "usb%d:%d", pegasus->usb->bus->busnum,
+ pegasus->usb->devnum);
+ strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
+ if (copy_to_user(uaddr, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ case ETHTOOL_GSET: {
+ struct ethtool_cmd ecmd;
+ short lpa, bmcr;
+
+ if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
+ return -EFAULT;
+ ecmd.supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_TP |
+ SUPPORTED_MII);
+ ecmd.port = PORT_TP;
+ ecmd.transceiver = XCVR_INTERNAL;
+ ecmd.phy_address = pegasus->phy;
+ read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
+ read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa);
+ if (bmcr & BMCR_ANENABLE) {
+ ecmd.autoneg = AUTONEG_ENABLE;
+ ecmd.speed = lpa & (LPA_100HALF|LPA_100FULL) ?
+ SPEED_100 : SPEED_10;
+ if (ecmd.speed == SPEED_100)
+ ecmd.duplex = lpa & LPA_100FULL ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ else
+ ecmd.duplex = lpa & LPA_10FULL ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ } else {
+ ecmd.autoneg = AUTONEG_DISABLE;
+ ecmd.speed = bmcr & BMCR_SPEED100 ?
+ SPEED_100 : SPEED_10;
+ ecmd.duplex = bmcr & BMCR_FULLDPLX ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ }
+ if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case ETHTOOL_SSET: {
+ return -EOPNOTSUPP;
+ }
+ case ETHTOOL_GLINK: {
+ struct ethtool_value edata = {ETHTOOL_GLINK};
+ edata.data = netif_carrier_ok(net);
+ if (copy_to_user(uaddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+
static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
{
__u16 *data = (__u16 *)&rq->ifr_data;
pegasus_t *pegasus = net->priv;
switch(cmd) {
- case SIOCDEVPRIVATE:
- data[0] = pegasus->phy;
- case SIOCDEVPRIVATE+1:
- read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
- return 0;
- case SIOCDEVPRIVATE+2:
- if ( !capable(CAP_NET_ADMIN) )
- return -EPERM;
- write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
- return 0;
- default:
- return -EOPNOTSUPP;
+ case SIOCETHTOOL:
+ return pegasus_ethtool_ioctl(net, rq->ifr_data);
+ case SIOCDEVPRIVATE:
+ data[0] = pegasus->phy;
+ case SIOCDEVPRIVATE+1:
+ read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
+ return 0;
+ case SIOCDEVPRIVATE+2:
+ if ( !capable(CAP_NET_ADMIN) )
+ return -EPERM;
+ write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
}
}
diff --git a/drivers/usb/pegasus.h b/drivers/usb/pegasus.h
index f9621b21ea2f..ba586b5a37a2 100644
--- a/drivers/usb/pegasus.h
+++ b/drivers/usb/pegasus.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999,2000 Petko Manolov - Petkan (pmanolov@lnxw.com)
+ * Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,14 +31,6 @@
#define EPROM_WR_ENABLE 0x10
#define EPROM_LOAD 0x20
-#define MII_BMCR 0x00
-#define MII_BMSR 0x01
-#define BMSR_MEDIA 0x7808
-#define MII_ANLPA 0x05
-#define ANLPA_100TX_FD 0x0100
-#define ANLPA_100TX_HD 0x0080
-#define ANLPA_10T_FD 0x0040
-#define ANLPA_10T_HD 0x0020
#define PHY_DONE 0x80
#define PHY_READ 0x40
#define PHY_WRITE 0x20
@@ -184,6 +176,8 @@ PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval. board)",
VENDOR_ADMTEK, 0x0986,
DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "AN986A USB MAC", VENDOR_ADMTEK, 1986,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121,
@@ -254,6 +248,8 @@ PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index b67fe4805ce3..6025a0176103 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -91,7 +91,7 @@ struct usblp {
struct usb_device *dev; /* USB device */
devfs_handle_t devfs; /* devfs device */
struct semaphore sem; /* locks this struct, especially "dev" */
- struct urb readurb, writeurb; /* The urbs */
+ struct urb *readurb, *writeurb; /* The urbs */
wait_queue_head_t wait; /* Zzzzz ... */
int readcount; /* Counter for reads */
int ifnum; /* Interface number */
@@ -253,15 +253,15 @@ static int usblp_open(struct inode *inode, struct file *file)
usblp->used = 1;
file->private_data = usblp;
- usblp->writeurb.transfer_buffer_length = 0;
- usblp->writeurb.status = 0;
+ usblp->writeurb->transfer_buffer_length = 0;
+ usblp->writeurb->status = 0;
usblp->wcomplete = 1; /* we begin writeable */
usblp->rcomplete = 0;
if (usblp->bidir) {
usblp->readcount = 0;
- usblp->readurb.dev = usblp->dev;
- if (usb_submit_urb(&usblp->readurb, GFP_KERNEL) < 0) {
+ usblp->readurb->dev = usblp->dev;
+ if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
retval = -EIO;
usblp->used = 0;
file->private_data = NULL;
@@ -278,8 +278,10 @@ static void usblp_cleanup (struct usblp *usblp)
usblp_table [usblp->minor] = NULL;
info ("usblp%d: removed", usblp->minor);
- kfree (usblp->writeurb.transfer_buffer);
+ kfree (usblp->writeurb->transfer_buffer);
kfree (usblp->device_id_string);
+ usb_free_urb(usblp->writeurb);
+ usb_free_urb(usblp->readurb);
kfree (usblp);
}
@@ -292,8 +294,8 @@ static int usblp_release(struct inode *inode, struct file *file)
usblp->used = 0;
if (usblp->dev) {
if (usblp->bidir)
- usb_unlink_urb(&usblp->readurb);
- usb_unlink_urb(&usblp->writeurb);
+ usb_unlink_urb(usblp->readurb);
+ usb_unlink_urb(usblp->writeurb);
up(&usblp->sem);
} else /* finish cleanup from disconnect */
usblp_cleanup (usblp);
@@ -306,8 +308,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
{
struct usblp *usblp = file->private_data;
poll_wait(file, &usblp->wait, wait);
- return ((!usblp->bidir || usblp->readurb.status == -EINPROGRESS) ? 0 : POLLIN | POLLRDNORM)
- | (usblp->writeurb.status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM);
+ return ((!usblp->bidir || usblp->readurb->status == -EINPROGRESS) ? 0 : POLLIN | POLLRDNORM)
+ | (usblp->writeurb->status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM);
}
static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -423,12 +425,12 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count,
return -ENODEV;
}
- if (usblp->writeurb.status != 0) {
+ if (usblp->writeurb->status != 0) {
if (usblp->quirks & USBLP_QUIRK_BIDIR) {
if (!usblp->wcomplete)
err("usblp%d: error %d writing to printer",
- usblp->minor, usblp->writeurb.status);
- err = usblp->writeurb.status;
+ usblp->minor, usblp->writeurb->status);
+ err = usblp->writeurb->status;
} else
err = usblp_check_status(usblp, err);
up (&usblp->sem);
@@ -440,23 +442,23 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count,
continue;
}
- writecount += usblp->writeurb.transfer_buffer_length;
- usblp->writeurb.transfer_buffer_length = 0;
+ writecount += usblp->writeurb->transfer_buffer_length;
+ usblp->writeurb->transfer_buffer_length = 0;
if (writecount == count) {
up (&usblp->sem);
break;
}
- usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
- (count - writecount) : USBLP_BUF_SIZE;
+ usblp->writeurb->transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
+ (count - writecount) : USBLP_BUF_SIZE;
- if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount,
- usblp->writeurb.transfer_buffer_length)) return -EFAULT;
+ if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount,
+ usblp->writeurb->transfer_buffer_length)) return -EFAULT;
- usblp->writeurb.dev = usblp->dev;
+ usblp->writeurb->dev = usblp->dev;
usblp->wcomplete = 0;
- if (usb_submit_urb(&usblp->writeurb, GFP_KERNEL)) {
+ if (usb_submit_urb(usblp->writeurb, GFP_KERNEL)) {
count = -EIO;
up (&usblp->sem);
break;
@@ -516,29 +518,29 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t
goto done;
}
- if (usblp->readurb.status) {
+ if (usblp->readurb->status) {
err("usblp%d: error %d reading from printer",
- usblp->minor, usblp->readurb.status);
- usblp->readurb.dev = usblp->dev;
+ usblp->minor, usblp->readurb->status);
+ usblp->readurb->dev = usblp->dev;
usblp->readcount = 0;
- usb_submit_urb(&usblp->readurb, GFP_KERNEL);
+ usb_submit_urb(usblp->readurb, GFP_KERNEL);
count = -EIO;
goto done;
}
- count = count < usblp->readurb.actual_length - usblp->readcount ?
- count : usblp->readurb.actual_length - usblp->readcount;
+ count = count < usblp->readurb->actual_length - usblp->readcount ?
+ count : usblp->readurb->actual_length - usblp->readcount;
- if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count)) {
+ if (copy_to_user(buffer, usblp->readurb->transfer_buffer + usblp->readcount, count)) {
count = -EFAULT;
goto done;
}
- if ((usblp->readcount += count) == usblp->readurb.actual_length) {
+ if ((usblp->readcount += count) == usblp->readurb->actual_length) {
usblp->readcount = 0;
- usblp->readurb.dev = usblp->dev;
+ usblp->readurb->dev = usblp->dev;
usblp->rcomplete = 0;
- if (usb_submit_urb(&usblp->readurb, GFP_KERNEL)) {
+ if (usb_submit_urb(usblp->readurb, GFP_KERNEL)) {
count = -EIO;
goto done;
}
@@ -668,24 +670,42 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
init_waitqueue_head(&usblp->wait);
+ usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!usblp->writeurb) {
+ err("out of memory");
+ kfree(usblp);
+ return NULL;
+ }
+ usblp->readurb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!usblp->readurb) {
+ err("out of memory");
+ usb_free_urb(usblp->writeurb);
+ kfree(usblp);
+ return NULL;
+ }
+
if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) {
err("out of memory");
+ usb_free_urb(usblp->writeurb);
+ usb_free_urb(usblp->readurb);
kfree(usblp);
return NULL;
}
if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) {
err("out of memory");
+ usb_free_urb(usblp->writeurb);
+ usb_free_urb(usblp->readurb);
kfree(usblp);
kfree(buf);
return NULL;
}
- FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
+ FILL_BULK_URB(usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
buf, 0, usblp_bulk_write, usblp);
if (bidir)
- FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
+ FILL_BULK_URB(usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk_read, usblp);
/* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */
@@ -737,9 +757,9 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr)
lock_kernel();
usblp->dev = NULL;
- usb_unlink_urb(&usblp->writeurb);
+ usb_unlink_urb(usblp->writeurb);
if (usblp->bidir)
- usb_unlink_urb(&usblp->readurb);
+ usb_unlink_urb(usblp->readurb);
if (!usblp->used)
usblp_cleanup (usblp);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 033d90411d26..f44ae514529a 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -1,8 +1,8 @@
/*
* USB IR Dongle driver
*
- * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.com)
+ * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,6 +21,11 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * 2002_Mar_07 greg kh
+ * moved some needed structures and #define values from the
+ * net/irda/irda-usb.h file into our file, as we don't want to depend on
+ * that codebase compiling correctly :)
+ *
* 2002_Jan_14 gb
* Added module parameter to force specific number of XBOFs.
* Added ir_xbof_change().
@@ -56,7 +61,6 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
-#include <net/irda/irda-usb.h>
#ifdef CONFIG_USB_SERIAL_DEBUG
static int debug = 1;
@@ -73,6 +77,33 @@
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
#define DRIVER_DESC "USB IR Dongle driver"
+/* USB IrDA class spec information */
+#define USB_CLASS_IRDA 0x02
+#define USB_DT_IRDA 0x21
+#define IU_REQ_GET_CLASS_DESC 0x06
+#define SPEED_2400 0x01
+#define SPEED_9600 0x02
+#define SPEED_19200 0x03
+#define SPEED_38400 0x04
+#define SPEED_57600 0x05
+#define SPEED_115200 0x06
+#define SPEED_576000 0x07
+#define SPEED_1152000 0x08
+#define SPEED_4000000 0x09
+
+struct irda_class_desc {
+ u8 bLength;
+ u8 bDescriptorType;
+ u16 bcdSpecRevision;
+ u8 bmDataSize;
+ u8 bmWindowSize;
+ u8 bmMinTurnaroundTime;
+ u16 wBaudRate;
+ u8 bmAdditionalBOFs;
+ u8 bIrdaRateSniff;
+ u8 bMaxUnicastList;
+} __attribute__ ((packed));
+
/* if overridden by the user, then use their value for the size of the read and
* write urbs */
static int buffer_size = 0;
@@ -158,7 +189,7 @@ static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev,
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
IU_REQ_GET_CLASS_DESC,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500));
+ 0, ifnum, desc, sizeof(*desc), HZ);
dbg("%s - ret=%d", __FUNCTION__, ret);
if (ret < sizeof(*desc)) {