forked from luck/tmp_suning_uos_patched
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:
commit
1f9bd4c96a
@ -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(&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>
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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}
|
||||
};
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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 }
|
||||
};
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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 *
|
||||
****************************************************************************/
|
||||
|
@ -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++;
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
@ -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)
|
||||
|
@ -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
208
drivers/usb/core/generic.c
Normal 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,
|
||||
};
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
1337
drivers/usb/gadget/gmidi.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
@ -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",
|
||||
},
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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) */,
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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, ®s->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, ®s->intrdisable);
|
||||
hcd->poll_rh = 1;
|
||||
ohci->next_statechange = jiffies + STATECHANGE_DELAY;
|
||||
ohci_writel (ohci, OHCI_INTR_RHSC, ®s->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
|
||||
|
@ -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);
|
||||
|
@ -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 = {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
||||
|
476
drivers/usb/host/ohci-pnx4008.c
Normal file
476
drivers/usb/host/ohci-pnx4008.c
Normal 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);
|
@ -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,*/
|
||||
|
@ -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,
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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
3295
drivers/usb/host/u132-hcd.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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 },
|
||||
|
@ -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,
|
||||
|
@ -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__);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__);
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user