Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (129 commits)
  [PATCH] USB Storage: fix Rio Karma eject support build error
  USB: Airprime driver improvements to allow full speed EvDO transfers
  USB: remove OTG build warning
  USB: EHCI update VIA workaround
  USB: force root hub resume after power loss
  USB: ohci_usb can oops on shutdown
  USB: Dealias -110 code (more complete)
  USB: Remove unneeded void * casts in core files
  USB: u132-hcd: host controller driver for ELAN U132 adapter
  USB: ftdi-elan: client driver for ELAN Uxxx adapters
  usb serial: support Alcor Micro Corp. USB 2.0 TO RS-232 through pl2303 driver
  USB: Moschip 7840 USB-Serial Driver
  USB: add PlayStation 2 Trance Vibrator driver
  USB: Add ADU support for Ontrak ADU devices
  aircable: fix printk format warnings
  Add AIRcable USB Bluetooth Dongle Driver
  cypress_m8: implement graceful failure handling
  cypress_m8: improve control endpoint error handling
  cypress_m8: use usb_fill_int_urb where appropriate
  cypress_m8: use appropriate URB polling interval
  ...
This commit is contained in:
Linus Torvalds 2006-09-27 14:40:30 -07:00
commit 1f9bd4c96a
172 changed files with 20342 additions and 4139 deletions

View File

@ -43,59 +43,52 @@
<para>A Universal Serial Bus (USB) is used to connect a host,
such as a PC or workstation, to a number of peripheral
devices. USB uses a tree structure, with the host at the
devices. USB uses a tree structure, with the host as the
root (the system's master), hubs as interior nodes, and
peripheral devices as leaves (and slaves).
peripherals as leaves (and slaves).
Modern PCs support several such trees of USB devices, usually
one USB 2.0 tree (480 Mbit/sec each) with
a few USB 1.1 trees (12 Mbit/sec each) that are used when you
connect a USB 1.1 device directly to the machine's "root hub".
</para>
<para>That master/slave asymmetry was designed in part for
ease of use. It is not physically possible to assemble
(legal) USB cables incorrectly: all upstream "to-the-host"
connectors are the rectangular type, matching the sockets on
root hubs, and the downstream type are the squarish type
(or they are built in to the peripheral).
Software doesn't need to deal with distributed autoconfiguration
since the pre-designated master node manages all that.
At the electrical level, bus protocol overhead is reduced by
eliminating arbitration and moving scheduling into host software.
<para>That master/slave asymmetry was designed-in for a number of
reasons, one being ease of use. It is not physically possible to
assemble (legal) USB cables incorrectly: all upstream "to the host"
connectors are the rectangular type (matching the sockets on
root hubs), and all downstream connectors are the squarish type
(or they are built into the peripheral).
Also, the host software doesn't need to deal with distributed
auto-configuration since the pre-designated master node manages all that.
And finally, at the electrical level, bus protocol overhead is reduced by
eliminating arbitration and moving scheduling into the host software.
</para>
<para>USB 1.0 was announced in January 1996, and was revised
<para>USB 1.0 was announced in January 1996 and was revised
as USB 1.1 (with improvements in hub specification and
support for interrupt-out transfers) in September 1998.
USB 2.0 was released in April 2000, including high speed
transfers and transaction translating hubs (used for USB 1.1
USB 2.0 was released in April 2000, adding high-speed
transfers and transaction-translating hubs (used for USB 1.1
and 1.0 backward compatibility).
</para>
<para>USB support was added to Linux early in the 2.2 kernel series
shortly before the 2.3 development forked off. Updates
from 2.3 were regularly folded back into 2.2 releases, bringing
new features such as <filename>/sbin/hotplug</filename> support,
more drivers, and more robustness.
The 2.5 kernel series continued such improvements, and also
worked on USB 2.0 support,
higher performance,
better consistency between host controller drivers,
API simplification (to make bugs less likely),
and providing internal "kerneldoc" documentation.
<para>Kernel developers added USB support to Linux early in the 2.2 kernel
series, shortly before 2.3 development forked. Updates from 2.3 were
regularly folded back into 2.2 releases, which improved reliability and
brought <filename>/sbin/hotplug</filename> support as well more drivers.
Such improvements were continued in the 2.5 kernel series, where they added
USB 2.0 support, improved performance, and made the host controller drivers
(HCDs) more consistent. They also simplified the API (to make bugs less
likely) and added internal "kerneldoc" documentation.
</para>
<para>Linux can run inside USB devices as well as on
the hosts that control the devices.
Because the Linux 2.x USB support evolved to support mass market
platforms such as Apple Macintosh or PC-compatible systems,
it didn't address design concerns for those types of USB systems.
So it can't be used inside mass-market PDAs, or other peripherals.
USB device drivers running inside those Linux peripherals
But USB device drivers running inside those peripherals
don't do the same things as the ones running inside hosts,
and so they've been given a different name:
they're called <emphasis>gadget drivers</emphasis>.
This document does not present gadget drivers.
so they've been given a different name:
<emphasis>gadget drivers</emphasis>.
This document does not cover gadget drivers.
</para>
</chapter>
@ -103,17 +96,14 @@
<chapter id="host">
<title>USB Host-Side API Model</title>
<para>Within the kernel,
host-side drivers for USB devices talk to the "usbcore" APIs.
There are two types of public "usbcore" APIs, targetted at two different
layers of USB driver. Those are
<emphasis>general purpose</emphasis> drivers, exposed through
driver frameworks such as block, character, or network devices;
and drivers that are <emphasis>part of the core</emphasis>,
which are involved in managing a USB bus.
Such core drivers include the <emphasis>hub</emphasis> driver,
which manages trees of USB devices, and several different kinds
of <emphasis>host controller driver (HCD)</emphasis>,
<para>Host-side drivers for USB devices talk to the "usbcore" APIs.
There are two. One is intended for
<emphasis>general-purpose</emphasis> drivers (exposed through
driver frameworks), and the other is for drivers that are
<emphasis>part of the core</emphasis>.
Such core drivers include the <emphasis>hub</emphasis> driver
(which manages trees of USB devices) and several different kinds
of <emphasis>host controller drivers</emphasis>,
which control individual busses.
</para>
@ -122,21 +112,21 @@
<itemizedlist>
<listitem><para>USB supports four kinds of data transfer
(control, bulk, interrupt, and isochronous). Two transfer
types use bandwidth as it's available (control and bulk),
while the other two types of transfer (interrupt and isochronous)
<listitem><para>USB supports four kinds of data transfers
(control, bulk, interrupt, and isochronous). Two of them (control
and bulk) use bandwidth as it's available,
while the other two (interrupt and isochronous)
are scheduled to provide guaranteed bandwidth.
</para></listitem>
<listitem><para>The device description model includes one or more
"configurations" per device, only one of which is active at a time.
Devices that are capable of high speed operation must also support
full speed configurations, along with a way to ask about the
"other speed" configurations that might be used.
Devices that are capable of high-speed operation must also support
full-speed configurations, along with a way to ask about the
"other speed" configurations which might be used.
</para></listitem>
<listitem><para>Configurations have one or more "interface", each
<listitem><para>Configurations have one or more "interfaces", each
of which may have "alternate settings". Interfaces may be
standardized by USB "Class" specifications, or may be specific to
a vendor or device.</para>
@ -162,7 +152,7 @@
</para></listitem>
<listitem><para>The Linux USB API supports synchronous calls for
control and bulk messaging.
control and bulk messages.
It also supports asynchnous calls for all kinds of data transfer,
using request structures called "URBs" (USB Request Blocks).
</para></listitem>
@ -463,14 +453,25 @@
file in your Linux kernel sources.
</para>
<para>Otherwise the main use for this file from programs
is to poll() it to get notifications of usb devices
as they're plugged or unplugged.
To see what changed, you'd need to read the file and
compare "before" and "after" contents, scan the filesystem,
or see its hotplug event.
</para>
<para>This file, in combination with the poll() system call, can
also be used to detect when devices are added or removed:
<programlisting>int fd;
struct pollfd pfd;
fd = open("/proc/bus/usb/devices", O_RDONLY);
pfd = { fd, POLLIN, 0 };
for (;;) {
/* The first time through, this call will return immediately. */
poll(&amp;pfd, 1, -1);
/* To see what's changed, compare the file's previous and current
contents or scan the filesystem. (Scanning is more precise.) */
}</programlisting>
Note that this behavior is intended to be used for informational
and debug purposes. It would be more appropriate to use programs
such as udev or HAL to initialize a device or start a user-mode
helper program, for instance.
</para>
</sect1>
<sect1>

View File

@ -2543,6 +2543,9 @@ Your cooperation is appreciated.
64 = /dev/usb/rio500 Diamond Rio 500
65 = /dev/usb/usblcd USBLCD Interface (info@usblcd.de)
66 = /dev/usb/cpad0 Synaptics cPad (mouse/LCD)
67 = /dev/usb/adutux0 1st Ontrak ADU device
...
76 = /dev/usb/adutux10 10th Ontrak ADU device
96 = /dev/usb/hiddev0 1st USB HID device
...
111 = /dev/usb/hiddev15 16th USB HID device

View File

@ -98,13 +98,13 @@ one or more packets could finish before an error stops further endpoint I/O.
error, a failure to respond (often caused by
device disconnect), or some other fault.
-ETIMEDOUT (**) No response packet received within the prescribed
-ETIME (**) No response packet received within the prescribed
bus turn-around time. This error may instead be
reported as -EPROTO or -EILSEQ.
Note that the synchronous USB message functions
also use this code to indicate timeout expired
before the transfer completed.
-ETIMEDOUT Synchronous USB message functions use this code
to indicate timeout expired before the transfer
completed, and no other error was reported by HC.
-EPIPE (**) Endpoint stalled. For non-control endpoints,
reset this status with usb_clear_halt().
@ -163,6 +163,3 @@ usb_get_*/usb_set_*():
usb_control_msg():
usb_bulk_msg():
-ETIMEDOUT Timeout expired before the transfer completed.
In the future this code may change to -ETIME,
whose definition is a closer match to this sort
of error.

View File

@ -433,6 +433,11 @@ Options supported:
See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
information on this driver.
AIRcable USB Dongle Bluetooth driver
If there is the cdc_acm driver loaded in the system, you will find that the
cdc_acm claims the device before AIRcable can. This is simply corrected
by unloading both modules and then loading the aircable module before
cdc_acm module
Generic Serial driver

View File

@ -284,21 +284,9 @@ static struct pxaficp_platform_data corgi_ficp_platform_data = {
/*
* USB Device Controller
*/
static void corgi_udc_command(int cmd)
{
switch(cmd) {
case PXA2XX_UDC_CMD_CONNECT:
GPSR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
break;
case PXA2XX_UDC_CMD_DISCONNECT:
GPCR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
break;
}
}
static struct pxa2xx_udc_mach_info udc_info __initdata = {
/* no connect GPIO; corgi can't tell connection status */
.udc_command = corgi_udc_command,
.gpio_pullup = CORGI_GPIO_USB_PULLUP,
};
@ -350,7 +338,6 @@ static void __init corgi_init(void)
corgi_ssp_set_machinfo(&corgi_ssp_machinfo);
pxa_gpio_mode(CORGI_GPIO_IR_ON | GPIO_OUT);
pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT);
pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
pxa_set_udc_info(&udc_info);

View File

@ -26,7 +26,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/usb_otg.h>
#include <linux/usb/otg.h>
#include <asm/io.h>
#include <asm/irq.h>

View File

@ -358,7 +358,7 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
struct ub_scsi_cmd *cmd, struct ub_request *urq);
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
static void ub_end_rq(struct request *rq, int uptodate);
static void ub_end_rq(struct request *rq, unsigned int status);
static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
struct ub_request *urq, struct ub_scsi_cmd *cmd);
static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
@ -639,9 +639,15 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
struct ub_request *urq;
int n_elem;
if (atomic_read(&sc->poison) || lun->changed) {
if (atomic_read(&sc->poison)) {
blkdev_dequeue_request(rq);
ub_end_rq(rq, 0);
ub_end_rq(rq, DID_NO_CONNECT << 16);
return 0;
}
if (lun->changed && !blk_pc_request(rq)) {
blkdev_dequeue_request(rq);
ub_end_rq(rq, SAM_STAT_CHECK_CONDITION);
return 0;
}
@ -693,7 +699,7 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
drop:
ub_put_cmd(lun, cmd);
ub_end_rq(rq, 0);
ub_end_rq(rq, DID_ERROR << 16);
return 0;
}
@ -761,47 +767,53 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
struct ub_lun *lun = cmd->lun;
struct ub_request *urq = cmd->back;
struct request *rq;
int uptodate;
unsigned int scsi_status;
rq = urq->rq;
if (cmd->error == 0) {
uptodate = 1;
if (blk_pc_request(rq)) {
if (cmd->act_len >= rq->data_len)
rq->data_len = 0;
else
rq->data_len -= cmd->act_len;
}
scsi_status = 0;
} else {
uptodate = 0;
if (blk_pc_request(rq)) {
/* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */
memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
rq->sense_len = UB_SENSE_SIZE;
if (sc->top_sense[0] != 0)
rq->errors = SAM_STAT_CHECK_CONDITION;
scsi_status = SAM_STAT_CHECK_CONDITION;
else
rq->errors = DID_ERROR << 16;
scsi_status = DID_ERROR << 16;
} else {
if (cmd->error == -EIO) {
if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
return;
}
scsi_status = SAM_STAT_CHECK_CONDITION;
}
}
urq->rq = NULL;
ub_put_cmd(lun, cmd);
ub_end_rq(rq, uptodate);
ub_end_rq(rq, scsi_status);
blk_start_queue(lun->disk->queue);
}
static void ub_end_rq(struct request *rq, int uptodate)
static void ub_end_rq(struct request *rq, unsigned int scsi_status)
{
int uptodate;
if (scsi_status == 0) {
uptodate = 1;
} else {
uptodate = 0;
rq->errors = scsi_status;
}
end_that_request_first(rq, uptodate, rq->hard_nr_sectors);
end_that_request_last(rq, uptodate);
}

View File

@ -30,7 +30,7 @@
#include <linux/usb_ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb.h>
#include <linux/usb_otg.h>
#include <linux/usb/otg.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>

View File

@ -192,7 +192,7 @@ static char *get_usb_statmsg(int status)
return "bit stuffing error, timeout, or unknown USB error";
case -EILSEQ:
return "CRC mismatch, timeout, or unknown USB error";
case -ETIMEDOUT:
case -ETIME:
return "timed out";
case -EPIPE:
return "endpoint stalled";

View File

@ -137,11 +137,11 @@ static struct hfcusb_symbolic_list urb_errlist[] = {
{-ENXIO, "URB already queued"},
{-EFBIG, "Too much ISO frames requested"},
{-ENOSR, "Buffer error (overrun)"},
{-EPIPE, "Specified endpoint is stalled (device not responding)"},
{-EPIPE, "Specified endpoint is stalled"},
{-EOVERFLOW, "Babble (bad cable?)"},
{-EPROTO, "Bit-stuff error (bad cable?)"},
{-EILSEQ, "CRC/Timeout"},
{-ETIMEDOUT, "NAK (device does not respond)"},
{-EILSEQ, "CRC or missing token"},
{-ETIME, "Device did not respond"},
{-ESHUTDOWN, "Device unplugged"},
{-1, NULL}
};

View File

@ -80,7 +80,6 @@ static void dvb_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
switch (urb->status) {
case 0: /* success */
case -ETIMEDOUT: /* NAK */
break;
case -ECONNRESET: /* kill */
case -ENOENT:

View File

@ -215,7 +215,7 @@ static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
case -ETIMEDOUT:
case -ETIME:
/* this urb is dead, cleanup */
dprintk("%s:urb shutting down with status: %d\n",
__FUNCTION__, urb->status);

View File

@ -301,10 +301,11 @@ static struct symbolic_list senlist[] = {
static struct symbolic_list urb_errlist[] = {
{ -ENOSR, "Buffer error (overrun)" },
{ -EPIPE, "Stalled (device not responding)" },
{ -EOVERFLOW, "Babble (bad cable?)" },
{ -EOVERFLOW, "Babble (device sends too much data)" },
{ -EPROTO, "Bit-stuff error (bad cable?)" },
{ -EILSEQ, "CRC/Timeout" },
{ -ETIMEDOUT, "NAK (device does not respond)" },
{ -EILSEQ, "CRC/Timeout (bad cable?)" },
{ -ETIME, "Device does not respond to token" },
{ -ETIMEDOUT, "Device does not respond to command" },
{ -1, NULL }
};

View File

@ -711,7 +711,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break;
case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break;
case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break;
case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break;
case -ETIME: errmsg = "Device does not respond"; break;
}
PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
/* Give up after a number of contiguous errors on the USB bus.

View File

@ -586,15 +586,14 @@ static struct w9968cf_symbolic_list urb_errlist[] = {
{ -EFBIG, "Too much ISO frames requested" },
{ -ENOSR, "Buffer error (overrun)" },
{ -EPIPE, "Specified endpoint is stalled (device not responding)"},
{ -EOVERFLOW, "Babble (bad cable?)" },
{ -EOVERFLOW, "Babble (too much data)" },
{ -EPROTO, "Bit-stuff error (bad cable?)" },
{ -EILSEQ, "CRC/Timeout" },
{ -ETIMEDOUT, "NAK (device does not respond)" },
{ -ETIME, "Device does not respond to token" },
{ -ETIMEDOUT, "Device does not respond to command" },
{ -1, NULL }
};
/****************************************************************************
* Memory management functions *
****************************************************************************/

View File

@ -671,10 +671,8 @@ static void irda_usb_net_timeout(struct net_device *netdev)
* Jean II */
done = 1;
break;
case -ECONNABORTED: /* -103 */
case -ECONNRESET: /* -104 */
case -ETIMEDOUT: /* -110 */
case -ENOENT: /* -2 (urb unlinked by us) */
case -ECONNRESET:
case -ENOENT: /* urb unlinked by us */
default: /* ??? - Play safe */
urb->status = 0;
netif_wake_queue(self->netdev);
@ -712,10 +710,8 @@ static void irda_usb_net_timeout(struct net_device *netdev)
* Jean II */
done = 1;
break;
case -ECONNABORTED: /* -103 */
case -ECONNRESET: /* -104 */
case -ETIMEDOUT: /* -110 */
case -ENOENT: /* -2 (urb unlinked by us) */
case -ECONNRESET:
case -ENOENT: /* urb unlinked by us */
default: /* ??? - Play safe */
if(skb != NULL) {
dev_kfree_skb_any(skb);
@ -845,14 +841,14 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
self->stats.rx_crc_errors++;
/* Also precursor to a hot-unplug on UHCI. */
/* Fallthrough... */
case -ECONNRESET: /* -104 */
case -ECONNRESET:
/* Random error, if I remember correctly */
/* uhci_cleanup_unlink() is going to kill the Rx
* URB just after we return. No problem, at this
* point the URB will be idle ;-) - Jean II */
case -ESHUTDOWN: /* -108 */
case -ESHUTDOWN:
/* That's usually a hot-unplug. Submit will fail... */
case -ETIMEDOUT: /* -110 */
case -ETIME:
/* Usually precursor to a hot-unplug on OHCI. */
default:
self->stats.rx_errors++;

View File

@ -119,7 +119,7 @@ static void zd1201_usbfree(struct urb *urb, struct pt_regs *regs)
switch(urb->status) {
case -EILSEQ:
case -ENODEV:
case -ETIMEDOUT:
case -ETIME:
case -ENOENT:
case -EPIPE:
case -EOVERFLOW:
@ -201,7 +201,7 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
switch(urb->status) {
case -EILSEQ:
case -ENODEV:
case -ETIMEDOUT:
case -ETIME:
case -ENOENT:
case -EPIPE:
case -EOVERFLOW:

View File

@ -25,6 +25,7 @@ config USB_ARCH_HAS_OHCI
default y if PXA27x
default y if ARCH_EP93XX
default y if (ARCH_AT91RM9200 || ARCH_AT91SAM9261)
default y if ARCH_PNX4008
# PPC:
default y if STB03xxx
default y if PPC_MPC52xx

View File

@ -14,6 +14,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += host/
obj-$(CONFIG_USB_OHCI_HCD) += host/
obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_ETRAX_USB_HOST) += host/
obj-$(CONFIG_USB_OHCI_AT91) += host/
@ -23,6 +24,7 @@ obj-$(CONFIG_USB_PRINTER) += class/
obj-$(CONFIG_USB_STORAGE) += storage/
obj-$(CONFIG_USB) += storage/
obj-$(CONFIG_USB_ACECAD) += input/
obj-$(CONFIG_USB_AIPTEK) += input/
obj-$(CONFIG_USB_ATI_REMOTE) += input/
obj-$(CONFIG_USB_HID) += input/
@ -31,8 +33,8 @@ obj-$(CONFIG_USB_KBTAB) += input/
obj-$(CONFIG_USB_MOUSE) += input/
obj-$(CONFIG_USB_MTOUCH) += input/
obj-$(CONFIG_USB_POWERMATE) += input/
obj-$(CONFIG_USB_TRANCEVIBRATOR)+= input/
obj-$(CONFIG_USB_WACOM) += input/
obj-$(CONFIG_USB_ACECAD) += input/
obj-$(CONFIG_USB_XPAD) += input/
obj-$(CONFIG_USB_CATC) += net/
@ -47,22 +49,24 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB_ADUTUX) += misc/
obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
obj-$(CONFIG_USB_AUERSWALD) += misc/
obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
obj-$(CONFIG_USB_CYTHERM) += misc/
obj-$(CONFIG_USB_EMI26) += misc/
obj-$(CONFIG_USB_EMI62) += misc/
obj-$(CONFIG_USB_FTDI_ELAN) += misc/
obj-$(CONFIG_USB_IDMOUSE) += misc/
obj-$(CONFIG_USB_LCD) += misc/
obj-$(CONFIG_USB_LD) += misc/
obj-$(CONFIG_USB_LED) += misc/
obj-$(CONFIG_USB_LEGOTOWER) += misc/
obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
obj-$(CONFIG_USB_RIO500) += misc/
obj-$(CONFIG_USB_SISUSBVGA) += misc/
obj-$(CONFIG_USB_TEST) += misc/
obj-$(CONFIG_USB_USS720) += misc/
obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
obj-$(CONFIG_USB_SISUSBVGA) += misc/
obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/

View File

@ -1621,26 +1621,32 @@ static int claim_interface(struct usb_device *usb_dev,
return ret;
}
static void create_fs_entries(struct uea_softc *sc, struct usb_interface *intf)
static struct attribute *attrs[] = {
&dev_attr_stat_status.attr,
&dev_attr_stat_mflags.attr,
&dev_attr_stat_human_status.attr,
&dev_attr_stat_delin.attr,
&dev_attr_stat_vidcpe.attr,
&dev_attr_stat_usrate.attr,
&dev_attr_stat_dsrate.attr,
&dev_attr_stat_usattenuation.attr,
&dev_attr_stat_dsattenuation.attr,
&dev_attr_stat_usmargin.attr,
&dev_attr_stat_dsmargin.attr,
&dev_attr_stat_txflow.attr,
&dev_attr_stat_rxflow.attr,
&dev_attr_stat_uscorr.attr,
&dev_attr_stat_dscorr.attr,
&dev_attr_stat_usunc.attr,
&dev_attr_stat_dsunc.attr,
};
static struct attribute_group attr_grp = {
.attrs = attrs,
};
static int create_fs_entries(struct usb_interface *intf)
{
/* sysfs interface */
device_create_file(&intf->dev, &dev_attr_stat_status);
device_create_file(&intf->dev, &dev_attr_stat_mflags);
device_create_file(&intf->dev, &dev_attr_stat_human_status);
device_create_file(&intf->dev, &dev_attr_stat_delin);
device_create_file(&intf->dev, &dev_attr_stat_vidcpe);
device_create_file(&intf->dev, &dev_attr_stat_usrate);
device_create_file(&intf->dev, &dev_attr_stat_dsrate);
device_create_file(&intf->dev, &dev_attr_stat_usattenuation);
device_create_file(&intf->dev, &dev_attr_stat_dsattenuation);
device_create_file(&intf->dev, &dev_attr_stat_usmargin);
device_create_file(&intf->dev, &dev_attr_stat_dsmargin);
device_create_file(&intf->dev, &dev_attr_stat_txflow);
device_create_file(&intf->dev, &dev_attr_stat_rxflow);
device_create_file(&intf->dev, &dev_attr_stat_uscorr);
device_create_file(&intf->dev, &dev_attr_stat_dscorr);
device_create_file(&intf->dev, &dev_attr_stat_usunc);
device_create_file(&intf->dev, &dev_attr_stat_dsunc);
return sysfs_create_group(&intf->dev.kobj, &attr_grp);
}
static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
@ -1708,37 +1714,25 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
return ret;
}
create_fs_entries(sc, intf);
ret = create_fs_entries(intf);
if (ret) {
uea_stop(sc);
kfree(sc);
return ret;
}
return 0;
}
static void destroy_fs_entries(struct uea_softc *sc, struct usb_interface *intf)
static void destroy_fs_entries(struct usb_interface *intf)
{
/* sysfs interface */
device_remove_file(&intf->dev, &dev_attr_stat_status);
device_remove_file(&intf->dev, &dev_attr_stat_mflags);
device_remove_file(&intf->dev, &dev_attr_stat_human_status);
device_remove_file(&intf->dev, &dev_attr_stat_delin);
device_remove_file(&intf->dev, &dev_attr_stat_vidcpe);
device_remove_file(&intf->dev, &dev_attr_stat_usrate);
device_remove_file(&intf->dev, &dev_attr_stat_dsrate);
device_remove_file(&intf->dev, &dev_attr_stat_usattenuation);
device_remove_file(&intf->dev, &dev_attr_stat_dsattenuation);
device_remove_file(&intf->dev, &dev_attr_stat_usmargin);
device_remove_file(&intf->dev, &dev_attr_stat_dsmargin);
device_remove_file(&intf->dev, &dev_attr_stat_txflow);
device_remove_file(&intf->dev, &dev_attr_stat_rxflow);
device_remove_file(&intf->dev, &dev_attr_stat_uscorr);
device_remove_file(&intf->dev, &dev_attr_stat_dscorr);
device_remove_file(&intf->dev, &dev_attr_stat_usunc);
device_remove_file(&intf->dev, &dev_attr_stat_dsunc);
sysfs_remove_group(&intf->dev.kobj, &attr_grp);
}
static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
{
struct uea_softc *sc = usbatm->driver_data;
destroy_fs_entries(sc, intf);
destroy_fs_entries(intf);
uea_stop(sc);
kfree(sc);
}

View File

