Commit 6d22ea1b authored by Linus Torvalds's avatar Linus Torvalds

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

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents ed65e2d3 7a803754
...@@ -15,7 +15,7 @@ if [ "$CONFIG_USB" = "y" -o "$CONFIG_USB" = "m" ]; then ...@@ -15,7 +15,7 @@ if [ "$CONFIG_USB" = "y" -o "$CONFIG_USB" = "m" ]; then
source drivers/usb/storage/Config.in source drivers/usb/storage/Config.in
source drivers/usb/input/Config.in source drivers/usb/input/Config.in
source drivers/usb/image/Config.in source drivers/usb/image/Config.in
source drivers/usb/media/Config.in source drivers/usb/media/Config.in
......
...@@ -17,7 +17,7 @@ subdir-$(CONFIG_USB_UHCI) += host ...@@ -17,7 +17,7 @@ subdir-$(CONFIG_USB_UHCI) += host
subdir-$(CONFIG_USB_ACM) += class subdir-$(CONFIG_USB_ACM) += class
subdir-$(CONFIG_USB_AUDIO) += class subdir-$(CONFIG_USB_AUDIO) += class
subdir-$(CONFIG_USB_BLUETOOTH) += class subdir-$(CONFIG_USB_BLUETOOTH_TTY) += class
subdir-$(CONFIG_USB_PRINTER) += class subdir-$(CONFIG_USB_PRINTER) += class
subdir-$(CONFIG_USB_STORAGE) += storage subdir-$(CONFIG_USB_STORAGE) += storage
......
...@@ -828,12 +828,12 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -828,12 +828,12 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL); usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
if (!usblp->writeurb) { if (!usblp->writeurb) {
err("out of memory"); err("out of memory");
goto abort; goto abort_minor;
} }
usblp->readurb = usb_alloc_urb(0, GFP_KERNEL); usblp->readurb = usb_alloc_urb(0, GFP_KERNEL);
if (!usblp->readurb) { if (!usblp->readurb) {
err("out of memory"); err("out of memory");
goto abort; goto abort_minor;
} }
/* Malloc device ID string buffer to the largest expected length, /* Malloc device ID string buffer to the largest expected length,
...@@ -841,7 +841,7 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -841,7 +841,7 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
* could change in length. */ * could change in length. */
if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) { if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) {
err("out of memory for device_id_string"); err("out of memory for device_id_string");
goto abort; goto abort_minor;
} }
/* Malloc write/read buffers in one chunk. We somewhat wastefully /* Malloc write/read buffers in one chunk. We somewhat wastefully
...@@ -849,7 +849,7 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -849,7 +849,7 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
* 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->buf = kmalloc(2 * USBLP_BUF_SIZE, GFP_KERNEL))) {
err("out of memory for buf"); err("out of memory for buf");
goto abort; goto abort_minor;
} }
/* Lookup quirks for this printer. */ /* Lookup quirks for this printer. */
...@@ -863,12 +863,12 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -863,12 +863,12 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
dbg("incompatible printer-class device 0x%4.4X/0x%4.4X", dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
dev->descriptor.idVendor, dev->descriptor.idVendor,
dev->descriptor.idProduct); dev->descriptor.idProduct);
goto abort; goto abort_minor;
} }
/* Setup the selected alternate setting and endpoints. */ /* Setup the selected alternate setting and endpoints. */
if (usblp_set_protocol(usblp, protocol) < 0) if (usblp_set_protocol(usblp, protocol) < 0)
goto abort; goto abort_minor;
/* Retrieve and store the device ID string. */ /* Retrieve and store the device ID string. */
usblp_cache_device_id_string(usblp); usblp_cache_device_id_string(usblp);
...@@ -897,6 +897,8 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -897,6 +897,8 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
return usblp; return usblp;
abort_minor:
usb_deregister_dev (&usblp_driver, 1, usblp->minor);
abort: abort:
if (usblp) { if (usblp) {
usb_free_urb(usblp->writeurb); usb_free_urb(usblp->writeurb);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
*/ */
#include <linux/list.h> #include <linux/list.h>
#include <linux/compiler.h> /* likely()/unlikely() */
/* /*
* Hub request types * Hub request types
......
...@@ -1899,11 +1899,12 @@ void usb_disconnect(struct usb_device **pdev) ...@@ -1899,11 +1899,12 @@ void usb_disconnect(struct usb_device **pdev)
down(&driver->serialize); down(&driver->serialize);
driver->disconnect(dev, interface->private_data); driver->disconnect(dev, interface->private_data);
up(&driver->serialize); up(&driver->serialize);
if (driver->owner)
__MOD_DEC_USE_COUNT(driver->owner);
/* if driver->disconnect didn't release the interface */ /* if driver->disconnect didn't release the interface */
if (interface->driver) if (interface->driver)
usb_driver_release_interface(driver, interface); usb_driver_release_interface(driver, interface);
/* we don't need the driver any longer */
if (driver->owner)
__MOD_DEC_USE_COUNT(driver->owner);
} }
/* remove our device node for this interface */ /* remove our device node for this interface */
put_device(&interface->dev); put_device(&interface->dev);
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
/* /*
* EHCI hc_driver implementation ... experimental, incomplete. * EHCI hc_driver implementation ... experimental, incomplete.
* Based on the 0.96 register interface specification. * Based on the final 1.0 register interface specification.
* *
* There are lots of things to help out with here ... notably * There are lots of things to help out with here ... notably
* everything "periodic", and of course testing with all sorts * everything "periodic", and of course testing with all sorts
...@@ -70,6 +70,8 @@ ...@@ -70,6 +70,8 @@
* *
* HISTORY: * HISTORY:
* *
* 2002-05-07 Some error path cleanups to report better errors; wmb();
* use non-CVS version id; better iso bandwidth claim.
* 2002-04-19 Control/bulk/interrupt submit no longer uses giveback() on * 2002-04-19 Control/bulk/interrupt submit no longer uses giveback() on
* errors in submit path. Bugfixes to interrupt scheduling/processing. * errors in submit path. Bugfixes to interrupt scheduling/processing.
* 2002-03-05 Initial high-speed ISO support; reduce ITD memory; shift * 2002-03-05 Initial high-speed ISO support; reduce ITD memory; shift
...@@ -83,7 +85,7 @@ ...@@ -83,7 +85,7 @@
* 2001-June Works with usb-storage and NEC EHCI on 2.4 * 2001-June Works with usb-storage and NEC EHCI on 2.4
*/ */
#define DRIVER_VERSION "$Revision: 0.31 $" #define DRIVER_VERSION "2002-May-07"
#define DRIVER_AUTHOR "David Brownell" #define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
...@@ -582,7 +584,7 @@ dbg ("wait for dequeue: state %d, reclaim %p, hcd state %d", ...@@ -582,7 +584,7 @@ dbg ("wait for dequeue: state %d, reclaim %p, hcd state %d",
intr_deschedule (ehci, urb->start_frame, qh, urb->interval); intr_deschedule (ehci, urb->start_frame, qh, urb->interval);
if (ehci->hcd.state == USB_STATE_HALT) if (ehci->hcd.state == USB_STATE_HALT)
urb->status = -ESHUTDOWN; urb->status = -ESHUTDOWN;
qh_completions (ehci, &qh->qtd_list, 1); qh_completions (ehci, qh, 1);
return 0; return 0;
case PIPE_ISOCHRONOUS: case PIPE_ISOCHRONOUS:
......
...@@ -21,17 +21,17 @@ ...@@ -21,17 +21,17 @@
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* /*
* EHCI hardware queue manipulation * EHCI hardware queue manipulation ... the core. QH/QTD manipulation.
* *
* Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd" * Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd"
* entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
* buffers needed for the larger number). We use one QH per endpoint, queue * buffers needed for the larger number). We use one QH per endpoint, queue
* multiple (bulk or control) urbs per endpoint. URBs may need several qtds. * multiple (bulk or control) urbs per endpoint. URBs may need several qtds.
* A scheduled interrupt qh always has one qtd, one urb. * A scheduled interrupt qh always (for now) has one qtd, one urb.
* *
* ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
* interrupts) needs careful scheduling. Performance improvements can be * interrupts) needs careful scheduling. Performance improvements can be
* an ongoing challenge. * an ongoing challenge. That's in "ehci-sched.c".
* *
* USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs, * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
* or otherwise through transaction translators (TTs) in USB 2.0 hubs using * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
...@@ -91,6 +91,7 @@ static inline void qh_update (struct ehci_qh *qh, struct ehci_qtd *qtd) ...@@ -91,6 +91,7 @@ static inline void qh_update (struct ehci_qh *qh, struct ehci_qtd *qtd)
qh->hw_alt_next = EHCI_LIST_END; qh->hw_alt_next = EHCI_LIST_END;
/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
wmb ();
qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING); qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
} }
...@@ -105,29 +106,29 @@ static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token) ...@@ -105,29 +106,29 @@ static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token)
/* don't modify error codes */ /* don't modify error codes */
if (unlikely (urb->status == -EINPROGRESS && (token & QTD_STS_HALT))) { if (unlikely (urb->status == -EINPROGRESS && (token & QTD_STS_HALT))) {
if (token & QTD_STS_BABBLE) { if (token & QTD_STS_BABBLE) {
/* FIXME "must" disable babbling device's port too */
urb->status = -EOVERFLOW; urb->status = -EOVERFLOW;
} else if (!QTD_CERR (token)) { } else if (token & QTD_STS_MMF) {
if (token & QTD_STS_DBE) /* fs/ls interrupt xfer missed the complete-split */
urb->status = (QTD_PID (token) == 1) /* IN ? */ urb->status = -EPROTO;
? -ENOSR /* hc couldn't read data */ } else if (token & QTD_STS_DBE) {
: -ECOMM; /* hc couldn't write data */ urb->status = (QTD_PID (token) == 1) /* IN ? */
else if (token & QTD_STS_MMF) /* missed tt uframe */ ? -ENOSR /* hc couldn't read data */
urb->status = -EPROTO; : -ECOMM; /* hc couldn't write data */
else if (token & QTD_STS_XACT) { } else if (token & QTD_STS_XACT) {
if (QTD_LENGTH (token)) /* timeout, bad crc, wrong PID, etc; retried */
urb->status = -EPIPE; if (QTD_CERR (token))
else {
dbg ("3strikes");
urb->status = -EPROTO;
}
} else /* presumably a stall */
urb->status = -EPIPE; urb->status = -EPIPE;
else {
/* CERR nonzero + data left + halt --> stall */ dbg ("3strikes");
} else if (QTD_LENGTH (token)) urb->status = -EPROTO;
}
/* CERR nonzero + no errors + halt --> stall */
} else if (QTD_CERR (token))
urb->status = -EPIPE; urb->status = -EPIPE;
else /* unknown */ else /* unknown */
urb->status = -EPROTO; urb->status = -EPROTO;
dbg ("ep %d-%s qtd token %08x --> status %d", dbg ("ep %d-%s qtd token %08x --> status %d",
/* devpath */ /* devpath */
usb_pipeendpoint (urb->pipe), usb_pipeendpoint (urb->pipe),
...@@ -220,12 +221,11 @@ static void ehci_urb_done ( ...@@ -220,12 +221,11 @@ static void ehci_urb_done (
static int static int
qh_completions ( qh_completions (
struct ehci_hcd *ehci, struct ehci_hcd *ehci,
struct list_head *qtd_list, struct ehci_qh *qh,
int freeing int freeing
) { ) {
struct ehci_qtd *qtd, *last; struct ehci_qtd *qtd, *last;
struct list_head *next; struct list_head *next, *qtd_list = &qh->qtd_list;
struct ehci_qh *qh = 0;
int unlink = 0, halted = 0; int unlink = 0, halted = 0;
unsigned long flags; unsigned long flags;
int retval = 0; int retval = 0;
...@@ -245,9 +245,6 @@ qh_completions ( ...@@ -245,9 +245,6 @@ qh_completions (
struct urb *urb = qtd->urb; struct urb *urb = qtd->urb;
u32 token = 0; u32 token = 0;
/* qh is non-null iff these qtds were queued to the HC */
qh = (struct ehci_qh *) urb->hcpriv;
/* 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)) {
...@@ -266,7 +263,7 @@ qh_completions ( ...@@ -266,7 +263,7 @@ qh_completions (
/* qh overlays can have HC's old cached copies of /* qh overlays can have HC's old cached copies of
* next qtd ptrs, if an URB was queued afterwards. * next qtd ptrs, if an URB was queued afterwards.
*/ */
if (qh && cpu_to_le32 (last->qtd_dma) == qh->hw_current if (cpu_to_le32 (last->qtd_dma) == qh->hw_current
&& last->hw_next != qh->hw_qtd_next) { && last->hw_next != qh->hw_qtd_next) {
qh->hw_alt_next = last->hw_alt_next; qh->hw_alt_next = last->hw_alt_next;
qh->hw_qtd_next = last->hw_next; qh->hw_qtd_next = last->hw_next;
...@@ -278,70 +275,60 @@ qh_completions ( ...@@ -278,70 +275,60 @@ qh_completions (
} }
next = qtd->qtd_list.next; next = qtd->qtd_list.next;
/* if these qtds were queued to the HC, some may be active. /* QTDs at tail may be active if QH+HC are running,
* else we're cleaning up after a failed URB submission. * or when unlinking some urbs queued to this QH
*
* FIXME can simplify: cleanup case is gone now.
*/ */
if (likely (qh != 0)) { token = le32_to_cpu (qtd->hw_token);
int qh_halted; halted = halted
|| (__constant_cpu_to_le32 (QTD_STS_HALT)
qh_halted = __constant_cpu_to_le32 (QTD_STS_HALT) & qh->hw_token) != 0
& qh->hw_token; || (ehci->hcd.state == USB_STATE_HALT)
token = le32_to_cpu (qtd->hw_token); || (qh->qh_state == QH_STATE_IDLE);
halted = halted
|| qh_halted /* fault: unlink the rest, since this qtd saw an error? */
|| (ehci->hcd.state == USB_STATE_HALT) if (unlikely ((token & QTD_STS_HALT) != 0)) {
|| (qh->qh_state == QH_STATE_IDLE); freeing = unlink = 1;
/* status copied below */
/* QH halts only because of fault or unlink; in both
* cases, queued URBs get unlinked. But for unlink, /* QH halts only because of fault (above) or unlink (here). */
* URBs at the head of the queue can stay linked. } else if (unlikely (halted != 0)) {
*/
if (unlikely (halted != 0)) { /* unlinking everything because of HC shutdown? */
if (ehci->hcd.state == USB_STATE_HALT) {
/* unlink everything because of HC shutdown? */ freeing = unlink = 1;
if (ehci->hcd.state == USB_STATE_HALT) {
freeing = unlink = 1; /* explicit unlink, maybe starting here? */
urb->status = -ESHUTDOWN; } else if (qh->qh_state == QH_STATE_IDLE
/* explicit unlink, starting here? */
} else if (qh->qh_state == QH_STATE_IDLE
&& (urb->status == -ECONNRESET && (urb->status == -ECONNRESET
|| urb->status == -ENOENT)) { || urb->status == -ENOENT)) {
freeing = unlink = 1; freeing = unlink = 1;
/* unlink everything because of error? */
} else if (qh_halted
&& !(token & QTD_STS_HALT)) {
freeing = unlink = 1;
if (urb->status == -EINPROGRESS)
urb->status = -ECONNRESET;
/* unlink the rest? */
} else if (unlink) {
urb->status = -ECONNRESET;
/* QH halted to unlink urbs after this? */
} else if ((token & QTD_STS_ACTIVE) != 0) {
qtd = 0;
continue;
}
/* Else QH is active, so we must not modify QTDs /* QH halted to unlink urbs _after_ this? */
* that HC may be working on. Break from loop. } else if (!unlink && (token & QTD_STS_ACTIVE) != 0) {
*/
} else if (unlikely ((token & QTD_STS_ACTIVE) != 0)) {
next = qtd_list;
qtd = 0; qtd = 0;
continue; continue;
} }
spin_lock (&urb->lock); /* unlink the rest? once we start unlinking, after
qtd_copy_status (urb, qtd->length, token); * a fault or explicit unlink, we unlink all later
spin_unlock (&urb->lock); * urbs. usb spec requires that.
*/
if (unlink && urb->status == -EINPROGRESS)
urb->status = -ECONNRESET;
/* Else QH is active, so we must not modify QTDs
* that HC may be working on. No more qtds to check.
*/
} else if (unlikely ((token & QTD_STS_ACTIVE) != 0)) {
next = qtd_list;
qtd = 0;
continue;
} }
spin_lock (&urb->lock);
qtd_copy_status (urb, qtd->length, token);
spin_unlock (&urb->lock);
/* /*
* NOTE: this won't work right with interrupt urbs that * NOTE: this won't work right with interrupt urbs that
* need multiple qtds ... only the first scan of qh->qtd_list * need multiple qtds ... only the first scan of qh->qtd_list
...@@ -356,11 +343,10 @@ qh_completions ( ...@@ -356,11 +343,10 @@ qh_completions (
* from an interrupt QTD * from an interrupt QTD
*/ */
qtd->hw_token = (qtd->hw_token qtd->hw_token = (qtd->hw_token
& ~__constant_cpu_to_le32 (0x8300)) & __constant_cpu_to_le32 (0x8300))
| cpu_to_le32 (qtd->length << 16) | cpu_to_le32 (qtd->length << 16)
| __constant_cpu_to_le32 (QTD_IOC | __constant_cpu_to_le32 (QTD_STS_ACTIVE
| (EHCI_TUNE_CERR << 10) | (EHCI_TUNE_CERR << 10));
| QTD_STS_ACTIVE);
qtd->hw_buf [0] &= ~__constant_cpu_to_le32 (0x0fff); qtd->hw_buf [0] &= ~__constant_cpu_to_le32 (0x0fff);
/* this offset, and the length above, /* this offset, and the length above,
...@@ -387,7 +373,7 @@ qh_completions ( ...@@ -387,7 +373,7 @@ qh_completions (
} }
/* patch up list head? */ /* patch up list head? */
if (unlikely (halted && qh && !list_empty (qtd_list))) { if (unlikely (halted && !list_empty (qtd_list))) {
qh_update (qh, list_entry (qtd_list->next, qh_update (qh, list_entry (qtd_list->next,
struct ehci_qtd, qtd_list)); struct ehci_qtd, qtd_list));
} }
...@@ -737,6 +723,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -737,6 +723,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); /* [4.8] */ qh->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
qh->qh_next.qh = qh; qh->qh_next.qh = qh;
qh->hw_next = dma; qh->hw_next = dma;
wmb ();
ehci->async = qh; ehci->async = qh;
writel ((u32)qh->qh_dma, &ehci->regs->async_next); writel ((u32)qh->qh_dma, &ehci->regs->async_next);
cmd |= CMD_ASE | CMD_RUN; cmd |= CMD_ASE | CMD_RUN;
...@@ -748,6 +735,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -748,6 +735,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->hw_info1 &= ~__constant_cpu_to_le32 (QH_HEAD); /* [4.8] */ qh->hw_info1 &= ~__constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
qh->qh_next = q->qh_next; qh->qh_next = q->qh_next;
qh->hw_next = q->hw_next; qh->hw_next = q->hw_next;
wmb ();
q->qh_next.qh = qh; q->qh_next.qh = qh;
q->hw_next = dma; q->hw_next = dma;
} }
...@@ -885,7 +873,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) ...@@ -885,7 +873,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
ehci->reclaim = 0; ehci->reclaim = 0;
ehci->reclaim_ready = 0; ehci->reclaim_ready = 0;
qh_completions (ehci, &qh->qtd_list, 1); qh_completions (ehci, qh, 1);
// unlink any urb should now unlink all following urbs, so that // unlink any urb should now unlink all following urbs, so that
// relinking only happens for urbs before the unlinked ones. // relinking only happens for urbs before the unlinked ones.
...@@ -961,6 +949,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -961,6 +949,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
} }
prev->hw_next = qh->hw_next; prev->hw_next = qh->hw_next;
prev->qh_next = qh->qh_next; prev->qh_next = qh->qh_next;
wmb ();
ehci->reclaim_ready = 0; ehci->reclaim_ready = 0;
cmd |= CMD_IAAD; cmd |= CMD_IAAD;
...@@ -987,7 +976,7 @@ static void scan_async (struct ehci_hcd *ehci) ...@@ -987,7 +976,7 @@ static void scan_async (struct ehci_hcd *ehci)
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
/* concurrent unlink could happen here */ /* concurrent unlink could happen here */
qh_completions (ehci, &qh->qtd_list, 1); qh_completions (ehci, qh, 1);
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
qh_put (ehci, qh); qh_put (ehci, qh);
......
...@@ -23,6 +23,14 @@ ...@@ -23,6 +23,14 @@
/* /*
* EHCI scheduled transaction support: interrupt, iso, split iso * EHCI scheduled transaction support: interrupt, iso, split iso
* These are called "periodic" transactions in the EHCI spec. * These are called "periodic" transactions in the EHCI spec.
*
* Note that for interrupt transfers, the QH/QTD manipulation is shared
* with the "asynchronous" transaction support (control/bulk transfers).
* The only real difference is in how interrupt transfers are scheduled.
* We get some funky API restrictions from the current URB model, which
* works notably better for reading transfers than for writing. (And
* which accordingly needs to change before it'll work inside devices,
* or with "USB On The Go" additions to USB 2.0 ...)
*/ */
/* /*
...@@ -430,6 +438,7 @@ static int intr_submit ( ...@@ -430,6 +438,7 @@ static int intr_submit (
ehci->periodic [frame] = ehci->periodic [frame] =
QH_NEXT (qh->qh_dma); QH_NEXT (qh->qh_dma);
} }
wmb ();
frame += period; frame += period;
} while (frame < ehci->periodic_size); } while (frame < ehci->periodic_size);
...@@ -478,7 +487,7 @@ intr_complete ( ...@@ -478,7 +487,7 @@ intr_complete (
/* call any completions, after patching for reactivation */ /* call any completions, after patching for reactivation */
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
/* NOTE: currently restricted to one qtd per qh! */ /* NOTE: currently restricted to one qtd per qh! */
if (qh_completions (ehci, &qh->qtd_list, 0) == 0) if (qh_completions (ehci, qh, 0) == 0)
urb = 0; urb = 0;
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
...@@ -825,17 +834,26 @@ itd_schedule (struct ehci_hcd *ehci, struct urb *urb) ...@@ -825,17 +834,26 @@ itd_schedule (struct ehci_hcd *ehci, struct urb *urb)
itd->hw_transaction [uframe & 0x07] = itd->transaction; itd->hw_transaction [uframe & 0x07] = itd->transaction;
itd_link (ehci, (uframe >> 3) % ehci->periodic_size, itd_link (ehci, (uframe >> 3) % ehci->periodic_size,
itd); itd);
wmb ();
usecs += itd->usecs; usecs += itd->usecs;
itd = list_entry (itd->itd_list.next, itd = list_entry (itd->itd_list.next,
struct ehci_itd, itd_list); struct ehci_itd, itd_list);
} }
/* update bandwidth utilization records (for usbfs) */ /* update bandwidth utilization records (for usbfs)
/* FIXME usbcore expects per-frame average, which isn't *
* most accurate model... this provides the total claim, * FIXME This claims each URB queued to an endpoint, as if
* and expects the average to be computed only display. * transfers were concurrent, not sequential. So bandwidth
* typically gets double-billed ... comes from tying it to
* URBs rather than endpoints in the schedule. Luckily we
* don't use this usbfs data for serious decision making.
*/ */
usecs /= urb->number_of_packets;
usecs /= urb->interval;
usecs >>= 3;
if (usecs < 1)
usecs = 1;
usb_claim_bandwidth (urb->dev, urb, usecs, 1); usb_claim_bandwidth (urb->dev, urb, usecs, 1);
/* maybe enable periodic schedule processing */ /* maybe enable periodic schedule processing */
......
...@@ -83,7 +83,8 @@ ...@@ -83,7 +83,8 @@
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
#include <asm/feature.h> #include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/pci-bridge.h> #include <asm/pci-bridge.h>
#ifndef CONFIG_PM #ifndef CONFIG_PM
#define CONFIG_PM #define CONFIG_PM
...@@ -2727,12 +2728,12 @@ ohci_pci_suspend (struct pci_dev *dev, u32 state) ...@@ -2727,12 +2728,12 @@ ohci_pci_suspend (struct pci_dev *dev, u32 state)
pci_write_config_word (dev, PCI_COMMAND, cmd); pci_write_config_word (dev, PCI_COMMAND, cmd);
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
{ {
struct device_node *of_node; struct device_node *of_node;
/* Disable USB PAD & cell clock */ /* Disable USB PAD & cell clock */
of_node = pci_device_to_OF_node (ohci->ohci_dev); of_node = pci_device_to_OF_node (ohci->ohci_dev);
if (of_node && _machine == _MACH_Pmac) if (of_node)
feature_set_usb_power (of_node, 0); pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
} }
#endif #endif
return 0; return 0;
...@@ -2757,12 +2758,12 @@ ohci_pci_resume (struct pci_dev *dev) ...@@ -2757,12 +2758,12 @@ ohci_pci_resume (struct pci_dev *dev)
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
{ {
struct device_node *of_node; struct device_node *of_node;
/* Re-enable USB PAD & cell clock */ /* Re-enable USB PAD & cell clock */
of_node = pci_device_to_OF_node (ohci->ohci_dev); of_node = pci_device_to_OF_node (ohci->ohci_dev);
if (of_node && _machine == _MACH_Pmac) if (of_node)
feature_set_usb_power (of_node, 1); pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1);
} }
#endif #endif
......
...@@ -1396,12 +1396,12 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum) ...@@ -1396,12 +1396,12 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
if (usb_string(dev, dev->descriptor.iManufacturer, buf, 64) > 0) { if (usb_string(dev, dev->descriptor.iManufacturer, buf, 64) > 0) {
strcat(hid->name, buf); strcat(hid->name, buf);
if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0) if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0)
sprintf(hid->name, "%s %s", hid->name, buf); snprintf(hid->name, 64, "%s %s", hid->name, buf);
} else } else
sprintf(hid->name, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct); snprintf(hid->name, 128, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct);
usb_make_path(dev, buf, 63); usb_make_path(dev, buf, 64);
sprintf(hid->phys, "%s/input%d", buf, ifnum); snprintf(hid->phys, 64, "%s/input%d", buf, ifnum);
if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0) if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
hid->uniq[0] = 0; hid->uniq[0] = 0;
...@@ -1477,20 +1477,20 @@ static void hid_disconnect(struct usb_device *dev, void *ptr) ...@@ -1477,20 +1477,20 @@ static void hid_disconnect(struct usb_device *dev, void *ptr)
{ {
struct hid_device *hid = ptr; struct hid_device *hid = ptr;
dbg("cleanup called");
usb_unlink_urb(hid->urbin); usb_unlink_urb(hid->urbin);
usb_unlink_urb(hid->urbout); usb_unlink_urb(hid->urbout);
usb_unlink_urb(hid->urbctrl); usb_unlink_urb(hid->urbctrl);
if (hid->claimed & HID_CLAIMED_INPUT)
hidinput_disconnect(hid);
if (hid->claimed & HID_CLAIMED_HIDDEV)
hiddev_disconnect(hid);
usb_free_urb(hid->urbin); usb_free_urb(hid->urbin);
usb_free_urb(hid->urbctrl); usb_free_urb(hid->urbctrl);
if (hid->urbout) if (hid->urbout)
usb_free_urb(hid->urbout); usb_free_urb(hid->urbout);
if (hid->claimed & HID_CLAIMED_INPUT)
hidinput_disconnect(hid);
if (hid->claimed & HID_CLAIMED_HIDDEV)
hiddev_disconnect(hid);
hid_free_device(hid); hid_free_device(hid);
} }
......
...@@ -33,19 +33,32 @@ ...@@ -33,19 +33,32 @@
* re-enable queues to get higher bandwidth utilization (without needing * re-enable queues to get higher bandwidth utilization (without needing
* to tweak MTU for larger packets). * to tweak MTU for larger packets).
* *
* Add support for more "network cable" chips; interop with their Win32 * - AN2720 ... not widely available, but reportedly works well
* drivers may be a good thing. Test the AnchorChip 2720 support..
* Figure out the initialization protocol used by the Prolific chips,
* for better robustness ... there's some powerup/reset handshake that's
* needed when only one end reboots.
* *
* Use interrupt on PL230x to detect peer connect/disconnect, and call * - Belkin/eTEK ... no known issues
* netif_carrier_{on,off} (?) appropriately. For Net1080, detect peer
* connect/disconnect with async control messages.
* *
* Find some way to report "peer connected" network hotplug events; it'll * - Both GeneSys and PL-230x use interrupt transfers for driver-to-driver
* likely mean updating the networking layer. (This has been discussed * handshaking; it'd be worth implementing those as "carrier detect".
* on the netdev list...) * Prefer generic hooks, not minidriver-specific hacks.
*
* - Linux devices ... the www.handhelds.org SA-1100 support works nicely,
* but the Sharp Zaurus uses an incompatible protocol (extra checksums).
* No reason not to merge the Zaurus protocol here too (got patch? :)
*
* - For Netchip, use keventd to poll via control requests to detect hardware
* level "carrier detect".
*
* - PL-230x ... the initialization protocol doesn't seem to match chip data
* sheets, sometimes it's not needed and sometimes it hangs. Prolific has
* not responded to repeated support/information requests.
*
* Interop with more Win32 drivers may be a good thing.
*
* Seems like reporting "peer connected" (carrier present) events may end
* up going through the netlink event system, not hotplug ... that may be
* awkward in terms of automatic configuration though.
*
* There are reports that bridging gives lower-than-usual throughput.
* *
* Craft smarter hotplug policy scripts ... ones that know how to arrange * Craft smarter hotplug policy scripts ... ones that know how to arrange
* bridging with "brctl", and can handle static and dynamic ("pump") setups. * bridging with "brctl", and can handle static and dynamic ("pump") setups.
...@@ -88,6 +101,9 @@ ...@@ -88,6 +101,9 @@
* Level of diagnostics is more configurable; they use device * Level of diagnostics is more configurable; they use device
* location (usb_device->devpath) instead of address (2.5). * location (usb_device->devpath) instead of address (2.5).
* For tx_fixup, memflags can't be NOIO. * For tx_fixup, memflags can't be NOIO.
* 07-may-2002 Generalize/cleanup keventd support, handling rx stalls (mostly
* for USB 2.0 TTs) and memory shortages (potential) too. (db)
* Use "locally assigned" IEEE802 address space. (Brad Hards)
* *
*-------------------------------------------------------------------------*/ *-------------------------------------------------------------------------*/
...@@ -113,6 +129,7 @@ ...@@ -113,6 +129,7 @@
#include <linux/usb.h> #include <linux/usb.h>
/* minidrivers _could_ be individually configured */
#define CONFIG_USB_AN2720 #define CONFIG_USB_AN2720
#define CONFIG_USB_BELKIN #define CONFIG_USB_BELKIN
#define CONFIG_USB_GENESYS #define CONFIG_USB_GENESYS
...@@ -121,7 +138,7 @@ ...@@ -121,7 +138,7 @@
#define CONFIG_USB_PL2301 #define CONFIG_USB_PL2301
#define DRIVER_VERSION "26-Apr-2002" #define DRIVER_VERSION "07-May-2002"
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -185,7 +202,12 @@ struct usbnet { ...@@ -185,7 +202,12 @@ struct usbnet {
struct sk_buff_head txq; struct sk_buff_head txq;
struct sk_buff_head done; struct sk_buff_head done;
struct tasklet_struct bh; struct tasklet_struct bh;
struct tq_struct ctrl_task;
struct tq_struct kevent;
unsigned long flags;
# define EVENT_TX_HALT 0
# define EVENT_RX_HALT 1
# define EVENT_RX_MEMORY 2
}; };
// device-specific info used by the driver // device-specific info used by the driver
...@@ -1238,6 +1260,21 @@ static void defer_bh (struct usbnet *dev, struct sk_buff *skb) ...@@ -1238,6 +1260,21 @@ static void defer_bh (struct usbnet *dev, struct sk_buff *skb)
spin_unlock_irqrestore (&dev->done.lock, flags); spin_unlock_irqrestore (&dev->done.lock, flags);
} }
/* some work can't be done in tasklets, so we use keventd
*
* NOTE: annoying asymmetry: if it's active, schedule_task() fails,
* but tasklet_schedule() doesn't. hope the failure is rare.
*/
static void defer_kevent (struct usbnet *dev, int work)
{
set_bit (work, &dev->flags);
if (!schedule_task (&dev->kevent))
err ("%s: kevent %d may have been dropped",
dev->net.name, work);
else
dbg ("%s: kevent %d scheduled", dev->net.name, work);
}
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static void rx_complete (struct urb *urb); static void rx_complete (struct urb *urb);
...@@ -1264,7 +1301,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags) ...@@ -1264,7 +1301,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
if ((skb = alloc_skb (size, flags)) == 0) { if ((skb = alloc_skb (size, flags)) == 0) {
dbg ("no rx skb"); dbg ("no rx skb");
tasklet_schedule (&dev->bh); defer_kevent (dev, EVENT_RX_MEMORY);
usb_free_urb (urb); usb_free_urb (urb);
return; return;
} }
...@@ -1290,11 +1327,20 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags) ...@@ -1290,11 +1327,20 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
spin_lock_irqsave (&dev->rxq.lock, lockflags); spin_lock_irqsave (&dev->rxq.lock, lockflags);
if (netif_running (&dev->net)) { if (netif_running (&dev->net)
if ((retval = usb_submit_urb (urb, GFP_ATOMIC)) != 0) { && !test_bit (EVENT_RX_HALT, &dev->flags)) {
switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){
case -EPIPE:
defer_kevent (dev, EVENT_RX_HALT);
break;
case -ENOMEM:
defer_kevent (dev, EVENT_RX_MEMORY);
break;
default:
dbg ("%s rx submit, %d", dev->net.name, retval); dbg ("%s rx submit, %d", dev->net.name, retval);
tasklet_schedule (&dev->bh); tasklet_schedule (&dev->bh);
} else { break;
case 0:
__skb_queue_tail (&dev->rxq, skb); __skb_queue_tail (&dev->rxq, skb);
} }
} else { } else {
...@@ -1368,12 +1414,20 @@ static void rx_complete (struct urb *urb) ...@@ -1368,12 +1414,20 @@ static void rx_complete (struct urb *urb)
} }
break; break;
// stalls need manual reset. this is rare ... except that
// when going through USB 2.0 TTs, unplug appears this way.
// we avoid the highspeed version of the ETIMEOUT/EILSEQ
// storm, recovering as needed.
case -EPIPE:
defer_kevent (dev, EVENT_RX_HALT);
// FALLTHROUGH
// software-driven interface shutdown // software-driven interface shutdown
case -ECONNRESET: // usb-ohci, usb-uhci case -ECONNRESET: // according to API spec
case -ECONNABORTED: // uhci ... for usb-uhci, INTR case -ECONNABORTED: // some (now fixed?) UHCI bugs
dbg ("%s shutdown, code %d", dev->net.name, urb_status); dbg ("%s rx shutdown, code %d", dev->net.name, urb_status);
entry->state = rx_cleanup; entry->state = rx_cleanup;
// do urb frees only in the tasklet // do urb frees only in the tasklet (UHCI has oopsed ...)
entry->urb = urb; entry->urb = urb;
urb = 0; urb = 0;
break; break;
...@@ -1384,8 +1438,9 @@ static void rx_complete (struct urb *urb) ...@@ -1384,8 +1438,9 @@ static void rx_complete (struct urb *urb)
// FALLTHROUGH // FALLTHROUGH
default: default:
// on unplug we'll get a burst of ETIMEDOUT/EILSEQ // on unplug we get ETIMEDOUT (ohci) or EILSEQ (uhci)
// till the khubd gets and handles its interrupt. // until khubd sees its interrupt and disconnects us.
// that can easily be hundreds of passes through here.
entry->state = rx_cleanup; entry->state = rx_cleanup;
dev->stats.rx_errors++; dev->stats.rx_errors++;
dbg ("%s rx: status %d", dev->net.name, urb_status); dbg ("%s rx: status %d", dev->net.name, urb_status);
...@@ -1395,10 +1450,12 @@ static void rx_complete (struct urb *urb) ...@@ -1395,10 +1450,12 @@ static void rx_complete (struct urb *urb)
defer_bh (dev, skb); defer_bh (dev, skb);
if (urb) { if (urb) {
if (netif_running (&dev->net)) { if (netif_running (&dev->net)
&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
rx_submit (dev, urb, GFP_ATOMIC); rx_submit (dev, urb, GFP_ATOMIC);
return; return;
} }
usb_free_urb (urb);
} }
#ifdef VERBOSE #ifdef VERBOSE
dbg ("no read resubmitted"); dbg ("no read resubmitted");
...@@ -1428,7 +1485,7 @@ static int unlink_urbs (struct sk_buff_head *q) ...@@ -1428,7 +1485,7 @@ static int unlink_urbs (struct sk_buff_head *q)
// during some PM-driven resume scenarios, // during some PM-driven resume scenarios,
// these (async) unlinks complete immediately // these (async) unlinks complete immediately
retval = usb_unlink_urb (urb); retval = usb_unlink_urb (urb);
if (retval < 0) if (retval != -EINPROGRESS && retval != 0)
dbg ("unlink urb err, %d", retval); dbg ("unlink urb err, %d", retval);
else else
count++; count++;
...@@ -1600,16 +1657,62 @@ static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd) ...@@ -1600,16 +1657,62 @@ static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* usb_clear_halt cannot be called in interrupt context */ /* work that cannot be done in interrupt context uses keventd.
*
* NOTE: "uhci" and "usb-uhci" may have trouble with this since they don't
* queue control transfers to individual devices, and other threads could
* trigger control requests concurrently. hope that's rare.
*/
static void static void
tx_clear_halt (void *data) kevent (void *data)
{ {
struct usbnet *dev = data; struct usbnet *dev = data;
int status;
usb_clear_halt (dev->udev, /* usb_clear_halt() needs a thread context */
usb_sndbulkpipe (dev->udev, dev->driver_info->out)); if (test_bit (EVENT_TX_HALT, &dev->flags)) {
netif_wake_queue (&dev->net); unlink_urbs (&dev->txq);
status = usb_clear_halt (dev->udev,
usb_sndbulkpipe (dev->udev, dev->driver_info->out));
if (status < 0)
err ("%s: can't clear tx halt, status %d",
dev->net.name, status);
else {
clear_bit (EVENT_TX_HALT, &dev->flags);
netif_wake_queue (&dev->net);
}
}
if (test_bit (EVENT_RX_HALT, &dev->flags)) {
unlink_urbs (&dev->rxq);
status = usb_clear_halt (dev->udev,
usb_rcvbulkpipe (dev->udev, dev->driver_info->in));
if (status < 0)
err ("%s: can't clear rx halt, status %d",
dev->net.name, status);
else {
clear_bit (EVENT_RX_HALT, &dev->flags);
tasklet_schedule (&dev->bh);
}
}
/* tasklet could resubmit itself forever if memory is tight */
if (test_bit (EVENT_RX_MEMORY, &dev->flags)) {
struct urb *urb = 0;
if (netif_running (&dev->net))
urb = usb_alloc_urb (0, GFP_KERNEL);
else
clear_bit (EVENT_RX_MEMORY, &dev->flags);
if (urb != 0) {
clear_bit (EVENT_RX_MEMORY, &dev->flags);
rx_submit (dev, urb, GFP_KERNEL);
tasklet_schedule (&dev->bh);
}
}
if (dev->flags)
dbg ("%s: kevent done, flags = 0x%lx",
dev->net.name, dev->flags);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1620,15 +1723,8 @@ static void tx_complete (struct urb *urb) ...@@ -1620,15 +1723,8 @@ static void tx_complete (struct urb *urb)
struct skb_data *entry = (struct skb_data *) skb->cb; struct skb_data *entry = (struct skb_data *) skb->cb;
struct usbnet *dev = entry->dev; struct usbnet *dev = entry->dev;
if (urb->status == -EPIPE) { if (urb->status == -EPIPE)
if (dev->ctrl_task.sync == 0) { defer_kevent (dev, EVENT_TX_HALT);
dev->ctrl_task.routine = tx_clear_halt;
dev->ctrl_task.data = dev;
schedule_task (&dev->ctrl_task);
} else {
dbg ("Cannot clear TX stall");
}
}
urb->dev = 0; urb->dev = 0;
entry->state = tx_done; entry->state = tx_done;
defer_bh (dev, skb); defer_bh (dev, skb);
...@@ -1725,10 +1821,15 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) ...@@ -1725,10 +1821,15 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
#endif /* CONFIG_USB_NET1080 */ #endif /* CONFIG_USB_NET1080 */
netif_stop_queue (net); netif_stop_queue (net);
if ((retval = usb_submit_urb (urb, GFP_ATOMIC)) != 0) { switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) {
case -EPIPE:
defer_kevent (dev, EVENT_TX_HALT);
break;
default:
netif_start_queue (net); netif_start_queue (net);
dbg ("%s tx: submit urb err %d", net->name, retval); dbg ("%s tx: submit urb err %d", net->name, retval);
} else { break;
case 0:
net->trans_start = jiffies; net->trans_start = jiffies;
__skb_queue_tail (&dev->txq, skb); __skb_queue_tail (&dev->txq, skb);
if (dev->txq.qlen < TX_QLEN) if (dev->txq.qlen < TX_QLEN)
...@@ -1799,7 +1900,8 @@ static void usbnet_bh (unsigned long param) ...@@ -1799,7 +1900,8 @@ static void usbnet_bh (unsigned long param)
} }
// or are we maybe short a few urbs? // or are we maybe short a few urbs?
} else if (netif_running (&dev->net)) { } else if (netif_running (&dev->net)
&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
int temp = dev->rxq.qlen; int temp = dev->rxq.qlen;
if (temp < RX_QLEN) { if (temp < RX_QLEN) {
...@@ -1845,6 +1947,9 @@ static void usbnet_disconnect (struct usb_device *udev, void *ptr) ...@@ -1845,6 +1947,9 @@ static void usbnet_disconnect (struct usb_device *udev, void *ptr)
list_del (&dev->dev_list); list_del (&dev->dev_list);
mutex_unlock (&usbnet_mutex); mutex_unlock (&usbnet_mutex);
// assuming we used keventd, it must quiesce too
flush_scheduled_tasks ();
kfree (dev); kfree (dev);
usb_dec_dev_use (udev); usb_dec_dev_use (udev);
} }
...@@ -1902,6 +2007,7 @@ usbnet_probe (struct usb_device *udev, unsigned ifnum, ...@@ -1902,6 +2007,7 @@ usbnet_probe (struct usb_device *udev, unsigned ifnum,
skb_queue_head_init (&dev->done); skb_queue_head_init (&dev->done);
dev->bh.func = usbnet_bh; dev->bh.func = usbnet_bh;
dev->bh.data = (unsigned long) dev; dev->bh.data = (unsigned long) dev;
INIT_TQUEUE (&dev->kevent, kevent, dev);
// set up network interface records // set up network interface records
net = &dev->net; net = &dev->net;
...@@ -2038,6 +2144,7 @@ static int __init usbnet_init (void) ...@@ -2038,6 +2144,7 @@ static int __init usbnet_init (void)
get_random_bytes (node_id, sizeof node_id); get_random_bytes (node_id, sizeof node_id);
node_id [0] &= 0xfe; // clear multicast bit node_id [0] &= 0xfe; // clear multicast bit
node_id [0] |= 0x02; // set local assignment bit (IEEE802)
if (usb_register (&usbnet_driver) < 0) if (usb_register (&usbnet_driver) < 0)
return -1; return -1;
......
...@@ -73,6 +73,7 @@ static __devinitdata struct usb_device_id id_table [] = { ...@@ -73,6 +73,7 @@ static __devinitdata struct usb_device_id id_table [] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
......
...@@ -16,3 +16,6 @@ ...@@ -16,3 +16,6 @@
#define IODATA_VENDOR_ID 0x04bb #define IODATA_VENDOR_ID 0x04bb
#define IODATA_PRODUCT_ID 0x0a03 #define IODATA_PRODUCT_ID 0x0a03
#define ELCOM_VENDOR_ID 0x056e
#define ELCOM_PRODUCT_ID 0x5003
...@@ -1665,7 +1665,7 @@ EXPORT_SYMBOL(usb_serial_deregister); ...@@ -1665,7 +1665,7 @@ EXPORT_SYMBOL(usb_serial_deregister);
#if 0 #if 0
static kdev_t usb_console_device(struct console *co) static kdev_t usb_console_device(struct console *co)
{ {
return MKDEV(SERIAL_TTY_MAJOR, co->index); /* TBD */ return mk_kdev(SERIAL_TTY_MAJOR, co->index); /* TBD */
} }
#endif #endif
......
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