@ -813,7 +813,7 @@ static unsigned int usblp_quirks (__u16 vendor, __u16 product)
return 0;
}
static struct file_operations usblp_fops = {
static const struct file_operations usblp_fops = {
.owner = THIS_MODULE,
.read = usblp_read,
.write = usblp_write,
@ -927,7 +927,9 @@ static int usblp_probe(struct usb_interface *intf,
/* Retrieve and store the device ID string. */
usblp_cache_device_id_string(usblp);
device_create_file(&intf->dev, &dev_attr_ieee1284_id);
retval = device_create_file(&intf->dev, &dev_attr_ieee1284_id);
if (retval)
goto abort_intfdata;
#ifdef DEBUG
usblp_check_status(usblp, 0);
@ -1021,18 +1023,13 @@ static int usblp_select_alts(struct usblp *usblp)
for (e = 0; e < ifd->desc.bNumEndpoints; e++) {
epd = &ifd->endpoint[e].desc;
if ((epd->bmAttributes&USB_ENDPOINT_XFERTYPE_MASK)!=
USB_ENDPOINT_XFER_BULK)
continue;
if (!(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)) {
if (usb_endpoint_is_bulk_out(epd))
if (!epwrite)
epwrite = epd;
} else {
if (usb_endpoint_is_bulk_in(epd))
if (!epread)
epread = epd;
}
}
/* Ignore buggy hardware without the right endpoints. */

View File

@ -4,7 +4,7 @@
usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \
config.o file.o buffer.o sysfs.o endpoint.o \
devio.o notify.o
devio.o notify.o generic.o
ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o

View File

@ -104,7 +104,7 @@ void *hcd_buffer_alloc (
dma_addr_t *dma
)
{
struct usb_hcd *hcd = bus->hcpriv;
struct usb_hcd *hcd = bus_to_hcd(bus);
int i;
/* some USB hosts just use PIO */
@ -127,7 +127,7 @@ void hcd_buffer_free (
dma_addr_t dma
)
{
struct usb_hcd *hcd = bus->hcpriv;
struct usb_hcd *hcd = bus_to_hcd(bus);
int i;
if (!addr)

View File

@ -475,7 +475,9 @@ int usb_get_configuration(struct usb_device *dev)
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
"descriptor/%s\n", cfgno, "start");
goto err;
dev_err(ddev, "chopping to %d config(s)\n", cfgno);
dev->descriptor.bNumConfigurations = cfgno;
break;
} else if (result < 4) {
dev_err(ddev, "config index %d descriptor too short "
"(expected %i, got %i)\n", cfgno,

View File

@ -593,7 +593,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
/* Kernel lock for "lastev" protection */
static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
{
struct usb_device_status *st = (struct usb_device_status *)file->private_data;
struct usb_device_status *st = file->private_data;
unsigned int mask = 0;
lock_kernel();
@ -603,7 +603,7 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct
unlock_kernel();
return POLLIN;
}
/* we may have dropped BKL - need to check for having lost the race */
if (file->private_data) {
kfree(st);
@ -667,7 +667,7 @@ static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
return ret;
}
struct file_operations usbfs_devices_fops = {
const struct file_operations usbfs_devices_fops = {
.llseek = usb_device_lseek,
.read = usb_device_read,
.poll = usb_device_poll,

View File

@ -59,6 +59,9 @@
#define USB_DEVICE_MAX USB_MAXBUS * 128
static struct class *usb_device_class;
/* Mutual exclusion for removal, open, and release */
DEFINE_MUTEX(usbfs_mutex);
struct async {
struct list_head asynclist;
struct dev_state *ps;
@ -87,9 +90,10 @@ MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");
#define MAX_USBFS_BUFFER_SIZE 16384
static inline int connected (struct usb_device *dev)
static inline int connected (struct dev_state *ps)
{
return dev->state != USB_STATE_NOTATTACHED;
return (!list_empty(&ps->list) &&
ps->dev->state != USB_STATE_NOTATTACHED);
}
static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
@ -118,7 +122,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
struct dev_state *ps = (struct dev_state *)file->private_data;
struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
ssize_t ret = 0;
unsigned len;
@ -127,7 +131,7 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
pos = *ppos;
usb_lock_device(dev);
if (!connected(dev)) {
if (!connected(ps)) {
ret = -ENODEV;
goto err;
} else if (pos < 0) {
@ -301,7 +305,7 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
static void async_completed(struct urb *urb, struct pt_regs *regs)
{
struct async *as = (struct async *)urb->context;
struct async *as = urb->context;
struct dev_state *ps = as->ps;
struct siginfo sinfo;
@ -541,25 +545,25 @@ static int usbdev_open(struct inode *inode, struct file *file)
struct dev_state *ps;
int ret;
/*
* no locking necessary here, as chrdev_open has the kernel lock
* (still acquire the kernel lock for safety)
*/
/* Protect against simultaneous removal or release */
mutex_lock(&usbfs_mutex);
ret = -ENOMEM;
if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
goto out_nolock;
goto out;
lock_kernel();
ret = -ENOENT;
/* check if we are called from a real node or usbfs */
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_minor(iminor(inode));
if (!dev)
dev = inode->i_private;
if (!dev) {
kfree(ps);
if (!dev)
goto out;
}
ret = usb_autoresume_device(dev, 1);
if (ret)
goto out;
usb_get_dev(dev);
ret = 0;
ps->dev = dev;
@ -579,30 +583,36 @@ static int usbdev_open(struct inode *inode, struct file *file)
list_add_tail(&ps->list, &dev->filelist);
file->private_data = ps;
out:
unlock_kernel();
out_nolock:
return ret;
if (ret)
kfree(ps);
mutex_unlock(&usbfs_mutex);
return ret;
}
static int usbdev_release(struct inode *inode, struct file *file)
{
struct dev_state *ps = (struct dev_state *)file->private_data;
struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
unsigned int ifnum;
usb_lock_device(dev);
/* Protect against simultaneous open */
mutex_lock(&usbfs_mutex);
list_del_init(&ps->list);
mutex_unlock(&usbfs_mutex);
for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
ifnum++) {
if (test_bit(ifnum, &ps->ifclaimed))
releaseintf(ps, ifnum);
}
destroy_all_async(ps);
usb_autosuspend_device(dev, 1);
usb_unlock_device(dev);
usb_put_dev(dev);
ps->dev = NULL;
kfree(ps);
return 0;
return 0;
}
static int proc_control(struct dev_state *ps, void __user *arg)
@ -1322,7 +1332,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
}
}
if (!connected(ps->dev)) {
if (!connected(ps)) {
kfree(buf);
return -ENODEV;
}
@ -1349,7 +1359,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
/* let kernel drivers try to (re)bind to the interface */
case USBDEVFS_CONNECT:
usb_unlock_device(ps->dev);
bus_rescan_devices(intf->dev.bus);
retval = bus_rescan_devices(intf->dev.bus);
usb_lock_device(ps->dev);
break;
@ -1413,7 +1423,7 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
*/
static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct dev_state *ps = (struct dev_state *)file->private_data;
struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
void __user *p = (void __user *)arg;
int ret = -ENOTTY;
@ -1421,7 +1431,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
usb_lock_device(dev);
if (!connected(dev)) {
if (!connected(ps)) {
usb_unlock_device(dev);
return -ENODEV;
}
@ -1556,18 +1566,18 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
/* No kernel lock - fine */
static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
{
struct dev_state *ps = (struct dev_state *)file->private_data;
unsigned int mask = 0;
struct dev_state *ps = file->private_data;
unsigned int mask = 0;
poll_wait(file, &ps->wait, wait);
if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
mask |= POLLOUT | POLLWRNORM;
if (!connected(ps->dev))
if (!connected(ps))
mask |= POLLERR | POLLHUP;
return mask;
}
struct file_operations usbfs_device_file_operations = {
const struct file_operations usbfs_device_file_operations = {
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,

File diff suppressed because it is too large Load Diff

View File

@ -207,9 +207,9 @@ static void ep_device_release(struct device *dev)
kfree(ep_dev);
}
void usb_create_ep_files(struct device *parent,
struct usb_host_endpoint *endpoint,
struct usb_device *udev)
int usb_create_ep_files(struct device *parent,
struct usb_host_endpoint *endpoint,
struct usb_device *udev)
{
char name[8];
struct ep_device *ep_dev;
@ -242,19 +242,33 @@ void usb_create_ep_files(struct device *parent,
retval = device_register(&ep_dev->dev);
if (retval)
goto error;
sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
if (retval)
goto error_group;
endpoint->ep_dev = ep_dev;
/* create the symlink to the old-style "ep_XX" directory */
sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
sysfs_create_link(&parent->kobj, &endpoint->ep_dev->dev.kobj, name);
retval = sysfs_create_link(&parent->kobj,
&endpoint->ep_dev->dev.kobj, name);
if (retval)
goto error_link;
exit:
return;
return retval;
error_link:
sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
error_group:
device_unregister(&ep_dev->dev);
endpoint->ep_dev = NULL;
destroy_endpoint_class();
return retval;
error:
kfree(ep_dev);
return;
destroy_endpoint_class();
return retval;
}
void usb_remove_ep_files(struct usb_host_endpoint *endpoint)

View File

@ -55,7 +55,7 @@ static int usb_open(struct inode * inode, struct file * file)
return err;
}
static struct file_operations usb_fops = {
static const struct file_operations usb_fops = {
.owner = THIS_MODULE,
.open = usb_open,
};

208
drivers/usb/core/generic.c Normal file
View File

@ -0,0 +1,208 @@
/*
* drivers/usb/generic.c - generic driver for USB devices (not interfaces)
*
* (C) Copyright 2005 Greg Kroah-Hartman <gregkh@suse.de>
*
* based on drivers/usb/usb.c which had the following copyrights:
* (C) Copyright Linus Torvalds 1999
* (C) Copyright Johannes Erdfelt 1999-2001
* (C) Copyright Andreas Gal 1999
* (C) Copyright Gregory P. Smith 1999
* (C) Copyright Deti Fliegl 1999 (new USB architecture)
* (C) Copyright Randy Dunlap 2000
* (C) Copyright David Brownell 2000-2004
* (C) Copyright Yggdrasil Computing, Inc. 2000
* (usb_device_id matching changes by Adam J. Richter)
* (C) Copyright Greg Kroah-Hartman 2002-2003
*
*/
#include <linux/config.h>
#include <linux/usb.h>
#include "usb.h"
static inline const char *plural(int n)
{
return (n == 1 ? "" : "s");
}
static int choose_configuration(struct usb_device *udev)
{
int i;
int num_configs;
int insufficient_power = 0;
struct usb_host_config *c, *best;
best = NULL;
c = udev->config;
num_configs = udev->descriptor.bNumConfigurations;
for (i = 0; i < num_configs; (i++, c++)) {
struct usb_interface_descriptor *desc = NULL;
/* It's possible that a config has no interfaces! */
if (c->desc.bNumInterfaces > 0)
desc = &c->intf_cache[0]->altsetting->desc;
/*
* HP's USB bus-powered keyboard has only one configuration
* and it claims to be self-powered; other devices may have
* similar errors in their descriptors. If the next test
* were allowed to execute, such configurations would always
* be rejected and the devices would not work as expected.
* In the meantime, we run the risk of selecting a config
* that requires external power at a time when that power
* isn't available. It seems to be the lesser of two evils.
*
* Bugzilla #6448 reports a device that appears to crash
* when it receives a GET_DEVICE_STATUS request! We don't
* have any other way to tell whether a device is self-powered,
* but since we don't use that information anywhere but here,
* the call has been removed.
*
* Maybe the GET_DEVICE_STATUS call and the test below can
* be reinstated when device firmwares become more reliable.
* Don't hold your breath.
*/
#if 0
/* Rule out self-powered configs for a bus-powered device */
if (bus_powered && (c->desc.bmAttributes &
USB_CONFIG_ATT_SELFPOWER))
continue;
#endif
/*
* The next test may not be as effective as it should be.
* Some hubs have errors in their descriptor, claiming
* to be self-powered when they are really bus-powered.
* We will overestimate the amount of current such hubs
* make available for each port.
*
* This is a fairly benign sort of failure. It won't
* cause us to reject configurations that we should have
* accepted.
*/
/* Rule out configs that draw too much bus current */
if (c->desc.bMaxPower * 2 > udev->bus_mA) {
insufficient_power++;
continue;
}
/* If the first config's first interface is COMM/2/0xff
* (MSFT RNDIS), rule it out unless Linux has host-side
* RNDIS support. */
if (i == 0 && desc
&& desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
&& desc->bInterfaceProtocol == 0xff) {
#ifndef CONFIG_USB_NET_RNDIS_HOST
continue;
#else
best = c;
#endif
}
/* From the remaining configs, choose the first one whose
* first interface is for a non-vendor-specific class.
* Reason: Linux is more likely to have a class driver
* than a vendor-specific driver. */
else if (udev->descriptor.bDeviceClass !=
USB_CLASS_VENDOR_SPEC &&
(!desc || desc->bInterfaceClass !=
USB_CLASS_VENDOR_SPEC)) {
best = c;
break;
}
/* If all the remaining configs are vendor-specific,
* choose the first one. */
else if (!best)
best = c;
}
if (insufficient_power > 0)
dev_info(&udev->dev, "rejected %d configuration%s "
"due to insufficient available bus power\n",
insufficient_power, plural(insufficient_power));
if (best) {
i = best->desc.bConfigurationValue;
dev_info(&udev->dev,
"configuration #%d chosen from %d choice%s\n",
i, num_configs, plural(num_configs));
} else {
i = -1;
dev_warn(&udev->dev,
"no configuration chosen from %d choice%s\n",
num_configs, plural(num_configs));
}
return i;
}
static int generic_probe(struct usb_device *udev)
{
int err, c;
/* put device-specific files into sysfs */
usb_create_sysfs_dev_files(udev);
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
c = choose_configuration(udev);
if (c >= 0) {
err = usb_set_configuration(udev, c);
if (err) {
dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
/* This need not be fatal. The user can try to
* set other configurations. */
}
}
/* USB device state == configured ... usable */
usb_notify_add_device(udev);
return 0;
}
static void generic_disconnect(struct usb_device *udev)
{
usb_notify_remove_device(udev);
/* if this is only an unbind, not a physical disconnect, then
* unconfigure the device */
if (udev->actconfig)
usb_set_configuration(udev, 0);
usb_remove_sysfs_dev_files(udev);
}
#ifdef CONFIG_PM
static int generic_suspend(struct usb_device *udev, pm_message_t msg)
{
/* USB devices enter SUSPEND state through their hubs, but can be
* marked for FREEZE as soon as their children are already idled.
* But those semantics are useless, so we equate the two (sigh).
*/
return usb_port_suspend(udev);
}
static int generic_resume(struct usb_device *udev)
{
return usb_port_resume(udev);
}
#endif /* CONFIG_PM */
struct usb_device_driver usb_generic_driver = {
.name = "usb",
.probe = generic_probe,
.disconnect = generic_disconnect,
#ifdef CONFIG_PM
.suspend = generic_suspend,
.resume = generic_resume,
#endif
.supports_autosuspend = 1,
};

View File

@ -413,4 +413,20 @@ EXPORT_SYMBOL (usb_hcd_pci_resume);
#endif /* CONFIG_PM */
/**
* usb_hcd_pci_shutdown - shutdown host controller
* @dev: USB Host Controller being shutdown
*/
void usb_hcd_pci_shutdown (struct pci_dev *dev)
{
struct usb_hcd *hcd;
hcd = pci_get_drvdata(dev);
if (!hcd)
return;
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
}
EXPORT_SYMBOL (usb_hcd_pci_shutdown);

View File

@ -36,6 +36,7 @@
#include <linux/mutex.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
@ -632,31 +633,20 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
/*-------------------------------------------------------------------------*/
/* Asynchronous unlinks of root-hub control URBs are legal, but they
* don't do anything. Status URB unlinks must be made in process context
* with interrupts enabled.
/* Unlinks of root-hub control URBs are legal, but they don't do anything
* since these URBs always execute synchronously.
*/
static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
unsigned long flags;
if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
if (in_interrupt())
return 0; /* nothing to do */
spin_lock_irq(&urb->lock); /* from usb_kill_urb */
++urb->reject;
spin_unlock_irq(&urb->lock);
wait_event(usb_kill_urb_queue,
atomic_read(&urb->use_count) == 0);
spin_lock_irq(&urb->lock);
--urb->reject;
spin_unlock_irq(&urb->lock);
; /* Do nothing */
} else { /* Status URB */
if (!hcd->uses_new_polling)
del_timer_sync (&hcd->rh_timer);
local_irq_disable ();
del_timer (&hcd->rh_timer);
local_irq_save (flags);
spin_lock (&hcd_root_hub_lock);
if (urb == hcd->status_urb) {
hcd->status_urb = NULL;
@ -666,7 +656,7 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
spin_unlock (&hcd_root_hub_lock);
if (urb)
usb_hcd_giveback_urb (hcd, urb, NULL);
local_irq_enable ();
local_irq_restore (flags);
}
return 0;
@ -674,31 +664,6 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
/*-------------------------------------------------------------------------*/
/* exported only within usbcore */
struct usb_bus *usb_bus_get(struct usb_bus *bus)
{
if (bus)
kref_get(&bus->kref);
return bus;
}
static void usb_host_release(struct kref *kref)
{
struct usb_bus *bus = container_of(kref, struct usb_bus, kref);
if (bus->release)
bus->release(bus);
}
/* exported only within usbcore */
void usb_bus_put(struct usb_bus *bus)
{
if (bus)
kref_put(&bus->kref, usb_host_release);
}
/*-------------------------------------------------------------------------*/
static struct class *usb_host_class;
int usb_host_init(void)
@ -730,39 +695,12 @@ static void usb_bus_init (struct usb_bus *bus)
bus->devnum_next = 1;
bus->root_hub = NULL;
bus->hcpriv = NULL;
bus->busnum = -1;
bus->bandwidth_allocated = 0;
bus->bandwidth_int_reqs = 0;
bus->bandwidth_isoc_reqs = 0;
INIT_LIST_HEAD (&bus->bus_list);
kref_init(&bus->kref);
}
/**
* usb_alloc_bus - creates a new USB host controller structure
* @op: pointer to a struct usb_operations that this bus structure should use
* Context: !in_interrupt()
*
* Creates a USB host controller bus structure with the specified
* usb_operations and initializes all the necessary internal objects.
*
* If no memory is available, NULL is returned.
*
* The caller should call usb_put_bus() when it is finished with the structure.
*/
struct usb_bus *usb_alloc_bus (struct usb_operations *op)
{
struct usb_bus *bus;
bus = kzalloc (sizeof *bus, GFP_KERNEL);
if (!bus)
return NULL;
usb_bus_init (bus);
bus->op = op;
return bus;
}
/*-------------------------------------------------------------------------*/
@ -1112,10 +1050,10 @@ static void urb_unlink (struct urb *urb)
* expects usb_submit_urb() to have sanity checked and conditioned all
* inputs in the urb
*/
static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
{
int status;
struct usb_hcd *hcd = urb->dev->bus->hcpriv;
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
struct usb_host_endpoint *ep;
unsigned long flags;
@ -1186,7 +1124,7 @@ static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
/* lower level hcd code should use *_dma exclusively,
* unless it uses pio or talks to another transport.
*/
if (hcd->self.controller->dma_mask) {
if (hcd->self.uses_dma) {
if (usb_pipecontrol (urb->pipe)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
urb->setup_dma = dma_map_single (
@ -1221,9 +1159,10 @@ static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
/*-------------------------------------------------------------------------*/
/* called in any context */
static int hcd_get_frame_number (struct usb_device *udev)
int usb_hcd_get_frame_number (struct usb_device *udev)
{
struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv;
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
if (!HC_IS_RUNNING (hcd->state))
return -ESHUTDOWN;
return hcd->driver->get_frame_number (hcd);
@ -1263,7 +1202,7 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
* caller guarantees urb won't be recycled till both unlink()
* and the urb's completion function return
*/
static int hcd_unlink_urb (struct urb *urb, int status)
int usb_hcd_unlink_urb (struct urb *urb, int status)
{
struct usb_host_endpoint *ep;
struct usb_hcd *hcd = NULL;
@ -1296,7 +1235,7 @@ static int hcd_unlink_urb (struct urb *urb, int status)
spin_lock (&hcd_data_lock);
sys = &urb->dev->dev;
hcd = urb->dev->bus->hcpriv;
hcd = bus_to_hcd(urb->dev->bus);
if (hcd == NULL) {
retval = -ENODEV;
goto done;
@ -1354,41 +1293,33 @@ static int hcd_unlink_urb (struct urb *urb, int status)
/*-------------------------------------------------------------------------*/
/* disables the endpoint: cancels any pending urbs, then synchronizes with
* the hcd to make sure all endpoint state is gone from hardware. use for
* the hcd to make sure all endpoint state is gone from hardware, and then
* waits until the endpoint's queue is completely drained. use for
* set_configuration, set_interface, driver removal, physical disconnect.
*
* example: a qh stored in ep->hcpriv, holding state related to endpoint
* type, maxpacket size, toggle, halt status, and scheduling.
*/
static void
hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep)
void usb_hcd_endpoint_disable (struct usb_device *udev,
struct usb_host_endpoint *ep)
{
struct usb_hcd *hcd;
struct urb *urb;
hcd = udev->bus->hcpriv;
hcd = bus_to_hcd(udev->bus);
WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT &&
udev->state != USB_STATE_NOTATTACHED);
local_irq_disable ();
/* FIXME move most of this into message.c as part of its
* endpoint disable logic
*/
/* ep is already gone from udev->ep_{in,out}[]; no more submits */
rescan:
spin_lock (&hcd_data_lock);
list_for_each_entry (urb, &ep->urb_list, urb_list) {
int tmp;
/* another cpu may be in hcd, spinning on hcd_data_lock
* to giveback() this urb. the races here should be
* small, but a full fix needs a new "can't submit"
* urb state.
* FIXME urb->reject should allow that...
*/
/* the urb may already have been unlinked */
if (urb->status != -EINPROGRESS)
continue;
usb_get_urb (urb);
@ -1430,6 +1361,30 @@ hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep)
might_sleep ();
if (hcd->driver->endpoint_disable)
hcd->driver->endpoint_disable (hcd, ep);
/* Wait until the endpoint queue is completely empty. Most HCDs
* will have done this already in their endpoint_disable method,
* but some might not. And there could be root-hub control URBs
* still pending since they aren't affected by the HCDs'
* endpoint_disable methods.
*/
while (!list_empty (&ep->urb_list)) {
spin_lock_irq (&hcd_data_lock);
/* The list may have changed while we acquired the spinlock */
urb = NULL;
if (!list_empty (&ep->urb_list)) {
urb = list_entry (ep->urb_list.prev, struct urb,
urb_list);
usb_get_urb (urb);
}
spin_unlock_irq (&hcd_data_lock);
if (urb) {
usb_kill_urb (urb);
usb_put_urb (urb);
}
}
}
/*-------------------------------------------------------------------------*/
@ -1476,50 +1431,6 @@ int hcd_bus_resume (struct usb_bus *bus)
return status;
}
/*
* usb_hcd_suspend_root_hub - HCD autosuspends downstream ports
* @hcd: host controller for this root hub
*
* This call arranges that usb_hcd_resume_root_hub() is safe to call later;
* that the HCD's root hub polling is deactivated; and that the root's hub
* driver is suspended. HCDs may call this to autosuspend when their root
* hub's downstream ports are all inactive: unpowered, disconnected,
* disabled, or suspended.
*
* The HCD will autoresume on device connect change detection (using SRP
* or a D+/D- pullup). The HCD also autoresumes on remote wakeup signaling
* from any ports that are suspended (if that is enabled). In most cases,
* overcurrent signaling (on powered ports) will also start autoresume.
*
* Always called with IRQs blocked.
*/
void usb_hcd_suspend_root_hub (struct usb_hcd *hcd)
{
struct urb *urb;
spin_lock (&hcd_root_hub_lock);
usb_suspend_root_hub (hcd->self.root_hub);
/* force status urb to complete/unlink while suspended */
if (hcd->status_urb) {
urb = hcd->status_urb;
urb->status = -ECONNRESET;
urb->hcpriv = NULL;
urb->actual_length = 0;
del_timer (&hcd->rh_timer);
hcd->poll_pending = 0;
hcd->status_urb = NULL;
} else
urb = NULL;
spin_unlock (&hcd_root_hub_lock);
hcd->state = HC_STATE_SUSPENDED;
if (urb)
usb_hcd_giveback_urb (hcd, urb, NULL);
}
EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub);
/**
* usb_hcd_resume_root_hub - called by HCD to resume its root hub
* @hcd: host controller for this root hub
@ -1583,20 +1494,6 @@ EXPORT_SYMBOL (usb_bus_start_enum);
/*-------------------------------------------------------------------------*/
/*
* usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue)
*/
static struct usb_operations usb_hcd_operations = {
.get_frame_number = hcd_get_frame_number,
.submit_urb = hcd_submit_urb,
.unlink_urb = hcd_unlink_urb,
.buffer_alloc = hcd_buffer_alloc,
.buffer_free = hcd_buffer_free,
.disable = hcd_endpoint_disable,
};
/*-------------------------------------------------------------------------*/
/**
* usb_hcd_giveback_urb - return URB from HCD to device driver
* @hcd: host controller returning the URB
@ -1617,8 +1514,9 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs
at_root_hub = (urb->dev == hcd->self.root_hub);
urb_unlink (urb);
/* lower level hcd code should use *_dma exclusively */
if (hcd->self.controller->dma_mask && !at_root_hub) {
/* lower level hcd code should use *_dma exclusively if the
* host controller does DMA */
if (hcd->self.uses_dma && !at_root_hub) {
if (usb_pipecontrol (urb->pipe)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
dma_unmap_single (hcd->self.controller, urb->setup_dma,
@ -1704,14 +1602,6 @@ EXPORT_SYMBOL_GPL (usb_hc_died);
/*-------------------------------------------------------------------------*/
static void hcd_release (struct usb_bus *bus)
{
struct usb_hcd *hcd;
hcd = container_of(bus, struct usb_hcd, self);
kfree(hcd);
}
/**
* usb_create_hcd - create and initialize an HCD structure
* @driver: HC driver that will use this hcd
@ -1736,13 +1626,12 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
return NULL;
}
dev_set_drvdata(dev, hcd);
kref_init(&hcd->kref);
usb_bus_init(&hcd->self);
hcd->self.op = &usb_hcd_operations;
hcd->self.hcpriv = hcd;
hcd->self.release = &hcd_release;
hcd->self.controller = dev;
hcd->self.bus_name = bus_name;
hcd->self.uses_dma = (dev->dma_mask != NULL);
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
@ -1756,10 +1645,25 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
}
EXPORT_SYMBOL (usb_create_hcd);
static void hcd_release (struct kref *kref)
{
struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
kfree(hcd);
}
struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd)
{
if (hcd)
kref_get (&hcd->kref);
return hcd;
}
EXPORT_SYMBOL (usb_get_hcd);
void usb_put_hcd (struct usb_hcd *hcd)
{
dev_set_drvdata(hcd->self.controller, NULL);
usb_bus_put(&hcd->self);
if (hcd)
kref_put (&hcd->kref, hcd_release);
}
EXPORT_SYMBOL (usb_put_hcd);
@ -1915,6 +1819,16 @@ void usb_remove_hcd(struct usb_hcd *hcd)
}
EXPORT_SYMBOL (usb_remove_hcd);
void
usb_hcd_platform_shutdown(struct platform_device* dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
}
EXPORT_SYMBOL (usb_hcd_platform_shutdown);
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_USB_MON)

View File

@ -55,12 +55,13 @@
/*-------------------------------------------------------------------------*/
struct usb_hcd { /* usb_bus.hcpriv points to this */
struct usb_hcd {
/*
* housekeeping
*/
struct usb_bus self; /* hcd is-a bus */
struct kref kref; /* reference counter */
const char *product_desc; /* product/vendor string */
char irq_descr[24]; /* driver + bus # */
@ -85,6 +86,7 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
unsigned uses_new_polling:1;
unsigned poll_rh:1; /* poll for rh status? */
unsigned poll_pending:1; /* status has changed? */
unsigned wireless:1; /* Wireless USB HCD */
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
@ -128,8 +130,10 @@ static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
return &hcd->self;
}
// urb.hcpriv is really hardware-specific
static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus)
{
return container_of(bus, struct usb_hcd, self);
}
struct hcd_timeout { /* timeouts we allocate */
struct list_head timeout_list;
@ -138,28 +142,6 @@ struct hcd_timeout { /* timeouts we allocate */
/*-------------------------------------------------------------------------*/
/*
* FIXME usb_operations should vanish or become hc_driver,
* when usb_bus and usb_hcd become the same thing.
*/
struct usb_operations {
int (*get_frame_number) (struct usb_device *usb_dev);
int (*submit_urb) (struct urb *urb, gfp_t mem_flags);
int (*unlink_urb) (struct urb *urb, int status);
/* allocate dma-consistent buffer for URB_DMA_NOMAPPING */
void *(*buffer_alloc)(struct usb_bus *bus, size_t size,
gfp_t mem_flags,
dma_addr_t *dma);
void (*buffer_free)(struct usb_bus *bus, size_t size,
void *addr, dma_addr_t dma);
void (*disable)(struct usb_device *udev,
struct usb_host_endpoint *ep);
};
/* each driver provides one of these, and hardware init support */
struct pt_regs;
@ -192,6 +174,9 @@ struct hc_driver {
/* cleanly make HCD stop writing memory and doing I/O */
void (*stop) (struct usb_hcd *hcd);
/* shutdown HCD */
void (*shutdown) (struct usb_hcd *hcd);
/* return current frame number */
int (*get_frame_number) (struct usb_hcd *hcd);
@ -218,15 +203,25 @@ struct hc_driver {
/* Needed only if port-change IRQs are level-triggered */
};
extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
extern int usb_hcd_unlink_urb (struct urb *urb, int status);
extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb,
struct pt_regs *regs);
extern void usb_hcd_endpoint_disable (struct usb_device *udev,
struct usb_host_endpoint *ep);
extern int usb_hcd_get_frame_number (struct usb_device *udev);
extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
struct device *dev, char *bus_name);
extern struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd);
extern void usb_put_hcd (struct usb_hcd *hcd);
extern int usb_add_hcd(struct usb_hcd *hcd,
unsigned int irqnum, unsigned long irqflags);
extern void usb_remove_hcd(struct usb_hcd *hcd);
struct platform_device;
extern void usb_hcd_platform_shutdown(struct platform_device* dev);
#ifdef CONFIG_PCI
struct pci_dev;
struct pci_device_id;
@ -239,6 +234,8 @@ extern int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t state);
extern int usb_hcd_pci_resume (struct pci_dev *dev);
#endif /* CONFIG_PM */
extern void usb_hcd_pci_shutdown (struct pci_dev *dev);
#endif /* CONFIG_PCI */
/* pci-ish (pdev null is ok) buffer alloc/mapping support */
@ -352,8 +349,6 @@ extern long usb_calc_bus_time (int speed, int is_input,
/*-------------------------------------------------------------------------*/
extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
extern void usb_set_device_state(struct usb_device *udev,
enum usb_device_state new_state);
@ -365,9 +360,6 @@ extern struct list_head usb_bus_list;
extern struct mutex usb_bus_list_lock;
extern wait_queue_head_t usb_kill_urb_queue;
extern struct usb_bus *usb_bus_get (struct usb_bus *bus);
extern void usb_bus_put (struct usb_bus *bus);
extern void usb_enable_root_hub_irq (struct usb_bus *bus);
extern int usb_find_interface_driver (struct usb_device *dev,
@ -376,17 +368,11 @@ extern int usb_find_interface_driver (struct usb_device *dev,
#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
#ifdef CONFIG_PM
extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd);
extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
extern void usb_root_hub_lost_power (struct usb_device *rhdev);
extern int hcd_bus_suspend (struct usb_bus *bus);
extern int hcd_bus_resume (struct usb_bus *bus);
#else
static inline void usb_hcd_suspend_root_hub(struct usb_hcd *hcd)
{
return;
}
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
{
return;

View File

@ -293,7 +293,7 @@ void usb_kick_khubd(struct usb_device *hdev)
/* completion function, fires on port status changes and various faults */
static void hub_irq(struct urb *urb, struct pt_regs *regs)
{
struct usb_hub *hub = (struct usb_hub *)urb->context;
struct usb_hub *hub = urb->context;
int status;
int i;
unsigned long bits;
@ -311,7 +311,7 @@ static void hub_irq(struct urb *urb, struct pt_regs *regs)
goto resubmit;
hub->error = urb->status;
/* FALL THROUGH */
/* let khubd handle things */
case 0: /* we got data: port status changed */
bits = 0;
@ -452,18 +452,14 @@ static void hub_power_on(struct usb_hub *hub)
msleep(max(pgood_delay, (unsigned) 100));
}
static inline void __hub_quiesce(struct usb_hub *hub)
static void hub_quiesce(struct usb_hub *hub)
{
/* (nonblocking) khubd and related activity won't re-trigger */
hub->quiescing = 1;
hub->activating = 0;
hub->resume_root_hub = 0;
}
static void hub_quiesce(struct usb_hub *hub)
{
/* (blocking) stop khubd and related activity */
__hub_quiesce(hub);
usb_kill_urb(hub->urb);
if (hub->has_indicators)
cancel_delayed_work(&hub->leds);
@ -868,13 +864,8 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
endpoint = &desc->endpoint[0].desc;
/* Output endpoint? Curiouser and curiouser.. */
if (!(endpoint->bEndpointAddress & USB_DIR_IN))
goto descriptor_error;
/* If it's not an interrupt endpoint, we'd better punt! */
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_INT)
/* If it's not an interrupt in endpoint, we'd better punt! */
if (!usb_endpoint_is_int_in(endpoint))
goto descriptor_error;
/* We found a hub */
@ -1022,26 +1013,29 @@ void usb_set_device_state(struct usb_device *udev,
if (udev->state == USB_STATE_NOTATTACHED)
; /* do nothing */
else if (new_state != USB_STATE_NOTATTACHED) {
udev->state = new_state;
/* root hub wakeup capabilities are managed out-of-band
* and may involve silicon errata ... ignore them here.
*/
if (udev->parent) {
if (new_state == USB_STATE_CONFIGURED)
if (udev->state == USB_STATE_SUSPENDED
|| new_state == USB_STATE_SUSPENDED)
; /* No change to wakeup settings */
else if (new_state == USB_STATE_CONFIGURED)
device_init_wakeup(&udev->dev,
(udev->actconfig->desc.bmAttributes
& USB_CONFIG_ATT_WAKEUP));
else if (new_state != USB_STATE_SUSPENDED)
else
device_init_wakeup(&udev->dev, 0);
}
udev->state = new_state;
} else
recursively_mark_NOTATTACHED(udev);
spin_unlock_irqrestore(&device_state_lock, flags);
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM
/**
* usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
@ -1059,6 +1053,12 @@ void usb_root_hub_lost_power(struct usb_device *rhdev)
unsigned long flags;
dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
/* Make sure no potential wakeup events get lost,
* by forcing the root hub to be resumed.
*/
rhdev->dev.power.prev_state.event = PM_EVENT_ON;
spin_lock_irqsave(&device_state_lock, flags);
hub = hdev_to_hub(rhdev);
for (port1 = 1; port1 <= rhdev->maxchild; ++port1) {
@ -1072,7 +1072,7 @@ void usb_root_hub_lost_power(struct usb_device *rhdev)
}
EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
#endif
#endif /* CONFIG_PM */
static void choose_address(struct usb_device *udev)
{
@ -1148,144 +1148,28 @@ void usb_disconnect(struct usb_device **pdev)
* cleaning up all state associated with the current configuration
* so that the hardware is now fully quiesced.
*/
dev_dbg (&udev->dev, "unregistering device\n");
usb_disable_device(udev, 0);
usb_notify_remove_device(udev);
usb_unlock_device(udev);
/* Free the device number, remove the /proc/bus/usb entry and
* the sysfs attributes, and delete the parent's children[]
/* Unregister the device. The device driver is responsible
* for removing the device files from usbfs and sysfs and for
* de-configuring the device.
*/
device_del(&udev->dev);
/* Free the device number and delete the parent's children[]
* (or root_hub) pointer.
*/
dev_dbg (&udev->dev, "unregistering device\n");
release_address(udev);
usb_remove_sysfs_dev_files(udev);
/* Avoid races with recursively_mark_NOTATTACHED() */
spin_lock_irq(&device_state_lock);
*pdev = NULL;
spin_unlock_irq(&device_state_lock);
usb_unlock_device(udev);
device_unregister(&udev->dev);
}
static inline const char *plural(int n)
{
return (n == 1 ? "" : "s");
}
static int choose_configuration(struct usb_device *udev)
{
int i;
int num_configs;
int insufficient_power = 0;
struct usb_host_config *c, *best;
best = NULL;
c = udev->config;
num_configs = udev->descriptor.bNumConfigurations;
for (i = 0; i < num_configs; (i++, c++)) {
struct usb_interface_descriptor *desc = NULL;
/* It's possible that a config has no interfaces! */
if (c->desc.bNumInterfaces > 0)
desc = &c->intf_cache[0]->altsetting->desc;
/*
* HP's USB bus-powered keyboard has only one configuration
* and it claims to be self-powered; other devices may have
* similar errors in their descriptors. If the next test
* were allowed to execute, such configurations would always
* be rejected and the devices would not work as expected.
* In the meantime, we run the risk of selecting a config
* that requires external power at a time when that power
* isn't available. It seems to be the lesser of two evils.
*
* Bugzilla #6448 reports a device that appears to crash
* when it receives a GET_DEVICE_STATUS request! We don't
* have any other way to tell whether a device is self-powered,
* but since we don't use that information anywhere but here,
* the call has been removed.
*
* Maybe the GET_DEVICE_STATUS call and the test below can
* be reinstated when device firmwares become more reliable.
* Don't hold your breath.
*/
#if 0
/* Rule out self-powered configs for a bus-powered device */
if (bus_powered && (c->desc.bmAttributes &
USB_CONFIG_ATT_SELFPOWER))
continue;
#endif
/*
* The next test may not be as effective as it should be.
* Some hubs have errors in their descriptor, claiming
* to be self-powered when they are really bus-powered.
* We will overestimate the amount of current such hubs
* make available for each port.
*
* This is a fairly benign sort of failure. It won't
* cause us to reject configurations that we should have
* accepted.
*/
/* Rule out configs that draw too much bus current */
if (c->desc.bMaxPower * 2 > udev->bus_mA) {
insufficient_power++;
continue;
}
/* If the first config's first interface is COMM/2/0xff
* (MSFT RNDIS), rule it out unless Linux has host-side
* RNDIS support. */
if (i == 0 && desc
&& desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
&& desc->bInterfaceProtocol == 0xff) {
#ifndef CONFIG_USB_NET_RNDIS_HOST
continue;
#else
best = c;
#endif
}
/* From the remaining configs, choose the first one whose
* first interface is for a non-vendor-specific class.
* Reason: Linux is more likely to have a class driver
* than a vendor-specific driver. */
else if (udev->descriptor.bDeviceClass !=
USB_CLASS_VENDOR_SPEC &&
(!desc || desc->bInterfaceClass !=
USB_CLASS_VENDOR_SPEC)) {
best = c;
break;
}
/* If all the remaining configs are vendor-specific,
* choose the first one. */
else if (!best)
best = c;
}
if (insufficient_power > 0)
dev_info(&udev->dev, "rejected %d configuration%s "
"due to insufficient available bus power\n",
insufficient_power, plural(insufficient_power));
if (best) {
i = best->desc.bConfigurationValue;
dev_info(&udev->dev,
"configuration #%d chosen from %d choice%s\n",
i, num_configs, plural(num_configs));
} else {
i = -1;
dev_warn(&udev->dev,
"no configuration chosen from %d choice%s\n",
num_configs, plural(num_configs));
}
return i;
put_device(&udev->dev);
}
#ifdef DEBUG
@ -1328,7 +1212,6 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
int usb_new_device(struct usb_device *udev)
{
int err;
int c;
err = usb_get_configuration(udev);
if (err < 0) {
@ -1371,8 +1254,7 @@ int usb_new_device(struct usb_device *udev)
USB_DT_OTG, (void **) &desc) == 0) {
if (desc->bmAttributes & USB_OTG_HNP) {
unsigned port1 = udev->portnum;
struct usb_device *root = udev->parent;
dev_info(&udev->dev,
"Dual-Role OTG device on %sHNP port\n",
(port1 == bus->otg_port)
@ -1407,9 +1289,9 @@ int usb_new_device(struct usb_device *udev)
* (Includes HNP test device.)
*/
if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
static int __usb_suspend_device(struct usb_device *,
static int __usb_port_suspend(struct usb_device *,
int port1);
err = __usb_suspend_device(udev, udev->bus->otg_port);
err = __usb_port_suspend(udev, udev->bus->otg_port);
if (err < 0)
dev_dbg(&udev->dev, "HNP fail, %d\n", err);
}
@ -1418,34 +1300,15 @@ int usb_new_device(struct usb_device *udev)
}
#endif
/* put device-specific files into sysfs */
/* Register the device. The device driver is responsible
* for adding the device files to usbfs and sysfs and for
* configuring the device.
*/
err = device_add (&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
goto fail;
}
usb_create_sysfs_dev_files (udev);
usb_lock_device(udev);
/* choose and set the configuration. that registers the interfaces
* with the driver core, and lets usb device drivers bind to them.
*/
c = choose_configuration(udev);
if (c >= 0) {
err = usb_set_configuration(udev, c);
if (err) {
dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
/* This need not be fatal. The user can try to
* set other configurations. */
}
}
/* USB device state == configured ... usable */
usb_notify_add_device(udev);
usb_unlock_device(udev);
return 0;
@ -1472,6 +1335,18 @@ static int hub_port_status(struct usb_hub *hub, int port1,
return ret;
}
/* Returns 1 if @hub is a WUSB root hub, 0 otherwise */
static unsigned hub_is_wusb(struct usb_hub *hub)
{
struct usb_hcd *hcd;
if (hub->hdev->parent != NULL) /* not a root hub? */
return 0;
hcd = container_of(hub->hdev->bus, struct usb_hcd, self);
return hcd->wireless;
}
#define PORT_RESET_TRIES 5
#define SET_ADDRESS_TRIES 2
#define GET_DESCRIPTOR_TRIES 2
@ -1512,7 +1387,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
/* if we`ve finished resetting, then break out of the loop */
if (!(portstatus & USB_PORT_STAT_RESET) &&
(portstatus & USB_PORT_STAT_ENABLE)) {
if (portstatus & USB_PORT_STAT_HIGH_SPEED)
if (hub_is_wusb(hub))
udev->speed = USB_SPEED_VARIABLE;
else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
udev->speed = USB_SPEED_HIGH;
else if (portstatus & USB_PORT_STAT_LOW_SPEED)
udev->speed = USB_SPEED_LOW;
@ -1607,6 +1484,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
kick_khubd(hub);
}
#ifdef CONFIG_PM
#ifdef CONFIG_USB_SUSPEND
@ -1633,7 +1511,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
* NOTE: OTG devices may issue remote wakeup (or SRP) even when
* we don't explicitly enable it here.
*/
if (device_may_wakeup(&udev->dev)) {
if (udev->do_remote_wakeup) {
status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
USB_DEVICE_REMOTE_WAKEUP, 0,
@ -1659,7 +1537,8 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
USB_CTRL_SET_TIMEOUT);
} else {
/* device has up to 10 msec to fully suspend */
dev_dbg(&udev->dev, "usb suspend\n");
dev_dbg(&udev->dev, "usb %ssuspend\n",
udev->auto_pm ? "auto-" : "");
usb_set_device_state(udev, USB_STATE_SUSPENDED);
msleep(10);
}
@ -1684,7 +1563,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
* the root hub for their bus goes into global suspend ... so we don't
* (falsely) update the device power state to say it suspended.
*/
static int __usb_suspend_device (struct usb_device *udev, int port1)
static int __usb_port_suspend (struct usb_device *udev, int port1)
{
int status = 0;
@ -1692,49 +1571,29 @@ static int __usb_suspend_device (struct usb_device *udev, int port1)
if (port1 < 0)
return port1;
if (udev->state == USB_STATE_SUSPENDED
|| udev->state == USB_STATE_NOTATTACHED) {
return 0;
}
/* all interfaces must already be suspended */
if (udev->actconfig) {
int i;
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *intf;
intf = udev->actconfig->interface[i];
if (is_active(intf)) {
dev_dbg(&intf->dev, "nyet suspended\n");
return -EBUSY;
}
}
}
/* we only change a device's upstream USB link.
* root hubs have no upstream USB link.
/* we change the device's upstream USB link,
* but root hubs have no upstream USB link.
*/
if (udev->parent)
status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
udev);
if (status == 0)
udev->dev.power.power_state = PMSG_SUSPEND;
else {
dev_dbg(&udev->dev, "usb %ssuspend\n",
udev->auto_pm ? "auto-" : "");
usb_set_device_state(udev, USB_STATE_SUSPENDED);
}
return status;
}
#endif
/*
* usb_suspend_device - suspend a usb device
* usb_port_suspend - suspend a usb device's upstream port
* @udev: device that's no longer in active use
* Context: must be able to sleep; device not locked; pm locks held
*
* Suspends a USB device that isn't in active use, conserving power.
* Devices may wake out of a suspend, if anything important happens,
* using the remote wakeup mechanism. They may also be taken out of
* suspend by the host, using usb_resume_device(). It's also routine
* suspend by the host, using usb_port_resume(). It's also routine
* to disconnect devices while they are suspended.
*
* This only affects the USB hardware for a device; its interfaces
@ -1746,17 +1605,9 @@ static int __usb_suspend_device (struct usb_device *udev, int port1)
*
* Returns 0 on success, else negative errno.
*/
int usb_suspend_device(struct usb_device *udev)
int usb_port_suspend(struct usb_device *udev)
{
#ifdef CONFIG_USB_SUSPEND
if (udev->state == USB_STATE_NOTATTACHED)
return -ENODEV;
return __usb_suspend_device(udev, udev->portnum);
#else
/* NOTE: udev->state unchanged, it's not lying ... */
udev->dev.power.power_state = PMSG_SUSPEND;
return 0;
#endif
return __usb_port_suspend(udev, udev->portnum);
}
/*
@ -1767,7 +1618,7 @@ int usb_suspend_device(struct usb_device *udev)
* resume (by host) or remote wakeup (by device) ... now see what changed
* in the tree that's rooted at this device.
*/
static int finish_device_resume(struct usb_device *udev)
static int finish_port_resume(struct usb_device *udev)
{
int status;
u16 devstatus;
@ -1783,7 +1634,6 @@ static int finish_device_resume(struct usb_device *udev)
usb_set_device_state(udev, udev->actconfig
? USB_STATE_CONFIGURED
: USB_STATE_ADDRESS);
udev->dev.power.power_state = PMSG_ON;
/* 10.5.4.5 says be sure devices in the tree are still there.
* For now let's assume the device didn't go crazy on resume,
@ -1798,9 +1648,6 @@ static int finish_device_resume(struct usb_device *udev)
"gone after usb resume? status %d\n",
status);
else if (udev->actconfig) {
unsigned i;
int (*resume)(struct device *);
le16_to_cpus(&devstatus);
if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
&& udev->parent) {
@ -1811,24 +1658,9 @@ static int finish_device_resume(struct usb_device *udev)
USB_DEVICE_REMOTE_WAKEUP, 0,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
if (status) {
if (status)
dev_dbg(&udev->dev, "disable remote "
"wakeup, status %d\n", status);
status = 0;
}
}
/* resume interface drivers; if this is a hub, it
* may have a child resume event to deal with soon
*/
resume = udev->dev.bus->resume;
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
struct device *dev =
&udev->actconfig->interface[i]->dev;
down(&dev->sem);
(void) resume(dev);
up(&dev->sem);
}
status = 0;
@ -1839,8 +1671,6 @@ static int finish_device_resume(struct usb_device *udev)
return status;
}
#ifdef CONFIG_USB_SUSPEND
static int
hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
{
@ -1848,6 +1678,8 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
// dev_dbg(hub->intfdev, "resume port %d\n", port1);
set_bit(port1, hub->busy_bits);
/* see 7.1.7.7; affects power usage, but not budgeting */
status = clear_port_feature(hub->hdev,
port1, USB_PORT_FEAT_SUSPEND);
@ -1861,7 +1693,8 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
/* drive resume for at least 20 msec */
if (udev)
dev_dbg(&udev->dev, "RESUME\n");
dev_dbg(&udev->dev, "usb %sresume\n",
udev->auto_pm ? "auto-" : "");
msleep(25);
#define LIVE_FLAGS ( USB_PORT_STAT_POWER \
@ -1891,19 +1724,21 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
/* TRSMRCY = 10 msec */
msleep(10);
if (udev)
status = finish_device_resume(udev);
status = finish_port_resume(udev);
}
}
if (status < 0)
hub_port_logical_disconnect(hub, port1);
clear_bit(port1, hub->busy_bits);
if (!hub->hdev->parent && !hub->busy_bits[0])
usb_enable_root_hub_irq(hub->hdev->bus);
return status;
}
#endif
/*
* usb_resume_device - re-activate a suspended usb device
* usb_port_resume - re-activate a suspended usb device's upstream port
* @udev: device to re-activate
* Context: must be able to sleep; device not locked; pm locks held
*
@ -1915,36 +1750,24 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
*
* Returns 0 on success, else negative errno.
*/
int usb_resume_device(struct usb_device *udev)
int usb_port_resume(struct usb_device *udev)
{
int status;
if (udev->state == USB_STATE_NOTATTACHED)
return -ENODEV;
/* selective resume of one downstream hub-to-device port */
/* we change the device's upstream USB link,
* but root hubs have no upstream USB link.
*/
if (udev->parent) {
#ifdef CONFIG_USB_SUSPEND
if (udev->state == USB_STATE_SUSPENDED) {
// NOTE swsusp may bork us, device state being wrong...
// NOTE this fails if parent is also suspended...
status = hub_port_resume(hdev_to_hub(udev->parent),
udev->portnum, udev);
} else
#endif
status = 0;
} else
status = finish_device_resume(udev);
if (status < 0)
dev_dbg(&udev->dev, "can't resume, status %d\n",
status);
/* rebind drivers that had no suspend() */
if (status == 0) {
usb_unlock_device(udev);
bus_rescan_devices(&usb_bus_type);
usb_lock_device(udev);
// NOTE this fails if parent is also suspended...
status = hub_port_resume(hdev_to_hub(udev->parent),
udev->portnum, udev);
} else {
dev_dbg(&udev->dev, "usb %sresume\n",
udev->auto_pm ? "auto-" : "");
status = finish_port_resume(udev);
}
if (status < 0)
dev_dbg(&udev->dev, "can't resume, status %d\n", status);
return status;
}
@ -1952,23 +1775,60 @@ static int remote_wakeup(struct usb_device *udev)
{
int status = 0;
#ifdef CONFIG_USB_SUSPEND
/* All this just to avoid sending a port-resume message
* to the parent hub! */
/* don't repeat RESUME sequence if this device
* was already woken up by some other task
*/
usb_lock_device(udev);
mutex_lock_nested(&udev->pm_mutex, udev->level);
if (udev->state == USB_STATE_SUSPENDED) {
dev_dbg(&udev->dev, "RESUME (wakeup)\n");
dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
/* TRSMRCY = 10 msec */
msleep(10);
status = finish_device_resume(udev);
status = finish_port_resume(udev);
if (status == 0)
udev->dev.power.power_state.event = PM_EVENT_ON;
}
mutex_unlock(&udev->pm_mutex);
if (status == 0)
usb_autoresume_device(udev, 0);
usb_unlock_device(udev);
#endif
return status;
}
#else /* CONFIG_USB_SUSPEND */
/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */
int usb_port_suspend(struct usb_device *udev)
{
return 0;
}
static inline int
finish_port_resume(struct usb_device *udev)
{
return 0;
}
static inline int
hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
{
return 0;
}
int usb_port_resume(struct usb_device *udev)
{
return 0;
}
static inline int remote_wakeup(struct usb_device *udev)
{
return 0;
}
#endif
static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
{
struct usb_hub *hub = usb_get_intfdata (intf);
@ -1980,13 +1840,17 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_device *udev;
udev = hdev->children [port1-1];
if (udev && (udev->dev.power.power_state.event
== PM_EVENT_ON
if (udev && msg.event == PM_EVENT_SUSPEND &&
#ifdef CONFIG_USB_SUSPEND
|| udev->state != USB_STATE_SUSPENDED
udev->state != USB_STATE_SUSPENDED
#else
udev->dev.power.power_state.event
== PM_EVENT_ON
#endif
)) {
dev_dbg(&intf->dev, "port %d nyet suspended\n", port1);
) {
if (!hdev->auto_pm)
dev_dbg(&intf->dev, "port %d nyet suspended\n",
port1);
return -EBUSY;
}
}
@ -2035,66 +1899,22 @@ static int hub_resume(struct usb_interface *intf)
}
}
/* tell khubd to look for changes on this hub */
hub_activate(hub);
/* REVISIT: this recursion probably shouldn't exist. Remove
* this code sometime, after retesting with different root and
* external hubs.
*/
#ifdef CONFIG_USB_SUSPEND
{
unsigned port1;
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
struct usb_device *udev;
u16 portstat, portchange;
udev = hdev->children [port1-1];
status = hub_port_status(hub, port1, &portstat, &portchange);
if (status == 0) {
if (portchange & USB_PORT_STAT_C_SUSPEND) {
clear_port_feature(hdev, port1,
USB_PORT_FEAT_C_SUSPEND);
portchange &= ~USB_PORT_STAT_C_SUSPEND;
}
/* let khubd handle disconnects etc */
if (portchange)
continue;
}
if (!udev || status < 0)
continue;
usb_lock_device(udev);
if (portstat & USB_PORT_STAT_SUSPEND)
status = hub_port_resume(hub, port1, udev);
else {
status = finish_device_resume(udev);
if (status < 0) {
dev_dbg(&intf->dev, "resume port %d --> %d\n",
port1, status);
hub_port_logical_disconnect(hub, port1);
}
}
usb_unlock_device(udev);
}
}
#endif
return 0;
}
void usb_suspend_root_hub(struct usb_device *hdev)
{
struct usb_hub *hub = hdev_to_hub(hdev);
#else /* CONFIG_PM */
/* This also makes any led blinker stop retriggering. We're called
* from irq, so the blinker might still be scheduled. Caller promises
* that the root hub status URB will be canceled.
*/
__hub_quiesce(hub);
mark_quiesced(to_usb_interface(hub->intfdev));
static inline int remote_wakeup(struct usb_device *udev)
{
return 0;
}
#define hub_suspend NULL
#define hub_resume NULL
#endif
void usb_resume_root_hub(struct usb_device *hdev)
{
struct usb_hub *hub = hdev_to_hub(hdev);
@ -2214,6 +2034,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
int i, j, retval;
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
char *speed, *type;
/* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5)
@ -2246,8 +2067,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
* For Wireless USB devices, ep0 max packet is always 512 (tho
* reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
*/
switch (udev->speed) {
case USB_SPEED_VARIABLE: /* fixed at 512 */
udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(512);
break;
case USB_SPEED_HIGH: /* fixed at 64 */
udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
break;
@ -2265,17 +2091,21 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}
type = "";
switch (udev->speed) {
case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break;
case USB_SPEED_HIGH: speed = "high"; break;
case USB_SPEED_VARIABLE:
speed = "variable";
type = "Wireless ";
break;
default: speed = "?"; break;
}
dev_info (&udev->dev,
"%s %s speed USB device using %s and address %d\n",
(udev->config) ? "reset" : "new",
({ char *speed; switch (udev->speed) {
case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break;
case USB_SPEED_HIGH: speed = "high"; break;
default: speed = "?"; break;
}; speed;}),
udev->bus->controller->driver->name,
udev->devnum);
"%s %s speed %sUSB device using %s and address %d\n",
(udev->config) ? "reset" : "new", speed, type,
udev->bus->controller->driver->name, udev->devnum);
/* Set up TT records, if needed */
if (hdev->tt) {
@ -2317,6 +2147,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
* down tremendously by NAKing the unexpectedly
* early status stage. Also, retry on all errors;
* some devices are flakey.
* 255 is for WUSB devices, we actually need to use 512.
* WUSB1.0[4.8.1].
*/
for (j = 0; j < 3; ++j) {
buf->bMaxPacketSize0 = 0;
@ -2326,7 +2158,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
buf, GET_DESCRIPTOR_BUFSIZE,
(i ? USB_CTRL_GET_TIMEOUT : 1000));
switch (buf->bMaxPacketSize0) {
case 8: case 16: case 32: case 64:
case 8: case 16: case 32: case 64: case 255:
if (buf->bDescriptorType ==
USB_DT_DEVICE) {
r = 0;
@ -2400,7 +2232,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval)
goto fail;
i = udev->descriptor.bMaxPacketSize0;
i = udev->descriptor.bMaxPacketSize0 == 0xff?
512 : udev->descriptor.bMaxPacketSize0;
if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
if (udev->speed != USB_SPEED_FULL ||
!(i == 8 || i == 16 || i == 32 || i == 64)) {
@ -2585,6 +2418,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
usb_set_device_state(udev, USB_STATE_POWERED);
udev->speed = USB_SPEED_UNKNOWN;
udev->bus_mA = hub->mA_per_port;
udev->level = hdev->level + 1;
/* set the address */
choose_address(udev);
@ -2736,17 +2570,6 @@ static void hub_events(void)
usb_get_intf(intf);
spin_unlock_irq(&hub_event_lock);
/* Is this is a root hub wanting to reactivate the downstream
* ports? If so, be sure the interface resumes even if its
* stub "device" node was never suspended.
*/
if (i) {
dpm_runtime_resume(&hdev->dev);
dpm_runtime_resume(&intf->dev);
usb_put_intf(intf);
continue;
}
/* Lock the device, then check to see if we were
* disconnected while waiting for the lock to succeed. */
if (locktree(hdev) < 0) {
@ -2763,6 +2586,13 @@ static void hub_events(void)
goto loop;
}
/* Is this is a root hub wanting to reactivate the downstream
* ports? If so, be sure the interface resumes even if its
* stub "device" node was never suspended.
*/
if (i)
usb_autoresume_device(hdev, 0);
/* If this is an inactive or suspended hub, do nothing */
if (hub->quiescing)
goto loop;
@ -2900,7 +2730,7 @@ static void hub_events(void)
/* If this is a root hub, tell the HCD it's okay to
* re-enable port-change interrupts now. */
if (!hdev->parent)
if (!hdev->parent && !hub->busy_bits[0])
usb_enable_root_hub_irq(hdev->bus);
loop:
@ -3075,6 +2905,9 @@ int usb_reset_device(struct usb_device *udev)
break;
}
clear_bit(port1, parent_hub->busy_bits);
if (!parent_hdev->parent && !parent_hub->busy_bits[0])
usb_enable_root_hub_irq(parent_hdev->bus);
if (ret < 0)
goto re_enumerate;
@ -3128,6 +2961,7 @@ int usb_reset_device(struct usb_device *udev)
hub_port_logical_disconnect(parent_hub, port1);
return -ENODEV;
}
EXPORT_SYMBOL(usb_reset_device);
/**
* usb_reset_composite_device - warn interface drivers and perform a USB port reset
@ -3163,6 +2997,9 @@ int usb_reset_composite_device(struct usb_device *udev,
return -EINVAL;
}
/* Prevent autosuspend during the reset */
usb_autoresume_device(udev, 1);
if (iface && iface->condition != USB_INTERFACE_BINDING)
iface = NULL;
@ -3204,5 +3041,7 @@ int usb_reset_composite_device(struct usb_device *udev,
}
}
usb_autosuspend_device(udev, 1);
return ret;
}
EXPORT_SYMBOL(usb_reset_composite_device);

View File

@ -212,7 +212,8 @@ struct usb_hub {
unsigned long event_bits[1]; /* status change bitmask */
unsigned long change_bits[1]; /* ports with logical connect
status change */
unsigned long busy_bits[1]; /* ports being reset */
unsigned long busy_bits[1]; /* ports being reset or
resumed */
#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
#error event_bits[] is too short!
#endif

View File

@ -44,7 +44,7 @@
#include "hcd.h"
static struct super_operations usbfs_ops;
static struct file_operations default_file_operations;
static const struct file_operations default_file_operations;
static struct vfsmount *usbfs_mount;
static int usbfs_mount_count; /* = 0 */
static int ignore_mount = 0;
@ -407,7 +407,7 @@ static int default_open (struct inode *inode, struct file *file)
return 0;
}
static struct file_operations default_file_operations = {
static const struct file_operations default_file_operations = {
.read = default_read_file,
.write = default_write_file,
.open = default_open,
@ -494,7 +494,7 @@ static int fs_create_by_name (const char *name, mode_t mode,
static struct dentry *fs_create_file (const char *name, mode_t mode,
struct dentry *parent, void *data,
struct file_operations *fops,
const struct file_operations *fops,
uid_t uid, gid_t gid)
{
struct dentry *dentry;

View File

@ -23,59 +23,44 @@ static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)
}
static void timeout_kill(unsigned long data)
{
struct urb *urb = (struct urb *) data;
usb_unlink_urb(urb);
}
// Starts urb and waits for completion or timeout
// note that this call is NOT interruptible, while
// many device driver i/o requests should be interruptible
static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
/*
* Starts urb and waits for completion or timeout. Note that this call
* is NOT interruptible. Many device driver i/o requests should be
* interruptible and therefore these drivers should implement their
* own interruptible routines.
*/
static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
{
struct completion done;
struct timer_list timer;
int status;
struct completion done;
unsigned long expire;
int status;
init_completion(&done);
urb->context = &done;
urb->actual_length = 0;
status = usb_submit_urb(urb, GFP_NOIO);
if (unlikely(status))
goto out;
if (status == 0) {
if (timeout > 0) {
init_timer(&timer);
timer.expires = jiffies + msecs_to_jiffies(timeout);
timer.data = (unsigned long)urb;
timer.function = timeout_kill;
/* grr. timeout _should_ include submit delays. */
add_timer(&timer);
}
wait_for_completion(&done);
expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
if (!wait_for_completion_timeout(&done, expire)) {
dev_dbg(&urb->dev->dev,
"%s timed out on ep%d%s len=%d/%d\n",
current->comm,
usb_pipeendpoint(urb->pipe),
usb_pipein(urb->pipe) ? "in" : "out",
urb->actual_length,
urb->transfer_buffer_length);
usb_kill_urb(urb);
status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
} else
status = urb->status;
/* note: HCDs return ETIMEDOUT for other reasons too */
if (status == -ECONNRESET) {
dev_dbg(&urb->dev->dev,
"%s timed out on ep%d%s len=%d/%d\n",
current->comm,
usb_pipeendpoint(urb->pipe),
usb_pipein(urb->pipe) ? "in" : "out",
urb->actual_length,
urb->transfer_buffer_length
);
if (urb->actual_length > 0)
status = 0;
else
status = -ETIMEDOUT;
}
if (timeout > 0)
del_timer_sync(&timer);
}
out:
if (actual_length)
*actual_length = urb->actual_length;
usb_free_urb(urb);
return status;
}
@ -263,7 +248,7 @@ static void sg_clean (struct usb_sg_request *io)
static void sg_complete (struct urb *urb, struct pt_regs *regs)
{
struct usb_sg_request *io = (struct usb_sg_request *) urb->context;
struct usb_sg_request *io = urb->context;
spin_lock (&io->lock);
@ -999,8 +984,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
ep = dev->ep_in[epnum];
dev->ep_in[epnum] = NULL;
}
if (ep && dev->bus && dev->bus->op && dev->bus->op->disable)
dev->bus->op->disable(dev, ep);
if (ep && dev->bus)
usb_hcd_endpoint_disable(dev, ep);
}
/**
@ -1381,9 +1366,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
if (cp && configuration == 0)
dev_warn(&dev->dev, "config 0 descriptor??\n");
if (dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
/* Allocate memory for new interfaces before doing anything else,
* so that if we run out then nothing will have changed. */
n = nintf = 0;
@ -1418,6 +1400,11 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
configuration, -i);
}
/* Wake up the device so we can send it the Set-Config request */
ret = usb_autoresume_device(dev, 1);
if (ret)
goto free_interfaces;
/* if it's already configured, clear out old state first.
* getting rid of old interfaces means unbinding their drivers.
*/
@ -1437,6 +1424,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
dev->actconfig = cp;
if (!cp) {
usb_set_device_state(dev, USB_STATE_ADDRESS);
usb_autosuspend_device(dev, 1);
goto free_interfaces;
}
usb_set_device_state(dev, USB_STATE_CONFIGURED);
@ -1505,9 +1493,69 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
usb_create_sysfs_intf_files (intf);
}
usb_autosuspend_device(dev, 1);
return 0;
}
struct set_config_request {
struct usb_device *udev;
int config;
struct work_struct work;
};
/* Worker routine for usb_driver_set_configuration() */
static void driver_set_config_work(void *_req)
{
struct set_config_request *req = _req;
usb_lock_device(req->udev);
usb_set_configuration(req->udev, req->config);
usb_unlock_device(req->udev);
usb_put_dev(req->udev);
kfree(req);
}
/**
* usb_driver_set_configuration - Provide a way for drivers to change device configurations
* @udev: the device whose configuration is being updated
* @config: the configuration being chosen.
* Context: In process context, must be able to sleep
*
* Device interface drivers are not allowed to change device configurations.
* This is because changing configurations will destroy the interface the
* driver is bound to and create new ones; it would be like a floppy-disk
* driver telling the computer to replace the floppy-disk drive with a
* tape drive!
*
* Still, in certain specialized circumstances the need may arise. This
* routine gets around the normal restrictions by using a work thread to
* submit the change-config request.
*
* Returns 0 if the request was succesfully queued, error code otherwise.
* The caller has no way to know whether the queued request will eventually
* succeed.
*/
int usb_driver_set_configuration(struct usb_device *udev, int config)
{
struct set_config_request *req;
req = kmalloc(sizeof(*req), GFP_KERNEL);
if (!req)
return -ENOMEM;
req->udev = udev;
req->config = config;
INIT_WORK(&req->work, driver_set_config_work, req);
usb_get_dev(udev);
if (!schedule_work(&req->work)) {
usb_put_dev(udev);
kfree(req);
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
// synchronous request completion model
EXPORT_SYMBOL(usb_control_msg);
EXPORT_SYMBOL(usb_bulk_msg);

View File

@ -50,8 +50,11 @@ void usb_notify_add_device(struct usb_device *udev)
void usb_notify_remove_device(struct usb_device *udev)
{
/* Protect against simultaneous usbfs open */
mutex_lock(&usbfs_mutex);
blocking_notifier_call_chain(&usb_notifier_list,
USB_DEVICE_REMOVE, udev);
mutex_unlock(&usbfs_mutex);
}
void usb_notify_add_bus(struct usb_bus *ubus)

View File

@ -60,7 +60,7 @@ static ssize_t
set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = udev = to_usb_device (dev);
struct usb_device *udev = to_usb_device (dev);
int config, value;
if (sscanf (buf, "%u", &config) != 1 || config > 255)
@ -186,6 +186,7 @@ usb_descriptor_attr (bMaxPacketSize0, "%d\n")
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
&dev_attr_configuration.attr,
&dev_attr_bNumInterfaces.attr,
&dev_attr_bConfigurationValue.attr,
&dev_attr_bmAttributes.attr,
@ -209,20 +210,40 @@ static struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
};
void usb_create_sysfs_dev_files (struct usb_device *udev)
int usb_create_sysfs_dev_files(struct usb_device *udev)
{
struct device *dev = &udev->dev;
int retval;
sysfs_create_group(&dev->kobj, &dev_attr_grp);
retval = sysfs_create_group(&dev->kobj, &dev_attr_grp);
if (retval)
return retval;
if (udev->manufacturer)
device_create_file (dev, &dev_attr_manufacturer);
if (udev->product)
device_create_file (dev, &dev_attr_product);
if (udev->serial)
device_create_file (dev, &dev_attr_serial);
device_create_file (dev, &dev_attr_configuration);
usb_create_ep_files(dev, &udev->ep0, udev);
if (udev->manufacturer) {
retval = device_create_file (dev, &dev_attr_manufacturer);
if (retval)
goto error;
}
if (udev->product) {
retval = device_create_file (dev, &dev_attr_product);
if (retval)
goto error;
}
if (udev->serial) {
retval = device_create_file (dev, &dev_attr_serial);
if (retval)
goto error;
}
retval = usb_create_ep_files(dev, &udev->ep0, udev);
if (retval)
goto error;
return 0;
error:
usb_remove_ep_files(&udev->ep0);
device_remove_file(dev, &dev_attr_manufacturer);
device_remove_file(dev, &dev_attr_product);
device_remove_file(dev, &dev_attr_serial);
return retval;
}
void usb_remove_sysfs_dev_files (struct usb_device *udev)
@ -238,7 +259,6 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev)
device_remove_file(dev, &dev_attr_product);
if (udev->serial)
device_remove_file(dev, &dev_attr_serial);
device_remove_file (dev, &dev_attr_configuration);
}
/* Interface fields */
@ -340,18 +360,28 @@ static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
usb_remove_ep_files(&iface_desc->endpoint[i]);
}
void usb_create_sysfs_intf_files (struct usb_interface *intf)
int usb_create_sysfs_intf_files(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_host_interface *alt = intf->cur_altsetting;
int retval;
sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
retval = sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
if (retval)
goto error;
if (alt->string == NULL)
alt->string = usb_cache_string(udev, alt->desc.iInterface);
if (alt->string)
device_create_file(&intf->dev, &dev_attr_interface);
retval = device_create_file(&intf->dev, &dev_attr_interface);
usb_create_intf_ep_files(intf, udev);
return 0;
error:
if (alt->string)
device_remove_file(&intf->dev, &dev_attr_interface);
sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
usb_remove_intf_ep_files(intf);
return retval;
}
void usb_remove_sysfs_intf_files (struct usb_interface *intf)

View File

@ -57,7 +57,7 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
{
struct urb *urb;
urb = (struct urb *)kmalloc(sizeof(struct urb) +
urb = kmalloc(sizeof(struct urb) +
iso_packets * sizeof(struct usb_iso_packet_descriptor),
mem_flags);
if (!urb) {
@ -221,7 +221,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
int pipe, temp, max;
struct usb_device *dev;
struct usb_operations *op;
int is_out;
if (!urb || urb->hcpriv || !urb->complete)
@ -233,8 +232,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
|| dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
if (!(op = dev->bus->op) || !op->submit_urb)
return -ENODEV;
urb->status = -EINPROGRESS;
urb->actual_length = 0;
@ -376,7 +373,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb->interval = temp;
}
return op->submit_urb (urb, mem_flags);
return usb_hcd_submit_urb (urb, mem_flags);
}
/*-------------------------------------------------------------------*/
@ -440,9 +437,9 @@ int usb_unlink_urb(struct urb *urb)
{
if (!urb)
return -EINVAL;
if (!(urb->dev && urb->dev->bus && urb->dev->bus->op))
if (!(urb->dev && urb->dev->bus))
return -ENODEV;
return urb->dev->bus->op->unlink_urb(urb, -ECONNRESET);
return usb_hcd_unlink_urb(urb, -ECONNRESET);
}
/**
@ -468,13 +465,13 @@ int usb_unlink_urb(struct urb *urb)
void usb_kill_urb(struct urb *urb)
{
might_sleep();
if (!(urb && urb->dev && urb->dev->bus && urb->dev->bus->op))
if (!(urb && urb->dev && urb->dev->bus))
return;
spin_lock_irq(&urb->lock);
++urb->reject;
spin_unlock_irq(&urb->lock);
urb->dev->bus->op->unlink_urb(urb, -ENOENT);
usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
spin_lock_irq(&urb->lock);

View File

@ -67,7 +67,8 @@ static int nousb; /* Disable USB when built into kernel image */
* Don't call this function unless you are bound to one of the interfaces
* on this device or you have locked the device!
*/
struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
unsigned ifnum)
{
struct usb_host_config *config = dev->actconfig;
int i;
@ -100,8 +101,8 @@ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
* Don't call this function unless you are bound to the intf interface
* or you have locked the device!
*/
struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
unsigned int altnum)
struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf,
unsigned int altnum)
{
int i;
@ -112,87 +113,6 @@ struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
return NULL;
}
/**
* usb_driver_claim_interface - bind a driver to an interface
* @driver: the driver to be bound
* @iface: the interface to which it will be bound; must be in the
* usb device's active configuration
* @priv: driver data associated with that interface
*
* This is used by usb device drivers that need to claim more than one
* interface on a device when probing (audio and acm are current examples).
* No device driver should directly modify internal usb_interface or
* usb_device structure members.
*
* Few drivers should need to use this routine, since the most natural
* way to bind to an interface is to return the private data from
* the driver's probe() method.
*
* Callers must own the device lock and the driver model's usb_bus_type.subsys
* writelock. So driver probe() entries don't need extra locking,
* but other call contexts may need to explicitly claim those locks.
*/
int usb_driver_claim_interface(struct usb_driver *driver,
struct usb_interface *iface, void* priv)
{
struct device *dev = &iface->dev;
if (dev->driver)
return -EBUSY;
dev->driver = &driver->driver;
usb_set_intfdata(iface, priv);
iface->condition = USB_INTERFACE_BOUND;
mark_active(iface);
/* if interface was already added, bind now; else let
* the future device_add() bind it, bypassing probe()
*/
if (device_is_registered(dev))
device_bind_driver(dev);
return 0;
}
/**
* usb_driver_release_interface - unbind a driver from an interface
* @driver: the driver to be unbound
* @iface: the interface from which it will be unbound
*
* This can be used by drivers to release an interface without waiting
* for their disconnect() methods to be called. In typical cases this
* also causes the driver disconnect() method to be called.
*
* This call is synchronous, and may not be used in an interrupt context.
* Callers must own the device lock and the driver model's usb_bus_type.subsys
* writelock. So driver disconnect() entries don't need extra locking,
* but other call contexts may need to explicitly claim those locks.
*/
void usb_driver_release_interface(struct usb_driver *driver,
struct usb_interface *iface)
{
struct device *dev = &iface->dev;
/* this should never happen, don't release something that's not ours */
if (!dev->driver || dev->driver != &driver->driver)
return;
/* don't release from within disconnect() */
if (iface->condition != USB_INTERFACE_BOUND)
return;
/* don't release if the interface hasn't been added yet */
if (device_is_registered(dev)) {
iface->condition = USB_INTERFACE_UNBINDING;
device_release_driver(dev);
}
dev->driver = NULL;
usb_set_intfdata(iface, NULL);
iface->condition = USB_INTERFACE_UNBOUND;
mark_quiesced(iface);
}
struct find_interface_arg {
int minor;
struct usb_interface *interface;
@ -204,7 +124,7 @@ static int __find_interface(struct device * dev, void * data)
struct usb_interface *intf;
/* can't look at usb devices, only interfaces */
if (dev->driver == &usb_generic_driver)
if (is_usb_device(dev))
return 0;
intf = to_usb_interface(dev);
@ -227,127 +147,16 @@ static int __find_interface(struct device * dev, void * data)
struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
{
struct find_interface_arg argb;
int retval;
argb.minor = minor;
argb.interface = NULL;
driver_for_each_device(&drv->driver, NULL, &argb, __find_interface);
/* eat the error, it will be in argb.interface */
retval = driver_for_each_device(&drv->drvwrap.driver, NULL, &argb,
__find_interface);
return argb.interface;
}
#ifdef CONFIG_HOTPLUG
/*
* This sends an uevent to userspace, typically helping to load driver
* or other modules, configure the device, and more. Drivers can provide
* a MODULE_DEVICE_TABLE to help with module loading subtasks.
*
* We're called either from khubd (the typical case) or from root hub
* (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
* delays in event delivery. Use sysfs (and DEVPATH) to make sure the
* device (and this configuration!) are still present.
*/
static int usb_uevent(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
struct usb_interface *intf;
struct usb_device *usb_dev;
struct usb_host_interface *alt;
int i = 0;
int length = 0;
if (!dev)
return -ENODEV;
/* driver is often null here; dev_dbg() would oops */
pr_debug ("usb %s: uevent\n", dev->bus_id);
/* Must check driver_data here, as on remove driver is always NULL */
if ((dev->driver == &usb_generic_driver) ||
(dev->driver_data == &usb_generic_driver_data))
return 0;
intf = to_usb_interface(dev);
usb_dev = interface_to_usbdev (intf);
alt = intf->cur_altsetting;
if (usb_dev->devnum < 0) {
pr_debug ("usb %s: already deleted?\n", dev->bus_id);
return -ENODEV;
}
if (!usb_dev->bus) {
pr_debug ("usb %s: bus removed?\n", dev->bus_id);
return -ENODEV;
}
#ifdef CONFIG_USB_DEVICEFS
/* If this is available, userspace programs can directly read
* all the device descriptors we don't tell them about. Or
* even act as usermode drivers.
*
* FIXME reduce hardwired intelligence here
*/
if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"DEVICE=/proc/bus/usb/%03d/%03d",
usb_dev->bus->busnum, usb_dev->devnum))
return -ENOMEM;
#endif
/* per-device configurations are common */
if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PRODUCT=%x/%x/%x",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
le16_to_cpu(usb_dev->descriptor.bcdDevice)))
return -ENOMEM;
/* class-based driver binding models */
if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"TYPE=%d/%d/%d",
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
usb_dev->descriptor.bDeviceProtocol))
return -ENOMEM;
if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"INTERFACE=%d/%d/%d",
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol))
return -ENOMEM;
if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
le16_to_cpu(usb_dev->descriptor.bcdDevice),
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
usb_dev->descriptor.bDeviceProtocol,
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol))
return -ENOMEM;
envp[i] = NULL;
return 0;
}
#else
static int usb_uevent(struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size)
{
return -ENODEV;
}
#endif /* CONFIG_HOTPLUG */
/**
* usb_release_dev - free a usb device structure when all users of it are finished.
* @dev: device that's been disconnected
@ -361,14 +170,33 @@ static void usb_release_dev(struct device *dev)
udev = to_usb_device(dev);
#ifdef CONFIG_PM
cancel_delayed_work(&udev->autosuspend);
flush_scheduled_work();
#endif
usb_destroy_configuration(udev);
usb_bus_put(udev->bus);
usb_put_hcd(bus_to_hcd(udev->bus));
kfree(udev->product);
kfree(udev->manufacturer);
kfree(udev->serial);
kfree(udev);
}
#ifdef CONFIG_PM
/* usb_autosuspend_work - callback routine to autosuspend a USB device */
static void usb_autosuspend_work(void *_udev)
{
struct usb_device *udev = _udev;
mutex_lock_nested(&udev->pm_mutex, udev->level);
udev->auto_pm = 1;
usb_suspend_both(udev, PMSG_SUSPEND);
mutex_unlock(&udev->pm_mutex);
}
#endif
/**
* usb_alloc_dev - usb device constructor (usbcore-internal)
* @parent: hub to which device is connected; null to allocate a root hub
@ -390,8 +218,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
if (!dev)
return NULL;
bus = usb_bus_get(bus);
if (!bus) {
if (!usb_get_hcd(bus_to_hcd(bus))) {
kfree(dev);
return NULL;
}
@ -399,11 +226,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
device_initialize(&dev->dev);
dev->dev.bus = &usb_bus_type;
dev->dev.dma_mask = bus->controller->dma_mask;
dev->dev.driver_data = &usb_generic_driver_data;
dev->dev.driver = &usb_generic_driver;
dev->dev.release = usb_release_dev;
dev->state = USB_STATE_ATTACHED;
/* This magic assignment distinguishes devices from interfaces */
dev->dev.platform_data = &usb_generic_driver;
INIT_LIST_HEAD(&dev->ep0.urb_list);
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
@ -444,6 +272,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->parent = parent;
INIT_LIST_HEAD(&dev->filelist);
#ifdef CONFIG_PM
mutex_init(&dev->pm_mutex);
INIT_WORK(&dev->autosuspend, usb_autosuspend_work, dev);
#endif
return dev;
}
@ -549,7 +381,7 @@ void usb_put_intf(struct usb_interface *intf)
* case the driver already owns the device lock.)
*/
int usb_lock_device_for_reset(struct usb_device *udev,
struct usb_interface *iface)
const struct usb_interface *iface)
{
unsigned long jiffies_expire = jiffies + HZ;
@ -672,7 +504,139 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
*/
int usb_get_current_frame_number(struct usb_device *dev)
{
return dev->bus->op->get_frame_number (dev);
return usb_hcd_get_frame_number (dev);
}
/**
* usb_endpoint_dir_in - check if the endpoint has IN direction
* @epd: endpoint to be checked
*
* Returns true if the endpoint is of type IN, otherwise it returns false.
*/
int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
}
/**
* usb_endpoint_dir_out - check if the endpoint has OUT direction
* @epd: endpoint to be checked
*
* Returns true if the endpoint is of type OUT, otherwise it returns false.
*/
int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
}
/**
* usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type
* @epd: endpoint to be checked
*
* Returns true if the endpoint is of type bulk, otherwise it returns false.
*/
int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_BULK);
}
/**
* usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
* @epd: endpoint to be checked
*
* Returns true if the endpoint is of type interrupt, otherwise it returns
* false.
*/
int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_INT);
}
/**
* usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type
* @epd: endpoint to be checked
*
* Returns true if the endpoint is of type isochronous, otherwise it returns
* false.
*/
int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_ISOC);
}
/**
* usb_endpoint_is_bulk_in - check if the endpoint is bulk IN
* @epd: endpoint to be checked
*
* Returns true if the endpoint has bulk transfer type and IN direction,
* otherwise it returns false.
*/
int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
{
return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd));
}
/**
* usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT
* @epd: endpoint to be checked
*
* Returns true if the endpoint has bulk transfer type and OUT direction,
* otherwise it returns false.
*/
int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
{
return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd));
}
/**
* usb_endpoint_is_int_in - check if the endpoint is interrupt IN
* @epd: endpoint to be checked
*
* Returns true if the endpoint has interrupt transfer type and IN direction,
* otherwise it returns false.
*/
int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
{
return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd));
}
/**
* usb_endpoint_is_int_out - check if the endpoint is interrupt OUT
* @epd: endpoint to be checked
*
* Returns true if the endpoint has interrupt transfer type and OUT direction,
* otherwise it returns false.
*/
int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
{
return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd));
}
/**
* usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN
* @epd: endpoint to be checked
*
* Returns true if the endpoint has isochronous transfer type and IN direction,
* otherwise it returns false.
*/
int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
{
return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd));
}
/**
* usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT
* @epd: endpoint to be checked
*
* Returns true if the endpoint has isochronous transfer type and OUT direction,
* otherwise it returns false.
*/
int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
{
return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd));
}
/*-------------------------------------------------------------------*/
@ -737,9 +701,9 @@ void *usb_buffer_alloc (
dma_addr_t *dma
)
{
if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc)
if (!dev || !dev->bus)
return NULL;
return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma);
return hcd_buffer_alloc (dev->bus, size, mem_flags, dma);
}
/**
@ -760,9 +724,11 @@ void usb_buffer_free (
dma_addr_t dma
)
{
if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free)
return;
dev->bus->op->buffer_free (dev->bus, size, addr, dma);
if (!dev || !dev->bus)
return;
if (!addr)
return;
hcd_buffer_free (dev->bus, size, addr, dma);
}
/**
@ -911,8 +877,8 @@ void usb_buffer_unmap (struct urb *urb)
*
* Reverse the effect of this call with usb_buffer_unmap_sg().
*/
int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int nents)
int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int nents)
{
struct usb_bus *bus;
struct device *controller;
@ -946,8 +912,8 @@ int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
* Use this when you are re-using a scatterlist's data buffers for
* another USB request.
*/
void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents)
void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
struct device *controller;
@ -972,8 +938,8 @@ void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
*
* Reverses the effect of usb_buffer_map_sg().
*/
void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents)
void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
struct device *controller;
@ -988,116 +954,6 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
static int verify_suspended(struct device *dev, void *unused)
{
if (dev->driver == NULL)
return 0;
return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0;
}
static int usb_generic_suspend(struct device *dev, pm_message_t message)
{
struct usb_interface *intf;
struct usb_driver *driver;
int status;
/* USB devices enter SUSPEND state through their hubs, but can be
* marked for FREEZE as soon as their children are already idled.
* But those semantics are useless, so we equate the two (sigh).
*/
if (dev->driver == &usb_generic_driver) {
if (dev->power.power_state.event == message.event)
return 0;
/* we need to rule out bogus requests through sysfs */
status = device_for_each_child(dev, NULL, verify_suspended);
if (status)
return status;
return usb_suspend_device (to_usb_device(dev));
}
if ((dev->driver == NULL) ||
(dev->driver_data == &usb_generic_driver_data))
return 0;
intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver);
/* with no hardware, USB interfaces only use FREEZE and ON states */
if (!is_active(intf))
return 0;
if (driver->suspend && driver->resume) {
status = driver->suspend(intf, message);
if (status)
dev_err(dev, "%s error %d\n", "suspend", status);
else
mark_quiesced(intf);
} else {
// FIXME else if there's no suspend method, disconnect...
dev_warn(dev, "no suspend for driver %s?\n", driver->name);
mark_quiesced(intf);
status = 0;
}
return status;
}
static int usb_generic_resume(struct device *dev)
{
struct usb_interface *intf;
struct usb_driver *driver;
struct usb_device *udev;
int status;
if (dev->power.power_state.event == PM_EVENT_ON)
return 0;
/* mark things as "on" immediately, no matter what errors crop up */
dev->power.power_state.event = PM_EVENT_ON;
/* devices resume through their hubs */
if (dev->driver == &usb_generic_driver) {
udev = to_usb_device(dev);
if (udev->state == USB_STATE_NOTATTACHED)
return 0;
return usb_resume_device (to_usb_device(dev));
}
if ((dev->driver == NULL) ||
(dev->driver_data == &usb_generic_driver_data)) {
dev->power.power_state.event = PM_EVENT_FREEZE;
return 0;
}
intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver);
udev = interface_to_usbdev(intf);
if (udev->state == USB_STATE_NOTATTACHED)
return 0;
/* if driver was suspended, it has a resume method;
* however, sysfs can wrongly mark things as suspended
* (on the "no suspend method" FIXME path above)
*/
if (driver->resume) {
status = driver->resume(intf);
if (status) {
dev_err(dev, "%s error %d\n", "resume", status);
mark_quiesced(intf);
}
} else
dev_warn(dev, "no resume for driver %s?\n", driver->name);
return 0;
}
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
.suspend = usb_generic_suspend,
.resume = usb_generic_resume,
};
/* format to disable USB on kernel command line is: nousb */
__module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444);
@ -1141,7 +997,7 @@ static int __init usb_init(void)
retval = usb_hub_init();
if (retval)
goto hub_init_failed;
retval = driver_register(&usb_generic_driver);
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
if (!retval)
goto out;
@ -1171,7 +1027,7 @@ static void __exit usb_exit(void)
if (nousb)
return;
driver_unregister(&usb_generic_driver);
usb_deregister_device_driver(&usb_generic_driver);
usb_major_cleanup();
usbfs_cleanup();
usb_deregister(&usbfs_driver);
@ -1201,20 +1057,27 @@ EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
EXPORT_SYMBOL(usb_lock_device_for_reset);
EXPORT_SYMBOL(usb_driver_claim_interface);
EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_find_interface);
EXPORT_SYMBOL(usb_ifnum_to_if);
EXPORT_SYMBOL(usb_altnum_to_altsetting);
EXPORT_SYMBOL(usb_reset_device);
EXPORT_SYMBOL(usb_reset_composite_device);
EXPORT_SYMBOL(__usb_get_extra_descriptor);
EXPORT_SYMBOL(usb_find_device);
EXPORT_SYMBOL(usb_get_current_frame_number);
EXPORT_SYMBOL_GPL(usb_endpoint_dir_in);
EXPORT_SYMBOL_GPL(usb_endpoint_dir_out);
EXPORT_SYMBOL_GPL(usb_endpoint_xfer_bulk);
EXPORT_SYMBOL_GPL(usb_endpoint_xfer_int);
EXPORT_SYMBOL_GPL(usb_endpoint_xfer_isoc);
EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_in);
EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_out);
EXPORT_SYMBOL_GPL(usb_endpoint_is_int_in);
EXPORT_SYMBOL_GPL(usb_endpoint_is_int_out);
EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_in);
EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_out);
EXPORT_SYMBOL (usb_buffer_alloc);
EXPORT_SYMBOL (usb_buffer_free);

View File

@ -1,10 +1,10 @@
/* Functions local to drivers/usb/core/ */
extern void usb_create_sysfs_dev_files (struct usb_device *dev);
extern int usb_create_sysfs_dev_files (struct usb_device *dev);
extern void usb_remove_sysfs_dev_files (struct usb_device *dev);
extern void usb_create_sysfs_intf_files (struct usb_interface *intf);
extern int usb_create_sysfs_intf_files (struct usb_interface *intf);
extern void usb_remove_sysfs_intf_files (struct usb_interface *intf);
extern void usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint,
extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint,
struct usb_device *udev);
extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
@ -20,7 +20,6 @@ extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern void usb_kick_khubd(struct usb_device *dev);
extern void usb_suspend_root_hub(struct usb_device *hdev);
extern void usb_resume_root_hub(struct usb_device *dev);
extern int usb_hub_init(void);
@ -30,28 +29,74 @@ extern void usb_major_cleanup(void);
extern int usb_host_init(void);
extern void usb_host_cleanup(void);
extern int usb_suspend_device(struct usb_device *dev);
extern int usb_resume_device(struct usb_device *dev);
#ifdef CONFIG_PM
extern struct device_driver usb_generic_driver;
extern int usb_generic_driver_data;
extern int usb_device_match(struct device *dev, struct device_driver *drv);
extern int usb_suspend_both(struct usb_device *udev, pm_message_t msg);
extern int usb_resume_both(struct usb_device *udev);
extern int usb_port_suspend(struct usb_device *dev);
extern int usb_port_resume(struct usb_device *dev);
#else
#define usb_suspend_both(udev, msg) 0
static inline int usb_resume_both(struct usb_device *udev)
{
return 0;
}
#define usb_port_suspend(dev) 0
#define usb_port_resume(dev) 0
#endif
#ifdef CONFIG_USB_SUSPEND
#define USB_AUTOSUSPEND_DELAY (HZ*2)
extern void usb_autosuspend_device(struct usb_device *udev, int dec_busy_cnt);
extern int usb_autoresume_device(struct usb_device *udev, int inc_busy_cnt);
#else
#define usb_autosuspend_device(udev, dec_busy_cnt) do {} while (0)
#define usb_autoresume_device(udev, inc_busy_cnt) 0
#endif
extern struct bus_type usb_bus_type;
extern struct usb_device_driver usb_generic_driver;
/* Here's how we tell apart devices and interfaces. Luckily there's
* no such thing as a platform USB device, so we can steal the use
* of the platform_data field. */
static inline int is_usb_device(const struct device *dev)
{
return dev->platform_data == &usb_generic_driver;
}
/* Do the same for device drivers and interface drivers. */
static inline int is_usb_device_driver(struct device_driver *drv)
{
return container_of(drv, struct usbdrv_wrap, driver)->
for_devices;
}
/* Interfaces and their "power state" are owned by usbcore */
static inline void mark_active(struct usb_interface *f)
{
f->dev.power.power_state.event = PM_EVENT_ON;
f->is_active = 1;
}
static inline void mark_quiesced(struct usb_interface *f)
{
f->dev.power.power_state.event = PM_EVENT_FREEZE;
f->is_active = 0;
}
static inline int is_active(struct usb_interface *f)
static inline int is_active(const struct usb_interface *f)
{
return f->dev.power.power_state.event == PM_EVENT_ON;
return f->is_active;
}
@ -59,9 +104,10 @@ static inline int is_active(struct usb_interface *f)
extern const char *usbcore_name;
/* usbfs stuff */
extern struct mutex usbfs_mutex;
extern struct usb_driver usbfs_driver;
extern struct file_operations usbfs_devices_fops;
extern struct file_operations usbfs_device_file_operations;
extern const struct file_operations usbfs_devices_fops;
extern const struct file_operations usbfs_device_file_operations;
extern void usbfs_conn_disc_event(void);
extern int usbdev_init(void);

View File

@ -26,7 +26,7 @@ config USB_GADGET
you need a low level bus controller driver, and some software
talking to it. Peripheral controllers are often discrete silicon,
or are integrated with the CPU in a microcontroller. The more
familiar host side controllers have names like like "EHCI", "OHCI",
familiar host side controllers have names like "EHCI", "OHCI",
or "UHCI", and are usually integrated into southbridges on PC
motherboards.
@ -404,6 +404,20 @@ config USB_G_SERIAL
which includes instructions and a "driver info file" needed to
make MS-Windows work with this driver.
config USB_MIDI_GADGET
tristate "MIDI Gadget (EXPERIMENTAL)"
depends on SND && EXPERIMENTAL
select SND_RAWMIDI
help
The MIDI Gadget acts as a USB Audio device, with one MIDI
input and one MIDI output. These MIDI jacks appear as
a sound "card" in the ALSA sound system. Other MIDI
connections can then be made on the gadget system, using
ALSA's aconnect utility etc.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_midi".
# put drivers that need isochronous transfer support (for audio
# or video class gadget drivers), or specific hardware, here.

View File

@ -15,6 +15,7 @@ obj-$(CONFIG_USB_AT91) += at91_udc.o
g_zero-objs := zero.o usbstring.o config.o epautoconf.o
g_ether-objs := ether.o usbstring.o config.o epautoconf.o
g_serial-objs := serial.o usbstring.o config.o epautoconf.o
g_midi-objs := gmidi.o usbstring.o config.o epautoconf.o
gadgetfs-objs := inode.o
g_file_storage-objs := file_storage.o usbstring.o config.o \
epautoconf.o
@ -28,4 +29,5 @@ obj-$(CONFIG_USB_ETH) += g_ether.o
obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o

View File

@ -247,7 +247,7 @@ static int proc_udc_open(struct inode *inode, struct file *file)
return single_open(file, proc_udc_show, PDE(inode)->data);
}
static struct file_operations proc_ops = {
static const struct file_operations proc_ops = {
.open = proc_udc_open,
.read = seq_read,
.llseek = seq_lseek,

View File

@ -889,11 +889,9 @@ EXPORT_SYMBOL (net2280_set_fifo_mode);
static void
dummy_gadget_release (struct device *dev)
{
#if 0 /* usb_bus_put isn't EXPORTed! */
struct dummy *dum = gadget_dev_to_dummy (dev);
usb_bus_put (&dummy_to_hcd (dum)->self);
#endif
usb_put_hcd (dummy_to_hcd (dum));
}
static int dummy_udc_probe (struct platform_device *pdev)
@ -915,9 +913,7 @@ static int dummy_udc_probe (struct platform_device *pdev)
if (rc < 0)
return rc;
#if 0 /* usb_bus_get isn't EXPORTed! */
usb_bus_get (&dummy_to_hcd (dum)->self);
#endif
usb_get_hcd (dummy_to_hcd (dum));
platform_set_drvdata (pdev, dum);
device_create_file (&dum->gadget.dev, &dev_attr_function);

View File

@ -262,7 +262,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
#ifdef CONFIG_USB_GADGET_MUSBHDRC
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
#define DEV_CONFIG_CDC
#endif
@ -2014,7 +2014,7 @@ rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
static int rndis_control_ack (struct net_device *net)
{
struct eth_dev *dev = netdev_priv(net);
u32 length;
int length;
struct usb_request *resp = dev->stat_req;
/* in case RNDIS calls this after disconnect */
@ -2230,6 +2230,9 @@ eth_bind (struct usb_gadget *gadget)
if (gadget_is_pxa (gadget)) {
/* pxa doesn't support altsettings */
cdc = 0;
} else if (gadget_is_musbhdrc(gadget)) {
/* reduce tx dma overhead by avoiding special cases */
zlp = 0;
} else if (gadget_is_sh(gadget)) {
/* sh doesn't support multiple interfaces or configs */
cdc = 0;
@ -2564,7 +2567,7 @@ static struct usb_gadget_driver eth_driver = {
.function = (char *) driver_desc,
.bind = eth_bind,
.unbind = __exit_p(eth_unbind),
.unbind = eth_unbind,
.setup = eth_setup,
.disconnect = eth_disconnect,

1337
drivers/usb/gadget/gmidi.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,7 @@
#include <linux/compiler.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
@ -222,7 +223,6 @@ static void put_ep (struct ep_data *data)
/* needs no more cleanup */
BUG_ON (!list_empty (&data->epfiles));
BUG_ON (waitqueue_active (&data->wait));
BUG_ON (down_trylock (&data->lock) != 0);
kfree (data);
}
@ -477,6 +477,10 @@ static int
ep_release (struct inode *inode, struct file *fd)
{
struct ep_data *data = fd->private_data;
int value;
if ((value = down_interruptible(&data->lock)) < 0)
return value;
/* clean up if this can be reopened */
if (data->state != STATE_EP_UNBOUND) {
@ -485,6 +489,7 @@ ep_release (struct inode *inode, struct file *fd)
data->hs_desc.bDescriptorType = 0;
usb_ep_disable(data->ep);
}
up (&data->lock);
put_ep (data);
return 0;
}
@ -709,7 +714,7 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o)
/*----------------------------------------------------------------------*/
/* used after endpoint configuration */
static struct file_operations ep_io_operations = {
static const struct file_operations ep_io_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@ -741,7 +746,7 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
struct ep_data *data = fd->private_data;
struct usb_ep *ep;
u32 tag;
int value;
int value, length = len;
if ((value = down_interruptible (&data->lock)) < 0)
return value;
@ -792,7 +797,6 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
goto fail0;
}
}
value = len;
spin_lock_irq (&data->dev->lock);
if (data->dev->state == STATE_DEV_UNBOUND) {
@ -822,8 +826,10 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
data->name);
data->state = STATE_EP_DEFER_ENABLE;
}
if (value == 0)
if (value == 0) {
fd->f_op = &ep_io_operations;
value = length;
}
gone:
spin_unlock_irq (&data->dev->lock);
if (value < 0) {
@ -867,7 +873,7 @@ ep_open (struct inode *inode, struct file *fd)
}
/* used before endpoint configuration */
static struct file_operations ep_config_operations = {
static const struct file_operations ep_config_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@ -1009,7 +1015,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
else {
len = min (len, (size_t)dev->req->actual);
// FIXME don't call this with the spinlock held ...
if (copy_to_user (buf, &dev->req->buf, len))
if (copy_to_user (buf, dev->req->buf, len))
retval = -EFAULT;
clean_req (dev->gadget->ep0, dev->req);
/* NOTE userspace can't yet choose to stall */
@ -1229,6 +1235,35 @@ dev_release (struct inode *inode, struct file *fd)
return 0;
}
static unsigned int
ep0_poll (struct file *fd, poll_table *wait)
{
struct dev_data *dev = fd->private_data;
int mask = 0;
poll_wait(fd, &dev->wait, wait);
spin_lock_irq (&dev->lock);
/* report fd mode change before acting on it */
if (dev->setup_abort) {
dev->setup_abort = 0;
mask = POLLHUP;
goto out;
}
if (dev->state == STATE_SETUP) {
if (dev->setup_in || dev->setup_can_stall)
mask = POLLOUT;
} else {
if (dev->ev_next != 0)
mask = POLLIN;
}
out:
spin_unlock_irq(&dev->lock);
return mask;
}
static int dev_ioctl (struct inode *inode, struct file *fd,
unsigned code, unsigned long value)
{
@ -1241,14 +1276,14 @@ static int dev_ioctl (struct inode *inode, struct file *fd,
}
/* used after device configuration */
static struct file_operations ep0_io_operations = {
static const struct file_operations ep0_io_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = ep0_read,
.write = ep0_write,
.fasync = ep0_fasync,
// .poll = ep0_poll,
.poll = ep0_poll,
.ioctl = dev_ioctl,
.release = dev_release,
};
@ -1696,16 +1731,17 @@ gadgetfs_disconnect (struct usb_gadget *gadget)
{
struct dev_data *dev = get_gadget_data (gadget);
spin_lock (&dev->lock);
if (dev->state == STATE_UNCONNECTED) {
DBG (dev, "already unconnected\n");
return;
goto exit;
}
dev->state = STATE_UNCONNECTED;
INFO (dev, "disconnected\n");
spin_lock (&dev->lock);
next_event (dev, GADGETFS_DISCONNECT);
ep0_readable (dev);
exit:
spin_unlock (&dev->lock);
}
@ -1922,7 +1958,7 @@ dev_open (struct inode *inode, struct file *fd)
return value;
}
static struct file_operations dev_init_operations = {
static const struct file_operations dev_init_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,

View File

@ -2,7 +2,7 @@
* Driver for the PLX NET2280 USB device controller.
* Specs and errata are available from <http://www.plxtech.com>.
*
* PLX Technology Inc. (formerly NetChip Technology) supported the
* PLX Technology Inc. (formerly NetChip Technology) supported the
* development of this driver.
*
*
@ -26,7 +26,8 @@
* Copyright (C) 2003 David Brownell
* Copyright (C) 2003-2005 PLX Technology, Inc.
*
* Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility with 2282 chip
* Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility
* with 2282 chip
*
* 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
@ -85,7 +86,7 @@ static const char driver_name [] = "net2280";
static const char driver_desc [] = DRIVER_DESC;
static const char ep0name [] = "ep0";
static const char *ep_name [] = {
static const char *const ep_name [] = {
ep0name,
"ep-a", "ep-b", "ep-c", "ep-d",
"ep-e", "ep-f",
@ -225,7 +226,9 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
if (!ep->is_in)
writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
else if (dev->pdev->device != 0x2280) {
/* Added for 2282, Don't use nak packets on an in endpoint, this was ignored on 2280 */
/* Added for 2282, Don't use nak packets on an in endpoint,
* this was ignored on 2280
*/
writel ((1 << CLEAR_NAK_OUT_PACKETS)
| (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
}
@ -288,7 +291,7 @@ static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec)
return -ETIMEDOUT;
}
static struct usb_ep_ops net2280_ep_ops;
static const struct usb_ep_ops net2280_ep_ops;
static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)
{
@ -449,34 +452,15 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
/*-------------------------------------------------------------------------*/
#undef USE_KMALLOC
/* many common platforms have dma-coherent caches, which means that it's
* safe to use kmalloc() memory for all i/o buffers without using any
* cache flushing calls. (unless you're trying to share cache lines
* between dma and non-dma activities, which is a slow idea in any case.)
/*
* dma-coherent memory allocation (for dma-capable endpoints)
*
* other platforms need more care, with 2.5 having a moderately general
* solution (which falls down for allocations smaller than one page)
* that improves significantly on the 2.4 PCI allocators by removing
* the restriction that memory never be freed in_interrupt().
* NOTE: the dma_*_coherent() API calls suck. Most implementations are
* (a) page-oriented, so small buffers lose big; and (b) asymmetric with
* respect to calls with irqs disabled: alloc is safe, free is not.
* We currently work around (b), but not (a).
*/
#if defined(CONFIG_X86)
#define USE_KMALLOC
#elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
#define USE_KMALLOC
#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
#define USE_KMALLOC
/* FIXME there are other cases, including an x86-64 one ... */
#endif
/* allocating buffers this way eliminates dma mapping overhead, which
* on some platforms will mean eliminating a per-io buffer copy. with
* some kinds of system caches, further tweaks may still be needed.
*/
static void *
net2280_alloc_buffer (
struct usb_ep *_ep,
@ -493,43 +477,71 @@ net2280_alloc_buffer (
return NULL;
*dma = DMA_ADDR_INVALID;
#if defined(USE_KMALLOC)
retval = kmalloc(bytes, gfp_flags);
if (retval)
*dma = virt_to_phys(retval);
#else
if (ep->dma) {
/* the main problem with this call is that it wastes memory
* on typical 1/N page allocations: it allocates 1-N pages.
*/
#warning Using dma_alloc_coherent even with buffers smaller than a page.
if (ep->dma)
retval = dma_alloc_coherent(&ep->dev->pdev->dev,
bytes, dma, gfp_flags);
} else
else
retval = kmalloc(bytes, gfp_flags);
#endif
return retval;
}
static DEFINE_SPINLOCK(buflock);
static LIST_HEAD(buffers);
struct free_record {
struct list_head list;
struct device *dev;
unsigned bytes;
dma_addr_t dma;
};
static void do_free(unsigned long ignored)
{
spin_lock_irq(&buflock);
while (!list_empty(&buffers)) {
struct free_record *buf;
buf = list_entry(buffers.next, struct free_record, list);
list_del(&buf->list);
spin_unlock_irq(&buflock);
dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
spin_lock_irq(&buflock);
}
spin_unlock_irq(&buflock);
}
static DECLARE_TASKLET(deferred_free, do_free, 0);
static void
net2280_free_buffer (
struct usb_ep *_ep,
void *buf,
void *address,
dma_addr_t dma,
unsigned bytes
) {
/* free memory into the right allocator */
#ifndef USE_KMALLOC
if (dma != DMA_ADDR_INVALID) {
struct net2280_ep *ep;
struct free_record *buf = address;
unsigned long flags;
ep = container_of(_ep, struct net2280_ep, ep);
if (!_ep)
return;
dma_free_coherent(&ep->dev->pdev->dev, bytes, buf, dma);
ep = container_of (_ep, struct net2280_ep, ep);
buf->dev = &ep->dev->pdev->dev;
buf->bytes = bytes;
buf->dma = dma;
spin_lock_irqsave(&buflock, flags);
list_add_tail(&buf->list, &buffers);
tasklet_schedule(&deferred_free);
spin_unlock_irqrestore(&buflock, flags);
} else
#endif
kfree (buf);
kfree (address);
}
/*-------------------------------------------------------------------------*/
@ -737,7 +749,8 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
*/
if (ep->is_in)
dmacount |= (1 << DMA_DIRECTION);
if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || ep->dev->pdev->device != 0x2280)
if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0)
|| ep->dev->pdev->device != 0x2280)
dmacount |= (1 << END_OF_CHAIN);
req->valid = valid;
@ -812,7 +825,7 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req)
/* previous OUT packet might have been short */
if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat))
& (1 << NAK_OUT_PACKETS)) != 0) {
& (1 << NAK_OUT_PACKETS)) != 0) {
writel ((1 << SHORT_PACKET_TRANSFERRED_INTERRUPT),
&ep->regs->ep_stat);
@ -1373,7 +1386,7 @@ net2280_fifo_flush (struct usb_ep *_ep)
(void) readl (&ep->regs->ep_rsp);
}
static struct usb_ep_ops net2280_ep_ops = {
static const struct usb_ep_ops net2280_ep_ops = {
.enable = net2280_enable,
.disable = net2280_disable,
@ -1631,7 +1644,7 @@ show_registers (struct device *_dev, struct device_attribute *attr, char *buf)
}
/* Indexed Registers */
// none yet
// none yet
/* Statistics */
t = scnprintf (next, size, "\nirqs: ");
@ -1691,11 +1704,11 @@ show_queues (struct device *_dev, struct device_attribute *attr, char *buf)
({ char *val;
switch (d->bmAttributes & 0x03) {
case USB_ENDPOINT_XFER_BULK:
val = "bulk"; break;
val = "bulk"; break;
case USB_ENDPOINT_XFER_INT:
val = "intr"; break;
val = "intr"; break;
default:
val = "iso"; break;
val = "iso"; break;
}; val; }),
le16_to_cpu (d->wMaxPacketSize) & 0x1fff,
ep->dma ? "dma" : "pio", ep->fifo_size
@ -1808,8 +1821,8 @@ extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
* net2280_set_fifo_mode - change allocation of fifo buffers
* @gadget: access to the net2280 device that will be updated
* @mode: 0 for default, four 1kB buffers (ep-a through ep-d);
* 1 for two 2kB buffers (ep-a and ep-b only);
* 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
* 1 for two 2kB buffers (ep-a and ep-b only);
* 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
*
* returns zero on success, else negative errno. when this succeeds,
* the contents of gadget->ep_list may have changed.
@ -2241,7 +2254,8 @@ static void handle_ep_small (struct net2280_ep *ep)
req->td->dmacount = 0;
t = readl (&ep->regs->ep_avail);
dma_done (ep, req, count,
(ep->out_overflow || t) ? -EOVERFLOW : 0);
(ep->out_overflow || t)
? -EOVERFLOW : 0);
}
/* also flush to prevent erratum 0106 trouble */
@ -2411,7 +2425,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
, &ep->regs->ep_stat);
u.raw [0] = readl (&dev->usb->setup0123);
u.raw [1] = readl (&dev->usb->setup4567);
cpu_to_le32s (&u.raw [0]);
cpu_to_le32s (&u.raw [1]);
@ -2578,14 +2592,16 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
/* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set.
* Root Port Reset is indicated by ROOT_PORT_RESET_INTERRRUPT set and
* both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT
* both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT
* only indicates a change in the reset state).
*/
if (stat & tmp) {
writel (tmp, &dev->regs->irqstat1);
if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) &&
((readl (&dev->usb->usbstat) & mask) == 0))
|| ((readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0)
if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT))
&& ((readl (&dev->usb->usbstat) & mask)
== 0))
|| ((readl (&dev->usb->usbctl)
& (1 << VBUS_PIN)) == 0)
) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) {
DEBUG (dev, "disconnect %s\n",
dev->driver->driver.name);
@ -2852,7 +2868,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
/* now all the pci goodies ... */
if (pci_enable_device (pdev) < 0) {
retval = -ENODEV;
retval = -ENODEV;
goto done;
}
dev->enabled = 1;
@ -2870,6 +2886,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
}
dev->region = 1;
/* FIXME provide firmware download interface to put
* 8051 code into the chip, e.g. to turn on PCI PM.
*/
base = ioremap_nocache (resource, len);
if (base == NULL) {
DEBUG (dev, "can't map memory\n");
@ -2984,16 +3004,16 @@ static void net2280_shutdown (struct pci_dev *pdev)
/*-------------------------------------------------------------------------*/
static struct pci_device_id pci_ids [] = { {
.class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
.class_mask = ~0,
static const struct pci_device_id pci_ids [] = { {
.class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
.class_mask = ~0,
.vendor = 0x17cc,
.device = 0x2280,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
}, {
.class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
.class_mask = ~0,
.class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
.class_mask = ~0,
.vendor = 0x17cc,
.device = 0x2282,
.subvendor = PCI_ANY_ID,

View File

@ -40,7 +40,7 @@
#include <linux/platform_device.h>
#include <linux/usb_ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb_otg.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <asm/byteorder.h>
@ -2437,7 +2437,7 @@ static int proc_udc_open(struct inode *inode, struct file *file)
return single_open(file, proc_udc_show, NULL);
}
static struct file_operations proc_ops = {
static const struct file_operations proc_ops = {
.open = proc_udc_open,
.read = seq_read,
.llseek = seq_lseek,

View File

@ -150,6 +150,39 @@ MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode");
static void pxa2xx_ep_fifo_flush (struct usb_ep *ep);
static void nuke (struct pxa2xx_ep *, int status);
/* one GPIO should be used to detect VBUS from the host */
static int is_vbus_present(void)
{
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_vbus)
return pxa_gpio_get(mach->gpio_vbus);
if (mach->udc_is_connected)
return mach->udc_is_connected();
return 1;
}
/* one GPIO should control a D+ pullup, so host sees this device (or not) */
static void pullup_off(void)
{
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
pxa_gpio_set(mach->gpio_pullup, 0);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
static void pullup_on(void)
{
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
pxa_gpio_set(mach->gpio_pullup, 1);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
}
static void pio_irq_enable(int bEndpointAddress)
{
bEndpointAddress &= 0xf;
@ -1721,6 +1754,16 @@ lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r)
#endif
static irqreturn_t
udc_vbus_irq(int irq, void *_dev, struct pt_regs *r)
{
struct pxa2xx_udc *dev = _dev;
int vbus = pxa_gpio_get(dev->mach->gpio_vbus);
pxa2xx_udc_vbus_session(&dev->gadget, vbus);
return IRQ_HANDLED;
}
/*-------------------------------------------------------------------------*/
@ -2438,7 +2481,7 @@ static struct pxa2xx_udc memory = {
static int __init pxa2xx_udc_probe(struct platform_device *pdev)
{
struct pxa2xx_udc *dev = &memory;
int retval, out_dma = 1;
int retval, out_dma = 1, vbus_irq;
u32 chiprev;
/* insist on Intel/ARM/XScale */
@ -2502,6 +2545,16 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
/* other non-static parts of init */
dev->dev = &pdev->dev;
dev->mach = pdev->dev.platform_data;
if (dev->mach->gpio_vbus) {
vbus_irq = IRQ_GPIO(dev->mach->gpio_vbus & GPIO_MD_MASK_NR);
pxa_gpio_mode((dev->mach->gpio_vbus & GPIO_MD_MASK_NR)
| GPIO_IN);
set_irq_type(vbus_irq, IRQT_BOTHEDGE);
} else
vbus_irq = 0;
if (dev->mach->gpio_pullup)
pxa_gpio_mode((dev->mach->gpio_pullup & GPIO_MD_MASK_NR)
| GPIO_OUT | GPIO_DFLT_LOW);
init_timer(&dev->timer);
dev->timer.function = udc_watchdog;
@ -2557,8 +2610,19 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
HEX_DISPLAY(dev->stats.irqs);
LUB_DISC_BLNK_LED &= 0xff;
#endif
}
} else
#endif
if (vbus_irq) {
retval = request_irq(vbus_irq, udc_vbus_irq,
SA_INTERRUPT | SA_SAMPLE_RANDOM,
driver_name, dev);
if (retval != 0) {
printk(KERN_ERR "%s: can't get irq %i, err %d\n",
driver_name, vbus_irq, retval);
free_irq(IRQ_USB, dev);
return -EBUSY;
}
}
create_proc_files();
return 0;
@ -2587,6 +2651,8 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
free_irq(LUBBOCK_USB_IRQ, dev);
}
#endif
if (dev->mach->gpio_vbus)
free_irq(IRQ_GPIO(dev->mach->gpio_vbus), dev);
platform_set_drvdata(pdev, NULL);
the_controller = NULL;
return 0;

View File

@ -177,27 +177,19 @@ struct pxa2xx_udc {
static struct pxa2xx_udc *the_controller;
/* one GPIO should be used to detect VBUS from the host */
static inline int is_vbus_present(void)
static inline int pxa_gpio_get(unsigned gpio)
{
if (!the_controller->mach->udc_is_connected)
return 1;
return the_controller->mach->udc_is_connected();
return (GPLR(gpio) & GPIO_bit(gpio)) != 0;
}
/* one GPIO should control a D+ pullup, so host sees this device (or not) */
static inline void pullup_off(void)
static inline void pxa_gpio_set(unsigned gpio, int is_on)
{
if (!the_controller->mach->udc_command)
return;
the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
int mask = GPIO_bit(gpio);
static inline void pullup_on(void)
{
if (!the_controller->mach->udc_command)
return;
the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
if (is_on)
GPSR(gpio) = mask;
else
GPCR(gpio) = mask;
}
/*-------------------------------------------------------------------------*/

View File

@ -1120,12 +1120,15 @@ static int gs_send(struct gs_dev *dev)
gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
list_del(&req_entry->re_entry);
req->length = len;
spin_unlock_irqrestore(&dev->dev_lock, flags);
if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
printk(KERN_ERR
"gs_send: cannot queue read request, ret=%d\n",
ret);
spin_lock_irqsave(&dev->dev_lock, flags);
break;
}
spin_lock_irqsave(&dev->dev_lock, flags);
} else {
break;
}

View File

@ -83,6 +83,7 @@ config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
select I2C if ARCH_PNX4008
---help---
The Open Host Controller Interface (OHCI) is a standard for accessing
USB 1.1 host controller hardware. It does more in hardware than Intel's
@ -141,6 +142,34 @@ config USB_UHCI_HCD
To compile this driver as a module, choose M here: the
module will be called uhci-hcd.
config USB_U132_HCD
tristate "Elan U132 Adapter Host Controller"
depends on USB && USB_FTDI_ELAN
default M
help
The U132 adapter is a USB to CardBus adapter specifically designed
for PC cards that contain an OHCI host controller. Typical PC cards
are the Orange Mobile 3G Option GlobeTrotter Fusion card. The U132
adapter will *NOT* work with PC cards that do not contain an OHCI
controller.
For those PC cards that contain multiple OHCI controllers only ther
first one is used.
The driver consists of two modules, the "ftdi-elan" module is a
USB client driver that interfaces to the FTDI chip within ELAN's
USB-to-PCMCIA adapter, and this "u132-hcd" module is a USB host
controller driver that talks to the OHCI controller within the
CardBus cards that are inserted in the U132 adapter.
This driver has been tested with a CardBus OHCI USB adapter, and
worked with a USB PEN Drive inserted into the first USB port of
the PCCARD. A rather pointless thing to do, but useful for testing.
It is safe to say M here.
See also <http://www.elandigitalsystems.com/support/ufaq/u132linux.php>
config USB_SL811_HCD
tristate "SL811HS HCD support"
depends on USB

View File

@ -14,4 +14,5 @@ obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o

View File

@ -200,6 +200,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
.reset = ehci_init,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
@ -268,6 +269,7 @@ MODULE_ALIAS("au1xxx-ehci");
static struct platform_driver ehci_hcd_au1xxx_driver = {
.probe = ehci_hcd_au1xxx_drv_probe,
.remove = ehci_hcd_au1xxx_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
/*.suspend = ehci_hcd_au1xxx_drv_suspend, */
/*.resume = ehci_hcd_au1xxx_drv_resume, */
.driver = {

View File

@ -1,6 +1,6 @@
/*
* 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
* Free Software Foundation; either version 2 of the License, or (at your
@ -65,7 +65,7 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
for (i = 0; i < HCS_N_PORTS (params); i++) {
// FIXME MIPS won't readb() ...
byte = readb (&ehci->caps->portroute[(i>>1)]);
sprintf(tmp, "%d ",
sprintf(tmp, "%d ",
((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
strcat(buf, tmp);
}
@ -141,12 +141,12 @@ dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
}
static void __attribute__((__unused__))
dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
{
ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n",
label, itd->frame, itd, le32_to_cpu(itd->hw_next), itd->urb);
ehci_dbg (ehci,
" trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
" trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
le32_to_cpu(itd->hw_transaction[0]),
le32_to_cpu(itd->hw_transaction[1]),
le32_to_cpu(itd->hw_transaction[2]),
@ -156,7 +156,7 @@ dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
le32_to_cpu(itd->hw_transaction[6]),
le32_to_cpu(itd->hw_transaction[7]));
ehci_dbg (ehci,
" buf: %08x %08x %08x %08x %08x %08x %08x\n",
" buf: %08x %08x %08x %08x %08x %08x %08x\n",
le32_to_cpu(itd->hw_bufp[0]),
le32_to_cpu(itd->hw_bufp[1]),
le32_to_cpu(itd->hw_bufp[2]),
@ -171,12 +171,12 @@ dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
}
static void __attribute__((__unused__))
dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
{
ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
label, sitd->frame, sitd, le32_to_cpu(sitd->hw_next), sitd->urb);
ehci_dbg (ehci,
" addr %08x sched %04x result %08x buf %08x %08x\n",
" addr %08x sched %04x result %08x buf %08x %08x\n",
le32_to_cpu(sitd->hw_fullspeed_ep),
le32_to_cpu(sitd->hw_uframe),
le32_to_cpu(sitd->hw_results),
@ -451,7 +451,7 @@ show_async (struct class_device *class_dev, char *buf)
*buf = 0;
bus = class_get_devdata(class_dev);
hcd = bus->hcpriv;
hcd = bus_to_hcd(bus);
ehci = hcd_to_ehci (hcd);
next = buf;
size = PAGE_SIZE;
@ -497,7 +497,7 @@ show_periodic (struct class_device *class_dev, char *buf)
seen_count = 0;
bus = class_get_devdata(class_dev);
hcd = bus->hcpriv;
hcd = bus_to_hcd(bus);
ehci = hcd_to_ehci (hcd);
next = buf;
size = PAGE_SIZE;
@ -634,7 +634,7 @@ show_registers (struct class_device *class_dev, char *buf)
static char label [] = "";
bus = class_get_devdata(class_dev);
hcd = bus->hcpriv;
hcd = bus_to_hcd(bus);
ehci = hcd_to_ehci (hcd);
next = buf;
size = PAGE_SIZE;
@ -754,9 +754,7 @@ show_registers (struct class_device *class_dev, char *buf)
}
if (ehci->reclaim) {
temp = scnprintf (next, size, "reclaim qh %p%s\n",
ehci->reclaim,
ehci->reclaim_ready ? " ready" : "");
temp = scnprintf (next, size, "reclaim qh %p\n", ehci->reclaim);
size -= temp;
next += temp;
}
@ -785,10 +783,11 @@ static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
static inline void create_debug_files (struct ehci_hcd *ehci)
{
struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
int retval;
class_device_create_file(cldev, &class_device_attr_async);
class_device_create_file(cldev, &class_device_attr_periodic);
class_device_create_file(cldev, &class_device_attr_registers);
retval = class_device_create_file(cldev, &class_device_attr_async);
retval = class_device_create_file(cldev, &class_device_attr_periodic);
retval = class_device_create_file(cldev, &class_device_attr_registers);
}
static inline void remove_debug_files (struct ehci_hcd *ehci)

View File

@ -285,6 +285,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
.resume = ehci_bus_resume,
#endif
.stop = ehci_stop,
.shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
@ -329,6 +330,7 @@ MODULE_ALIAS("fsl-ehci");
static struct platform_driver ehci_fsl_driver = {
.probe = ehci_fsl_drv_probe,
.remove = ehci_fsl_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "fsl-ehci",
},

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2000-2004 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
* Free Software Foundation; either version 2 of the License, or (at your
@ -70,7 +70,7 @@
* 2002-08-06 Handling for bulk and interrupt transfers is mostly shared;
* only scheduling is different, no arbitrary limitations.
* 2002-07-25 Sanity check PCI reads, mostly for better cardbus support,
* clean up HC run state handshaking.
* clean up HC run state handshaking.
* 2002-05-24 Preliminary FS/LS interrupts, using scheduling shortcuts
* 2002-05-11 Clear TT errors for FS/LS ctrl/bulk. Fill in some other
* missing pieces: enabling 64bit dma, handoff from BIOS/SMM.
@ -111,7 +111,7 @@ static const char hcd_name [] = "ehci_hcd";
#define EHCI_TUNE_MULT_TT 1
#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
#define EHCI_IAA_MSECS 10 /* arbitrary */
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
@ -254,6 +254,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
/*-------------------------------------------------------------------------*/
static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs);
static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
#include "ehci-hub.c"
@ -263,6 +264,29 @@ static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
/*-------------------------------------------------------------------------*/
static void ehci_iaa_watchdog (unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
unsigned long flags;
u32 status;
spin_lock_irqsave (&ehci->lock, flags);
WARN_ON(!ehci->reclaim);
/* lost IAA irqs wedge things badly; seen first with a vt8235 */
if (ehci->reclaim) {
status = readl (&ehci->regs->status);
if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa);
writel (STS_IAA, &ehci->regs->status);
end_unlink_async (ehci, NULL);
}
}
spin_unlock_irqrestore (&ehci->lock, flags);
}
static void ehci_watchdog (unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
@ -270,21 +294,9 @@ static void ehci_watchdog (unsigned long param)
spin_lock_irqsave (&ehci->lock, flags);
/* lost IAA irqs wedge things badly; seen with a vt8235 */
if (ehci->reclaim) {
u32 status = readl (&ehci->regs->status);
if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa);
writel (STS_IAA, &ehci->regs->status);
ehci->reclaim_ready = 1;
}
}
/* stop async processing after it's idled a bit */
/* stop async processing after it's idled a bit */
if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
start_unlink_async (ehci, ehci->async);
start_unlink_async (ehci, ehci->async);
/* ehci could run by timer, without IRQs ... */
ehci_work (ehci, NULL);
@ -292,21 +304,20 @@ static void ehci_watchdog (unsigned long param)
spin_unlock_irqrestore (&ehci->lock, flags);
}
/* Reboot notifiers kick in for silicon on any bus (not just pci, etc).
/* ehci_shutdown kick in for silicon on any bus (not just pci, etc).
* This forcibly disables dma and IRQs, helping kexec and other cases
* where the next system software may expect clean state.
*/
static int
ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
static void
ehci_shutdown (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci;
struct ehci_hcd *ehci;
ehci = container_of (self, struct ehci_hcd, reboot_notifier);
ehci = hcd_to_ehci (hcd);
(void) ehci_halt (ehci);
/* make BIOS/etc use companion controller during reboot */
writel (0, &ehci->regs->configured_flag);
return 0;
}
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@ -334,8 +345,6 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
{
timer_action_done (ehci, TIMER_IO_WATCHDOG);
if (ehci->reclaim_ready)
end_unlink_async (ehci, regs);
/* another CPU may drop ehci->lock during a schedule scan while
* it reports urb completions. this flag guards against bogus
@ -370,6 +379,7 @@ static void ehci_stop (struct usb_hcd *hcd)
/* no more interrupts ... */
del_timer_sync (&ehci->watchdog);
del_timer_sync (&ehci->iaa_watchdog);
spin_lock_irq(&ehci->lock);
if (HC_IS_RUNNING (hcd->state))
@ -381,7 +391,6 @@ static void ehci_stop (struct usb_hcd *hcd)
/* let companion controllers work when we aren't */
writel (0, &ehci->regs->configured_flag);
unregister_reboot_notifier (&ehci->reboot_notifier);
remove_debug_files (ehci);
@ -417,6 +426,10 @@ static int ehci_init(struct usb_hcd *hcd)
ehci->watchdog.function = ehci_watchdog;
ehci->watchdog.data = (unsigned long) ehci;
init_timer(&ehci->iaa_watchdog);
ehci->iaa_watchdog.function = ehci_iaa_watchdog;
ehci->iaa_watchdog.data = (unsigned long) ehci;
/*
* hw default: 1K periodic list heads, one per frame.
* periodic_size can shrink by USBCMD update if hcc_params allows.
@ -427,13 +440,12 @@ static int ehci_init(struct usb_hcd *hcd)
/* controllers may cache some of the periodic schedule ... */
hcc_params = readl(&ehci->caps->hcc_params);
if (HCC_ISOC_CACHE(hcc_params)) // full frame cache
if (HCC_ISOC_CACHE(hcc_params)) // full frame cache
ehci->i_thresh = 8;
else // N microframes cached
ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
ehci->reclaim = NULL;
ehci->reclaim_ready = 0;
ehci->next_uframe = -1;
/*
@ -483,9 +495,6 @@ static int ehci_init(struct usb_hcd *hcd)
}
ehci->command = temp;
ehci->reboot_notifier.notifier_call = ehci_reboot;
register_reboot_notifier(&ehci->reboot_notifier);
return 0;
}
@ -499,7 +508,6 @@ static int ehci_run (struct usb_hcd *hcd)
/* EHCI spec section 4.1 */
if ((retval = ehci_reset(ehci)) != 0) {
unregister_reboot_notifier(&ehci->reboot_notifier);
ehci_mem_cleanup(ehci);
return retval;
}
@ -611,7 +619,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
/* complete the unlinking of some qh [4.15.2.3] */
if (status & STS_IAA) {
COUNT (ehci->stats.reclaim);
ehci->reclaim_ready = 1;
end_unlink_async (ehci, regs);
bh = 1;
}
@ -715,10 +723,14 @@ static int ehci_urb_enqueue (
static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
/* if we need to use IAA and it's busy, defer */
if (qh->qh_state == QH_STATE_LINKED
&& ehci->reclaim
&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
// BUG_ON(qh->qh_state != QH_STATE_LINKED);
/* failfast */
if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
end_unlink_async (ehci, NULL);
/* defer till later if busy */
else if (ehci->reclaim) {
struct ehci_qh *last;
for (last = ehci->reclaim;
@ -728,12 +740,8 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->qh_state = QH_STATE_UNLINK_WAIT;
last->reclaim = qh;
/* bypass IAA if the hc can't care */
} else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
end_unlink_async (ehci, NULL);
/* something else might have unlinked the qh by now */
if (qh->qh_state == QH_STATE_LINKED)
/* start IAA cycle */
} else
start_unlink_async (ehci, qh);
}
@ -755,7 +763,19 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
qh = (struct ehci_qh *) urb->hcpriv;
if (!qh)
break;
unlink_async (ehci, qh);
switch (qh->qh_state) {
case QH_STATE_LINKED:
case QH_STATE_COMPLETING:
unlink_async (ehci, qh);
break;
case QH_STATE_UNLINK:
case QH_STATE_UNLINK_WAIT:
/* already started */
break;
case QH_STATE_IDLE:
WARN_ON(1);
break;
}
break;
case PIPE_INTERRUPT:
@ -847,6 +867,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
unlink_async (ehci, qh);
/* FALL THROUGH */
case QH_STATE_UNLINK: /* wait for hw to finish? */
case QH_STATE_UNLINK_WAIT:
idle_timeout:
spin_unlock_irqrestore (&ehci->lock, flags);
schedule_timeout_uninterruptible(1);

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 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
* Free Software Foundation; either version 2 of the License, or (at your
@ -48,7 +48,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
}
ehci->command = readl (&ehci->regs->command);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
end_unlink_async (ehci, NULL);
ehci_work(ehci, NULL);
/* suspend any active/unsuspended ports, maybe allow wakeup */
@ -103,10 +103,10 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
/* re-init operational registers in case we lost power */
if (readl (&ehci->regs->intr_enable) == 0) {
/* at least some APM implementations will try to deliver
/* at least some APM implementations will try to deliver
* IRQs right away, so delay them until we're ready.
*/
intr_enable = 1;
*/
intr_enable = 1;
writel (0, &ehci->regs->segment);
writel (ehci->periodic_dma, &ehci->regs->frame_list);
writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
@ -232,7 +232,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
buf [1] = 0;
retval++;
}
/* no hub change reports (bit 0) for now (power, ...) */
/* port N changes (bit N)? */
@ -304,7 +304,7 @@ ehci_hub_descriptor (
/*-------------------------------------------------------------------------*/
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
static int ehci_hub_control (
struct usb_hcd *hcd,

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2001 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
* Free Software Foundation; either version 2 of the License, or (at your
@ -25,7 +25,7 @@
* - data used only by the HCD ... kmalloc is fine
* - async and periodic schedules, shared by HC and HCD ... these
* need to use dma_pool or dma_alloc_coherent
* - driver buffers, read/written by HC ... single shot DMA mapped
* - driver buffers, read/written by HC ... single shot DMA mapped
*
* There's also PCI "register" data, which is memory mapped.
* No memory seen by this driver is pageable.
@ -119,7 +119,7 @@ static inline void qh_put (struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
/* The queue heads and transfer descriptors are managed from pools tied
/* The queue heads and transfer descriptors are managed from pools tied
* to each of the "per device" structures.
* This is the initialisation and cleanup code.
*/
@ -165,7 +165,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
int i;
/* QTDs for control/bulk/intr transfers */
ehci->qtd_pool = dma_pool_create ("ehci_qtd",
ehci->qtd_pool = dma_pool_create ("ehci_qtd",
ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_qtd),
32 /* byte alignment (for hw parts) */,
@ -175,7 +175,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
}
/* QHs for control/bulk/intr transfers */
ehci->qh_pool = dma_pool_create ("ehci_qh",
ehci->qh_pool = dma_pool_create ("ehci_qh",
ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_qh),
32 /* byte alignment (for hw parts) */,
@ -189,7 +189,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
}
/* ITD for high speed ISO transfers */
ehci->itd_pool = dma_pool_create ("ehci_itd",
ehci->itd_pool = dma_pool_create ("ehci_itd",
ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_itd),
32 /* byte alignment (for hw parts) */,
@ -199,7 +199,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
}
/* SITD for full/low speed split ISO transfers */
ehci->sitd_pool = dma_pool_create ("ehci_sitd",
ehci->sitd_pool = dma_pool_create ("ehci_sitd",
ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_sitd),
32 /* byte alignment (for hw parts) */,

View File

@ -303,7 +303,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* emptying the schedule aborts any urbs */
spin_lock_irq(&ehci->lock);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
end_unlink_async (ehci, NULL);
ehci_work(ehci, NULL);
spin_unlock_irq(&ehci->lock);
@ -338,6 +338,7 @@ static const struct hc_driver ehci_pci_hc_driver = {
.resume = ehci_pci_resume,
#endif
.stop = ehci_stop,
.shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
@ -384,4 +385,5 @@ static struct pci_driver ehci_pci_driver = {
.suspend = usb_hcd_pci_suspend,
.resume = usb_hcd_pci_resume,
#endif
.shutdown = usb_hcd_pci_shutdown,
};

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 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
* Free Software Foundation; either version 2 of the License, or (at your
@ -31,7 +31,7 @@
* ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
* interrupts) needs careful scheduling. Performance improvements can be
* an ongoing challenge. That's in "ehci-sched.c".
*
*
* 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
* (b) special fields in qh entries or (c) split iso entries. TTs will
@ -199,7 +199,7 @@ static void qtd_copy_status (
&& ((token & QTD_STS_MMF) != 0
|| QTD_CERR(token) == 0)
&& (!ehci_is_TDI(ehci)
|| urb->dev->tt->hub !=
|| urb->dev->tt->hub !=
ehci_to_hcd(ehci)->self.root_hub)) {
#ifdef DEBUG
struct usb_device *tt = urb->dev->tt->hub;
@ -364,7 +364,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
*/
if (likely (urb->status == -EINPROGRESS))
continue;
/* issue status after short control reads */
if (unlikely (do_status != 0)
&& QTD_PID (token) == 0 /* OUT */) {
@ -388,7 +388,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
wmb ();
}
}
/* remove it from the queue */
spin_lock (&urb->lock);
qtd_copy_status (ehci, urb, qtd->length, token);
@ -518,7 +518,7 @@ qh_urb_transaction (
/* for zero length DATA stages, STATUS is always IN */
if (len == 0)
token |= (1 /* "in" */ << 8);
}
}
/*
* data transfer stage: buffer setup
@ -759,7 +759,7 @@ qh_make (
}
break;
default:
dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
done:
qh_put (qh);
return NULL;
@ -967,17 +967,16 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
struct ehci_qh *qh = ehci->reclaim;
struct ehci_qh *next;
timer_action_done (ehci, TIMER_IAA_WATCHDOG);
iaa_watchdog_done (ehci);
// qh->hw_next = cpu_to_le32 (qh->qh_dma);
qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = NULL;
qh_put (qh); // refcount from reclaim
qh_put (qh); // refcount from reclaim
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim;
ehci->reclaim = next;
ehci->reclaim_ready = 0;
qh->reclaim = NULL;
qh_completions (ehci, qh, regs);
@ -1031,7 +1030,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
timer_action_done (ehci, TIMER_ASYNC_OFF);
}
return;
}
}
qh->qh_state = QH_STATE_UNLINK;
ehci->reclaim = qh = qh_get (qh);
@ -1046,17 +1045,16 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (unlikely (ehci_to_hcd(ehci)->state == HC_STATE_HALT)) {
/* if (unlikely (qh->reclaim != 0))
* this will recurse, probably not much
* this will recurse, probably not much
*/
end_unlink_async (ehci, NULL);
return;
}
ehci->reclaim_ready = 0;
cmd |= CMD_IAAD;
writel (cmd, &ehci->regs->command);
(void) readl (&ehci->regs->command);
timer_action (ehci, TIMER_IAA_WATCHDOG);
iaa_watchdog_start (ehci);
}
/*-------------------------------------------------------------------------*/

View File

@ -1,7 +1,7 @@
/*
* Copyright (c) 2001-2004 by David Brownell
* Copyright (c) 2003 Michal Sojka, for high-speed iso transfers
*
*
* 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
* Free Software Foundation; either version 2 of the License, or (at your
@ -613,7 +613,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
static int check_period (
struct ehci_hcd *ehci,
struct ehci_hcd *ehci,
unsigned frame,
unsigned uframe,
unsigned period,
@ -629,7 +629,7 @@ static int check_period (
/*
* 80% periodic == 100 usec/uframe available
* convert "usecs we need" to "max already claimed"
* convert "usecs we need" to "max already claimed"
*/
usecs = 100 - usecs;
@ -659,14 +659,14 @@ static int check_period (
}
static int check_intr_schedule (
struct ehci_hcd *ehci,
struct ehci_hcd *ehci,
unsigned frame,
unsigned uframe,
const struct ehci_qh *qh,
__le32 *c_maskp
)
{
int retval = -ENOSPC;
int retval = -ENOSPC;
u8 mask = 0;
if (qh->c_usecs && uframe >= 6) /* FSTN territory? */
@ -701,7 +701,7 @@ static int check_intr_schedule (
/* Make sure this tt's buffer is also available for CSPLITs.
* We pessimize a bit; probably the typical full speed case
* doesn't need the second CSPLIT.
*
*
* NOTE: both SPLIT and CSPLIT could be checked in just
* one smart pass...
*/
@ -728,7 +728,7 @@ static int check_intr_schedule (
*/
static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
int status;
int status;
unsigned uframe;
__le32 c_mask;
unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
@ -784,7 +784,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
ehci_dbg (ehci, "reused qh %p schedule\n", qh);
/* stuff into the periodic schedule */
status = qh_link_periodic (ehci, qh);
status = qh_link_periodic (ehci, qh);
done:
return status;
}
@ -1681,7 +1681,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
status = -ESHUTDOWN;
else
status = iso_stream_schedule (ehci, urb, stream);
if (likely (status == 0))
if (likely (status == 0))
itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
spin_unlock_irqrestore (&ehci->lock, flags);
@ -1738,7 +1738,7 @@ sitd_sched_init (
if (packet->buf1 != (buf & ~(u64)0x0fff))
packet->cross = 1;
/* OUT uses multiple start-splits */
/* OUT uses multiple start-splits */
if (stream->bEndpointAddress & USB_DIR_IN)
continue;
length = (length + 187) / 188;
@ -1925,7 +1925,7 @@ sitd_link_urb (
/*-------------------------------------------------------------------------*/
#define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \
| SITD_STS_XACT | SITD_STS_MMF)
| SITD_STS_XACT | SITD_STS_MMF)
static unsigned
sitd_complete (
@ -2043,7 +2043,7 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
status = -ESHUTDOWN;
else
status = iso_stream_schedule (ehci, urb, stream);
if (status == 0)
if (status == 0)
sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
spin_unlock_irqrestore (&ehci->lock, flags);
@ -2226,5 +2226,5 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
now_uframe++;
now_uframe %= mod;
}
}
}
}

View File

@ -1,6 +1,6 @@
/*
* 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
* Free Software Foundation; either version 2 of the License, or (at your
@ -58,7 +58,6 @@ struct ehci_hcd { /* one per controller */
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *reclaim;
unsigned reclaim_ready : 1;
unsigned scanning : 1;
/* periodic schedule support */
@ -81,8 +80,8 @@ struct ehci_hcd { /* one per controller */
struct dma_pool *itd_pool; /* itd per iso urb */
struct dma_pool *sitd_pool; /* sitd per split iso urb */
struct timer_list iaa_watchdog;
struct timer_list watchdog;
struct notifier_block reboot_notifier;
unsigned long actions;
unsigned stamp;
unsigned long next_statechange;
@ -104,7 +103,7 @@ struct ehci_hcd { /* one per controller */
#endif
};
/* convert between an HCD pointer and the corresponding EHCI_HCD */
/* convert between an HCD pointer and the corresponding EHCI_HCD */
static inline struct ehci_hcd *hcd_to_ehci (struct usb_hcd *hcd)
{
return (struct ehci_hcd *) (hcd->hcd_priv);
@ -115,9 +114,21 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
}
static inline void
iaa_watchdog_start (struct ehci_hcd *ehci)
{
WARN_ON(timer_pending(&ehci->iaa_watchdog));
mod_timer (&ehci->iaa_watchdog,
jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
}
static inline void iaa_watchdog_done (struct ehci_hcd *ehci)
{
del_timer (&ehci->iaa_watchdog);
}
enum ehci_timer_action {
TIMER_IO_WATCHDOG,
TIMER_IAA_WATCHDOG,
TIMER_ASYNC_SHRINK,
TIMER_ASYNC_OFF,
};
@ -135,9 +146,6 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
unsigned long t;
switch (action) {
case TIMER_IAA_WATCHDOG:
t = EHCI_IAA_JIFFIES;
break;
case TIMER_IO_WATCHDOG:
t = EHCI_IO_JIFFIES;
break;
@ -154,8 +162,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
// async queue SHRINK often precedes IAA. while it's ready
// to go OFF neither can matter, and afterwards the IO
// watchdog stops unless there's still periodic traffic.
if (action != TIMER_IAA_WATCHDOG
&& t > ehci->watchdog.expires
if (time_before_eq(t, ehci->watchdog.expires)
&& timer_pending (&ehci->watchdog))
return;
mod_timer (&ehci->watchdog, t);
@ -179,8 +186,8 @@ struct ehci_caps {
#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
u32 hcc_params; /* HCCPARAMS - offset 0x8 */
@ -205,7 +212,7 @@ struct ehci_regs {
#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
#define CMD_ASE (1<<5) /* async schedule enable */
#define CMD_PSE (1<<4) /* periodic schedule enable */
#define CMD_PSE (1<<4) /* periodic schedule enable */
/* 3:2 is periodic frame list size */
#define CMD_RESET (1<<1) /* reset HC not bus */
#define CMD_RUN (1<<0) /* start/stop HC */
@ -231,9 +238,9 @@ struct ehci_regs {
/* FRINDEX: offset 0x0C */
u32 frame_index; /* current microframe number */
/* CTRLDSSEGMENT: offset 0x10 */
u32 segment; /* address bits 63:32 if needed */
u32 segment; /* address bits 63:32 if needed */
/* PERIODICLISTBASE: offset 0x14 */
u32 frame_list; /* points to periodic list */
u32 frame_list; /* points to periodic list */
/* ASYNCLISTADDR: offset 0x18 */
u32 async_next; /* address of next async queue head */
@ -302,7 +309,7 @@ struct ehci_dbg_port {
/*
* EHCI Specification 0.95 Section 3.5
* QTD: describe data transfer components (buffer, direction, ...)
* QTD: describe data transfer components (buffer, direction, ...)
* See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
*
* These are associated only with "QH" (Queue Head) structures,
@ -312,7 +319,7 @@ struct ehci_qtd {
/* first part defined by EHCI spec */
__le32 hw_next; /* see EHCI 3.5.1 */
__le32 hw_alt_next; /* see EHCI 3.5.2 */
__le32 hw_token; /* see EHCI 3.5.3 */
__le32 hw_token; /* see EHCI 3.5.3 */
#define QTD_TOGGLE (1 << 31) /* data toggle */
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
#define QTD_IOC (1 << 15) /* interrupt on complete */
@ -349,8 +356,8 @@ struct ehci_qtd {
/* values for that type tag */
#define Q_TYPE_ITD __constant_cpu_to_le32 (0 << 1)
#define Q_TYPE_QH __constant_cpu_to_le32 (1 << 1)
#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1)
#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1)
#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1)
#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1)
/* next async queue entry, or pointer to interrupt/periodic QH */
#define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
@ -367,7 +374,7 @@ struct ehci_qtd {
* For entries in the async schedule, the type tag always says "qh".
*/
union ehci_shadow {
struct ehci_qh *qh; /* Q_TYPE_QH */
struct ehci_qh *qh; /* Q_TYPE_QH */
struct ehci_itd *itd; /* Q_TYPE_ITD */
struct ehci_sitd *sitd; /* Q_TYPE_SITD */
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
@ -397,7 +404,7 @@ struct ehci_qh {
#define QH_HUBPORT 0x3f800000
#define QH_MULT 0xc0000000
__le32 hw_current; /* qtd list - see EHCI 3.6.4 */
/* qtd overlay (hardware parts of a struct ehci_qtd) */
__le32 hw_qtd_next;
__le32 hw_alt_next;
@ -472,7 +479,7 @@ struct ehci_iso_stream {
struct list_head td_list; /* queued itds/sitds */
struct list_head free_list; /* list of unused itds/sitds */
struct usb_device *udev;
struct usb_host_endpoint *ep;
struct usb_host_endpoint *ep;
/* output of (re)scheduling */
unsigned long start; /* jiffies */
@ -492,8 +499,8 @@ struct ehci_iso_stream {
unsigned bandwidth;
/* This is used to initialize iTD's hw_bufp fields */
__le32 buf0;
__le32 buf1;
__le32 buf0;
__le32 buf1;
__le32 buf2;
/* this is used to initialize sITD's tt info */
@ -521,7 +528,7 @@ struct ehci_itd {
#define ITD_ACTIVE __constant_cpu_to_le32(EHCI_ISOC_ACTIVE)
__le32 hw_bufp [7]; /* see EHCI 3.3.3 */
__le32 hw_bufp [7]; /* see EHCI 3.3.3 */
__le32 hw_bufp_hi [7]; /* Appendix B */
/* the rest is HCD-private */
@ -542,7 +549,7 @@ struct ehci_itd {
/*-------------------------------------------------------------------------*/
/*
* EHCI Specification 0.95 Section 3.4
* EHCI Specification 0.95 Section 3.4
* siTD, aka split-transaction isochronous Transfer Descriptor
* ... describe full speed iso xfers through TT in hubs
* see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)

View File

@ -1207,7 +1207,7 @@ static int isp116x_open_seq(struct inode *inode, struct file *file)
return single_open(file, isp116x_show_dbg, inode->i_private);
}
static struct file_operations isp116x_debug_fops = {
static const struct file_operations isp116x_debug_fops = {
.open = isp116x_open_seq,
.read = seq_read,
.llseek = seq_lseek,

View File

@ -233,7 +233,7 @@ static const int cc_to_error[16] = {
/* Bit Stuff */ -EPROTO,
/* Data Togg */ -EILSEQ,
/* Stall */ -EPIPE,
/* DevNotResp */ -ETIMEDOUT,
/* DevNotResp */ -ETIME,
/* PIDCheck */ -EPROTO,
/* UnExpPID */ -EPROTO,
/* DataOver */ -EOVERFLOW,

View File

@ -193,7 +193,7 @@ ohci_at91_start (struct usb_hcd *hcd)
if ((ret = ohci_init(ohci)) < 0)
return ret;
root->maxchild = board->ports;
ohci->num_ports = board->ports;
if ((ret = ohci_run(ohci)) < 0) {
err("can't start %s", hcd->self.bus_name);
@ -221,6 +221,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
*/
.start = ohci_at91_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@ -239,7 +240,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@ -296,6 +297,7 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
if (!clocked) {
clk_enable(iclk);
clk_enable(fclk);
clocked = 1;
}
return 0;
@ -310,6 +312,7 @@ MODULE_ALIAS("at91_ohci");
static struct platform_driver ohci_hcd_at91_driver = {
.probe = ohci_hcd_at91_drv_probe,
.remove = ohci_hcd_at91_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.suspend = ohci_hcd_at91_drv_suspend,
.resume = ohci_hcd_at91_drv_resume,
.driver = {

View File

@ -268,11 +268,8 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
* basic lifecycle operations
*/
.start = ohci_au1xxx_start,
#ifdef CONFIG_PM
/* suspend: ohci_au1xxx_suspend, -- tbd */
/* resume: ohci_au1xxx_resume, -- tbd */
#endif /*CONFIG_PM*/
.stop = ohci_stop,
.shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@ -291,6 +288,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@ -338,6 +336,7 @@ static int ohci_hcd_au1xxx_drv_resume(struct platform_device *dev)
static struct platform_driver ohci_hcd_au1xxx_driver = {
.probe = ohci_hcd_au1xxx_drv_probe,
.remove = ohci_hcd_au1xxx_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_au1xxx_drv_suspend, */
/*.resume = ohci_hcd_au1xxx_drv_resume, */
.driver = {

View File

@ -477,7 +477,7 @@ show_async (struct class_device *class_dev, char *buf)
unsigned long flags;
bus = class_get_devdata(class_dev);
hcd = bus->hcpriv;
hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
/* display control and bulk lists together, for simplicity */
@ -510,7 +510,7 @@ show_periodic (struct class_device *class_dev, char *buf)
seen_count = 0;
bus = class_get_devdata(class_dev);
hcd = bus->hcpriv;
hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
next = buf;
size = PAGE_SIZE;
@ -607,7 +607,7 @@ show_registers (struct class_device *class_dev, char *buf)
u32 rdata;
bus = class_get_devdata(class_dev);
hcd = bus->hcpriv;
hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
regs = ohci->regs;
next = buf;
@ -667,6 +667,11 @@ show_registers (struct class_device *class_dev, char *buf)
size -= temp;
next += temp;
temp = scnprintf (next, size, "hub poll timer %s\n",
ohci_to_hcd(ohci)->poll_rh ? "ON" : "off");
size -= temp;
next += temp;
/* roothub */
ohci_dump_roothub (ohci, 1, &next, &size);
@ -680,10 +685,11 @@ static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
static inline void create_debug_files (struct ohci_hcd *ohci)
{
struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev;
int retval;
class_device_create_file(cldev, &class_device_attr_async);
class_device_create_file(cldev, &class_device_attr_periodic);
class_device_create_file(cldev, &class_device_attr_registers);
retval = class_device_create_file(cldev, &class_device_attr_async);
retval = class_device_create_file(cldev, &class_device_attr_periodic);
retval = class_device_create_file(cldev, &class_device_attr_registers);
ohci_dbg (ohci, "created debug files\n");
}

View File

@ -128,12 +128,14 @@ static struct hc_driver ohci_ep93xx_hc_driver = {
.flags = HCD_USB11 | HCD_MEMORY,
.start = ohci_ep93xx_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,
.get_frame_number = ohci_get_frame,
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@ -202,6 +204,7 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev)
static struct platform_driver ohci_hcd_ep93xx_driver = {
.probe = ohci_hcd_ep93xx_drv_probe,
.remove = ohci_hcd_ep93xx_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_hcd_ep93xx_drv_suspend,
.resume = ohci_hcd_ep93xx_drv_resume,

View File

@ -88,7 +88,7 @@
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/usb.h>
#include <linux/usb_otg.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/reboot.h>
@ -101,7 +101,7 @@
#include "../core/hcd.h"
#define DRIVER_VERSION "2005 April 22"
#define DRIVER_VERSION "2006 August 04"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
@ -110,9 +110,10 @@
#undef OHCI_VERBOSE_DEBUG /* not always helpful */
/* For initializing controller (mask in an HCFS mode too) */
#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
#define OHCI_INTR_INIT \
(OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_WDH)
(OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_UE \
| OHCI_INTR_RD | OHCI_INTR_WDH)
#ifdef __hppa__
/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
@ -128,12 +129,13 @@
static const char hcd_name [] = "ohci_hcd";
#define STATECHANGE_DELAY msecs_to_jiffies(300)
#include "ohci.h"
static void ohci_dump (struct ohci_hcd *ohci, int verbose);
static int ohci_init (struct ohci_hcd *ohci);
static void ohci_stop (struct usb_hcd *hcd);
static int ohci_reboot (struct notifier_block *, unsigned long , void *);
#include "ohci-hub.c"
#include "ohci-dbg.c"
@ -416,21 +418,20 @@ static void ohci_usb_reset (struct ohci_hcd *ohci)
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
}
/* reboot notifier forcibly disables IRQs and DMA, helping kexec and
/* ohci_shutdown forcibly disables IRQs and DMA, helping kexec and
* other cases where the next software may expect clean state from the
* "firmware". this is bus-neutral, unlike shutdown() methods.
*/
static int
ohci_reboot (struct notifier_block *block, unsigned long code, void *null)
static void
ohci_shutdown (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci;
ohci = container_of (block, struct ohci_hcd, reboot_notifier);
ohci = hcd_to_ohci (hcd);
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
ohci_usb_reset (ohci);
/* flush the writes */
(void) ohci_readl (ohci, &ohci->regs->control);
return 0;
}
/*-------------------------------------------------------------------------*
@ -446,7 +447,6 @@ static int ohci_init (struct ohci_hcd *ohci)
disable (ohci);
ohci->regs = hcd->regs;
ohci->next_statechange = jiffies;
/* REVISIT this BIOS handshake is now moved into PCI "quirks", and
* was never needed for most non-PCI systems ... remove the code?
@ -502,7 +502,6 @@ static int ohci_init (struct ohci_hcd *ohci)
if ((ret = ohci_mem_init (ohci)) < 0)
ohci_stop (hcd);
else {
register_reboot_notifier (&ohci->reboot_notifier);
create_debug_files (ohci);
}
@ -637,10 +636,14 @@ static int ohci_run (struct ohci_hcd *ohci)
return -EOVERFLOW;
}
/* start controller operations */
/* use rhsc irqs after khubd is fully initialized */
hcd->poll_rh = 1;
hcd->uses_new_polling = 1;
/* start controller operations */
ohci->hc_control &= OHCI_CTRL_RWC;
ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
hcd->state = HC_STATE_RUNNING;
/* wake on ConnectStatusChange, matching external hubs */
@ -648,7 +651,7 @@ static int ohci_run (struct ohci_hcd *ohci)
/* Choose the interrupts we care about now, others later on demand */
mask = OHCI_INTR_INIT;
ohci_writel (ohci, mask, &ohci->regs->intrstatus);
ohci_writel (ohci, ~0, &ohci->regs->intrstatus);
ohci_writel (ohci, mask, &ohci->regs->intrenable);
/* handle root hub init quirks ... */
@ -672,6 +675,7 @@ static int ohci_run (struct ohci_hcd *ohci)
// flush those writes
(void) ohci_readl (ohci, &ohci->regs->control);
ohci->next_statechange = jiffies + STATECHANGE_DELAY;
spin_unlock_irq (&ohci->lock);
// POTPGT delay is bits 24-31, in 2 ms units.
@ -709,7 +713,23 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
/* interrupt for some other device? */
} else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) {
return IRQ_NOTMINE;
}
}
/* NOTE: vendors didn't always make the same implementation
* choices for RHSC. Sometimes it triggers on an edge (like
* setting and maybe clearing a port status change bit); and
* it's level-triggered on other silicon, active until khubd
* clears all active port status change bits. Poll by timer
* til it's fully debounced and the difference won't matter.
*/
if (ints & OHCI_INTR_RHSC) {
ohci_vdbg (ohci, "rhsc\n");
ohci_writel (ohci, OHCI_INTR_RHSC, &regs->intrdisable);
hcd->poll_rh = 1;
ohci->next_statechange = jiffies + STATECHANGE_DELAY;
ohci_writel (ohci, OHCI_INTR_RHSC, &regs->intrstatus);
usb_hcd_poll_rh_status(hcd);
}
if (ints & OHCI_INTR_UE) {
disable (ohci);
@ -775,9 +795,10 @@ static void ohci_stop (struct usb_hcd *hcd)
ohci_usb_reset (ohci);
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
free_irq(hcd->irq, hcd);
hcd->irq = -1;
remove_debug_files (ohci);
unregister_reboot_notifier (&ohci->reboot_notifier);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
dma_free_coherent (hcd->self.controller,
@ -917,6 +938,10 @@ MODULE_LICENSE ("GPL");
#include "ohci-at91.c"
#endif
#ifdef CONFIG_ARCH_PNX4008
#include "ohci-pnx4008.c"
#endif
#if !(defined(CONFIG_PCI) \
|| defined(CONFIG_SA1111) \
|| defined(CONFIG_ARCH_S3C2410) \
@ -928,6 +953,7 @@ MODULE_LICENSE ("GPL");
|| defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
|| defined (CONFIG_ARCH_AT91RM9200) \
|| defined (CONFIG_ARCH_AT91SAM9261) \
|| defined (CONFIG_ARCH_PNX4008) \
)
#error "missing bus glue for ohci-hcd"
#endif

View File

@ -36,6 +36,14 @@
/*-------------------------------------------------------------------------*/
/* hcd->hub_irq_enable() */
static void ohci_rhsc_enable (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
}
#ifdef CONFIG_PM
#define OHCI_SCHED_ENABLES \
@ -123,10 +131,10 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
/* no resumes until devices finish suspending */
ohci->next_statechange = jiffies + msecs_to_jiffies (5);
/* no timer polling */
hcd->poll_rh = 0;
done:
/* external suspend vs self autosuspend ... same effect */
if (status == 0)
usb_hcd_suspend_root_hub(hcd);
spin_unlock_irqrestore (&ohci->lock, flags);
return status;
}
@ -256,8 +264,8 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
/* TRSMRCY */
msleep (10);
/* keep it alive for ~5x suspend + resume costs */
ohci->next_statechange = jiffies + msecs_to_jiffies (250);
/* keep it alive for more than ~5x suspend + resume costs */
ohci->next_statechange = jiffies + STATECHANGE_DELAY;
/* maybe turn schedules back on */
enables = 0;
@ -302,9 +310,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int i, changed = 0, length = 1;
int can_suspend = device_may_wakeup(&hcd->self.root_hub->dev);
int can_suspend;
unsigned long flags;
can_suspend = device_may_wakeup(&hcd->self.root_hub->dev);
spin_lock_irqsave (&ohci->lock, flags);
/* handle autosuspended root: finish resuming before
@ -339,6 +348,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
for (i = 0; i < ohci->num_ports; i++) {
u32 status = roothub_portstatus (ohci, i);
/* can't autosuspend with active ports */
if ((status & RH_PS_PES) && !(status & RH_PS_PSS))
can_suspend = 0;
if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
| RH_PS_OCIC | RH_PS_PRSC)) {
changed = 1;
@ -348,32 +361,41 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
buf [1] |= 1 << (i - 7);
continue;
}
/* can suspend if no ports are enabled; or if all all
* enabled ports are suspended AND remote wakeup is on.
*/
if (!(status & RH_PS_CCS))
continue;
if ((status & RH_PS_PSS) && can_suspend)
continue;
can_suspend = 0;
}
done:
spin_unlock_irqrestore (&ohci->lock, flags);
#ifdef CONFIG_PM
/* save power by suspending idle root hubs;
* INTR_RD wakes us when there's work
/* after root hub changes, stop polling after debouncing
* for a while and maybe kicking in autosuspend
*/
if (can_suspend
&& !changed
if (changed) {
ohci->next_statechange = jiffies + STATECHANGE_DELAY;
can_suspend = 0;
} else if (time_before (jiffies, ohci->next_statechange)) {
can_suspend = 0;
} else {
#ifdef CONFIG_PM
can_suspend = can_suspend
&& !ohci->ed_rm_list
&& ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES)
& ohci->hc_control)
== OHCI_USB_OPER
&& time_after (jiffies, ohci->next_statechange)
&& usb_trylock_device (hcd->self.root_hub) == 0
) {
== OHCI_USB_OPER;
#endif
if (hcd->uses_new_polling) {
hcd->poll_rh = 0;
/* use INTR_RHSC iff INTR_RD won't apply */
if (!can_suspend)
ohci_writel (ohci, OHCI_INTR_RHSC,
&ohci->regs->intrenable);
}
}
done:
spin_unlock_irqrestore (&ohci->lock, flags);
#ifdef CONFIG_PM
/* save power by autosuspending idle root hubs;
* INTR_RD wakes us when there's work
*/
if (can_suspend && usb_trylock_device (hcd->self.root_hub) == 0) {
ohci_vdbg (ohci, "autosuspend\n");
(void) ohci_bus_suspend (hcd);
usb_unlock_device (hcd->self.root_hub);

View File

@ -173,11 +173,8 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
* basic lifecycle operations
*/
.start = ohci_lh7a404_start,
#ifdef CONFIG_PM
/* suspend: ohci_lh7a404_suspend, -- tbd */
/* resume: ohci_lh7a404_resume, -- tbd */
#endif /*CONFIG_PM*/
.stop = ohci_stop,
.shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@ -196,6 +193,7 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@ -244,6 +242,7 @@ static int ohci_hcd_lh7a404_drv_resume(struct platform_device *dev)
static struct platform_driver ohci_hcd_lh7a404_driver = {
.probe = ohci_hcd_lh7a404_drv_probe,
.remove = ohci_hcd_lh7a404_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_lh7a404_drv_suspend, */
/*.resume = ohci_hcd_lh7a404_drv_resume, */
.driver = {

View File

@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
ohci->next_statechange = jiffies;
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
ohci->reboot_notifier.notifier_call = ohci_reboot;
}
/*-------------------------------------------------------------------------*/

View File

@ -4,7 +4,7 @@
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2005 David Brownell
* (C) Copyright 2002 Hewlett-Packard Company
*
*
* OMAP Bus Glue
*
* Modified for OMAP by Tony Lindgren <tony@atomide.com>
@ -66,15 +66,20 @@ extern int usb_disabled(void);
extern int ocpi_enable(void);
static struct clk *usb_host_ck;
static struct clk *usb_dc_ck;
static int host_enabled;
static int host_initialized;
static void omap_ohci_clock_power(int on)
{
if (on) {
clk_enable(usb_dc_ck);
clk_enable(usb_host_ck);
/* guesstimate for T5 == 1x 32K clock + APLL lock time */
udelay(100);
} else {
clk_disable(usb_host_ck);
clk_disable(usb_dc_ck);
}
}
@ -87,14 +92,14 @@ static int omap_ohci_transceiver_power(int on)
if (on) {
if (machine_is_omap_innovator() && cpu_is_omap1510())
fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
| ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
| ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
INNOVATOR_FPGA_CAM_USB_CONTROL);
else if (machine_is_omap_osk())
tps65010_set_gpio_out_value(GPIO1, LOW);
} else {
if (machine_is_omap_innovator() && cpu_is_omap1510())
fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
& ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
& ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
INNOVATOR_FPGA_CAM_USB_CONTROL);
else if (machine_is_omap_osk())
tps65010_set_gpio_out_value(GPIO1, HIGH);
@ -103,6 +108,7 @@ static int omap_ohci_transceiver_power(int on)
return 0;
}
#ifdef CONFIG_ARCH_OMAP15XX
/*
* OMAP-1510 specific Local Bus clock on/off
*/
@ -121,8 +127,8 @@ static int omap_1510_local_bus_power(int on)
/*
* OMAP-1510 specific Local Bus initialization
* NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE.
* See also arch/mach-omap/memory.h for __virt_to_dma() and
* __dma_to_virt() which need to match with the physical
* See also arch/mach-omap/memory.h for __virt_to_dma() and
* __dma_to_virt() which need to match with the physical
* Local Bus address below.
*/
static int omap_1510_local_bus_init(void)
@ -130,7 +136,7 @@ static int omap_1510_local_bus_init(void)
unsigned int tlb;
unsigned long lbaddr, physaddr;
omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4,
omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4,
OMAP1510_LB_CLOCK_DIV);
/* Configure the Local Bus MMU table */
@ -138,7 +144,7 @@ static int omap_1510_local_bus_init(void)
lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET;
physaddr = tlb * 0x00100000 + PHYS_OFFSET;
omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H);
omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc,
omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc,
OMAP1510_LB_MMU_CAM_L);
omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H);
omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L);
@ -152,6 +158,10 @@ static int omap_1510_local_bus_init(void)
return 0;
}
#else
#define omap_1510_local_bus_power(x) {}
#define omap_1510_local_bus_init() {}
#endif
#ifdef CONFIG_USB_OTG
@ -173,13 +183,14 @@ static void start_hnp(struct ohci_hcd *ohci)
/*-------------------------------------------------------------------------*/
static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
static int ohci_omap_init(struct usb_hcd *hcd)
{
struct omap_usb_config *config = pdev->dev.platform_data;
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
struct omap_usb_config *config = hcd->self.controller->platform_data;
int need_transceiver = (config->otg != 0);
int ret;
dev_dbg(&pdev->dev, "starting USB Controller\n");
dev_dbg(hcd->self.controller, "starting USB Controller\n");
if (config->otg) {
ohci_to_hcd(ohci)->self.otg_port = config->otg;
@ -200,7 +211,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
if (ohci->transceiver) {
int status = otg_set_host(ohci->transceiver,
&ohci_to_hcd(ohci)->self);
dev_dbg(&pdev->dev, "init %s transceiver, status %d\n",
dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n",
ohci->transceiver->label, status);
if (status) {
if (ohci->transceiver)
@ -208,7 +219,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
return status;
}
} else {
dev_err(&pdev->dev, "can't find transceiver\n");
dev_err(hcd->self.controller, "can't find transceiver\n");
return -ENODEV;
}
}
@ -247,6 +258,10 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
}
ohci_writel(ohci, rh, &ohci->regs->roothub.a);
distrust_firmware = 0;
} else if (machine_is_nokia770()) {
/* We require a self-powered hub, which should have
* plenty of power. */
ohci_to_hcd(ohci)->power_budget = 0;
}
/* FIXME khubd hub requests should manage power switching */
@ -260,21 +275,15 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
return 0;
}
static void omap_stop_hc(struct platform_device *pdev)
static void ohci_omap_stop(struct usb_hcd *hcd)
{
dev_dbg(&pdev->dev, "stopping USB Controller\n");
dev_dbg(hcd->self.controller, "stopping USB Controller\n");
omap_ohci_clock_power(0);
}
/*-------------------------------------------------------------------------*/
void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
/**
* usb_hcd_omap_probe - initialize OMAP-based HCDs
* Context: !in_interrupt()
@ -283,7 +292,7 @@ void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
*/
int usb_hcd_omap_probe (const struct hc_driver *driver,
static int usb_hcd_omap_probe (const struct hc_driver *driver,
struct platform_device *pdev)
{
int retval, irq;
@ -291,12 +300,12 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
struct ohci_hcd *ohci;
if (pdev->num_resources != 2) {
printk(KERN_ERR "hcd probe: invalid num_resources: %i\n",
printk(KERN_ERR "hcd probe: invalid num_resources: %i\n",
pdev->num_resources);
return -ENODEV;
}
if (pdev->resource[0].flags != IORESOURCE_MEM
if (pdev->resource[0].flags != IORESOURCE_MEM
|| pdev->resource[1].flags != IORESOURCE_IRQ) {
printk(KERN_ERR "hcd probe: invalid resource type\n");
return -ENODEV;
@ -306,6 +315,17 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
if (IS_ERR(usb_host_ck))
return PTR_ERR(usb_host_ck);
if (!cpu_is_omap1510())
usb_dc_ck = clk_get(0, "usb_dc_ck");
else
usb_dc_ck = clk_get(0, "lb_ck");
if (IS_ERR(usb_dc_ck)) {
clk_put(usb_host_ck);
return PTR_ERR(usb_dc_ck);
}
hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
if (!hcd) {
retval = -ENOMEM;
@ -325,9 +345,8 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
ohci = hcd_to_ohci(hcd);
ohci_hcd_init(ohci);
retval = omap_start_hc(ohci, pdev);
if (retval < 0)
goto err2;
host_initialized = 0;
host_enabled = 1;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@ -335,15 +354,21 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
goto err2;
}
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
if (retval == 0)
return retval;
if (retval)
goto err2;
omap_stop_hc(pdev);
host_initialized = 1;
if (!host_enabled)
omap_ohci_clock_power(0);
return 0;
err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
usb_put_hcd(hcd);
err0:
clk_put(usb_dc_ck);
clk_put(usb_host_ck);
return retval;
}
@ -359,31 +384,41 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
* Reverses the effect of usb_hcd_omap_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
* context, normally "rmmod", "apmd", or something similar.
*
*/
void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
static inline void
usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
usb_remove_hcd(hcd);
if (ohci->transceiver) {
(void) otg_set_host(ohci->transceiver, 0);
put_device(ohci->transceiver->dev);
}
if (machine_is_omap_osk())
omap_free_gpio(9);
omap_stop_hc(pdev);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
clk_put(usb_dc_ck);
clk_put(usb_host_ck);
}
/*-------------------------------------------------------------------------*/
static int __devinit
static int
ohci_omap_start (struct usb_hcd *hcd)
{
struct omap_usb_config *config;
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret;
if (!host_enabled)
return 0;
config = hcd->self.controller->platform_data;
if (config->otg || config->rwc)
if (config->otg || config->rwc) {
ohci->hc_control = OHCI_CTRL_RWC;
writel(OHCI_CTRL_RWC, &ohci->regs->control);
}
if ((ret = ohci_run (ohci)) < 0) {
dev_err(hcd->self.controller, "can't start\n");
@ -409,8 +444,10 @@ static const struct hc_driver ohci_omap_hc_driver = {
/*
* basic lifecycle operations
*/
.reset = ohci_omap_init,
.start = ohci_omap_start,
.stop = ohci_stop,
.stop = ohci_omap_stop,
.shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@ -429,6 +466,7 @@ static const struct hc_driver ohci_omap_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@ -446,13 +484,8 @@ static int ohci_hcd_omap_drv_probe(struct platform_device *dev)
static int ohci_hcd_omap_drv_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
usb_hcd_omap_remove(hcd, dev);
if (ohci->transceiver) {
(void) otg_set_host(ohci->transceiver, 0);
put_device(ohci->transceiver->dev);
}
platform_set_drvdata(dev, NULL);
return 0;
@ -472,7 +505,7 @@ static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message)
omap_ohci_clock_power(0);
ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
dev->power.power_state = PMSG_SUSPEND;
dev->dev.power.power_state = PMSG_SUSPEND;
return 0;
}
@ -485,8 +518,8 @@ static int ohci_omap_resume(struct platform_device *dev)
ohci->next_statechange = jiffies;
omap_ohci_clock_power(1);
dev->power.power_state = PMSG_ON;
usb_hcd_resume_root_hub(dev_get_drvdata(dev));
dev->dev.power.power_state = PMSG_ON;
usb_hcd_resume_root_hub(platform_get_drvdata(dev));
return 0;
}
@ -500,6 +533,7 @@ static int ohci_omap_resume(struct platform_device *dev)
static struct platform_driver ohci_hcd_omap_driver = {
.probe = ohci_hcd_omap_drv_probe,
.remove = ohci_hcd_omap_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_omap_suspend,
.resume = ohci_omap_resume,

View File

@ -176,11 +176,14 @@ static const struct hc_driver ohci_pci_hc_driver = {
*/
.reset = ohci_pci_reset,
.start = ohci_pci_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
#ifdef CONFIG_PM
/* these suspend/resume entries are for upstream PCI glue ONLY */
.suspend = ohci_pci_suspend,
.resume = ohci_pci_resume,
#endif
.stop = ohci_stop,
/*
* managing i/o requests and associated device resources
@ -199,6 +202,7 @@ static const struct hc_driver ohci_pci_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@ -229,6 +233,8 @@ static struct pci_driver ohci_pci_driver = {
.suspend = usb_hcd_pci_suspend,
.resume = usb_hcd_pci_resume,
#endif
.shutdown = usb_hcd_pci_shutdown,
};

View File

@ -0,0 +1,476 @@
/*
* drivers/usb/host/ohci-pnx4008.c
*
* driver for Philips PNX4008 USB Host
*
* Authors: Dmitry Chigirev <source@mvista.com>
* Vitaly Wool <vitalywool@gmail.com>
*
* register initialization is based on code examples provided by Philips
* Copyright (c) 2005 Koninklijke Philips Electronics N.V.
*
* NOTE: This driver does not have suspend/resume functionality
* This driver is intended for engineering development purposes only
*
* 2005-2006 (c) MontaVista Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/mach-types.h>
#include <asm/arch/platform.h>
#include <asm/arch/irqs.h>
#include <asm/arch/gpio.h>
#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64)
/* USB_CTRL bit defines */
#define USB_SLAVE_HCLK_EN (1 << 24)
#define USB_HOST_NEED_CLK_EN (1 << 21)
#define USB_OTG_CLK_CTRL IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF4)
#define USB_OTG_CLK_STAT IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF8)
/* USB_OTG_CLK_CTRL bit defines */
#define AHB_M_CLOCK_ON (1 << 4)
#define OTG_CLOCK_ON (1 << 3)
#define I2C_CLOCK_ON (1 << 2)
#define DEV_CLOCK_ON (1 << 1)
#define HOST_CLOCK_ON (1 << 0)
#define USB_OTG_STAT_CONTROL IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0x110)
/* USB_OTG_STAT_CONTROL bit defines */
#define TRANSPARENT_I2C_EN (1 << 7)
#define HOST_EN (1 << 0)
/* ISP1301 USB transceiver I2C registers */
#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */
#define MC1_SPEED_REG (1 << 0)
#define MC1_SUSPEND_REG (1 << 1)
#define MC1_DAT_SE0 (1 << 2)
#define MC1_TRANSPARENT (1 << 3)
#define MC1_BDIS_ACON_EN (1 << 4)
#define MC1_OE_INT_EN (1 << 5)
#define MC1_UART_EN (1 << 6)
#define MC1_MASK 0x7f
#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */
#define MC2_GLOBAL_PWR_DN (1 << 0)
#define MC2_SPD_SUSP_CTRL (1 << 1)
#define MC2_BI_DI (1 << 2)
#define MC2_TRANSP_BDIR0 (1 << 3)
#define MC2_TRANSP_BDIR1 (1 << 4)
#define MC2_AUDIO_EN (1 << 5)
#define MC2_PSW_EN (1 << 6)
#define MC2_EN2V7 (1 << 7)
#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */
# define OTG1_DP_PULLUP (1 << 0)
# define OTG1_DM_PULLUP (1 << 1)
# define OTG1_DP_PULLDOWN (1 << 2)
# define OTG1_DM_PULLDOWN (1 << 3)
# define OTG1_ID_PULLDOWN (1 << 4)
# define OTG1_VBUS_DRV (1 << 5)
# define OTG1_VBUS_DISCHRG (1 << 6)
# define OTG1_VBUS_CHRG (1 << 7)
#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */
# define OTG_B_SESS_END (1 << 6)
# define OTG_B_SESS_VLD (1 << 7)
#define ISP1301_I2C_ADDR 0x2C
#define ISP1301_I2C_MODE_CONTROL_1 0x4
#define ISP1301_I2C_MODE_CONTROL_2 0x12
#define ISP1301_I2C_OTG_CONTROL_1 0x6
#define ISP1301_I2C_OTG_CONTROL_2 0x10
#define ISP1301_I2C_INTERRUPT_SOURCE 0x8
#define ISP1301_I2C_INTERRUPT_LATCH 0xA
#define ISP1301_I2C_INTERRUPT_FALLING 0xC
#define ISP1301_I2C_INTERRUPT_RISING 0xE
#define ISP1301_I2C_REG_CLEAR_ADDR 1
struct i2c_driver isp1301_driver;
struct i2c_client *isp1301_i2c_client;
extern int usb_disabled(void);
extern int ocpi_enable(void);
static struct clk *usb_clk;
static int isp1301_probe(struct i2c_adapter *adap);
static int isp1301_detach(struct i2c_client *client);
static int isp1301_command(struct i2c_client *client, unsigned int cmd,
void *arg);
static unsigned short normal_i2c[] =
{ ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
static unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
.probe = dummy_i2c_addrlist,
.ignore = dummy_i2c_addrlist,
};
struct i2c_driver isp1301_driver = {
.id = I2C_DRIVERID_I2CDEV, /* Fake Id */
.class = I2C_CLASS_HWMON,
.attach_adapter = isp1301_probe,
.detach_client = isp1301_detach,
.command = isp1301_command
};
static int isp1301_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct i2c_client *c;
c = (struct i2c_client *)kzalloc(sizeof(*c), SLAB_KERNEL);
if (!c)
return -ENOMEM;
strcpy(c->name, "isp1301");
c->flags = 0;
c->addr = addr;
c->adapter = adap;
c->driver = &isp1301_driver;
isp1301_i2c_client = c;
return i2c_attach_client(c);
}
static int isp1301_probe(struct i2c_adapter *adap)
{
return i2c_probe(adap, &addr_data, isp1301_attach);
}
static int isp1301_detach(struct i2c_client *client)
{
i2c_detach_client(client);
kfree(isp1301_i2c_client);
return 0;
}
/* No commands defined */
static int isp1301_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
return 0;
}
static void i2c_write(u8 buf, u8 subaddr)
{
char tmpbuf[2];
tmpbuf[0] = subaddr; /*register number */
tmpbuf[1] = buf; /*register data */
i2c_master_send(isp1301_i2c_client, &tmpbuf[0], 2);
}
static void isp1301_configure(void)
{
/* PNX4008 only supports DAT_SE0 USB mode */
/* PNX4008 R2A requires setting the MAX603 to output 3.6V */
/* Power up externel charge-pump */
i2c_write(MC1_DAT_SE0 | MC1_SPEED_REG, ISP1301_I2C_MODE_CONTROL_1);
i2c_write(~(MC1_DAT_SE0 | MC1_SPEED_REG),
ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
i2c_write(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL,
ISP1301_I2C_MODE_CONTROL_2);
i2c_write(~(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL),
ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR);
i2c_write(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN,
ISP1301_I2C_OTG_CONTROL_1);
i2c_write(~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN),
ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
i2c_write(0xFF,
ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR);
i2c_write(0xFF,
ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR);
i2c_write(0xFF,
ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR);
}
static inline void isp1301_vbus_on(void)
{
i2c_write(OTG1_VBUS_DRV, ISP1301_I2C_OTG_CONTROL_1);
}
static inline void isp1301_vbus_off(void)
{
i2c_write(OTG1_VBUS_DRV,
ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
}
static void pnx4008_start_hc(void)
{
unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN;
__raw_writel(tmp, USB_OTG_STAT_CONTROL);
isp1301_vbus_on();
}
static void pnx4008_stop_hc(void)
{
unsigned long tmp;
isp1301_vbus_off();
tmp = __raw_readl(USB_OTG_STAT_CONTROL) & ~HOST_EN;
__raw_writel(tmp, USB_OTG_STAT_CONTROL);
}
static int __devinit ohci_pnx4008_start(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int ret;
if ((ret = ohci_init(ohci)) < 0)
return ret;
if ((ret = ohci_run(ohci)) < 0) {
dev_err(hcd->self.controller, "can't start\n");
ohci_stop(hcd);
return ret;
}
return 0;
}
static const struct hc_driver ohci_pnx4008_hc_driver = {
.description = hcd_name,
.product_desc = "pnx4008 OHCI",
/*
* generic hardware linkage
*/
.irq = ohci_irq,
.flags = HCD_USB11 | HCD_MEMORY,
.hcd_priv_size = sizeof(struct ohci_hcd),
/*
* basic lifecycle operations
*/
.start = ohci_pnx4008_start,
.stop = ohci_stop,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,
/*
* scheduling support
*/
.get_frame_number = ohci_get_frame,
/*
* root hub support
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.start_port_reset = ohci_start_port_reset,
};
#define USB_CLOCK_MASK (AHB_M_CLOCK_ON| OTG_CLOCK_ON | HOST_CLOCK_ON | I2C_CLOCK_ON)
static void pnx4008_set_usb_bits(void)
{
start_int_set_falling_edge(SE_USB_OTG_ATX_INT_N);
start_int_ack(SE_USB_OTG_ATX_INT_N);
start_int_umask(SE_USB_OTG_ATX_INT_N);
start_int_set_rising_edge(SE_USB_OTG_TIMER_INT);
start_int_ack(SE_USB_OTG_TIMER_INT);
start_int_umask(SE_USB_OTG_TIMER_INT);
start_int_set_rising_edge(SE_USB_I2C_INT);
start_int_ack(SE_USB_I2C_INT);
start_int_umask(SE_USB_I2C_INT);
start_int_set_rising_edge(SE_USB_INT);
start_int_ack(SE_USB_INT);
start_int_umask(SE_USB_INT);
start_int_set_rising_edge(SE_USB_NEED_CLK_INT);
start_int_ack(SE_USB_NEED_CLK_INT);
start_int_umask(SE_USB_NEED_CLK_INT);
start_int_set_rising_edge(SE_USB_AHB_NEED_CLK_INT);
start_int_ack(SE_USB_AHB_NEED_CLK_INT);
start_int_umask(SE_USB_AHB_NEED_CLK_INT);
}
static void pnx4008_unset_usb_bits(void)
{
start_int_mask(SE_USB_OTG_ATX_INT_N);
start_int_mask(SE_USB_OTG_TIMER_INT);
start_int_mask(SE_USB_I2C_INT);
start_int_mask(SE_USB_INT);
start_int_mask(SE_USB_NEED_CLK_INT);
start_int_mask(SE_USB_AHB_NEED_CLK_INT);
}
static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd = 0;
struct ohci_hcd *ohci;
const struct hc_driver *driver = &ohci_pnx4008_hc_driver;
int ret = 0, irq;
dev_dbg(&pdev->dev, "%s: " DRIVER_INFO " (pnx4008)\n", hcd_name);
if (usb_disabled()) {
err("USB is disabled");
ret = -ENODEV;
goto out;
}
if (pdev->num_resources != 2
|| pdev->resource[0].flags != IORESOURCE_MEM
|| pdev->resource[1].flags != IORESOURCE_IRQ) {
err("Invalid resource configuration");
ret = -ENODEV;
goto out;
}
/* Enable AHB slave USB clock, needed for further USB clock control */
__raw_writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
ret = i2c_add_driver(&isp1301_driver);
if (ret < 0) {
err("failed to connect I2C to ISP1301 USB Transceiver");
goto out;
}
isp1301_configure();
/* Enable USB PLL */
usb_clk = clk_get(&pdev->dev, "ck_pll5");
if (IS_ERR(usb_clk)) {
err("failed to acquire USB PLL");
ret = PTR_ERR(usb_clk);
goto out1;
}
ret = clk_enable(usb_clk);
if (ret < 0) {
err("failed to start USB PLL");
goto out2;
}
ret = clk_set_rate(usb_clk, 48000);
if (ret < 0) {
err("failed to set USB clock rate");
goto out3;
}
__raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
/* Set to enable all needed USB clocks */
__raw_writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL);
while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) !=
USB_CLOCK_MASK) ;
hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
if (!hcd) {
err("Failed to allocate HC buffer");
ret = -ENOMEM;
goto out3;
}
/* Set all USB bits in the Start Enable register */
pnx4008_set_usb_bits();
hcd->rsrc_start = pdev->resource[0].start;
hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
dev_dbg(&pdev->dev, "request_mem_region failed\n");
ret = -ENOMEM;
goto out4;
}
hcd->regs = (void __iomem *)pdev->resource[0].start;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = -ENXIO;
goto out4;
}
hcd->self.hcpriv = (void *)hcd;
pnx4008_start_hc();
platform_set_drvdata(pdev, hcd);
ohci = hcd_to_ohci(hcd);
ohci_hcd_init(ohci);
dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq);
ret = usb_add_hcd(hcd, irq, SA_INTERRUPT);
if (ret == 0)
return ret;
pnx4008_stop_hc();
out4:
pnx4008_unset_usb_bits();
usb_put_hcd(hcd);
out3:
clk_disable(usb_clk);
out2:
clk_put(usb_clk);
out1:
i2c_del_driver(&isp1301_driver);
out:
return ret;
}
static int usb_hcd_pnx4008_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_remove_hcd(hcd);
pnx4008_stop_hc();
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
pnx4008_unset_usb_bits();
clk_disable(usb_clk);
clk_put(usb_clk);
i2c_del_driver(&isp1301_driver);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver usb_hcd_pnx4008_driver = {
.driver = {
.name = "usb-ohci",
},
.probe = usb_hcd_pnx4008_probe,
.remove = usb_hcd_pnx4008_remove,
};
static int __init usb_hcd_pnx4008_init(void)
{
return platform_driver_register(&usb_hcd_pnx4008_driver);
}
static void __exit usb_hcd_pnx4008_cleanup(void)
{
return platform_driver_unregister(&usb_hcd_pnx4008_driver);
}
module_init(usb_hcd_pnx4008_init);
module_exit(usb_hcd_pnx4008_cleanup);

View File

@ -148,6 +148,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
*/
.start = ohci_ppc_soc_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@ -166,6 +167,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@ -195,6 +197,7 @@ static int ohci_hcd_ppc_soc_drv_remove(struct platform_device *pdev)
static struct platform_driver ohci_hcd_ppc_soc_driver = {
.probe = ohci_hcd_ppc_soc_drv_probe,
.remove = ohci_hcd_ppc_soc_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
/*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
/*.resume = ohci_hcd_ppc_soc_drv_resume,*/

View File

@ -270,6 +270,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
*/
.start = ohci_pxa27x_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@ -288,6 +289,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@ -357,6 +359,7 @@ static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev)
static struct platform_driver ohci_hcd_pxa27x_driver = {
.probe = ohci_hcd_pxa27x_drv_probe,
.remove = ohci_hcd_pxa27x_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_hcd_pxa27x_drv_suspend,
.resume = ohci_hcd_pxa27x_drv_resume,

View File

@ -370,7 +370,7 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
goto err_mem;
}
usb_clk = clk_get(&dev->dev, "upll");
usb_clk = clk_get(&dev->dev, "usb-bus-host");
if (IS_ERR(usb_clk)) {
dev_err(&dev->dev, "cannot get usb-host clock\n");
retval = -ENOENT;
@ -447,6 +447,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
*/
.start = ohci_s3c2410_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@ -465,6 +466,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
*/
.hub_status_data = ohci_s3c2410_hub_status_data,
.hub_control = ohci_s3c2410_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@ -490,6 +492,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
static struct platform_driver ohci_hcd_s3c2410_driver = {
.probe = ohci_hcd_s3c2410_drv_probe,
.remove = ohci_hcd_s3c2410_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_s3c2410_drv_suspend, */
/*.resume = ohci_hcd_s3c2410_drv_resume, */
.driver = {

View File

@ -212,10 +212,6 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
* basic lifecycle operations
*/
.start = ohci_sa1111_start,
#ifdef CONFIG_PM
/* suspend: ohci_sa1111_suspend, -- tbd */
/* resume: ohci_sa1111_resume, -- tbd */
#endif
.stop = ohci_stop,
/*
@ -235,6 +231,7 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,

View File

@ -159,7 +159,7 @@ static const int cc_to_error [16] = {
/* Bit Stuff */ -EPROTO,
/* Data Togg */ -EILSEQ,
/* Stall */ -EPIPE,
/* DevNotResp */ -ETIMEDOUT,
/* DevNotResp */ -ETIME,
/* PIDCheck */ -EPROTO,
/* UnExpPID */ -EPROTO,
/* DataOver */ -EOVERFLOW,
@ -389,8 +389,6 @@ struct ohci_hcd {
unsigned long next_statechange; /* suspend/resume */
u32 fminterval; /* saved register */
struct notifier_block reboot_notifier;
unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */

View File

@ -597,7 +597,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs)
/* error? retry, until "3 strikes" */
} else if (++ep->error_count >= 3) {
if (status & SL11H_STATMASK_TMOUT)
urbstat = -ETIMEDOUT;
urbstat = -ETIME;
else if (status & SL11H_STATMASK_OVF)
urbstat = -EOVERFLOW;
else
@ -1517,7 +1517,7 @@ static int proc_sl811h_open(struct inode *inode, struct file *file)
return single_open(file, proc_sl811h_show, PDE(inode)->data);
}
static struct file_operations proc_ops = {
static const struct file_operations proc_ops = {
.open = proc_sl811h_open,
.read = seq_read,
.llseek = seq_lseek,

3295
drivers/usb/host/u132-hcd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@
#include "uhci-hcd.h"
#define uhci_debug_operations (* (struct file_operations *) NULL)
#define uhci_debug_operations (* (const struct file_operations *) NULL)
static struct dentry *uhci_debugfs_root;
#ifdef DEBUG
@ -500,7 +500,7 @@ static int uhci_debug_release(struct inode *inode, struct file *file)
}
#undef uhci_debug_operations
static struct file_operations uhci_debug_operations = {
static const struct file_operations uhci_debug_operations = {
.owner = THIS_MODULE,
.open = uhci_debug_open,
.llseek = uhci_debug_lseek,

View File

@ -84,6 +84,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
unsigned long port_addr)
{
int status;
int i;
if (inw(port_addr) & (USBPORTSC_SUSP | USBPORTSC_RD)) {
CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD);
@ -92,9 +93,14 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
/* The controller won't actually turn off the RD bit until
* it has had a chance to send a low-speed EOP sequence,
* which takes 3 bit times (= 2 microseconds). We'll delay
* slightly longer for good luck. */
udelay(4);
* which is supposed to take 3 bit times (= 2 microseconds).
* Experiments show that some controllers take longer, so
* we'll poll for completion. */
for (i = 0; i < 10; ++i) {
if (!(inw(port_addr) & USBPORTSC_RD))
break;
udelay(1);
}
}
clear_bit(port, &uhci->resuming_ports);
}

View File

@ -424,7 +424,7 @@ static void mdc800_usb_download_notify (struct urb *urb, struct pt_regs *res)
***************************************************************************/
static struct usb_driver mdc800_usb_driver;
static struct file_operations mdc800_device_ops;
static const struct file_operations mdc800_device_ops;
static struct usb_class_driver mdc800_class = {
.name = "mdc800%d",
.fops = &mdc800_device_ops,
@ -941,7 +941,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
****************************************************************************/
/* File Operations of this drivers */
static struct file_operations mdc800_device_ops =
static const struct file_operations mdc800_device_ops =
{
.owner = THIS_MODULE,
.read = mdc800_device_read,

View File

@ -205,10 +205,12 @@ config USB_TOUCHSCREEN
depends on USB && INPUT
---help---
USB Touchscreen driver for:
- eGalax Touchkit USB
- eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700)
- PanJit TouchSet USB
- 3M MicroTouch USB
- 3M MicroTouch USB (EX II series)
- ITM
- some other eTurboTouch
- Gunze AHL61
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
@ -218,7 +220,7 @@ config USB_TOUCHSCREEN
config USB_TOUCHSCREEN_EGALAX
default y
bool "eGalax device support" if EMBEDDED
bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
depends on USB_TOUCHSCREEN
config USB_TOUCHSCREEN_PANJIT
@ -228,7 +230,7 @@ config USB_TOUCHSCREEN_PANJIT
config USB_TOUCHSCREEN_3M
default y
bool "3M/Microtouch device support" if EMBEDDED
bool "3M/Microtouch EX II series device support" if EMBEDDED
depends on USB_TOUCHSCREEN
config USB_TOUCHSCREEN_ITM
@ -236,6 +238,16 @@ config USB_TOUCHSCREEN_ITM
bool "ITM device support" if EMBEDDED
depends on USB_TOUCHSCREEN
config USB_TOUCHSCREEN_ETURBO
default y
bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED
depends on USB_TOUCHSCREEN
config USB_TOUCHSCREEN_GUNZE
default y
bool "Gunze AHL61 device support" if EMBEDDED
depends on USB_TOUCHSCREEN
config USB_YEALINK
tristate "Yealink usb-p1k voip phone"
depends on USB && INPUT && EXPERIMENTAL
@ -326,3 +338,13 @@ config USB_APPLETOUCH
To compile this driver as a module, choose M here: the
module will be called appletouch.
config USB_TRANCEVIBRATOR
tristate "PlayStation 2 Trance Vibrator driver support"
depends on USB
help
Say Y here if you want to connect a PlayStation 2 Trance Vibrator
device to your computer's USB port.
To compile this driver as a module, choose M here: the
module will be called trancevibrator.

View File

@ -3,6 +3,7 @@
#
# Multipart objects.
wacom-objs := wacom_sys.o wacom_wac.o
usbhid-objs := hid-core.o
# Optional parts of multipart objects.
@ -44,6 +45,7 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o
obj-$(CONFIG_USB_YEALINK) += yealink.o
obj-$(CONFIG_USB_XPAD) += xpad.o
obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o
obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG

View File

@ -141,10 +141,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
endpoint = &interface->endpoint[0].desc;
if (!(endpoint->bEndpointAddress & 0x80))
return -ENODEV;
if ((endpoint->bmAttributes & 3) != 3)
if (!usb_endpoint_is_int_in(endpoint))
return -ENODEV;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);

View File

@ -436,10 +436,7 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
iface_desc = iface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
endpoint = &iface_desc->endpoint[i].desc;
if (!int_in_endpointAddr &&
(endpoint->bEndpointAddress & USB_DIR_IN) &&
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_INT)) {
if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) {
/* we found an interrupt in endpoint */
int_in_endpointAddr = endpoint->bEndpointAddress;
break;

View File

@ -732,12 +732,8 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
endpoint_in = &iface_host->endpoint[0].desc;
endpoint_out = &iface_host->endpoint[1].desc;
if (!(endpoint_in->bEndpointAddress & USB_DIR_IN)) {
err("%s: Unexpected endpoint_in->bEndpointAddress\n", __FUNCTION__);
return -ENODEV;
}
if ((endpoint_in->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
err("%s: Unexpected endpoint_in->bmAttributes\n", __FUNCTION__);
if (!usb_endpoint_is_int_in(endpoint_in)) {
err("%s: Unexpected endpoint_in\n", __FUNCTION__);
return -ENODEV;
}
if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {

View File

@ -1023,7 +1023,8 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs)
return;
case -EILSEQ: /* protocol error or unplug */
case -EPROTO: /* protocol error or unplug */
case -ETIMEDOUT: /* NAK */
case -ETIME: /* protocol error or unplug */
case -ETIMEDOUT: /* Should never happen, but... */
clear_bit(HID_IN_RUNNING, &hid->iofl);
hid_io_error(hid);
return;
@ -1535,13 +1536,17 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_GLAB 0x06c2
#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039
#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045
#define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040
#define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044
#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045
#define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051
#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053
#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058
#define USB_VENDOR_ID_WISEGROUP 0x0925
#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
#define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201
#define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866
#define USB_VENDOR_ID_WISEGROUP_LTD 0x6677
@ -1591,6 +1596,10 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_YEALINK 0x6993
#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
#define USB_VENDOR_ID_ALCOR 0x058f
#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720
/*
* Alphabetically sorted blacklist by quirk type.
*/
@ -1608,6 +1617,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
@ -1620,9 +1630,12 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE },
@ -1690,7 +1703,11 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
@ -1701,6 +1718,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },

View File

@ -722,7 +722,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return -EINVAL;
}
static struct file_operations hiddev_fops = {
static const struct file_operations hiddev_fops = {
.owner = THIS_MODULE,
.read = hiddev_read,
.write = hiddev_write,

View File

@ -87,7 +87,7 @@ static void itmtouch_irq(struct urb *urb, struct pt_regs *regs)
case 0:
/* success */
break;
case -ETIMEDOUT:
case -ETIME:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__);

View File

@ -420,8 +420,7 @@ static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_i
for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
endpoint = &iface->endpoint[i].desc;
if ((endpoint->bEndpointAddress & USB_DIR_IN) &&
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
if (usb_endpoint_is_int_in(endpoint)) {
/* we found our interrupt in endpoint */
return endpoint;
}

View File

@ -107,7 +107,7 @@ static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
case 0:
/* success */
break;
case -ETIMEDOUT:
case -ETIME:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__);

View File

@ -313,9 +313,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
if (!(endpoint->bEndpointAddress & 0x80))
return -EIO;
if ((endpoint->bmAttributes & 3) != 3)
if (!usb_endpoint_is_int_in(endpoint))
return -EIO;
usb_control_msg(udev, usb_sndctrlpipe(udev, 0),

Some files were not shown because too many files have changed in this diff Show More