Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
6c7a3c95
Commit
6c7a3c95
authored
Apr 06, 2003
by
Greg Kroah-Hartman
Browse files
Options
Browse Files
Download
Plain Diff
Merge kroah.com:/home/greg/linux/BK/bleed-2.5
into kroah.com:/home/greg/linux/BK/gregkh-2.5
parents
80d316b7
3fe52eb6
Changes
37
Hide whitespace changes
Inline
Side-by-side
Showing
37 changed files
with
1815 additions
and
549 deletions
+1815
-549
Documentation/DocBook/usb.tmpl
Documentation/DocBook/usb.tmpl
+680
-1
arch/i386/kernel/edd.c
arch/i386/kernel/edd.c
+1
-1
drivers/acpi/bus.c
drivers/acpi/bus.c
+1
-1
drivers/base/base.h
drivers/base/base.h
+0
-5
drivers/base/bus.c
drivers/base/bus.c
+1
-1
drivers/base/class.c
drivers/base/class.c
+3
-1
drivers/base/core.c
drivers/base/core.c
+46
-9
drivers/base/firmware.c
drivers/base/firmware.c
+1
-1
drivers/base/hotplug.c
drivers/base/hotplug.c
+2
-30
drivers/block/genhd.c
drivers/block/genhd.c
+13
-1
drivers/hotplug/pci_hotplug_core.c
drivers/hotplug/pci_hotplug_core.c
+1
-1
drivers/usb/class/usb-midi.c
drivers/usb/class/usb-midi.c
+0
-31
drivers/usb/core/hub.c
drivers/usb/core/hub.c
+16
-1
drivers/usb/core/message.c
drivers/usb/core/message.c
+2
-0
drivers/usb/core/usb.c
drivers/usb/core/usb.c
+0
-34
drivers/usb/host/ehci-mem.c
drivers/usb/host/ehci-mem.c
+1
-0
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-q.c
+7
-6
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-hcd.c
+8
-0
drivers/usb/host/ohci-q.c
drivers/usb/host/ohci-q.c
+2
-0
drivers/usb/input/hid-core.c
drivers/usb/input/hid-core.c
+3
-0
drivers/usb/input/kbtab.c
drivers/usb/input/kbtab.c
+1
-1
drivers/usb/input/usbkbd.c
drivers/usb/input/usbkbd.c
+3
-0
drivers/usb/input/usbmouse.c
drivers/usb/input/usbmouse.c
+3
-0
drivers/usb/misc/speedtch.c
drivers/usb/misc/speedtch.c
+18
-8
drivers/usb/net/pegasus.c
drivers/usb/net/pegasus.c
+9
-9
drivers/usb/net/pegasus.h
drivers/usb/net/pegasus.h
+2
-0
drivers/usb/net/usbnet.c
drivers/usb/net/usbnet.c
+566
-199
drivers/usb/serial/keyspan.h
drivers/usb/serial/keyspan.h
+13
-13
drivers/usb/storage/scsiglue.c
drivers/usb/storage/scsiglue.c
+35
-5
drivers/usb/storage/transport.c
drivers/usb/storage/transport.c
+24
-6
drivers/usb/storage/transport.h
drivers/usb/storage/transport.h
+1
-1
drivers/usb/storage/usb.c
drivers/usb/storage/usb.c
+166
-171
fs/filesystems.c
fs/filesystems.c
+1
-1
fs/partitions/check.c
fs/partitions/check.c
+1
-1
include/linux/kobject.h
include/linux/kobject.h
+21
-1
lib/kobject.c
lib/kobject.c
+162
-8
net/core/dev.c
net/core/dev.c
+1
-1
No files found.
Documentation/DocBook/usb.tmpl
View file @
6c7a3c95
...
...
@@ -100,7 +100,8 @@
<chapter
id=
"host"
>
<title>
USB Host-Side API Model
</title>
<para>
Host-side drivers for USB devices talk to the "usbcore" APIs.
<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
...
...
@@ -289,6 +290,684 @@
!Edrivers/usb/core/buffer.c
</chapter>
<chapter>
<title>
The USB Filesystem (usbfs)
</title>
<para>
This chapter presents the Linux
<emphasis>
usbfs
</emphasis>
.
You may prefer to avoid avoid writing new kernel code for your
USB driver; that's the problem that usbfs set out to solve.
User mode device drivers are usually packaged as applications
or libraries, and may use usbfs through some programming library
that wraps it. Such libraries include
<ulink
url=
"http://libusb.sourceforge.net"
>
libusb
</ulink>
for C/C++, and
<ulink
url=
"http://jUSB.sourceforge.net"
>
jUSB
</ulink>
for Java.
</para>
<note><title>
Unfinished
</title>
<para>
This particular documentation is incomplete,
especially with respect to the asynchronous mode.
As of kernel 2.5.66 the code and this (new) documentation
need to be cross-reviewed.
</para>
</note>
<para>
Configure usbfs into Linux kernels by enabling the
<emphasis>
USB filesystem
</emphasis>
option (CONFIG_USB_DEVICEFS),
and you get basic support for user mode USB device drivers.
Until relatively recently it was often (confusingly) called
<emphasis>
usbdevfs
</emphasis>
although it wasn't solving what
<emphasis>
devfs
</emphasis>
was.
Every USB device will appear in usbfs, regardless of whether or
not it has a kernel driver; but only devices with kernel drivers
show up in devfs.
</para>
<sect1>
<title>
What files are in "usbfs"?
</title>
<para>
Conventionally mounted at
<filename>
/proc/bus/usb
</filename>
, usbfs
features include:
<itemizedlist>
<listitem><para><filename>
/proc/bus/usb/devices
</filename>
... a text file
showing each of the USB devices on known to the kernel,
and their configuration descriptors.
You can also poll() this to learn about new devices.
</para></listitem>
<listitem><para><filename>
/proc/bus/usb/BBB/DDD
</filename>
... magic files
exposing the each device's configuration descriptors, and
supporting a series of ioctls for making device requests,
including I/O to devices. (Purely for access by programs.)
</para></listitem>
</itemizedlist>
</para>
<para>
Each bus is given a number (BBB) based on when it was
enumerated; within each bus, each device is given a similar
number (DDD).
Those BBB/DDD paths are not "stable" identifiers;
expect them to change even if you always leave the devices
plugged in to the same hub port.
<emphasis>
Don't even think of saving these in application
configuration files.
</emphasis>
Stable identifiers are available, for user mode applications
that want to use them. HID and networking devices expose
these IDs.
</para>
</sect1>
<sect1>
<title>
Mounting and Access Control
</title>
<para>
There are a number of mount options for usbfs, which will
be of most interest to you if you need to override the default
access control policy.
That policy is that only root may read or write device files
(
<filename>
/proc/bus/BBB/DDD
</filename>
) although anyone may read
the
<filename>
devices
</filename>
or
<filename>
drivers
</filename>
files.
I/O requests to the device also need the CAP_SYS_RAWIO capability,
</para>
<para>
The significance of that is that by default, all user mode
device drivers need super-user privileges.
You can change modes or ownership in a driver setup
when the device hotplugs, or maye just start the
driver right then, as a privileged server (or some activity
within one).
That's the most secure approach for multi-user systems,
but for single user systems ("trusted" by that user)
it's more convenient just to grant everyone all access
(using the
<emphasis>
devmode=0666
</emphasis>
option)
so the driver can start whenever it's needed.
</para>
<para>
The mount options for usbfs, usable in /etc/fstab or
in command line invocations of
<emphasis>
mount
</emphasis>
, are:
<variablelist>
<varlistentry>
<term><emphasis>
busgid
</emphasis>
=NNNNN
</term>
<listitem><para>
Controls the GID used for the
/proc/bus/usb/BBB
directories. (Default: 0)
</para></listitem></varlistentry>
<varlistentry><term><emphasis>
busmode
</emphasis>
=MMM
</term>
<listitem><para>
Controls the file mode used for the
/proc/bus/usb/BBB
directories. (Default: 0555)
</para></listitem></varlistentry>
<varlistentry><term><emphasis>
busuid
</emphasis>
=NNNNN
</term>
<listitem><para>
Controls the UID used for the
/proc/bus/usb/BBB
directories. (Default: 0)
</para></listitem></varlistentry>
<varlistentry><term><emphasis>
devgid
</emphasis>
=NNNNN
</term>
<listitem><para>
Controls the GID used for the
/proc/bus/usb/BBB/DDD
files. (Default: 0)
</para></listitem></varlistentry>
<varlistentry><term><emphasis>
devmode
</emphasis>
=MMM
</term>
<listitem><para>
Controls the file mode used for the
/proc/bus/usb/BBB/DDD
files. (Default: 0644)
</para></listitem></varlistentry>
<varlistentry><term><emphasis>
devuid
</emphasis>
=NNNNN
</term>
<listitem><para>
Controls the UID used for the
/proc/bus/usb/BBB/DDD
files. (Default: 0)
</para></listitem></varlistentry>
<varlistentry><term><emphasis>
listgid
</emphasis>
=NNNNN
</term>
<listitem><para>
Controls the GID used for the
/proc/bus/usb/devices and drivers files.
(Default: 0)
</para></listitem></varlistentry>
<varlistentry><term><emphasis>
listmode
</emphasis>
=MMM
</term>
<listitem><para>
Controls the file mode used for the
/proc/bus/usb/devices and drivers files.
(Default: 0444)
</para></listitem></varlistentry>
<varlistentry><term><emphasis>
listuid
</emphasis>
=NNNNN
</term>
<listitem><para>
Controls the UID used for the
/proc/bus/usb/devices and drivers files.
(Default: 0)
</para></listitem></varlistentry>
</variablelist>
</para>
<para>
Note that many Linux distributions hard-wire the mount options
for usbfs in their init scripts, such as
<filename>
/etc/rc.d/rc.sysinit
</filename>
,
rather than making it easy to set this per-system
policy in
<filename>
/etc/fstab
</filename>
.
</para>
</sect1>
<sect1>
<title>
/proc/bus/usb/devices
</title>
<para>
This file is handy for status viewing tools in user
mode, which can scan the text format and ignore most of it.
More detailed device status (including class and vendor
status) is available from device-specific files.
For information about the current format of this file,
see the
<filename>
Documentation/usb/proc_usb_info.txt
</filename>
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>
</sect1>
<sect1>
<title>
/proc/bus/usb/BBB/DDD
</title>
<para>
Use these files in one of these basic ways:
</para>
<para><emphasis>
They can be read,
</emphasis>
producing first the device descriptor
(18 bytes) and then the descriptors for the current configuration.
See the USB 2.0 spec for details about those binary data formats.
You'll need to convert most multibyte values from little endian
format to your native host byte order, although a few of the
fields in the device descriptor (both of the BCD-encoded fields,
and the vendor and product IDs) will be byteswapped for you.
Note that configuration descriptors include descriptors for
interfaces, altsettings, endpoints, and maybe additional
class descriptors.
</para>
<para><emphasis>
Perform USB operations
</emphasis>
using
<emphasis>
ioctl()
</emphasis>
requests to make endpoint I/O
requests (synchronously or asynchronously) or manage
the device.
These requests need the CAP_SYS_RAWIO capability,
as well as filesystem access permissions.
Only one ioctl request can be made on one of these
device files at a time.
This means that if you are synchronously reading an endpoint
from one thread, you won't be able to write to a different
endpoint from another thread until the read completes.
This works for
<emphasis>
half duplex
</emphasis>
protocols,
but otherwise you'd use asynchronous i/o requests.
</para>
</sect1>
<sect1>
<title>
Life Cycle of User Mode Drivers
</title>
<para>
Such a driver first needs to find a device file
for a device it knows how to handle.
Maybe it was told about it because a
<filename>
/sbin/hotplug
</filename>
event handling agent
chose that driver to handle the new device.
Or maybe it's an application that scans all the
/proc/bus/usb device files, and ignores most devices.
In either case, it should
<function>
read()
</function>
all
the descriptors from the device file,
and check them against what it knows how to handle.
It might just reject everything except a particular
vendor and product ID, or need a more complex policy.
</para>
<para>
Never assume there will only be one such device
on the system at a time!
If your code can't handle more than one device at
a time, at least detect when there's more than one, and
have your users choose which device to use.
</para>
<para>
Once your user mode driver knows what device to use,
it interacts with it in either of two styles.
The simple style is to make only control requests; some
devices don't need more complex interactions than those.
(An example might be software using vendor-specific control
requests for some initialization or configuration tasks,
with a kernel driver for the rest.)
</para>
<para>
More likely, you need a more complex style driver:
one using non-control endpoints, reading or writing data
and claiming exclusive use of an interface.
<emphasis>
Bulk
</emphasis>
transfers are easiest to use,
but only their sibling
<emphasis>
interrupt
</emphasis>
transfers
work with low speed devices.
Both interrupt and
<emphasis>
isochronous
</emphasis>
transfers
offer service guarantees because their bandwidth is reserved.
Such "periodic" transfers are awkward to use through usbfs,
unless you're using the asynchronous calls. However, interrupt
transfers can also be used in a synchronous "one shot" style.
</para>
<para>
Your user-mode driver should never need to worry
about cleaning up request state when the device is
disconnected, although it should close its open file
descriptors as soon as it starts seeing the ENODEV
errors.
</para>
</sect1>
<sect1><title>
The ioctl() Requests
</title>
<para>
To use these ioctls, you need to include the following
headers in your userspace program:
<programlisting>
#include
<
linux/usb.h
>
#include
<
linux/usbdevice_fs.h
>
#include
<
asm/byteorder.h
>
</programlisting>
The standard USB device model requests, from "Chapter 9" of
the USB 2.0 specification, are automatically included from
the
<filename>
<
linux/usb_ch9.h
>
</filename>
header.
</para>
<para>
Unless noted otherwise, the ioctl requests
described here will
update the modification time on the usbfs file to which
they are applied (unless they fail).
A return of zero indicates success; otherwise, a
standard USB error code is returned. (These are
documented in
<filename>
Documentation/usb/error-codes.txt
</filename>
in your kernel sources.)
</para>
<para>
Each of these files multiplexes access to several
I/O streams, one per endpoint.
Each device has one control endpoint (endpoint zero)
which supports a limited RPC style RPC access.
Devices are configured
by khubd (in the kernel) setting a device-wide
<emphasis>
configuration
</emphasis>
that affects things
like power consumption and basic functionality.
The endpoints are part of USB
<emphasis>
interfaces
</emphasis>
,
which may have
<emphasis>
altsettings
</emphasis>
affecting things like which endpoints are available.
Many devices only have a single configuration and interface,
so drivers for them will ignore configurations and altsettings.
</para>
<sect2>
<title>
Management/Status Requests
</title>
<para>
A number of usbfs requests don't deal very directly
with device I/O.
They mostly relate to device management and status.
These are all synchronous requests.
</para>
<variablelist>
<varlistentry><term>
USBDEVFS_CLAIMINTERFACE
</term>
<listitem><para>
This is used to force usbfs to
claim a specific interface,
which has not previously been claimed by usbfs or any other
kernel driver.
The ioctl parameter is an integer holding the number of
the interface (bInterfaceNumber from descriptor).
</para><para>
Note that if your driver doesn't claim an interface
before trying to use one of its endpoints, and no
other driver has bound to it, then the interface is
automatically claimed by usbfs.
</para><para>
This claim will be released by a RELEASEINTERFACE ioctl,
or by closing the file descriptor.
File modification time is not updated by this request.
</para></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_CONNECTINFO
</term>
<listitem><para>
Says whether the device is lowspeed.
The ioctl parameter points to a structure like this:
<programlisting>
struct usbdevfs_connectinfo {
unsigned int devnum;
unsigned char slow;
};
</programlisting>
File modification time is not updated by this request.
</para><para>
<emphasis>
You can't tell whether a "not slow"
device is connected at high speed (480 MBit/sec)
or just full speed (12 MBit/sec).
</emphasis>
You should know the devnum value already,
it's the DDD value of the device file name.
</para></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_GETDRIVER
</term>
<listitem><para>
Returns the name of the kernel driver
bound to a given interface (a string). Parameter
is a pointer to this structure, which is modified:
<programlisting>
struct usbdevfs_getdriver {
unsigned int interface;
char driver[USBDEVFS_MAXDRIVERNAME + 1];
};
</programlisting>
File modification time is not updated by this request.
</para></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_IOCTL
</term>
<listitem><para>
Passes a request from userspace through
to a kernel driver that has an ioctl entry in the
<emphasis>
struct usb_driver
</emphasis>
it registered.
<programlisting>
struct usbdevfs_ioctl {
int ifno;
int ioctl_code;
void *data;
};
/* user mode call looks like this.
* 'request' becomes the driver->ioctl() 'code' parameter.
* the size of 'param' is encoded in 'request', and that data
* is copied to or from the driver->ioctl() 'buf' parameter.
*/
static int
usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
{
struct usbdevfs_ioctl wrapper;
wrapper.ifno = ifno;
wrapper.ioctl_code = request;
wrapper.data = param;
return ioctl (fd, USBDEVFS_IOCTL,
&
wrapper);
}
</programlisting>
File modification time is not updated by this request.
</para><para>
This request lets kernel drivers talk to user mode code
through filesystem operations even when they don't create
a charactor or block special device.
It's also been used to do things like ask devices what
device special file should be used.
Two pre-defined ioctls are used
to disconnect and reconnect kernel drivers, so
that user mode code can completely manage binding
and configuration of devices.
</para></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_RELEASEINTERFACE
</term>
<listitem><para>
This is used to release the claim usbfs
made on interface, either implicitly or because of a
USBDEVFS_CLAIMINTERFACE call, before the file
descriptor is closed.
The ioctl parameter is an integer holding the number of
the interface (bInterfaceNumber from descriptor);
File modification time is not updated by this request.
</para><warning><para>
<emphasis>
No security check is made to ensure
that the task which made the claim is the one
which is releasing it.
This means that user mode driver may interfere
other ones.
</emphasis>
</para></warning></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_RESETEP
</term>
<listitem><para>
Resets the data toggle value for an endpoint
(bulk or interrupt) to DATA0.
The ioctl parameter is an integer endpoint number
(1 to 15, as identified in the endpoint descriptor),
with USB_DIR_IN added if the device's endpoint sends
data to the host.
</para><warning><para>
<emphasis>
Avoid using this request.
It should probably be removed.
</emphasis>
Using it typically means the device and driver will lose
toggle synchronization. If you really lost synchronization,
you likely need to completely handshake with the device,
using a request like CLEAR_HALT
or SET_INTERFACE.
</para></warning></listitem></varlistentry>
</variablelist>
</sect2>
<sect2>
<title>
Synchronous I/O Support
</title>
<para>
Synchronous requests involve the kernel blocking
until until the user mode request completes, either by
finishing successfully or by reporting an error.
In most cases this is the simplest way to use usbfs,
although as noted above it does prevent performing I/O
to more than one endpoint at a time.
</para>
<variablelist>
<varlistentry><term>
USBDEVFS_BULK
</term>
<listitem><para>
Issues a bulk read or write request to the
device.
The ioctl parameter is a pointer to this structure:
<programlisting>
struct usbdevfs_bulktransfer {
unsigned int ep;
unsigned int len;
unsigned int timeout; /* in milliseconds */
void *data;
};
</programlisting>
</para><para>
The "ep" value identifies a
bulk endpoint number (1 to 15, as identified in an endpoint
descriptor),
masked with USB_DIR_IN when referring to an endpoint which
sends data to the host from the device.
The length of the data buffer is identified by "len";
Recent kernels support requests up to about 128KBytes.
<emphasis>
FIXME say how read length is returned,
and how short reads are handled.
</emphasis>
.
</para></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_CLEAR_HALT
</term>
<listitem><para>
Clears endpoint halt (stall) and
resets the endpoint toggle. This is only
meaningful for bulk or interrupt endpoints.
The ioctl parameter is an integer endpoint number
(1 to 15, as identified in an endpoint descriptor),
masked with USB_DIR_IN when referring to an endpoint which
sends data to the host from the device.
</para><para>
Use this on bulk or interrupt endpoints which have
stalled, returning
<emphasis>
-EPIPE
</emphasis>
status
to a data transfer request.
Do not issue the control request directly, since
that could invalidate the host's record of the
data toggle.
</para></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_CONTROL
</term>
<listitem><para>
Issues a control request to the device.
The ioctl parameter points to a structure like this:
<programlisting>
struct usbdevfs_ctrltransfer {
__u8 bRequestType;
__u8 bRequest;
__u16 wValue;
__u16 wIndex;
__u16 wLength;
__u32 timeout; /* in milliseconds */
void *data;
};
</programlisting>
</para><para>
The first eight bytes of this structure are the contents
of the SETUP packet to be sent to the device; see the
USB 2.0 specification for details.
The bRequestType value is composed by combining a
USB_TYPE_* value, a USB_DIR_* value, and a
USB_RECIP_* value (from
<emphasis>
<
linux/usb.h
>
</emphasis>
).
If wLength is nonzero, it describes the length of the data
buffer, which is either written to the device
(USB_DIR_OUT) or read from the device (USB_DIR_IN).
</para><para>
At this writing, you can't transfer more than 4 KBytes
of data to or from a device; usbfs has a limit, and
some host controller drivers have a limit.
(That's not usually a problem.)
<emphasis>
Also
</emphasis>
there's no way to say it's
not OK to get a short read back from the device.
</para></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_RESET
</term>
<listitem><para>
Does a USB level device reset.
The ioctl parameter is ignored.
After the reset, this rebinds all device interfaces.
File modification time is not updated by this request.
</para><warning><para>
<emphasis>
Avoid using this call
</emphasis>
until some usbcore bugs get fixed,
since it does not fully synchronize device, interface,
and driver (not just usbfs) state.
</para></warning></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_SETINTERFACE
</term>
<listitem><para>
Sets the alternate setting for an
interface. The ioctl parameter is a pointer to a
structure like this:
<programlisting>
struct usbdevfs_setinterface {
unsigned int interface;
unsigned int altsetting;
};
</programlisting>
File modification time is not updated by this request.
</para><para>
Those struct members are from some interface descriptor
applying to the the current configuration.
The interface number is the bInterfaceNumber value, and
the altsetting number is the bAlternateSetting value.
(This resets each endpoint in the interface.)
</para></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_SETCONFIGURATION
</term>
<listitem><para>
Issues the
<function>
usb_set_configuration
</function>
call
for the device.
The parameter is an integer holding the number of
a configuration (bConfigurationValue from descriptor).
File modification time is not updated by this request.
</para><warning><para>
<emphasis>
Avoid using this call
</emphasis>
until some usbcore bugs get fixed,
since it does not fully synchronize device, interface,
and driver (not just usbfs) state.
</para></warning></listitem></varlistentry>
</variablelist>
</sect2>
<sect2>
<title>
Asynchronous I/O Support
</title>
<para>
As mentioned above, there are situations where it may be
important to initiate concurrent operations from user mode code.
This is particularly important for periodic transfers
(interrupt and isochronous), but it can be used for other
kinds of USB requests too.
In such cases, the asynchronous requests described here
are essential. Rather than submitting one request and having
the kernel block until it completes, the blocking is separate.
</para>
<para>
These requests are packaged into a structure that
resembles the URB used by kernel device drivers.
(No POSIX Async I/O support here, sorry.)
It identifies the endpoint type (USBDEVFS_URB_TYPE_*),
endpoint (number, masked with USB_DIR_IN as appropriate),
buffer and length, and a user "context" value serving to
uniquely identify each request.
(It's usually a pointer to per-request data.)
Flags can modify requests (not as many as supported for
kernel drivers).
</para>
<para>
Each request can specify a realtime signal number
(between SIGRTMIN and SIGRTMAX, inclusive) to request a
signal be sent when the request completes.
</para>
<para>
When usbfs returns these urbs, the status value
is updated, and the buffer may have been modified.
Except for isochronous transfers, the actual_length is
updated to say how many bytes were transferred; if the
USBDEVFS_URB_DISABLE_SPD flag is set
("short packets are not OK"), if fewer bytes were read
than were requested then you get an error report.
</para>
<programlisting>
struct usbdevfs_iso_packet_desc {
unsigned int length;
unsigned int actual_length;
unsigned int status;
};
struct usbdevfs_urb {
unsigned char type;
unsigned char endpoint;
int status;
unsigned int flags;
void *buffer;
int buffer_length;
int actual_length;
int start_frame;
int number_of_packets;
int error_count;
unsigned int signr;
void *usercontext;
struct usbdevfs_iso_packet_desc iso_frame_desc[];
};
</programlisting>
<para>
For these asynchronous requests, the file modification
time reflects when the request was initiated.
This contrasts with their use with the synchronous requests,
where it reflects when requests complete.
</para>
<variablelist>
<varlistentry><term>
USBDEVFS_DISCARDURB
</term>
<listitem><para>
<emphasis>
TBS
</emphasis>
File modification time is not updated by this request.
</para><para>
</para></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_DISCSIGNAL
</term>
<listitem><para>
<emphasis>
TBS
</emphasis>
File modification time is not updated by this request.
</para><para>
</para></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_REAPURB
</term>
<listitem><para>
<emphasis>
TBS
</emphasis>
File modification time is not updated by this request.
</para><para>
</para></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_REAPURBNDELAY
</term>
<listitem><para>
<emphasis>
TBS
</emphasis>
File modification time is not updated by this request.
</para><para>
</para></listitem></varlistentry>
<varlistentry><term>
USBDEVFS_SUBMITURB
</term>
<listitem><para>
<emphasis>
TBS
</emphasis>
</para><para>
</para></listitem></varlistentry>
</variablelist>
</sect2>
</sect1>
</chapter>
</book>
<!-- vim:syntax=sgml:sw=4
-->
arch/i386/kernel/edd.c
View file @
6c7a3c95
...
...
@@ -598,7 +598,7 @@ static struct kobj_type ktype_edd = {
.
default_attrs
=
def_attrs
,
};
static
decl_subsys
(
edd
,
&
ktype_edd
);
static
decl_subsys
(
edd
,
&
ktype_edd
,
NULL
);
/**
...
...
drivers/acpi/bus.c
View file @
6c7a3c95
...
...
@@ -676,7 +676,7 @@ acpi_bus_init (void)
return_VALUE
(
-
ENODEV
);
}
decl_subsys
(
acpi
,
NULL
);
decl_subsys
(
acpi
,
NULL
,
NULL
);
static
int
__init
acpi_init
(
void
)
{
...
...
drivers/base/base.h
View file @
6c7a3c95
...
...
@@ -18,13 +18,8 @@ extern void interface_remove_dev(struct device *);
#ifdef CONFIG_HOTPLUG
extern
int
dev_hotplug
(
struct
device
*
dev
,
const
char
*
action
);
extern
int
class_hotplug
(
struct
device
*
dev
,
const
char
*
action
);
#else
static
inline
int
dev_hotplug
(
struct
device
*
dev
,
const
char
*
action
)
{
return
0
;
}
static
inline
int
class_hotplug
(
struct
device
*
dev
,
const
char
*
action
)
{
return
0
;
...
...
drivers/base/bus.c
View file @
6c7a3c95
...
...
@@ -132,7 +132,7 @@ static struct kobj_type ktype_bus = {
};
decl_subsys
(
bus
,
&
ktype_bus
);
decl_subsys
(
bus
,
&
ktype_bus
,
NULL
);
/**
* bus_for_each_dev - device iterator.
...
...
drivers/base/class.c
View file @
6c7a3c95
...
...
@@ -49,7 +49,9 @@ static struct kobj_type ktype_devclass = {
.
sysfs_ops
=
&
class_sysfs_ops
,
};
static
decl_subsys
(
class
,
&
ktype_devclass
);
/* Classes can't use the kobject hotplug logic, as
* they do not add new kobjects to the system */
static
decl_subsys
(
class
,
&
ktype_devclass
,
NULL
);
static
int
devclass_dev_link
(
struct
device_class
*
cls
,
struct
device
*
dev
)
...
...
drivers/base/core.c
View file @
6c7a3c95
...
...
@@ -23,13 +23,12 @@ int (*platform_notify_remove)(struct device * dev) = NULL;
DECLARE_MUTEX
(
device_sem
);
#define to_dev(obj) container_of(obj,struct device,kobj)
/*
* sysfs bindings for devices.
*/
#define to_dev(obj) container_of(obj,struct device,kobj)
#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr)
extern
struct
attribute
*
dev_default_attrs
[];
...
...
@@ -86,11 +85,55 @@ static struct kobj_type ktype_device = {
.
default_attrs
=
dev_default_attrs
,
};
static
int
dev_hotplug_filter
(
struct
kset
*
kset
,
struct
kobject
*
kobj
)
{
struct
kobj_type
*
ktype
=
get_ktype
(
kobj
);
if
(
ktype
==
&
ktype_device
)
{
struct
device
*
dev
=
to_dev
(
kobj
);
if
(
dev
->
bus
)
return
1
;
}
return
0
;
}
static
char
*
dev_hotplug_name
(
struct
kset
*
kset
,
struct
kobject
*
kobj
)
{
struct
device
*
dev
=
to_dev
(
kobj
);
return
dev
->
bus
->
name
;
}
static
int
dev_hotplug
(
struct
kset
*
kset
,
struct
kobject
*
kobj
,
char
**
envp
,
int
num_envp
,
char
*
buffer
,
int
buffer_size
)
{
struct
device
*
dev
=
to_dev
(
kobj
);
int
retval
=
0
;
if
(
dev
->
bus
->
hotplug
)
{
/* have the bus specific function add its stuff */
retval
=
dev
->
bus
->
hotplug
(
dev
,
envp
,
num_envp
,
buffer
,
buffer_size
);
if
(
retval
)
{
pr_debug
(
"%s - hotplug() returned %d
\n
"
,
__FUNCTION__
,
retval
);
}
}
return
retval
;
}
static
struct
kset_hotplug_ops
device_hotplug_ops
=
{
.
filter
=
dev_hotplug_filter
,
.
name
=
dev_hotplug_name
,
.
hotplug
=
dev_hotplug
,
};
/**
* device_subsys - structure to be registered with kobject core.
*/
decl_subsys
(
devices
,
&
ktype_device
);
decl_subsys
(
devices
,
&
ktype_device
,
&
device_hotplug_ops
);
/**
...
...
@@ -192,9 +235,6 @@ int device_add(struct device *dev)
if
(
platform_notify
)
platform_notify
(
dev
);
/* notify userspace of device entry */
dev_hotplug
(
dev
,
"add"
);
devclass_add_device
(
dev
);
register_done:
if
(
error
&&
parent
)
...
...
@@ -278,9 +318,6 @@ void device_del(struct device * dev)
if
(
platform_notify_remove
)
platform_notify_remove
(
dev
);
/* notify userspace that this device is about to disappear */
dev_hotplug
(
dev
,
"remove"
);
bus_remove_device
(
dev
);
kobject_del
(
&
dev
->
kobj
);
...
...
drivers/base/firmware.c
View file @
6c7a3c95
...
...
@@ -6,7 +6,7 @@
#include <linux/module.h>
#include <linux/init.h>
static
decl_subsys
(
firmware
,
NULL
);
static
decl_subsys
(
firmware
,
NULL
,
NULL
);
int
firmware_register
(
struct
subsystem
*
s
)
{
...
...
drivers/base/hotplug.c
View file @
6c7a3c95
...
...
@@ -2,8 +2,8 @@
* drivers/base/hotplug.c - hotplug call code
*
* Copyright (c) 2000-2001 David Brownell
* Copyright (c) 2002 Greg Kroah-Hartman
* Copyright (c) 2002 IBM Corp.
* Copyright (c) 2002
-2003
Greg Kroah-Hartman
* Copyright (c) 2002
-2003
IBM Corp.
*
* Based off of drivers/usb/core/usb.c:call_agent(), which was
* written by David Brownell.
...
...
@@ -53,17 +53,6 @@ static int do_hotplug (struct device *dev, char *argv1, const char *action,
if
(
!
hotplug_path
[
0
])
return
-
ENODEV
;
if
(
in_interrupt
())
{
pr_debug
(
"%s - in_interrupt, not allowed!"
,
__FUNCTION__
);
return
-
EIO
;
}
if
(
!
current
->
fs
->
root
)
{
/* don't try to do anything unless we have a root partition */
pr_debug
(
"%s - %s -- no FS yet
\n
"
,
__FUNCTION__
,
action
);
return
-
EIO
;
}
envp
=
(
char
**
)
kmalloc
(
NUM_ENVP
*
sizeof
(
char
*
),
GFP_KERNEL
);
if
(
!
envp
)
return
-
ENOMEM
;
...
...
@@ -128,23 +117,6 @@ static int do_hotplug (struct device *dev, char *argv1, const char *action,
return
retval
;
}
/*
* dev_hotplug - called when any device is added or removed from a bus
*/
int
dev_hotplug
(
struct
device
*
dev
,
const
char
*
action
)
{
pr_debug
(
"%s
\n
"
,
__FUNCTION__
);
if
(
!
dev
)
return
-
ENODEV
;
if
(
!
dev
->
bus
)
return
-
ENODEV
;
return
do_hotplug
(
dev
,
dev
->
bus
->
name
,
action
,
dev
->
bus
->
hotplug
);
}
/*
* class_hotplug - called when a class is added or removed from a device
*/
...
...
drivers/block/genhd.c
View file @
6c7a3c95
...
...
@@ -525,9 +525,21 @@ static struct kobj_type ktype_block = {
.
default_attrs
=
default_attrs
,
};
extern
struct
kobj_type
ktype_part
;
static
int
block_hotplug_filter
(
struct
kset
*
kset
,
struct
kobject
*
kobj
)
{
struct
kobj_type
*
ktype
=
get_ktype
(
kobj
);
return
((
ktype
==
&
ktype_block
)
||
(
ktype
==
&
ktype_part
));
}
static
struct
kset_hotplug_ops
block_hotplug_ops
=
{
.
filter
=
block_hotplug_filter
,
};
/* declare block_subsys. */
static
decl_subsys
(
block
,
&
ktype_block
);
static
decl_subsys
(
block
,
&
ktype_block
,
&
block_hotplug_ops
);
struct
gendisk
*
alloc_disk
(
int
minors
)
...
...
drivers/hotplug/pci_hotplug_core.c
View file @
6c7a3c95
...
...
@@ -100,7 +100,7 @@ static struct kobj_type hotplug_slot_ktype = {
.
sysfs_ops
=
&
hotplug_slot_sysfs_ops
};
static
decl_subsys
(
hotplug_slots
,
&
hotplug_slot_ktype
);
static
decl_subsys
(
hotplug_slots
,
&
hotplug_slot_ktype
,
NULL
);
/* these strings match up with the values in pci_bus_speed */
...
...
drivers/usb/class/usb-midi.c
View file @
6c7a3c95
...
...
@@ -1806,22 +1806,6 @@ static int detect_yamaha_device( struct usb_device *d, unsigned int ifnum, struc
printk
(
KERN_INFO
"usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d
\n
"
,
d
->
descriptor
.
idVendor
,
d
->
descriptor
.
idProduct
,
ifnum
);
for
(
i
=
0
;
i
<
d
->
descriptor
.
bNumConfigurations
;
i
++
)
{
if
(
d
->
config
+
i
==
c
)
goto
configfound
;
}
printk
(
KERN_INFO
"usb-midi: Config not found.
\n
"
);
return
-
EINVAL
;
configfound:
/* this may not be necessary. */
if
(
usb_set_configuration
(
d
,
c
->
desc
.
bConfigurationValue
)
<
0
)
{
printk
(
KERN_INFO
"usb-midi: Could not set config.
\n
"
);
return
-
EINVAL
;
}
ret
=
usb_get_descriptor
(
d
,
USB_DT_CONFIG
,
i
,
buf
,
USB_DT_CONFIG_SIZE
);
if
(
ret
<
0
)
{
printk
(
KERN_INFO
"usb-midi: Could not get config (error=%d).
\n
"
,
ret
);
...
...
@@ -1916,21 +1900,6 @@ static int detect_midi_subclass(struct usb_device *d, unsigned int ifnum, struct
printk
(
KERN_INFO
"usb-midi: Found MIDISTREAMING on dev %04x:%04x, iface %d
\n
"
,
d
->
descriptor
.
idVendor
,
d
->
descriptor
.
idProduct
,
ifnum
);
for
(
i
=
0
;
i
<
d
->
descriptor
.
bNumConfigurations
;
i
++
)
{
if
(
d
->
config
+
i
==
c
)
goto
configfound
;
}
printk
(
KERN_INFO
"usb-midi: Config not found.
\n
"
);
return
-
EINVAL
;
configfound:
/* this may not be necessary. */
if
(
usb_set_configuration
(
d
,
c
->
desc
.
bConfigurationValue
)
<
0
)
{
printk
(
KERN_INFO
"usb-midi: Could not set config.
\n
"
);
return
-
EINVAL
;
}
/* From USB Spec v2.0, Section 9.5.
If the class or vendor specific descriptors use the same format
...
...
drivers/usb/core/hub.c
View file @
6c7a3c95
...
...
@@ -1175,8 +1175,10 @@ void usb_hub_cleanup(void)
*
* Take a look at proc_resetdevice in devio.c for some sample code to
* do this.
* Use this only from within your probe function, otherwise use
* usb_reset_device() below, which ensure proper locking
*/
int
usb_reset_device
(
struct
usb_device
*
dev
)
int
usb_
physical_
reset_device
(
struct
usb_device
*
dev
)
{
struct
usb_device
*
parent
=
dev
->
parent
;
struct
usb_device_descriptor
*
descriptor
;
...
...
@@ -1306,3 +1308,16 @@ int usb_reset_device(struct usb_device *dev)
return
0
;
}
int
usb_reset_device
(
struct
usb_device
*
udev
)
{
struct
device
*
gdev
=
&
udev
->
dev
;
int
r
;
down_read
(
&
gdev
->
bus
->
subsys
.
rwsem
);
r
=
usb_physical_reset_device
(
udev
);
up_read
(
&
gdev
->
bus
->
subsys
.
rwsem
);
return
r
;
}
drivers/usb/core/message.c
View file @
6c7a3c95
...
...
@@ -930,6 +930,8 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
/* reset more hc/hcd endpoint state */
dev
->
toggle
[
0
]
=
0
;
dev
->
toggle
[
1
]
=
0
;
dev
->
halted
[
0
]
=
0
;
dev
->
halted
[
1
]
=
0
;
usb_set_maxpacket
(
dev
);
return
0
;
...
...
drivers/usb/core/usb.c
View file @
6c7a3c95
...
...
@@ -89,11 +89,6 @@ int usb_device_probe(struct device *dev)
if
(
!
driver
->
probe
)
return
error
;
if
(
!
try_module_get
(
driver
->
owner
))
{
dev_err
(
dev
,
"Can't get a module reference for %s
\n
"
,
driver
->
name
);
return
error
;
}
id
=
usb_match_id
(
intf
,
driver
->
id_table
);
if
(
id
)
{
dev_dbg
(
dev
,
"%s - got id
\n
"
,
__FUNCTION__
);
...
...
@@ -104,8 +99,6 @@ int usb_device_probe(struct device *dev)
if
(
!
error
)
intf
->
driver
=
driver
;
module_put
(
driver
->
owner
);
return
error
;
}
...
...
@@ -117,22 +110,6 @@ int usb_device_remove(struct device *dev)
intf
=
list_entry
(
dev
,
struct
usb_interface
,
dev
);
driver
=
to_usb_driver
(
dev
->
driver
);
if
(
!
driver
)
{
dev_err
(
dev
,
"%s does not have a valid driver to work with!"
,
__FUNCTION__
);
return
-
ENODEV
;
}
if
(
!
try_module_get
(
driver
->
owner
))
{
// FIXME this happens even when we just rmmod
// drivers that aren't in active use...
dev_err
(
dev
,
"Dieing driver still bound to device.
\n
"
);
return
-
EIO
;
}
/* if we sleep here on an umanaged driver
* the holder of the lock guards against
* module unload */
down
(
&
driver
->
serialize
);
if
(
intf
->
driver
&&
intf
->
driver
->
disconnect
)
...
...
@@ -143,7 +120,6 @@ int usb_device_remove(struct device *dev)
usb_driver_release_interface
(
driver
,
intf
);
up
(
&
driver
->
serialize
);
module_put
(
driver
->
owner
);
return
0
;
}
...
...
@@ -498,9 +474,6 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, kdev_t kdev)
continue
;
intf
=
to_usb_interface
(
dev
);
if
(
!
intf
)
continue
;
if
(
kdev_same
(
intf
->
kdev
,
kdev
))
{
return
intf
;
}
...
...
@@ -566,12 +539,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
return
0
;
intf
=
to_usb_interface
(
dev
);
if
(
!
intf
)
return
-
ENODEV
;
usb_dev
=
interface_to_usbdev
(
intf
);
if
(
!
usb_dev
)
return
-
ENODEV
;
if
(
usb_dev
->
devnum
<
0
)
{
dbg
(
"device already deleted ??"
);
...
...
@@ -748,8 +716,6 @@ static void usb_release_dev(struct device *dev)
struct
usb_device
*
udev
;
udev
=
to_usb_device
(
dev
);
if
(
!
udev
)
return
;
if
(
udev
->
bus
&&
udev
->
bus
->
op
&&
udev
->
bus
->
op
->
deallocate
)
udev
->
bus
->
op
->
deallocate
(
udev
);
...
...
drivers/usb/host/ehci-mem.c
View file @
6c7a3c95
...
...
@@ -62,6 +62,7 @@ static inline void ehci_qtd_init (struct ehci_qtd *qtd, dma_addr_t dma)
{
memset
(
qtd
,
0
,
sizeof
*
qtd
);
qtd
->
qtd_dma
=
dma
;
qtd
->
hw_token
=
cpu_to_le32
(
QTD_STS_HALT
);
qtd
->
hw_next
=
EHCI_LIST_END
;
qtd
->
hw_alt_next
=
EHCI_LIST_END
;
INIT_LIST_HEAD
(
&
qtd
->
qtd_list
);
...
...
drivers/usb/host/ehci-q.c
View file @
6c7a3c95
...
...
@@ -137,7 +137,10 @@ static void qtd_copy_status (
if
(
QTD_CERR
(
token
))
urb
->
status
=
-
EPIPE
;
else
{
dbg
(
"3strikes"
);
ehci_dbg
(
ehci
,
"devpath %s ep%d%s 3strikes
\n
"
,
urb
->
dev
->
devpath
,
usb_pipeendpoint
(
urb
->
pipe
),
usb_pipein
(
urb
->
pipe
)
?
"in"
:
"out"
);
urb
->
status
=
-
EPROTO
;
}
/* CERR nonzero + no errors + halt --> stall */
...
...
@@ -213,7 +216,6 @@ ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
/* complete() can reenter this HCD */
spin_unlock
(
&
ehci
->
lock
);
usb_hcd_giveback_urb
(
&
ehci
->
hcd
,
urb
,
regs
);
spin_lock
(
&
ehci
->
lock
);
}
...
...
@@ -827,7 +829,7 @@ static struct ehci_qh *qh_append_tds (
* HC is allowed to fetch the old dummy (4.10.2).
*/
token
=
qtd
->
hw_token
;
qtd
->
hw_token
=
0
;
qtd
->
hw_token
=
cpu_to_le32
(
QTD_STS_HALT
)
;
wmb
();
dummy
=
qh
->
dummy
;
...
...
@@ -879,8 +881,7 @@ submit_async (
if
(
usb_pipein
(
urb
->
pipe
)
&&
!
usb_pipecontrol
(
urb
->
pipe
))
epnum
|=
0x10
;
vdbg
(
"%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]"
,
hcd_to_bus
(
&
ehci
->
hcd
)
->
bus_name
,
ehci_vdbg
(
ehci
,
"submit_async urb %p len %d ep%d%s qtd %p [qh %p]
\n
"
,
urb
,
urb
->
transfer_buffer_length
,
epnum
&
0x0f
,
(
epnum
&
0x10
)
?
"in"
:
"out"
,
qtd
,
dev
?
dev
->
ep
[
epnum
]
:
(
void
*
)
~
0
);
...
...
@@ -916,7 +917,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
del_timer
(
&
ehci
->
watchdog
);
qh
->
hw_next
=
cpu_to_le32
(
qh
->
qh_dma
);
//
qh->hw_next = cpu_to_le32 (qh->qh_dma);
qh
->
qh_state
=
QH_STATE_IDLE
;
qh
->
qh_next
.
qh
=
0
;
qh_put
(
ehci
,
qh
);
// refcount from reclaim
...
...
drivers/usb/host/ohci-hcd.c
View file @
6c7a3c95
...
...
@@ -429,6 +429,8 @@ static int hc_reset (struct ohci_hcd *ohci)
ohci
->
hc_control
=
readl
(
&
ohci
->
regs
->
control
);
ohci
->
hc_control
&=
OHCI_CTRL_RWC
;
/* hcfs 0 = RESET */
writel
(
ohci
->
hc_control
,
&
ohci
->
regs
->
control
);
// flush those pci writes
(
void
)
readl
(
&
ohci
->
regs
->
control
);
wait_ms
(
50
);
/* HC Reset requires max 10 us delay */
...
...
@@ -450,6 +452,8 @@ static int hc_reset (struct ohci_hcd *ohci)
* this if we write fmInterval after we're OPERATIONAL.
*/
writel
(
ohci
->
hc_control
,
&
ohci
->
regs
->
control
);
// flush those pci writes
(
void
)
readl
(
&
ohci
->
regs
->
control
);
return
0
;
}
...
...
@@ -524,6 +528,8 @@ static int hc_start (struct ohci_hcd *ohci)
writel
(
tmp
,
&
ohci
->
regs
->
roothub
.
a
);
writel
(
RH_HS_LPSC
,
&
ohci
->
regs
->
roothub
.
status
);
writel
(
0
,
&
ohci
->
regs
->
roothub
.
b
);
// flush those pci writes
(
void
)
readl
(
&
ohci
->
regs
->
control
);
// POTPGT delay is bits 24-31, in 2 ms units.
mdelay
((
roothub_a
(
ohci
)
>>
23
)
&
0x1fe
);
...
...
@@ -610,6 +616,8 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
writel
(
ints
,
&
regs
->
intrstatus
);
writel
(
OHCI_INTR_MIE
,
&
regs
->
intrenable
);
// flush those pci writes
(
void
)
readl
(
&
ohci
->
regs
->
control
);
}
/*-------------------------------------------------------------------------*/
...
...
drivers/usb/host/ohci-q.c
View file @
6c7a3c95
...
...
@@ -446,6 +446,8 @@ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
if
(
!
ohci
->
sleeping
)
{
writel
(
OHCI_INTR_SF
,
&
ohci
->
regs
->
intrstatus
);
writel
(
OHCI_INTR_SF
,
&
ohci
->
regs
->
intrenable
);
// flush those pci writes
(
void
)
readl
(
&
ohci
->
regs
->
control
);
}
}
...
...
drivers/usb/input/hid-core.c
View file @
6c7a3c95
...
...
@@ -1664,6 +1664,9 @@ static struct usb_driver hid_driver = {
.
probe
=
hid_probe
,
.
disconnect
=
hid_disconnect
,
.
id_table
=
hid_usb_ids
,
.
driver
=
{
.
devclass
=
&
input_devclass
,
},
};
static
int
__init
hid_init
(
void
)
...
...
drivers/usb/input/kbtab.c
View file @
6c7a3c95
...
...
@@ -91,7 +91,7 @@ static void kbtab_irq(struct urb *urb, struct pt_regs *regs)
}
struct
usb_device_id
kbtab_ids
[]
=
{
{
USB_DEVICE
(
USB_VENDOR_ID_KBGEAR
,
0x1001
),
driver_info
:
0
},
{
USB_DEVICE
(
USB_VENDOR_ID_KBGEAR
,
0x1001
),
.
driver_info
=
0
},
{
}
};
...
...
drivers/usb/input/usbkbd.c
View file @
6c7a3c95
...
...
@@ -359,6 +359,9 @@ static struct usb_driver usb_kbd_driver = {
.
probe
=
usb_kbd_probe
,
.
disconnect
=
usb_kbd_disconnect
,
.
id_table
=
usb_kbd_id_table
,
.
driver
=
{
.
devclass
=
&
input_devclass
,
},
};
static
int
__init
usb_kbd_init
(
void
)
...
...
drivers/usb/input/usbmouse.c
View file @
6c7a3c95
...
...
@@ -242,6 +242,9 @@ static struct usb_driver usb_mouse_driver = {
.
probe
=
usb_mouse_probe
,
.
disconnect
=
usb_mouse_disconnect
,
.
id_table
=
usb_mouse_id_table
,
.
driver
=
{
.
devclass
=
&
input_devclass
,
},
};
static
int
__init
usb_mouse_init
(
void
)
...
...
drivers/usb/misc/speedtch.c
View file @
6c7a3c95
...
...
@@ -1034,6 +1034,23 @@ static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
** USB **
**********/
static
int
udsl_set_alternate
(
struct
udsl_instance_data
*
instance
)
{
down
(
&
instance
->
serialize
);
/* vs self */
if
(
!
instance
->
firmware_loaded
)
{
int
ret
;
if
((
ret
=
usb_set_interface
(
instance
->
usb_dev
,
1
,
1
))
<
0
)
{
up
(
&
instance
->
serialize
);
return
ret
;
}
instance
->
firmware_loaded
=
1
;
}
up
(
&
instance
->
serialize
);
udsl_fire_receivers
(
instance
);
return
0
;
}
static
int
udsl_usb_ioctl
(
struct
usb_interface
*
intf
,
unsigned
int
code
,
void
*
user_data
)
{
struct
udsl_instance_data
*
instance
=
usb_get_intfdata
(
intf
);
...
...
@@ -1048,14 +1065,7 @@ static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *
switch
(
code
)
{
case
UDSL_IOCTL_START
:
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_FOUND
;
down
(
&
instance
->
serialize
);
/* vs self */
if
(
!
instance
->
firmware_loaded
)
{
usb_set_interface
(
instance
->
usb_dev
,
1
,
1
);
instance
->
firmware_loaded
=
1
;
}
up
(
&
instance
->
serialize
);
udsl_fire_receivers
(
instance
);
return
0
;
return
udsl_set_alternate
(
instance
);
case
UDSL_IOCTL_STOP
:
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_LOST
;
return
0
;
...
...
drivers/usb/net/pegasus.c
View file @
6c7a3c95
...
...
@@ -45,7 +45,7 @@
/*
* Version Information
*/
#define DRIVER_VERSION "v0.5.
9 (2002/12/3
1)"
#define DRIVER_VERSION "v0.5.
10 (2003/04/0
1)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
...
...
@@ -121,7 +121,7 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
char
*
buffer
;
DECLARE_WAITQUEUE
(
wait
,
current
);
buffer
=
kmalloc
(
size
,
GFP_
KERNEL
);
buffer
=
kmalloc
(
size
,
GFP_
DMA
);
if
(
!
buffer
)
{
warn
(
"%s: looks like we're out of memory"
,
__FUNCTION__
);
return
-
ENOMEM
;
...
...
@@ -170,7 +170,7 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
char
*
buffer
;
DECLARE_WAITQUEUE
(
wait
,
current
);
buffer
=
kmalloc
(
size
,
GFP_
KERNEL
);
buffer
=
kmalloc
(
size
,
GFP_
DMA
);
if
(
!
buffer
)
{
warn
(
"%s: looks like we're out of memory"
,
__FUNCTION__
);
return
-
ENOMEM
;
...
...
@@ -218,7 +218,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
char
*
tmp
;
DECLARE_WAITQUEUE
(
wait
,
current
);
tmp
=
kmalloc
(
1
,
GFP_
KERNEL
);
tmp
=
kmalloc
(
1
,
GFP_
DMA
);
if
(
!
tmp
)
{
warn
(
"%s: looks like we're out of memory"
,
__FUNCTION__
);
return
-
ENOMEM
;
...
...
@@ -233,7 +233,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
pegasus
->
dr
.
bRequestType
=
PEGASUS_REQT_WRITE
;
pegasus
->
dr
.
bRequest
=
PEGASUS_REQ_SET_REG
;
pegasus
->
dr
.
wValue
=
cpu_to_le16
p
(
&
data
);
pegasus
->
dr
.
wValue
=
cpu_to_le16
(
data
);
pegasus
->
dr
.
wIndex
=
cpu_to_le16p
(
&
indx
);
pegasus
->
dr
.
wLength
=
cpu_to_le16
(
1
);
pegasus
->
ctrl_urb
->
transfer_buffer_length
=
1
;
...
...
@@ -711,11 +711,11 @@ static void intr_callback(struct urb *urb, struct pt_regs *regs)
pegasus
->
stats
.
tx_aborted_errors
++
;
if
(
d
[
0
]
&
LATE_COL
)
pegasus
->
stats
.
tx_window_errors
++
;
if
(
d
[
0
]
&
(
NO_CARRIER
|
LOSS_CARRIER
))
{
pegasus
->
stats
.
tx_carrier_errors
++
;
netif_carrier_off
(
net
);
}
else
{
if
(
d
[
5
]
&
LINK_STATUS
)
{
netif_carrier_on
(
net
);
}
else
{
pegasus
->
stats
.
tx_carrier_errors
++
;
netif_carrier_off
(
net
);
}
}
...
...
drivers/usb/net/pegasus.h
View file @
6c7a3c95
...
...
@@ -52,6 +52,8 @@
#define LOSS_CARRIER 0x08
#define JABBER_TIMEOUT 0x04
#define LINK_STATUS 0x01
#define PEGASUS_REQT_READ 0xc0
#define PEGASUS_REQT_WRITE 0x40
#define PEGASUS_REQ_GET_REGS 0xf0
...
...
drivers/usb/net/usbnet.c
View file @
6c7a3c95
...
...
@@ -122,6 +122,11 @@
* cleanups and stubbed PXA-250 support (db), fix for framing
* issues on Z, net1080, and gl620a (Toby Milne)
*
* 31-mar-2003 Use endpoint descriptors: high speed support, simpler sa1100
* vs pxa25x, and CDC Ethernet. Throttle down log floods on
* disconnect; other cleanups. (db) Flush net1080 fifos
* after several sequential framing errors. (Johannes Erdfelt)
*
*-------------------------------------------------------------------------*/
#include <linux/config.h>
...
...
@@ -155,16 +160,17 @@
/* minidrivers _could_ be individually configured */
#define CONFIG_USB_AN2720
#define CONFIG_USB_BELKIN
#undef CONFIG_USB_CDCETHER
//#define CONFIG_USB_CDCETHER /* NYET */
#define CONFIG_USB_EPSON2888
#define CONFIG_USB_GENESYS
#define CONFIG_USB_NET1080
#define CONFIG_USB_PL2301
// #define CONFIG_USB_PXA
#define CONFIG_USB_SA1100
#define CONFIG_USB_ARMLINUX
#define CONFIG_USB_ZAURUS
#define DRIVER_VERSION "
18-Oct-2002
"
#define DRIVER_VERSION "
31-Mar-2003
"
/*-------------------------------------------------------------------------*/
...
...
@@ -176,11 +182,11 @@
* Ethernet packets (so queues should be bigger).
*/
#ifdef REALLY_QUEUE
#define RX_QLEN
4
#define TX_QLEN
4
#define RX_QLEN
(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
#define TX_QLEN
(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
#else
#define RX_QLEN 1
#define TX_QLEN 1
#define RX_QLEN
(dev)
1
#define TX_QLEN
(dev)
1
#endif
// packets are always ethernet inside
...
...
@@ -191,6 +197,10 @@
// reawaken network queue this soon after stopping; else watchdog barks
#define TX_TIMEOUT_JIFFIES (5*HZ)
// throttle rx/tx briefly after some faults, so khubd might disconnect()
// us (it polls at HZ/4 usually) before we report too many false errors.
#define THROTTLE_JIFFIES (HZ/8)
// for vendor-specific control operations
#define CONTROL_TIMEOUT_MS (500)
/* msec */
#define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000)
...
...
@@ -200,10 +210,6 @@
/*-------------------------------------------------------------------------*/
// list of all devices we manage
static
DECLARE_MUTEX
(
usbnet_mutex
);
static
LIST_HEAD
(
usbnet_list
);
// randomly generated ethernet address
static
u8
node_id
[
ETH_ALEN
];
...
...
@@ -213,17 +219,18 @@ struct usbnet {
struct
usb_device
*
udev
;
struct
driver_info
*
driver_info
;
struct
semaphore
mutex
;
struct
list_head
dev_list
;
wait_queue_head_t
*
wait
;
// i/o info: pipes etc
unsigned
in
,
out
;
unsigned
maxpacket
;
struct
timer_list
delay
;
// protocol/interface state
struct
net_device
net
;
struct
net_device_stats
stats
;
int
msg_level
;
#ifdef CONFIG_USB_NET1080
u16
packet_id
;
#endif
unsigned
long
data
[
5
];
// various kinds of pending driver work
struct
sk_buff_head
rxq
;
...
...
@@ -231,7 +238,7 @@ struct usbnet {
struct
sk_buff_head
done
;
struct
tasklet_struct
bh
;
struct
work_struct
kevent
;
struct
work_struct
kevent
;
unsigned
long
flags
;
# define EVENT_TX_HALT 0
# define EVENT_RX_HALT 1
...
...
@@ -243,11 +250,19 @@ struct driver_info {
char
*
description
;
int
flags
;
/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */
#define FLAG_FRAMING_NC 0x0001
/* guard against device dropouts */
#define FLAG_FRAMING_GL 0x0002
/* genelink batches packets */
#define FLAG_FRAMING_Z 0x0004
/* zaurus adds a trailer */
#define FLAG_NO_SETINT 0x0010
/* device can't set_interface() */
/* init device ... can sleep, or cause probe() failure */
int
(
*
bind
)(
struct
usbnet
*
,
struct
usb_interface
*
);
/* cleanup device ... can sleep, but can't fail */
void
(
*
unbind
)(
struct
usbnet
*
,
struct
usb_interface
*
);
/* reset device ... can sleep */
int
(
*
reset
)(
struct
usbnet
*
);
...
...
@@ -263,15 +278,13 @@ struct driver_info {
// FIXME -- also an interrupt mechanism
// useful for at least PL2301/2302 and GL620USB-A
// and CDC use them to report 'is it connected' changes
/* f
ramework currently "knows" bulk EPs talk packets
*/
/* f
or new devices, use the descriptor-reading code instead
*/
int
in
;
/* rx endpoint */
int
out
;
/* tx endpoint */
int
epsize
;
};
#define EP_SIZE(usbnet) ((usbnet)->driver_info->epsize)
// we record the state for each of our queued skbs
enum
skb_state
{
illegal
=
0
,
...
...
@@ -300,14 +313,6 @@ MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)");
#define RUN_CONTEXT (in_irq () ? "in_irq" \
: (in_interrupt () ? "in_interrupt" : "can sleep"))
/* mostly for PDA style devices, which are always present */
static
int
always_connected
(
struct
usbnet
*
dev
)
{
return
0
;
}
/*-------------------------------------------------------------------------*/
#ifdef DEBUG
#define devdbg(usbnet, fmt, arg...) \
printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net.name, ## arg)
...
...
@@ -315,11 +320,76 @@ static int always_connected (struct usbnet *dev)
#define devdbg(usbnet, fmt, arg...) do {} while(0)
#endif
#define deverr(usbnet, fmt, arg...) \
printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net.name, ## arg)
#define devwarn(usbnet, fmt, arg...) \
printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net.name, ## arg)
#define devinfo(usbnet, fmt, arg...) \
do { if ((usbnet)->msg_level >= 1) \
printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg); \
} while (0)
/*-------------------------------------------------------------------------*/
/* mostly for PDA style devices, which are always connected if present */
static
int
always_connected
(
struct
usbnet
*
dev
)
{
return
0
;
}
/* handles CDC Ethernet and many other network "bulk data" interfaces */
static
int
get_endpoints
(
struct
usbnet
*
dev
,
struct
usb_interface
*
intf
)
{
int
tmp
;
struct
usb_host_interface
*
alt
;
struct
usb_host_endpoint
*
in
,
*
out
;
for
(
tmp
=
0
;
tmp
<
intf
->
max_altsetting
;
tmp
++
)
{
unsigned
ep
;
in
=
out
=
0
;
alt
=
intf
->
altsetting
+
tmp
;
/* take the first altsetting with in-bulk + out-bulk;
* ignore other endpoints and altsetttings.
*/
for
(
ep
=
0
;
ep
<
alt
->
desc
.
bNumEndpoints
;
ep
++
)
{
struct
usb_host_endpoint
*
e
;
e
=
alt
->
endpoint
+
ep
;
if
(
e
->
desc
.
bmAttributes
!=
USB_ENDPOINT_XFER_BULK
)
continue
;
if
(
e
->
desc
.
bEndpointAddress
&
USB_DIR_IN
)
{
if
(
!
in
)
in
=
e
;
}
else
{
if
(
!
out
)
out
=
e
;
}
if
(
in
&&
out
)
goto
found
;
}
}
return
-
EINVAL
;
found:
if
(
alt
->
desc
.
bAlternateSetting
!=
0
||
!
(
dev
->
driver_info
->
flags
&
FLAG_NO_SETINT
))
{
tmp
=
usb_set_interface
(
dev
->
udev
,
alt
->
desc
.
bInterfaceNumber
,
alt
->
desc
.
bAlternateSetting
);
if
(
tmp
<
0
)
return
tmp
;
}
dev
->
in
=
usb_rcvbulkpipe
(
dev
->
udev
,
in
->
desc
.
bEndpointAddress
&
USB_ENDPOINT_NUMBER_MASK
);
dev
->
out
=
usb_sndbulkpipe
(
dev
->
udev
,
out
->
desc
.
bEndpointAddress
&
USB_ENDPOINT_NUMBER_MASK
);
return
0
;
}
#ifdef CONFIG_USB_AN2720
...
...
@@ -340,7 +410,6 @@ static const struct driver_info an2720_info = {
// no check_connect available!
.
in
=
2
,
.
out
=
2
,
// direction distinguishes these
.
epsize
=
64
,
};
#endif
/* CONFIG_USB_AN2720 */
...
...
@@ -359,14 +428,225 @@ static const struct driver_info an2720_info = {
static
const
struct
driver_info
belkin_info
=
{
.
description
=
"Belkin, eTEK, or compatible"
,
.
in
=
1
,
.
out
=
1
,
// direction distinguishes these
.
epsize
=
64
,
};
#endif
/* CONFIG_USB_BELKIN */
#if defined (CONFIG_USB_CDCETHER) || defined (CONFIG_USB_ZAURUS)
/*-------------------------------------------------------------------------
*
* Communications Device Class, Ethernet Control model
*
* Takes two interfaces. The DATA interface is inactive till an altsetting
* is selected. Configuration data includes class descriptors.
*
* Zaurus uses nonstandard framing, but is otherwise CDC Ether.
*
*-------------------------------------------------------------------------*/
/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
struct
header_desc
{
u8
bLength
;
u8
bDescriptorType
;
u8
bDescriptorSubType
;
u16
bcdCDC
;
}
__attribute__
((
packed
));
/* "Union Functional Descriptor" from CDC spec 5.2.3.X */
struct
union_desc
{
u8
bLength
;
u8
bDescriptorType
;
u8
bDescriptorSubType
;
u8
bMasterInterface0
;
u8
bSlaveInterface0
;
/* ... and there could be other slave interfaces */
}
__attribute__
((
packed
));
/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
struct
ether_desc
{
u8
bLength
;
u8
bDescriptorType
;
u8
bDescriptorSubType
;
u8
iMACAddress
;
u32
bmEthernetStatistics
;
u16
wMaxSegmentSize
;
u16
wNumberMCFilters
;
u8
bNumberPowerFilters
;
}
__attribute__
((
packed
));
struct
cdc_info
{
struct
header_desc
*
header
;
struct
union_desc
*
u
;
struct
ether_desc
*
ether
;
struct
usb_interface
*
control
;
struct
usb_interface
*
data
;
};
#include <linux/ctype.h>
static
u8
nibble
(
unsigned
char
c
)
{
if
(
likely
(
isdigit
(
c
)))
return
c
-
'0'
;
c
=
toupper
(
c
);
if
(
likely
(
isxdigit
(
c
)))
return
10
+
c
-
'A'
;
return
0
;
}
static
inline
int
get_ethernet_addr
(
struct
usbnet
*
dev
,
struct
ether_desc
*
e
)
{
int
tmp
,
i
;
unsigned
char
buf
[
13
];
tmp
=
usb_string
(
dev
->
udev
,
e
->
iMACAddress
,
buf
,
sizeof
buf
);
if
(
tmp
<
0
)
return
tmp
;
else
if
(
tmp
!=
12
)
return
-
EINVAL
;
for
(
i
=
tmp
=
0
;
i
<
6
;
i
++
,
tmp
+=
2
)
dev
->
net
.
dev_addr
[
i
]
=
(
nibble
(
buf
[
tmp
])
<<
4
)
+
nibble
(
buf
[
tmp
+
1
]);
return
0
;
}
static
struct
usb_driver
usbnet_driver
;
static
int
cdc_bind
(
struct
usbnet
*
dev
,
struct
usb_interface
*
intf
)
{
u8
*
buf
=
intf
->
altsetting
->
extra
;
int
len
=
intf
->
altsetting
->
extralen
;
struct
usb_interface_descriptor
*
d
;
struct
cdc_info
*
info
=
(
void
*
)
&
dev
->
data
;
int
status
;
if
(
sizeof
dev
->
data
<
sizeof
*
info
)
return
-
EDOM
;
/* expect strict spec conformance for the descriptors */
memset
(
info
,
0
,
sizeof
*
info
);
info
->
control
=
intf
;
while
(
len
>
3
)
{
/* ignore bDescriptorType != CS_INTERFACE */
if
(
buf
[
1
]
!=
0x24
)
goto
next_desc
;
/* bDescriptorSubType identifies three "must have" descriptors;
* save them for later.
*/
switch
(
buf
[
2
])
{
case
0x00
:
/* Header, mostly useless */
if
(
info
->
header
)
goto
bad_desc
;
info
->
header
=
(
void
*
)
buf
;
if
(
info
->
header
->
bLength
!=
sizeof
*
info
->
header
)
goto
bad_desc
;
break
;
case
0x06
:
/* Union (groups interfaces) */
if
(
info
->
u
)
goto
bad_desc
;
info
->
u
=
(
void
*
)
buf
;
if
(
info
->
u
->
bLength
!=
sizeof
*
info
->
u
)
goto
bad_desc
;
d
=
&
intf
->
altsetting
->
desc
;
if
(
info
->
u
->
bMasterInterface0
!=
d
->
bInterfaceNumber
)
goto
bad_desc
;
info
->
data
=
dev
->
udev
->
actconfig
->
interface
;
if
(
intf
!=
(
info
->
data
+
info
->
u
->
bMasterInterface0
))
goto
bad_desc
;
/* a data interface altsetting does the real i/o */
info
->
data
+=
info
->
u
->
bSlaveInterface0
;
d
=
&
info
->
data
->
altsetting
->
desc
;
if
(
info
->
u
->
bSlaveInterface0
!=
d
->
bInterfaceNumber
||
d
->
bInterfaceClass
!=
USB_CLASS_CDC_DATA
)
goto
bad_desc
;
if
(
usb_interface_claimed
(
info
->
data
))
return
-
EBUSY
;
break
;
case
0x0F
:
/* Ethernet Networking */
if
(
info
->
ether
)
goto
bad_desc
;
info
->
ether
=
(
void
*
)
buf
;
if
(
info
->
ether
->
bLength
!=
sizeof
*
info
->
ether
)
goto
bad_desc
;
break
;
}
next_desc:
len
-=
buf
[
0
];
/* bLength */
buf
+=
buf
[
0
];
}
if
(
!
info
->
header
||
!
info
->
u
||
!
info
->
ether
)
goto
bad_desc
;
status
=
get_ethernet_addr
(
dev
,
info
->
ether
);
if
(
status
<
0
)
return
status
;
/* claim data interface and set it up ... with side effects.
* network traffic can't flow until an altsetting is enabled.
*/
usb_driver_claim_interface
(
&
usbnet_driver
,
info
->
data
,
dev
);
status
=
get_endpoints
(
dev
,
info
->
data
);
if
(
status
<
0
)
{
usb_driver_release_interface
(
&
usbnet_driver
,
info
->
data
);
return
status
;
}
/* FIXME cdc-ether has some multicast code too, though it complains
* in routine cases. info->ether describes the multicast support.
*/
dev
->
net
.
mtu
=
cpu_to_le16p
(
&
info
->
ether
->
wMaxSegmentSize
)
-
ETH_HLEN
;
if
((
dev
->
driver_info
->
flags
&
FLAG_FRAMING_Z
)
==
0
)
strcpy
(
dev
->
net
.
name
,
"eth%d"
);
return
0
;
bad_desc:
// devdbg (dev, "bad CDC descriptors");
return
-
ENODEV
;
}
static
void
cdc_unbind
(
struct
usbnet
*
dev
,
struct
usb_interface
*
intf
)
{
struct
cdc_info
*
info
=
(
void
*
)
&
dev
->
data
;
/* disconnect master --> disconnect slave */
if
(
intf
==
info
->
control
&&
info
->
data
)
{
usb_driver_release_interface
(
&
usbnet_driver
,
info
->
data
);
info
->
data
=
0
;
}
/* and vice versa (just in case) */
else
if
(
intf
==
info
->
data
&&
info
->
control
)
{
usb_driver_release_interface
(
&
usbnet_driver
,
info
->
control
);
info
->
control
=
0
;
}
}
#endif
/* CONFIG_USB_ZAURUS || CONFIG_USB_CDCETHER */
#ifdef CONFIG_USB_CDCETHER
static
const
struct
driver_info
cdc_info
=
{
.
description
=
"CDC Ethernet Device"
,
// .check_connect = cdc_check_connect,
.
bind
=
cdc_bind
,
.
unbind
=
cdc_unbind
,
};
#endif
/* CONFIG_USB_CDCETHER */
#ifdef CONFIG_USB_EPSON2888
...
...
@@ -386,7 +666,6 @@ static const struct driver_info epson2888_info = {
.
check_connect
=
always_connected
,
.
in
=
4
,
.
out
=
3
,
.
epsize
=
64
,
};
#endif
/* CONFIG_USB_EPSON2888 */
...
...
@@ -704,7 +983,7 @@ genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
*
packet_len
=
length
;
// add padding byte
if
((
skb
->
len
%
EP_SIZE
(
dev
)
)
==
0
)
if
((
skb
->
len
%
dev
->
maxpacket
)
==
0
)
skb_put
(
skb
,
1
);
return
skb
;
...
...
@@ -717,7 +996,6 @@ static const struct driver_info genelink_info = {
.
tx_fixup
=
genelink_tx_fixup
,
.
in
=
1
,
.
out
=
2
,
.
epsize
=
64
,
#ifdef GENELINK_ACK
.
check_connect
=
genelink_check_connect
,
...
...
@@ -737,6 +1015,9 @@ static const struct driver_info genelink_info = {
*
*-------------------------------------------------------------------------*/
#define dev_packet_id data[0]
#define frame_errors data[1]
/*
* NetChip framing of ethernet packets, supporting additional error
* checks for links that may drop bulk packets from inside messages.
...
...
@@ -1064,6 +1345,60 @@ static int net1080_check_connect (struct usbnet *dev)
return
0
;
}
static
void
nc_flush_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
{
kfree
(
urb
->
context
);
usb_free_urb
(
urb
);
}
static
void
nc_ensure_sync
(
struct
usbnet
*
dev
)
{
dev
->
frame_errors
++
;
if
(
dev
->
frame_errors
>
5
)
{
struct
urb
*
urb
;
struct
usb_ctrlrequest
*
req
;
int
status
;
/* Send a flush */
urb
=
usb_alloc_urb
(
0
,
SLAB_ATOMIC
);
if
(
!
urb
)
return
;
req
=
kmalloc
(
sizeof
*
req
,
GFP_ATOMIC
);
if
(
!
req
)
{
usb_free_urb
(
urb
);
return
;
}
req
->
bRequestType
=
USB_DIR_OUT
|
USB_TYPE_VENDOR
|
USB_RECIP_DEVICE
;
req
->
bRequest
=
REQUEST_REGISTER
;
req
->
wValue
=
cpu_to_le16
(
USBCTL_FLUSH_THIS
|
USBCTL_FLUSH_OTHER
);
req
->
wIndex
=
cpu_to_le16
(
REG_USBCTL
);
req
->
wLength
=
cpu_to_le16
(
0
);
/* queue an async control request, we don't need
* to do anything when it finishes except clean up.
*/
usb_fill_control_urb
(
urb
,
dev
->
udev
,
usb_sndctrlpipe
(
dev
->
udev
,
0
),
(
unsigned
char
*
)
req
,
NULL
,
0
,
nc_flush_complete
,
req
);
status
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
status
)
{
kfree
(
req
);
usb_free_urb
(
urb
);
return
;
}
devdbg
(
dev
,
"flush net1080; too many framing errors"
);
dev
->
frame_errors
=
0
;
}
}
static
int
net1080_rx_fixup
(
struct
usbnet
*
dev
,
struct
sk_buff
*
skb
)
{
struct
nc_header
*
header
;
...
...
@@ -1076,6 +1411,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
dbg
(
"rx framesize %d range %d..%d mtu %d"
,
skb
->
len
,
(
int
)
MIN_FRAMED
,
(
int
)
FRAMED_SIZE
(
dev
->
net
.
mtu
),
dev
->
net
.
mtu
);
nc_ensure_sync
(
dev
);
return
0
;
}
...
...
@@ -1085,15 +1421,18 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
if
(
FRAMED_SIZE
(
header
->
packet_len
)
>
MAX_PACKET
)
{
dev
->
stats
.
rx_frame_errors
++
;
dbg
(
"packet too big, %d"
,
header
->
packet_len
);
nc_ensure_sync
(
dev
);
return
0
;
}
else
if
(
header
->
hdr_len
<
MIN_HEADER
)
{
dev
->
stats
.
rx_frame_errors
++
;
dbg
(
"header too short, %d"
,
header
->
hdr_len
);
nc_ensure_sync
(
dev
);
return
0
;
}
else
if
(
header
->
hdr_len
>
MIN_HEADER
)
{
// out of band data for us?
dbg
(
"header OOB, %d bytes"
,
header
->
hdr_len
-
MIN_HEADER
);
nc_ensure_sync
(
dev
);
// switch (vendor/product ids) { ... }
}
skb_pull
(
skb
,
header
->
hdr_len
);
...
...
@@ -1114,6 +1453,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
dev
->
stats
.
rx_frame_errors
++
;
dbg
(
"bad packet len %d (expected %d)"
,
skb
->
len
,
header
->
packet_len
);
nc_ensure_sync
(
dev
);
return
0
;
}
if
(
header
->
packet_id
!=
get_unaligned
(
&
trailer
->
packet_id
))
{
...
...
@@ -1126,6 +1466,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
devdbg (dev, "frame <rx h %d p %d id %d", header->hdr_len,
header->packet_len, header->packet_id);
#endif
dev
->
frame_errors
=
0
;
return
1
;
}
...
...
@@ -1143,11 +1484,13 @@ net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
if
((
padlen
+
sizeof
(
struct
nc_trailer
))
<=
tailroom
&&
sizeof
(
struct
nc_header
)
<=
headroom
)
/* There's enough head and tail room */
return
skb
;
if
((
sizeof
(
struct
nc_header
)
+
padlen
+
sizeof
(
struct
nc_trailer
))
<
(
headroom
+
tailroom
))
{
/* There's enough total room, so just readjust */
skb
->
data
=
memmove
(
skb
->
head
+
sizeof
(
struct
nc_header
),
skb
->
data
,
skb
->
len
);
...
...
@@ -1155,6 +1498,8 @@ net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
return
skb
;
}
}
/* Create a new skb to use with the correct size */
skb2
=
skb_copy_expand
(
skb
,
sizeof
(
struct
nc_header
),
sizeof
(
struct
nc_trailer
)
+
padlen
,
...
...
@@ -1170,9 +1515,6 @@ static const struct driver_info net1080_info = {
.
check_connect
=
net1080_check_connect
,
.
rx_fixup
=
net1080_rx_fixup
,
.
tx_fixup
=
net1080_tx_fixup
,
.
in
=
1
,
.
out
=
1
,
// direction distinguishes these
.
epsize
=
64
,
};
#endif
/* CONFIG_USB_NET1080 */
...
...
@@ -1237,37 +1579,13 @@ static const struct driver_info prolific_info = {
.
flags
=
FLAG_NO_SETINT
,
/* some PL-2302 versions seem to fail usb_set_interface() */
.
reset
=
pl_reset
,
.
in
=
3
,
.
out
=
2
,
.
epsize
=
64
,
};
#endif
/* CONFIG_USB_PL2301 */
#ifdef CONFIG_USB_PXA
/*-------------------------------------------------------------------------
*
* PXA250 and PXA210 use XScale cores (ARM v5TE) with better USB support,
* and different USB endpoint numbering than the SA1100 devices.
*
*-------------------------------------------------------------------------*/
static
const
struct
driver_info
pxa_info
=
{
.
description
=
"PXA-250 Linux Device"
,
.
check_connect
=
always_connected
,
.
in
=
1
,
.
out
=
2
,
.
epsize
=
64
,
};
#endif
/* CONFIG_USB_PXA */
#ifdef CONFIG_USB_SA1100
#ifdef CONFIG_USB_ARMLINUX
/*-------------------------------------------------------------------------
*
...
...
@@ -1279,25 +1597,24 @@ static const struct driver_info pxa_info = {
* This describes the driver currently in standard ARM Linux kernels.
* The Zaurus uses a different driver (see later).
*
* PXA25x and PXA210 use XScale cores (ARM v5TE) with better USB support
* and different USB endpoint numbering than the SA1100 devices. The
* mach-pxa/usb-eth.c driver re-uses the device ids from mach-sa1100
* so we rely on the endpoint descriptors.
*
*-------------------------------------------------------------------------*/
static
const
struct
driver_info
linuxdev_info
=
{
.
description
=
"
SA-1100
Linux Device"
,
.
description
=
"Linux Device"
,
.
check_connect
=
always_connected
,
.
in
=
2
,
.
out
=
1
,
.
epsize
=
64
,
};
static
const
struct
driver_info
yopy_info
=
{
.
description
=
"Yopy"
,
.
check_connect
=
always_connected
,
.
in
=
2
,
.
out
=
1
,
.
epsize
=
64
,
};
#endif
/* CONFIG_USB_
SA1100
*/
#endif
/* CONFIG_USB_
ARMLINUX
*/
#ifdef CONFIG_USB_ZAURUS
...
...
@@ -1349,10 +1666,9 @@ static const struct driver_info zaurus_sl5x00_info = {
.
description
=
"Sharp Zaurus SL-5x00"
,
.
flags
=
FLAG_FRAMING_Z
,
.
check_connect
=
always_connected
,
.
bind
=
cdc_bind
,
.
unbind
=
cdc_unbind
,
.
tx_fixup
=
zaurus_tx_fixup
,
.
in
=
2
,
.
out
=
1
,
.
epsize
=
64
,
};
static
const
struct
driver_info
zaurus_sla300_info
=
{
.
description
=
"Sharp Zaurus SL-A300"
,
...
...
@@ -1361,7 +1677,6 @@ static const struct driver_info zaurus_sla300_info = {
.
tx_fixup
=
zaurus_tx_fixup
,
.
in
=
1
,
.
out
=
2
,
.
epsize
=
64
,
};
static
const
struct
driver_info
zaurus_slb500_info
=
{
/* Japanese B500 ~= US SL-5600 */
...
...
@@ -1371,7 +1686,6 @@ static const struct driver_info zaurus_slb500_info = {
.
tx_fixup
=
zaurus_tx_fixup
,
.
in
=
1
,
.
out
=
2
,
.
epsize
=
64
,
};
// SL-5600 and C-700 are PXA based; should resemble A300
...
...
@@ -1403,7 +1717,7 @@ static int usbnet_change_mtu (struct net_device *net, int new_mtu)
return
-
EINVAL
;
#endif
// no second zero-length packet read wanted after mtu-sized packets
if
(((
new_mtu
+
sizeof
(
struct
ethhdr
))
%
EP_SIZE
(
dev
)
)
==
0
)
if
(((
new_mtu
+
sizeof
(
struct
ethhdr
))
%
dev
->
maxpacket
)
==
0
)
return
-
EDOM
;
net
->
mtu
=
new_mtu
;
return
0
;
...
...
@@ -1444,10 +1758,9 @@ static void defer_kevent (struct usbnet *dev, int work)
{
set_bit
(
work
,
&
dev
->
flags
);
if
(
!
schedule_work
(
&
dev
->
kevent
))
err
(
"%s: kevent %d may have been dropped"
,
dev
->
net
.
name
,
work
);
deverr
(
dev
,
"kevent %d may have been dropped"
,
work
);
else
d
bg
(
"%s: kevent %d scheduled"
,
dev
->
net
.
name
,
work
);
d
evdbg
(
dev
,
"kevent %d scheduled"
,
work
);
}
/*-------------------------------------------------------------------------*/
...
...
@@ -1480,7 +1793,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
size
=
(
sizeof
(
struct
ethhdr
)
+
dev
->
net
.
mtu
);
if
((
skb
=
alloc_skb
(
size
,
flags
))
==
0
)
{
d
bg
(
"no rx skb"
);
d
evdbg
(
dev
,
"no rx skb"
);
defer_kevent
(
dev
,
EVENT_RX_MEMORY
);
usb_free_urb
(
urb
);
return
;
...
...
@@ -1492,14 +1805,14 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
entry
->
state
=
rx_start
;
entry
->
length
=
0
;
usb_fill_bulk_urb
(
urb
,
dev
->
udev
,
usb_rcvbulkpipe
(
dev
->
udev
,
dev
->
driver_info
->
in
),
usb_fill_bulk_urb
(
urb
,
dev
->
udev
,
dev
->
in
,
skb
->
data
,
size
,
rx_complete
,
skb
);
urb
->
transfer_flags
|=
URB_ASYNC_UNLINK
;
spin_lock_irqsave
(
&
dev
->
rxq
.
lock
,
lockflags
);
if
(
netif_running
(
&
dev
->
net
)
&&
netif_device_present
(
&
dev
->
net
)
&&
!
test_bit
(
EVENT_RX_HALT
,
&
dev
->
flags
))
{
switch
(
retval
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
)){
case
-
EPIPE
:
...
...
@@ -1508,15 +1821,19 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
case
-
ENOMEM
:
defer_kevent
(
dev
,
EVENT_RX_MEMORY
);
break
;
case
-
ENODEV
:
devdbg
(
dev
,
"device gone"
);
netif_device_detach
(
&
dev
->
net
);
break
;
default:
d
bg
(
"%s rx submit, %d"
,
dev
->
net
.
name
,
retval
);
d
evdbg
(
dev
,
"rx submit, %d"
,
retval
);
tasklet_schedule
(
&
dev
->
bh
);
break
;
case
0
:
__skb_queue_tail
(
&
dev
->
rxq
,
skb
);
}
}
else
{
d
bg
(
"rx: stopped"
);
d
evdbg
(
dev
,
"rx: stopped"
);
retval
=
-
ENOLINK
;
}
spin_unlock_irqrestore
(
&
dev
->
rxq
.
lock
,
lockflags
);
...
...
@@ -1553,7 +1870,7 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
if
(
status
!=
NET_RX_SUCCESS
)
devdbg
(
dev
,
"netif_rx status %d"
,
status
);
}
else
{
d
bg
(
"drop"
);
d
evdbg
(
dev
,
"drop"
);
error:
dev
->
stats
.
rx_errors
++
;
skb_queue_tail
(
&
dev
->
done
,
skb
);
...
...
@@ -1580,7 +1897,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
entry
->
state
=
rx_cleanup
;
dev
->
stats
.
rx_errors
++
;
dev
->
stats
.
rx_length_errors
++
;
d
bg
(
"rx length %d"
,
skb
->
len
);
d
evdbg
(
dev
,
"rx length %d"
,
skb
->
len
);
}
break
;
...
...
@@ -1589,15 +1906,31 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
// we avoid the highspeed version of the ETIMEOUT/EILSEQ
// storm, recovering as needed.
case
-
EPIPE
:
dev
->
stats
.
rx_errors
++
;
defer_kevent
(
dev
,
EVENT_RX_HALT
);
// FALLTHROUGH
// software-driven interface shutdown
case
-
ECONNRESET
:
// according to API spec
case
-
ECONNABORTED
:
// some (now fixed?) UHCI bugs
dbg
(
"%s rx shutdown, code %d"
,
dev
->
net
.
name
,
urb_status
);
case
-
ECONNRESET
:
// async unlink
case
-
ESHUTDOWN
:
// hardware gone
#ifdef VERBOSE
devdbg
(
dev
,
"rx shutdown, code %d"
,
urb_status
);
#endif
goto
block
;
// we get controller i/o faults during khubd disconnect() delays.
// throttle down resubmits, to avoid log floods; just temporarily,
// so we still recover when the fault isn't a khubd delay.
case
-
EPROTO
:
// ehci
case
-
ETIMEDOUT
:
// ohci
case
-
EILSEQ
:
// uhci
dev
->
stats
.
rx_errors
++
;
if
(
!
timer_pending
(
&
dev
->
delay
))
{
mod_timer
(
&
dev
->
delay
,
jiffies
+
THROTTLE_JIFFIES
);
devdbg
(
dev
,
"rx throttle %d"
,
urb_status
);
}
block:
entry
->
state
=
rx_cleanup
;
// do urb frees only in the tasklet (UHCI has oopsed ...)
entry
->
urb
=
urb
;
urb
=
0
;
break
;
...
...
@@ -1608,12 +1941,9 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
// FALLTHROUGH
default:
// on unplug we get ETIMEDOUT (ohci) or EILSEQ (uhci)
// until khubd sees its interrupt and disconnects us.
// that can easily be hundreds of passes through here.
entry
->
state
=
rx_cleanup
;
dev
->
stats
.
rx_errors
++
;
d
bg
(
"%s rx: status %d"
,
dev
->
net
.
name
,
urb_status
);
d
evdbg
(
dev
,
"rx status %d"
,
urb_status
);
break
;
}
...
...
@@ -1628,7 +1958,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
usb_free_urb
(
urb
);
}
#ifdef VERBOSE
d
bg
(
"no read resubmitted"
);
d
evdbg
(
dev
,
"no read resubmitted"
);
#endif
/* VERBOSE */
}
...
...
@@ -1636,7 +1966,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
// unlink pending rx/tx; completion handlers do all other cleanup
static
int
unlink_urbs
(
struct
sk_buff_head
*
q
)
static
int
unlink_urbs
(
struct
usbnet
*
dev
,
struct
sk_buff_head
*
q
)
{
unsigned
long
flags
;
struct
sk_buff
*
skb
,
*
skbnext
;
...
...
@@ -1656,7 +1986,7 @@ static int unlink_urbs (struct sk_buff_head *q)
// these (async) unlinks complete immediately
retval
=
usb_unlink_urb
(
urb
);
if
(
retval
!=
-
EINPROGRESS
&&
retval
!=
0
)
d
bg
(
"unlink urb err, %d"
,
retval
);
d
evdbg
(
dev
,
"unlink urb err, %d"
,
retval
);
else
count
++
;
}
...
...
@@ -1688,7 +2018,7 @@ static int usbnet_stop (struct net_device *net)
// ensure there are no more active urbs
add_wait_queue
(
&
unlink_wakeup
,
&
wait
);
dev
->
wait
=
&
unlink_wakeup
;
temp
=
unlink_urbs
(
&
dev
->
txq
)
+
unlink_urbs
(
&
dev
->
rxq
);
temp
=
unlink_urbs
(
dev
,
&
dev
->
txq
)
+
unlink_urbs
(
dev
,
&
dev
->
rxq
);
// maybe wait for deletions to finish.
while
(
skb_queue_len
(
&
dev
->
rxq
)
...
...
@@ -1696,11 +2026,16 @@ static int usbnet_stop (struct net_device *net)
&&
skb_queue_len
(
&
dev
->
done
))
{
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
UNLINK_TIMEOUT_JIFFIES
);
d
bg
(
"waited for %d urb completions"
,
temp
);
d
evdbg
(
dev
,
"waited for %d urb completions"
,
temp
);
}
dev
->
wait
=
0
;
remove_wait_queue
(
&
unlink_wakeup
,
&
wait
);
// deferred work (task, timer, softirq) must also stop
flush_scheduled_work
();
del_timer_sync
(
&
dev
->
delay
);
tasklet_kill
(
&
dev
->
bh
);
mutex_unlock
(
&
dev
->
mutex
);
return
0
;
}
...
...
@@ -1738,7 +2073,7 @@ static int usbnet_open (struct net_device *net)
if
(
dev
->
msg_level
>=
2
)
devinfo
(
dev
,
"open: enable queueing "
"(rx %d, tx %d) mtu %d %s framing"
,
RX_QLEN
,
TX_QLEN
,
dev
->
net
.
mtu
,
RX_QLEN
(
dev
),
TX_QLEN
(
dev
)
,
dev
->
net
.
mtu
,
(
info
->
flags
&
(
FLAG_FRAMING_NC
|
FLAG_FRAMING_GL
))
?
((
info
->
flags
&
FLAG_FRAMING_NC
)
?
"NetChip"
...
...
@@ -1755,7 +2090,8 @@ static int usbnet_open (struct net_device *net)
/*-------------------------------------------------------------------------*/
static
int
usbnet_ethtool_ioctl
(
struct
net_device
*
net
,
void
*
useraddr
)
static
inline
int
usbnet_ethtool_ioctl
(
struct
net_device
*
net
,
void
*
useraddr
)
{
struct
usbnet
*
dev
=
(
struct
usbnet
*
)
net
->
priv
;
u32
cmd
;
...
...
@@ -1829,9 +2165,8 @@ static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
/* work that cannot be done in interrupt context uses keventd.
*
* NOTE: "uhci" and "usb-uhci" may have trouble with this since they don't
* queue control transfers to individual devices, and other threads could
* trigger control requests concurrently. hope that's rare.
* NOTE: with 2.5 we could do more of this using completion callbacks,
* especially now that control transfers can be queued.
*/
static
void
kevent
(
void
*
data
)
...
...
@@ -1841,24 +2176,22 @@ kevent (void *data)
/* usb_clear_halt() needs a thread context */
if
(
test_bit
(
EVENT_TX_HALT
,
&
dev
->
flags
))
{
unlink_urbs
(
&
dev
->
txq
);
status
=
usb_clear_halt
(
dev
->
udev
,
usb_sndbulkpipe
(
dev
->
udev
,
dev
->
driver_info
->
out
));
unlink_urbs
(
dev
,
&
dev
->
txq
);
status
=
usb_clear_halt
(
dev
->
udev
,
dev
->
out
);
if
(
status
<
0
)
err
(
"%s:
can't clear tx halt, status %d"
,
dev
->
net
.
name
,
status
);
deverr
(
dev
,
"
can't clear tx halt, status %d"
,
status
);
else
{
clear_bit
(
EVENT_TX_HALT
,
&
dev
->
flags
);
netif_wake_queue
(
&
dev
->
net
);
}
}
if
(
test_bit
(
EVENT_RX_HALT
,
&
dev
->
flags
))
{
unlink_urbs
(
&
dev
->
rxq
);
status
=
usb_clear_halt
(
dev
->
udev
,
usb_rcvbulkpipe
(
dev
->
udev
,
dev
->
driver_info
->
in
));
unlink_urbs
(
dev
,
&
dev
->
rxq
);
status
=
usb_clear_halt
(
dev
->
udev
,
dev
->
in
);
if
(
status
<
0
)
err
(
"%s:
can't clear rx halt, status %d"
,
dev
->
net
.
name
,
status
);
deverr
(
dev
,
"
can't clear rx halt, status %d"
,
status
);
else
{
clear_bit
(
EVENT_RX_HALT
,
&
dev
->
flags
);
tasklet_schedule
(
&
dev
->
bh
);
...
...
@@ -1881,8 +2214,8 @@ kevent (void *data)
}
if
(
dev
->
flags
)
d
bg
(
"%s:
kevent done, flags = 0x%lx"
,
dev
->
net
.
name
,
dev
->
flags
);
d
evdbg
(
dev
,
"
kevent done, flags = 0x%lx"
,
dev
->
flags
);
}
/*-------------------------------------------------------------------------*/
...
...
@@ -1893,8 +2226,35 @@ static void tx_complete (struct urb *urb, struct pt_regs *regs)
struct
skb_data
*
entry
=
(
struct
skb_data
*
)
skb
->
cb
;
struct
usbnet
*
dev
=
entry
->
dev
;
if
(
urb
->
status
==
-
EPIPE
)
defer_kevent
(
dev
,
EVENT_TX_HALT
);
if
(
urb
->
status
==
0
)
{
dev
->
stats
.
tx_packets
++
;
dev
->
stats
.
tx_bytes
+=
entry
->
length
;
}
else
{
dev
->
stats
.
tx_errors
++
;
switch
(
urb
->
status
)
{
case
-
EPIPE
:
defer_kevent
(
dev
,
EVENT_TX_HALT
);
break
;
// like rx, tx gets controller i/o faults during khubd delays
// and so it uses the same throttling mechanism.
case
-
EPROTO
:
// ehci
case
-
ETIMEDOUT
:
// ohci
case
-
EILSEQ
:
// uhci
if
(
!
timer_pending
(
&
dev
->
delay
))
{
mod_timer
(
&
dev
->
delay
,
jiffies
+
THROTTLE_JIFFIES
);
devdbg
(
dev
,
"tx throttle %d"
,
urb
->
status
);
}
netif_stop_queue
(
&
dev
->
net
);
break
;
default:
devdbg
(
dev
,
"tx err %d"
,
entry
->
urb
->
status
);
break
;
}
}
urb
->
dev
=
0
;
entry
->
state
=
tx_done
;
defer_bh
(
dev
,
skb
);
...
...
@@ -1906,7 +2266,7 @@ static void usbnet_tx_timeout (struct net_device *net)
{
struct
usbnet
*
dev
=
(
struct
usbnet
*
)
net
->
priv
;
unlink_urbs
(
&
dev
->
txq
);
unlink_urbs
(
dev
,
&
dev
->
txq
);
tasklet_schedule
(
&
dev
->
bh
);
// FIXME: device recovery -- reset?
...
...
@@ -1933,14 +2293,14 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
if
(
info
->
tx_fixup
)
{
skb
=
info
->
tx_fixup
(
dev
,
skb
,
GFP_ATOMIC
);
if
(
!
skb
)
{
d
bg
(
"can't tx_fixup skb"
);
d
evdbg
(
dev
,
"can't tx_fixup skb"
);
goto
drop
;
}
}
length
=
skb
->
len
;
if
(
!
(
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
)))
{
d
bg
(
"no urb"
);
d
evdbg
(
dev
,
"no urb"
);
goto
drop
;
}
...
...
@@ -1965,20 +2325,24 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
}
else
#endif
/* CONFIG_USB_NET1080 */
/* don't assume the hardware handles USB_ZERO_PACKET */
if
((
length
%
EP_SIZE
(
dev
))
==
0
)
skb
->
len
++
;
usb_fill_bulk_urb
(
urb
,
dev
->
udev
,
usb_sndbulkpipe
(
dev
->
udev
,
info
->
out
),
usb_fill_bulk_urb
(
urb
,
dev
->
udev
,
dev
->
out
,
skb
->
data
,
skb
->
len
,
tx_complete
,
skb
);
urb
->
transfer_flags
|=
URB_ASYNC_UNLINK
;
/* don't assume the hardware handles USB_ZERO_PACKET
* NOTE: strictly conforming cdc-ether devices should expect
* the ZLP here, but ignore the one-byte packet.
*
* FIXME zero that byte, if it doesn't require a new skb.
*/
if
((
length
%
dev
->
maxpacket
)
==
0
)
urb
->
transfer_buffer_length
++
;
spin_lock_irqsave
(
&
dev
->
txq
.
lock
,
flags
);
#ifdef CONFIG_USB_NET1080
if
(
info
->
flags
&
FLAG_FRAMING_NC
)
{
header
->
packet_id
=
cpu_to_le16
(
dev
->
packet_id
++
);
header
->
packet_id
=
cpu_to_le16
(
(
u16
)
dev
->
dev_
packet_id
++
);
put_unaligned
(
header
->
packet_id
,
&
trailer
->
packet_id
);
#if 0
devdbg (dev, "frame >tx h %d p %d id %d",
...
...
@@ -1994,12 +2358,12 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
defer_kevent
(
dev
,
EVENT_TX_HALT
);
break
;
default:
d
bg
(
"%s tx: submit urb err %d"
,
net
->
name
,
retval
);
d
evdbg
(
dev
,
"tx: submit urb err %d"
,
retval
);
break
;
case
0
:
net
->
trans_start
=
jiffies
;
__skb_queue_tail
(
&
dev
->
txq
,
skb
);
if
(
dev
->
txq
.
qlen
>=
TX_QLEN
)
if
(
dev
->
txq
.
qlen
>=
TX_QLEN
(
dev
)
)
netif_stop_queue
(
net
);
}
spin_unlock_irqrestore
(
&
dev
->
txq
.
lock
,
flags
);
...
...
@@ -2024,7 +2388,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
/*-------------------------------------------------------------------------*/
// tasklet
... work that avoided running in_irq()
// tasklet
(work deferred from completions, in_irq) or timer
static
void
usbnet_bh
(
unsigned
long
param
)
{
...
...
@@ -2040,23 +2404,12 @@ static void usbnet_bh (unsigned long param)
rx_process
(
dev
,
skb
);
continue
;
case
tx_done
:
if
(
entry
->
urb
->
status
)
{
// can this statistic become more specific?
dev
->
stats
.
tx_errors
++
;
dbg
(
"%s tx: err %d"
,
dev
->
net
.
name
,
entry
->
urb
->
status
);
}
else
{
dev
->
stats
.
tx_packets
++
;
dev
->
stats
.
tx_bytes
+=
entry
->
length
;
}
// FALLTHROUGH:
case
rx_cleanup
:
usb_free_urb
(
entry
->
urb
);
dev_kfree_skb
(
skb
);
continue
;
default:
dbg
(
"%s: bogus skb state %d"
,
dev
->
net
.
name
,
entry
->
state
);
devdbg
(
dev
,
"bogus skb state %d"
,
entry
->
state
);
}
}
...
...
@@ -2068,23 +2421,28 @@ static void usbnet_bh (unsigned long param)
// or are we maybe short a few urbs?
}
else
if
(
netif_running
(
&
dev
->
net
)
&&
netif_device_present
(
&
dev
->
net
)
&&
!
timer_pending
(
&
dev
->
delay
)
&&
!
test_bit
(
EVENT_RX_HALT
,
&
dev
->
flags
))
{
int
temp
=
dev
->
rxq
.
qlen
;
int
qlen
=
RX_QLEN
(
dev
);
if
(
temp
<
RX_QLEN
)
{
if
(
temp
<
qlen
)
{
struct
urb
*
urb
;
int
i
;
for
(
i
=
0
;
i
<
3
&&
dev
->
rxq
.
qlen
<
RX_QLEN
;
i
++
)
{
// don't refill the queue all at once
for
(
i
=
0
;
i
<
10
&&
dev
->
rxq
.
qlen
<
qlen
;
i
++
)
{
if
((
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
))
!=
0
)
rx_submit
(
dev
,
urb
,
GFP_ATOMIC
);
}
if
(
temp
!=
dev
->
rxq
.
qlen
)
devdbg
(
dev
,
"rxqlen %d --> %d"
,
temp
,
dev
->
rxq
.
qlen
);
if
(
dev
->
rxq
.
qlen
<
RX_QLEN
)
if
(
dev
->
rxq
.
qlen
<
qlen
)
tasklet_schedule
(
&
dev
->
bh
);
}
if
(
dev
->
txq
.
qlen
<
TX_QLEN
)
if
(
dev
->
txq
.
qlen
<
TX_QLEN
(
dev
)
)
netif_wake_queue
(
&
dev
->
net
);
}
}
...
...
@@ -2117,13 +2475,8 @@ static void usbnet_disconnect (struct usb_interface *intf)
unregister_netdev
(
&
dev
->
net
);
mutex_lock
(
&
usbnet_mutex
);
mutex_lock
(
&
dev
->
mutex
);
list_del
(
&
dev
->
dev_list
);
mutex_unlock
(
&
usbnet_mutex
);
// assuming we used keventd, it must quiesce too
flush_scheduled_work
();
if
(
dev
->
driver_info
->
unbind
)
dev
->
driver_info
->
unbind
(
dev
,
intf
);
kfree
(
dev
);
usb_put_dev
(
xdev
);
...
...
@@ -2142,20 +2495,12 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
struct
usb_host_interface
*
interface
;
struct
driver_info
*
info
;
struct
usb_device
*
xdev
;
int
status
;
info
=
(
struct
driver_info
*
)
prod
->
driver_info
;
xdev
=
interface_to_usbdev
(
udev
);
interface
=
&
udev
->
altsetting
[
udev
->
act_altsetting
];
if
(
!
(
info
->
flags
&
FLAG_NO_SETINT
))
{
if
(
usb_set_interface
(
xdev
,
interface
->
desc
.
bInterfaceNumber
,
interface
->
desc
.
bAlternateSetting
)
<
0
)
{
err
(
"set_interface failed"
);
return
-
EIO
;
}
}
// set up our own records
if
(
!
(
dev
=
kmalloc
(
sizeof
*
dev
,
GFP_KERNEL
)))
{
dbg
(
"can't kmalloc dev"
);
...
...
@@ -2168,13 +2513,15 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev
->
udev
=
xdev
;
dev
->
driver_info
=
info
;
dev
->
msg_level
=
msg_level
;
INIT_LIST_HEAD
(
&
dev
->
dev_list
);
skb_queue_head_init
(
&
dev
->
rxq
);
skb_queue_head_init
(
&
dev
->
txq
);
skb_queue_head_init
(
&
dev
->
done
);
dev
->
bh
.
func
=
usbnet_bh
;
dev
->
bh
.
data
=
(
unsigned
long
)
dev
;
INIT_WORK
(
&
dev
->
kevent
,
kevent
,
dev
);
dev
->
delay
.
function
=
usbnet_bh
;
dev
->
delay
.
data
=
(
unsigned
long
)
dev
;
init_timer
(
&
dev
->
delay
);
// set up network interface records
net
=
&
dev
->
net
;
...
...
@@ -2200,31 +2547,41 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
net
->
tx_timeout
=
usbnet_tx_timeout
;
net
->
do_ioctl
=
usbnet_ioctl
;
// allow device-specific bind/init procedures
// NOTE net->name still not usable ...
if
(
info
->
bind
)
status
=
info
->
bind
(
dev
,
udev
);
else
if
(
!
info
->
in
||
info
->
out
)
status
=
get_endpoints
(
dev
,
udev
);
else
{
dev
->
in
=
usb_rcvbulkpipe
(
xdev
,
info
->
in
);
dev
->
out
=
usb_sndbulkpipe
(
xdev
,
info
->
out
);
if
(
!
(
info
->
flags
&
FLAG_NO_SETINT
))
status
=
usb_set_interface
(
xdev
,
interface
->
desc
.
bInterfaceNumber
,
interface
->
desc
.
bAlternateSetting
);
else
status
=
0
;
}
if
(
status
<
0
)
{
kfree
(
dev
);
return
status
;
}
dev
->
maxpacket
=
usb_maxpacket
(
dev
->
udev
,
dev
->
out
,
1
);
register_netdev
(
&
dev
->
net
);
devinfo
(
dev
,
"register usbnet usb-%s-%s, %s"
,
devinfo
(
dev
,
"register usbnet
at
usb-%s-%s, %s"
,
xdev
->
bus
->
bus_name
,
xdev
->
devpath
,
dev
->
driver_info
->
description
);
#ifdef CONFIG_USB_ZAURUS
if
(
dev
->
driver_info
==
&
zaurus_sl5x00_info
)
{
int
status
;
status
=
usb_set_configuration
(
xdev
,
1
);
devinfo
(
dev
,
"set config --> %d"
,
status
);
status
=
usb_set_interface
(
xdev
,
1
,
1
);
devinfo
(
dev
,
"set altsetting --> %d"
,
status
);
}
#endif
// ok, it's ready to go.
usb_set_intfdata
(
udev
,
dev
);
mutex_lock
(
&
usbnet_mutex
);
list_add
(
&
dev
->
dev_list
,
&
usbnet_list
);
usb_set_intfdata
(
udev
,
dev
);
mutex_unlock
(
&
dev
->
mutex
);
// start as if the link is up
netif_device_attach
(
&
dev
->
net
);
mutex_unlock
(
&
usbnet_mutex
);
return
0
;
}
...
...
@@ -2298,28 +2655,19 @@ static const struct usb_device_id products [] = {
},
#endif
#ifdef CONFIG_USB_PXA
/*
* PXA250 or PXA210 ... these use a "usb-eth" driver much like
* the sa1100 one.
*/
{
// Compaq "Itsy" vendor/product id, version "2.0"
USB_DEVICE_VER
(
0x049F
,
0x505A
,
0x0200
,
0x0200
),
.
driver_info
=
(
unsigned
long
)
&
pxa_info
,
},
#endif
#ifdef CONFIG_USB_SA1100
#ifdef CONFIG_USB_ARMLINUX
/*
* SA-1100 using standard ARM Linux kernels, or compatible.
* Often used when talking to Linux PDAs (iPaq, Yopy, etc).
* The sa-1100 "usb-eth" driver handles the basic framing.
*
* PXA25x or PXA210 ... these use a "usb-eth" driver much like
* the sa1100 one, but hardware uses different endpoint numbers.
*/
{
// 1183 = 0x049F, both used as hex values?
// Compaq "Itsy" vendor/product id
, version "0.0"
USB_DEVICE
_VER
(
0x049F
,
0x505A
,
0
,
0
),
// Compaq "Itsy" vendor/product id
USB_DEVICE
(
0x049F
,
0x505A
),
.
driver_info
=
(
unsigned
long
)
&
linuxdev_info
,
},
{
USB_DEVICE
(
0x0E7E
,
0x1001
),
// G.Mate "Yopy"
...
...
@@ -2337,9 +2685,10 @@ static const struct usb_device_id products [] = {
|
USB_DEVICE_ID_MATCH_DEVICE
,
.
idVendor
=
0x04DD
,
.
idProduct
=
0x8004
,
.
bInterfaceClass
=
0x0a
,
.
bInterfaceSubClass
=
0x00
,
.
bInterfaceProtocol
=
0x00
,
/* match the master interface */
.
bInterfaceClass
=
USB_CLASS_COMM
,
.
bInterfaceSubClass
=
6
/* Ethernet model */
,
.
bInterfaceProtocol
=
0
,
.
driver_info
=
(
unsigned
long
)
&
zaurus_sl5x00_info
,
},
{
.
match_flags
=
USB_DEVICE_ID_MATCH_INT_INFO
...
...
@@ -2360,6 +2709,24 @@ static const struct usb_device_id products [] = {
.
bInterfaceProtocol
=
0x00
,
.
driver_info
=
(
unsigned
long
)
&
zaurus_slb500_info
,
},
#endif
#ifdef CONFIG_USB_CDCETHER
{
/* CDC Ether uses two interfaces, not necessarily consecutive.
* We match the main interface, ignoring the optional device
* class so we could handle devices that aren't exclusively
* CDC ether.
*
* NOTE: this match must come AFTER entries working around
* bugs/quirks in a given product (like Zaurus, above).
*/
.
match_flags
=
USB_DEVICE_ID_MATCH_INT_INFO
,
.
bInterfaceClass
=
USB_CLASS_COMM
,
.
bInterfaceSubClass
=
6
/* Ethernet model */
,
.
bInterfaceProtocol
=
0
,
.
driver_info
=
(
unsigned
long
)
&
cdc_info
,
},
#endif
{
},
// END
...
...
drivers/usb/serial/keyspan.h
View file @
6c7a3c95
...
...
@@ -411,19 +411,19 @@ static const struct keyspan_device_details usa49w_device_details = {
};
static
const
struct
keyspan_device_details
usa49wlc_device_details
=
{
product_id:
keyspan_usa49wlc_product_id
,
msg_format:
msg_usa49
,
num_ports:
4
,
indat_endp_flip:
0
,
outdat_endp_flip:
0
,
indat_endpoints:
{
0x81
,
0x82
,
0x83
,
0x84
},
outdat_endpoints:
{
0x01
,
0x02
,
0x03
,
0x04
},
inack_endpoints:
{
-
1
,
-
1
,
-
1
,
-
1
},
outcont_endpoints:
{
-
1
,
-
1
,
-
1
,
-
1
},
instat_endpoint:
0x87
,
glocont_endpoint:
0x07
,
calculate_baud_rate:
keyspan_usa19w_calc_baud
,
baudclk:
KEYSPAN_USA19W_BAUDCLK
,
.
product_id
=
keyspan_usa49wlc_product_id
,
.
msg_format
=
msg_usa49
,
.
num_ports
=
4
,
.
indat_endp_flip
=
0
,
.
outdat_endp_flip
=
0
,
.
indat_endpoints
=
{
0x81
,
0x82
,
0x83
,
0x84
},
.
outdat_endpoints
=
{
0x01
,
0x02
,
0x03
,
0x04
},
.
inack_endpoints
=
{
-
1
,
-
1
,
-
1
,
-
1
},
.
outcont_endpoints
=
{
-
1
,
-
1
,
-
1
,
-
1
},
.
instat_endpoint
=
0x87
,
.
glocont_endpoint
=
0x07
,
.
calculate_baud_rate
=
keyspan_usa19w_calc_baud
,
.
baudclk
=
KEYSPAN_USA19W_BAUDCLK
,
};
static
const
struct
keyspan_device_details
*
keyspan_devices
[]
=
{
...
...
drivers/usb/storage/scsiglue.c
View file @
6c7a3c95
...
...
@@ -141,13 +141,19 @@ static int usb_storage_release(struct Scsi_Host *psh)
static
int
usb_storage_queuecommand
(
Scsi_Cmnd
*
srb
,
void
(
*
done
)(
Scsi_Cmnd
*
))
{
struct
us_data
*
us
=
(
struct
us_data
*
)
srb
->
device
->
host
->
hostdata
[
0
];
int
state
=
atomic_read
(
&
us
->
sm_state
);
US_DEBUGP
(
"queuecommand() called
\n
"
);
srb
->
host_scribble
=
(
unsigned
char
*
)
us
;
/* enqueue the command */
BUG_ON
(
atomic_read
(
&
us
->
sm_state
)
!=
US_STATE_IDLE
);
BUG_ON
(
us
->
srb
!=
NULL
);
if
(
state
!=
US_STATE_IDLE
||
us
->
srb
!=
NULL
)
{
printk
(
KERN_ERR
USB_STORAGE
"Error in %s: "
"state = %d, us->srb = %p
\n
"
,
__FUNCTION__
,
state
,
us
->
srb
);
return
SCSI_MLQUEUE_HOST_BUSY
;
}
srb
->
scsi_done
=
done
;
us
->
srb
=
srb
;
...
...
@@ -175,8 +181,7 @@ static int usb_storage_command_abort( Scsi_Cmnd *srb )
return
FAILED
;
}
usb_stor_abort_transport
(
us
);
return
SUCCESS
;
return
usb_stor_abort_transport
(
us
);
}
/* This invokes the transport reset mechanism to reset the state of the
...
...
@@ -185,10 +190,15 @@ static int usb_storage_command_abort( Scsi_Cmnd *srb )
static
int
usb_storage_device_reset
(
Scsi_Cmnd
*
srb
)
{
struct
us_data
*
us
=
(
struct
us_data
*
)
srb
->
device
->
host
->
hostdata
[
0
];
int
state
=
atomic_read
(
&
us
->
sm_state
);
int
result
;
US_DEBUGP
(
"device_reset() called
\n
"
);
BUG_ON
(
atomic_read
(
&
us
->
sm_state
)
!=
US_STATE_IDLE
);
if
(
state
!=
US_STATE_IDLE
)
{
printk
(
KERN_ERR
USB_STORAGE
"Error in %s: "
"invalid state %d
\n
"
,
__FUNCTION__
,
state
);
return
FAILED
;
}
/* set the state and release the lock */
atomic_set
(
&
us
->
sm_state
,
US_STATE_RESETTING
);
...
...
@@ -260,6 +270,7 @@ static int usb_storage_proc_info (char *buffer, char **start, off_t offset,
struct
us_data
*
us
;
char
*
pos
=
buffer
;
struct
Scsi_Host
*
hostptr
;
unsigned
long
f
;
/* if someone is sending us data, just throw it away */
if
(
inout
)
...
...
@@ -274,6 +285,7 @@ static int usb_storage_proc_info (char *buffer, char **start, off_t offset,
/* if we couldn't find it, we return an error */
if
(
!
us
)
{
scsi_host_put
(
hostptr
);
return
-
ESRCH
;
}
...
...
@@ -289,6 +301,24 @@ static int usb_storage_proc_info (char *buffer, char **start, off_t offset,
SPRINTF
(
" Protocol: %s
\n
"
,
us
->
protocol_name
);
SPRINTF
(
" Transport: %s
\n
"
,
us
->
transport_name
);
/* show the device flags */
if
(
pos
<
buffer
+
length
)
{
pos
+=
sprintf
(
pos
,
" Quirks:"
);
f
=
us
->
flags
;
#define DO_FLAG(a) if (f & US_FL_##a) pos += sprintf(pos, " " #a)
DO_FLAG
(
SINGLE_LUN
);
DO_FLAG
(
MODE_XLATE
);
DO_FLAG
(
START_STOP
);
DO_FLAG
(
IGNORE_SER
);
DO_FLAG
(
SCM_MULT_TARG
);
DO_FLAG
(
FIX_INQUIRY
);
DO_FLAG
(
FIX_CAPACITY
);
#undef DO_FLAG
*
(
pos
++
)
=
'\n'
;
}
/* release the reference count on this host */
scsi_host_put
(
hostptr
);
...
...
drivers/usb/storage/transport.c
View file @
6c7a3c95
...
...
@@ -297,10 +297,11 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe,
/* stalled */
case
-
EPIPE
:
/* for control endpoints, a stall indicates a protocol error */
/* for control endpoints, (used by CB[I]) a stall indicates
* a failed command */
if
(
usb_pipecontrol
(
pipe
))
{
US_DEBUGP
(
"-- stall on control pipe
\n
"
);
return
USB_STOR_XFER_
ERROR
;
return
USB_STOR_XFER_
STALLED
;
}
/* for other sorts of endpoint, clear the stall */
...
...
@@ -691,7 +692,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
/* Abort the currently running scsi command or device reset.
* This must be called with scsi_lock(us->srb->host) held */
void
usb_stor_abort_transport
(
struct
us_data
*
us
)
int
usb_stor_abort_transport
(
struct
us_data
*
us
)
{
struct
Scsi_Host
*
host
;
int
state
=
atomic_read
(
&
us
->
sm_state
);
...
...
@@ -701,7 +702,11 @@ void usb_stor_abort_transport(struct us_data *us)
/* Normally the current state is RUNNING. If the control thread
* hasn't even started processing this command, the state will be
* IDLE. Anything else is a bug. */
BUG_ON
((
state
!=
US_STATE_RUNNING
&&
state
!=
US_STATE_IDLE
));
if
(
state
!=
US_STATE_RUNNING
&&
state
!=
US_STATE_IDLE
)
{
printk
(
KERN_ERR
USB_STORAGE
"Error in %s: "
"invalid state %d
\n
"
,
__FUNCTION__
,
state
);
return
FAILED
;
}
/* set state to abort and release the lock */
atomic_set
(
&
us
->
sm_state
,
US_STATE_ABORTING
);
...
...
@@ -730,6 +735,7 @@ void usb_stor_abort_transport(struct us_data *us)
/* Reacquire the lock: note that us->srb is now NULL */
scsi_lock
(
host
);
return
SUCCESS
;
}
/*
...
...
@@ -750,8 +756,14 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* check the return code for the command */
US_DEBUGP
(
"Call to usb_stor_ctrl_transfer() returned %d
\n
"
,
result
);
/* if we stalled the command, it means command failed */
if
(
result
==
USB_STOR_XFER_STALLED
)
{
return
USB_STOR_TRANSPORT_FAILED
;
}
/* Uh oh... serious problem here */
if
(
result
!=
USB_STOR_XFER_GOOD
)
{
/* Uh oh... serious problem here */
return
USB_STOR_TRANSPORT_ERROR
;
}
...
...
@@ -834,8 +846,14 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
/* check the return code for the command */
US_DEBUGP
(
"Call to usb_stor_ctrl_transfer() returned %d
\n
"
,
result
);
/* if we stalled the command, it means command failed */
if
(
result
==
USB_STOR_XFER_STALLED
)
{
return
USB_STOR_TRANSPORT_FAILED
;
}
/* Uh oh... serious problem here */
if
(
result
!=
USB_STOR_XFER_GOOD
)
{
/* Uh oh... serious problem here */
return
USB_STOR_TRANSPORT_ERROR
;
}
...
...
drivers/usb/storage/transport.h
View file @
6c7a3c95
...
...
@@ -154,7 +154,7 @@ extern int usb_stor_Bulk_max_lun(struct us_data*);
extern
int
usb_stor_Bulk_reset
(
struct
us_data
*
);
extern
void
usb_stor_invoke_transport
(
Scsi_Cmnd
*
,
struct
us_data
*
);
extern
void
usb_stor_abort_transport
(
struct
us_data
*
);
extern
int
usb_stor_abort_transport
(
struct
us_data
*
);
extern
int
usb_stor_bulk_msg
(
struct
us_data
*
us
,
void
*
data
,
unsigned
int
pipe
,
unsigned
int
len
,
unsigned
int
*
act_len
);
...
...
drivers/usb/storage/usb.c
View file @
6c7a3c95
...
...
@@ -430,39 +430,39 @@ static int usb_stor_control_thread(void * __us)
}
/* Set up the URB and the usb_ctrlrequest.
*
s
s->dev_semaphore must already be locked.
*
u
s->dev_semaphore must already be locked.
* Note that this function assumes that all the data in the us_data
* structure is current.
* Returns non-zero on failure, zero on success
*/
static
int
usb_stor_allocate_urbs
(
struct
us_data
*
s
s
)
static
int
usb_stor_allocate_urbs
(
struct
us_data
*
u
s
)
{
/* calculate and store the pipe values */
ss
->
send_ctrl_pipe
=
usb_sndctrlpipe
(
s
s
->
pusb_dev
,
0
);
ss
->
recv_ctrl_pipe
=
usb_rcvctrlpipe
(
s
s
->
pusb_dev
,
0
);
ss
->
send_bulk_pipe
=
usb_sndbulkpipe
(
ss
->
pusb_dev
,
s
s
->
ep_out
);
ss
->
recv_bulk_pipe
=
usb_rcvbulkpipe
(
ss
->
pusb_dev
,
s
s
->
ep_in
);
ss
->
recv_intr_pipe
=
usb_rcvintpipe
(
ss
->
pusb_dev
,
s
s
->
ep_int
);
us
->
send_ctrl_pipe
=
usb_sndctrlpipe
(
u
s
->
pusb_dev
,
0
);
us
->
recv_ctrl_pipe
=
usb_rcvctrlpipe
(
u
s
->
pusb_dev
,
0
);
us
->
send_bulk_pipe
=
usb_sndbulkpipe
(
us
->
pusb_dev
,
u
s
->
ep_out
);
us
->
recv_bulk_pipe
=
usb_rcvbulkpipe
(
us
->
pusb_dev
,
u
s
->
ep_in
);
us
->
recv_intr_pipe
=
usb_rcvintpipe
(
us
->
pusb_dev
,
u
s
->
ep_int
);
/* allocate the usb_ctrlrequest for control packets */
US_DEBUGP
(
"Allocating usb_ctrlrequest
\n
"
);
s
s
->
dr
=
kmalloc
(
sizeof
(
struct
usb_ctrlrequest
),
GFP_NOIO
);
if
(
!
s
s
->
dr
)
{
u
s
->
dr
=
kmalloc
(
sizeof
(
struct
usb_ctrlrequest
),
GFP_NOIO
);
if
(
!
u
s
->
dr
)
{
US_DEBUGP
(
"allocation failed
\n
"
);
return
1
;
}
/* allocate the URB we're going to use */
US_DEBUGP
(
"Allocating URB
\n
"
);
s
s
->
current_urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
s
s
->
current_urb
)
{
u
s
->
current_urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
u
s
->
current_urb
)
{
US_DEBUGP
(
"allocation failed
\n
"
);
return
2
;
}
US_DEBUGP
(
"Allocating scatter-gather request block
\n
"
);
ss
->
current_sg
=
kmalloc
(
sizeof
(
*
s
s
->
current_sg
),
GFP_KERNEL
);
if
(
!
s
s
->
current_sg
)
{
us
->
current_sg
=
kmalloc
(
sizeof
(
*
u
s
->
current_sg
),
GFP_KERNEL
);
if
(
!
u
s
->
current_sg
)
{
US_DEBUGP
(
"allocation failed
\n
"
);
return
5
;
}
...
...
@@ -471,32 +471,32 @@ static int usb_stor_allocate_urbs(struct us_data *ss)
}
/* Deallocate the URB, the usb_ctrlrequest, and the IRQ pipe.
*
s
s->dev_semaphore must already be locked.
*
u
s->dev_semaphore must already be locked.
*/
static
void
usb_stor_deallocate_urbs
(
struct
us_data
*
s
s
)
static
void
usb_stor_deallocate_urbs
(
struct
us_data
*
u
s
)
{
/* free the scatter-gather request block */
if
(
s
s
->
current_sg
)
{
kfree
(
s
s
->
current_sg
);
s
s
->
current_sg
=
NULL
;
if
(
u
s
->
current_sg
)
{
kfree
(
u
s
->
current_sg
);
u
s
->
current_sg
=
NULL
;
}
/* free up the main URB for this device */
if
(
s
s
->
current_urb
)
{
if
(
u
s
->
current_urb
)
{
US_DEBUGP
(
"-- releasing main URB
\n
"
);
usb_free_urb
(
s
s
->
current_urb
);
s
s
->
current_urb
=
NULL
;
usb_free_urb
(
u
s
->
current_urb
);
u
s
->
current_urb
=
NULL
;
}
/* free the usb_ctrlrequest buffer */
if
(
s
s
->
dr
)
{
kfree
(
s
s
->
dr
);
s
s
->
dr
=
NULL
;
if
(
u
s
->
dr
)
{
kfree
(
u
s
->
dr
);
u
s
->
dr
=
NULL
;
}
/* mark the device as gone */
usb_put_dev
(
s
s
->
pusb_dev
);
s
s
->
pusb_dev
=
NULL
;
usb_put_dev
(
u
s
->
pusb_dev
);
u
s
->
pusb_dev
=
NULL
;
}
/* Probe to see if a new device is actually a SCSI device */
...
...
@@ -512,7 +512,7 @@ static int storage_probe(struct usb_interface *intf,
char
serial
[
USB_STOR_STRING_LEN
];
/* serial number */
unsigned
int
flags
;
struct
us_unusual_dev
*
unusual_dev
;
struct
us_data
*
s
s
=
NULL
;
struct
us_data
*
u
s
=
NULL
;
int
result
;
/* these are temporary copies -- we test on these, then put them
...
...
@@ -633,212 +633,212 @@ static int storage_probe(struct usb_interface *intf,
serial
,
sizeof
(
serial
));
/* New device -- allocate memory and initialize */
if
((
s
s
=
(
struct
us_data
*
)
kmalloc
(
sizeof
(
struct
us_data
),
if
((
u
s
=
(
struct
us_data
*
)
kmalloc
(
sizeof
(
struct
us_data
),
GFP_KERNEL
))
==
NULL
)
{
printk
(
KERN_WARNING
USB_STORAGE
"Out of memory
\n
"
);
usb_put_dev
(
dev
);
return
-
ENOMEM
;
}
memset
(
s
s
,
0
,
sizeof
(
struct
us_data
));
memset
(
u
s
,
0
,
sizeof
(
struct
us_data
));
/* Initialize the mutexes only when the struct is new */
init_completion
(
&
(
s
s
->
notify
));
init_MUTEX_LOCKED
(
&
(
s
s
->
dev_semaphore
));
init_completion
(
&
(
u
s
->
notify
));
init_MUTEX_LOCKED
(
&
(
u
s
->
dev_semaphore
));
/* copy over the subclass and protocol data */
s
s
->
subclass
=
subclass
;
s
s
->
protocol
=
protocol
;
s
s
->
flags
=
flags
;
s
s
->
unusual_dev
=
unusual_dev
;
u
s
->
subclass
=
subclass
;
u
s
->
protocol
=
protocol
;
u
s
->
flags
=
flags
;
u
s
->
unusual_dev
=
unusual_dev
;
/* copy over the endpoint data */
s
s
->
ep_in
=
ep_in
->
bEndpointAddress
&
u
s
->
ep_in
=
ep_in
->
bEndpointAddress
&
USB_ENDPOINT_NUMBER_MASK
;
s
s
->
ep_out
=
ep_out
->
bEndpointAddress
&
u
s
->
ep_out
=
ep_out
->
bEndpointAddress
&
USB_ENDPOINT_NUMBER_MASK
;
if
(
ep_int
)
{
s
s
->
ep_int
=
ep_int
->
bEndpointAddress
&
u
s
->
ep_int
=
ep_int
->
bEndpointAddress
&
USB_ENDPOINT_NUMBER_MASK
;
s
s
->
ep_bInterval
=
ep_int
->
bInterval
;
u
s
->
ep_bInterval
=
ep_int
->
bInterval
;
}
else
ss
->
ep_int
=
s
s
->
ep_bInterval
=
0
;
us
->
ep_int
=
u
s
->
ep_bInterval
=
0
;
/* establish the connection to the new device */
s
s
->
ifnum
=
ifnum
;
s
s
->
pusb_dev
=
dev
;
u
s
->
ifnum
=
ifnum
;
u
s
->
pusb_dev
=
dev
;
/* copy over the identifiying strings */
strncpy
(
s
s
->
vendor
,
mf
,
USB_STOR_STRING_LEN
);
strncpy
(
s
s
->
product
,
prod
,
USB_STOR_STRING_LEN
);
strncpy
(
s
s
->
serial
,
serial
,
USB_STOR_STRING_LEN
);
if
(
strlen
(
s
s
->
vendor
)
==
0
)
{
strncpy
(
u
s
->
vendor
,
mf
,
USB_STOR_STRING_LEN
);
strncpy
(
u
s
->
product
,
prod
,
USB_STOR_STRING_LEN
);
strncpy
(
u
s
->
serial
,
serial
,
USB_STOR_STRING_LEN
);
if
(
strlen
(
u
s
->
vendor
)
==
0
)
{
if
(
unusual_dev
->
vendorName
)
strncpy
(
s
s
->
vendor
,
unusual_dev
->
vendorName
,
strncpy
(
u
s
->
vendor
,
unusual_dev
->
vendorName
,
USB_STOR_STRING_LEN
);
else
strncpy
(
s
s
->
vendor
,
"Unknown"
,
strncpy
(
u
s
->
vendor
,
"Unknown"
,
USB_STOR_STRING_LEN
);
}
if
(
strlen
(
s
s
->
product
)
==
0
)
{
if
(
strlen
(
u
s
->
product
)
==
0
)
{
if
(
unusual_dev
->
productName
)
strncpy
(
s
s
->
product
,
unusual_dev
->
productName
,
strncpy
(
u
s
->
product
,
unusual_dev
->
productName
,
USB_STOR_STRING_LEN
);
else
strncpy
(
s
s
->
product
,
"Unknown"
,
strncpy
(
u
s
->
product
,
"Unknown"
,
USB_STOR_STRING_LEN
);
}
if
(
strlen
(
s
s
->
serial
)
==
0
)
strncpy
(
s
s
->
serial
,
"None"
,
USB_STOR_STRING_LEN
);
if
(
strlen
(
u
s
->
serial
)
==
0
)
strncpy
(
u
s
->
serial
,
"None"
,
USB_STOR_STRING_LEN
);
/*
* Set the handler pointers based on the protocol
* Again, this data is persistent across reattachments
*/
switch
(
s
s
->
protocol
)
{
switch
(
u
s
->
protocol
)
{
case
US_PR_CB
:
s
s
->
transport_name
=
"Control/Bulk"
;
s
s
->
transport
=
usb_stor_CB_transport
;
s
s
->
transport_reset
=
usb_stor_CB_reset
;
s
s
->
max_lun
=
7
;
u
s
->
transport_name
=
"Control/Bulk"
;
u
s
->
transport
=
usb_stor_CB_transport
;
u
s
->
transport_reset
=
usb_stor_CB_reset
;
u
s
->
max_lun
=
7
;
break
;
case
US_PR_CBI
:
s
s
->
transport_name
=
"Control/Bulk/Interrupt"
;
s
s
->
transport
=
usb_stor_CBI_transport
;
s
s
->
transport_reset
=
usb_stor_CB_reset
;
s
s
->
max_lun
=
7
;
u
s
->
transport_name
=
"Control/Bulk/Interrupt"
;
u
s
->
transport
=
usb_stor_CBI_transport
;
u
s
->
transport_reset
=
usb_stor_CB_reset
;
u
s
->
max_lun
=
7
;
break
;
case
US_PR_BULK
:
s
s
->
transport_name
=
"Bulk"
;
s
s
->
transport
=
usb_stor_Bulk_transport
;
s
s
->
transport_reset
=
usb_stor_Bulk_reset
;
ss
->
max_lun
=
usb_stor_Bulk_max_lun
(
s
s
);
u
s
->
transport_name
=
"Bulk"
;
u
s
->
transport
=
usb_stor_Bulk_transport
;
u
s
->
transport_reset
=
usb_stor_Bulk_reset
;
us
->
max_lun
=
usb_stor_Bulk_max_lun
(
u
s
);
break
;
#ifdef CONFIG_USB_STORAGE_HP8200e
case
US_PR_SCM_ATAPI
:
s
s
->
transport_name
=
"SCM/ATAPI"
;
s
s
->
transport
=
hp8200e_transport
;
s
s
->
transport_reset
=
usb_stor_CB_reset
;
s
s
->
max_lun
=
1
;
u
s
->
transport_name
=
"SCM/ATAPI"
;
u
s
->
transport
=
hp8200e_transport
;
u
s
->
transport_reset
=
usb_stor_CB_reset
;
u
s
->
max_lun
=
1
;
break
;
#endif
#ifdef CONFIG_USB_STORAGE_SDDR09
case
US_PR_EUSB_SDDR09
:
s
s
->
transport_name
=
"EUSB/SDDR09"
;
s
s
->
transport
=
sddr09_transport
;
s
s
->
transport_reset
=
usb_stor_CB_reset
;
s
s
->
max_lun
=
0
;
u
s
->
transport_name
=
"EUSB/SDDR09"
;
u
s
->
transport
=
sddr09_transport
;
u
s
->
transport_reset
=
usb_stor_CB_reset
;
u
s
->
max_lun
=
0
;
break
;
#endif
#ifdef CONFIG_USB_STORAGE_SDDR55
case
US_PR_SDDR55
:
s
s
->
transport_name
=
"SDDR55"
;
s
s
->
transport
=
sddr55_transport
;
s
s
->
transport_reset
=
sddr55_reset
;
s
s
->
max_lun
=
0
;
u
s
->
transport_name
=
"SDDR55"
;
u
s
->
transport
=
sddr55_transport
;
u
s
->
transport_reset
=
sddr55_reset
;
u
s
->
max_lun
=
0
;
break
;
#endif
#ifdef CONFIG_USB_STORAGE_DPCM
case
US_PR_DPCM_USB
:
s
s
->
transport_name
=
"Control/Bulk-EUSB/SDDR09"
;
s
s
->
transport
=
dpcm_transport
;
s
s
->
transport_reset
=
usb_stor_CB_reset
;
s
s
->
max_lun
=
1
;
u
s
->
transport_name
=
"Control/Bulk-EUSB/SDDR09"
;
u
s
->
transport
=
dpcm_transport
;
u
s
->
transport_reset
=
usb_stor_CB_reset
;
u
s
->
max_lun
=
1
;
break
;
#endif
#ifdef CONFIG_USB_STORAGE_FREECOM
case
US_PR_FREECOM
:
s
s
->
transport_name
=
"Freecom"
;
s
s
->
transport
=
freecom_transport
;
s
s
->
transport_reset
=
usb_stor_freecom_reset
;
s
s
->
max_lun
=
0
;
u
s
->
transport_name
=
"Freecom"
;
u
s
->
transport
=
freecom_transport
;
u
s
->
transport_reset
=
usb_stor_freecom_reset
;
u
s
->
max_lun
=
0
;
break
;
#endif
#ifdef CONFIG_USB_STORAGE_DATAFAB
case
US_PR_DATAFAB
:
s
s
->
transport_name
=
"Datafab Bulk-Only"
;
s
s
->
transport
=
datafab_transport
;
s
s
->
transport_reset
=
usb_stor_Bulk_reset
;
s
s
->
max_lun
=
1
;
u
s
->
transport_name
=
"Datafab Bulk-Only"
;
u
s
->
transport
=
datafab_transport
;
u
s
->
transport_reset
=
usb_stor_Bulk_reset
;
u
s
->
max_lun
=
1
;
break
;
#endif
#ifdef CONFIG_USB_STORAGE_JUMPSHOT
case
US_PR_JUMPSHOT
:
s
s
->
transport_name
=
"Lexar Jumpshot Control/Bulk"
;
s
s
->
transport
=
jumpshot_transport
;
s
s
->
transport_reset
=
usb_stor_Bulk_reset
;
s
s
->
max_lun
=
1
;
u
s
->
transport_name
=
"Lexar Jumpshot Control/Bulk"
;
u
s
->
transport
=
jumpshot_transport
;
u
s
->
transport_reset
=
usb_stor_Bulk_reset
;
u
s
->
max_lun
=
1
;
break
;
#endif
default:
/*
s
s->transport_name = "Unknown"; */
/*
u
s->transport_name = "Unknown"; */
goto
BadDevice
;
}
US_DEBUGP
(
"Transport: %s
\n
"
,
s
s
->
transport_name
);
US_DEBUGP
(
"Transport: %s
\n
"
,
u
s
->
transport_name
);
/* fix for single-lun devices */
if
(
s
s
->
flags
&
US_FL_SINGLE_LUN
)
s
s
->
max_lun
=
0
;
if
(
u
s
->
flags
&
US_FL_SINGLE_LUN
)
u
s
->
max_lun
=
0
;
switch
(
s
s
->
subclass
)
{
switch
(
u
s
->
subclass
)
{
case
US_SC_RBC
:
s
s
->
protocol_name
=
"Reduced Block Commands (RBC)"
;
s
s
->
proto_handler
=
usb_stor_transparent_scsi_command
;
u
s
->
protocol_name
=
"Reduced Block Commands (RBC)"
;
u
s
->
proto_handler
=
usb_stor_transparent_scsi_command
;
break
;
case
US_SC_8020
:
s
s
->
protocol_name
=
"8020i"
;
s
s
->
proto_handler
=
usb_stor_ATAPI_command
;
s
s
->
max_lun
=
0
;
u
s
->
protocol_name
=
"8020i"
;
u
s
->
proto_handler
=
usb_stor_ATAPI_command
;
u
s
->
max_lun
=
0
;
break
;
case
US_SC_QIC
:
s
s
->
protocol_name
=
"QIC-157"
;
s
s
->
proto_handler
=
usb_stor_qic157_command
;
s
s
->
max_lun
=
0
;
u
s
->
protocol_name
=
"QIC-157"
;
u
s
->
proto_handler
=
usb_stor_qic157_command
;
u
s
->
max_lun
=
0
;
break
;
case
US_SC_8070
:
s
s
->
protocol_name
=
"8070i"
;
s
s
->
proto_handler
=
usb_stor_ATAPI_command
;
s
s
->
max_lun
=
0
;
u
s
->
protocol_name
=
"8070i"
;
u
s
->
proto_handler
=
usb_stor_ATAPI_command
;
u
s
->
max_lun
=
0
;
break
;
case
US_SC_SCSI
:
s
s
->
protocol_name
=
"Transparent SCSI"
;
s
s
->
proto_handler
=
usb_stor_transparent_scsi_command
;
u
s
->
protocol_name
=
"Transparent SCSI"
;
u
s
->
proto_handler
=
usb_stor_transparent_scsi_command
;
break
;
case
US_SC_UFI
:
s
s
->
protocol_name
=
"Uniform Floppy Interface (UFI)"
;
s
s
->
proto_handler
=
usb_stor_ufi_command
;
u
s
->
protocol_name
=
"Uniform Floppy Interface (UFI)"
;
u
s
->
proto_handler
=
usb_stor_ufi_command
;
break
;
#ifdef CONFIG_USB_STORAGE_ISD200
case
US_SC_ISD200
:
s
s
->
protocol_name
=
"ISD200 ATA/ATAPI"
;
s
s
->
proto_handler
=
isd200_ata_command
;
u
s
->
protocol_name
=
"ISD200 ATA/ATAPI"
;
u
s
->
proto_handler
=
isd200_ata_command
;
break
;
#endif
default:
/*
s
s->protocol_name = "Unknown"; */
/*
u
s->protocol_name = "Unknown"; */
goto
BadDevice
;
}
US_DEBUGP
(
"Protocol: %s
\n
"
,
s
s
->
protocol_name
);
US_DEBUGP
(
"Protocol: %s
\n
"
,
u
s
->
protocol_name
);
/* allocate the URB, the usb_ctrlrequest, and the IRQ URB */
if
(
usb_stor_allocate_urbs
(
s
s
))
if
(
usb_stor_allocate_urbs
(
u
s
))
goto
BadDevice
;
/*
...
...
@@ -849,59 +849,59 @@ static int storage_probe(struct usb_interface *intf,
/* Just before we start our control thread, initialize
* the device if it needs initialization */
if
(
unusual_dev
&&
unusual_dev
->
initFunction
)
unusual_dev
->
initFunction
(
s
s
);
unusual_dev
->
initFunction
(
u
s
);
/* start up our control thread */
atomic_set
(
&
s
s
->
sm_state
,
US_STATE_IDLE
);
ss
->
pid
=
kernel_thread
(
usb_stor_control_thread
,
s
s
,
atomic_set
(
&
u
s
->
sm_state
,
US_STATE_IDLE
);
us
->
pid
=
kernel_thread
(
usb_stor_control_thread
,
u
s
,
CLONE_VM
);
if
(
s
s
->
pid
<
0
)
{
if
(
u
s
->
pid
<
0
)
{
printk
(
KERN_WARNING
USB_STORAGE
"Unable to start control thread
\n
"
);
goto
BadDevice
;
}
/* wait for the thread to start */
wait_for_completion
(
&
(
s
s
->
notify
));
wait_for_completion
(
&
(
u
s
->
notify
));
/* unlock the device pointers */
up
(
&
(
s
s
->
dev_semaphore
));
up
(
&
(
u
s
->
dev_semaphore
));
/* now register */
ss
->
host
=
scsi_register
(
&
usb_stor_host_template
,
sizeof
(
s
s
));
if
(
!
s
s
->
host
)
{
us
->
host
=
scsi_register
(
&
usb_stor_host_template
,
sizeof
(
u
s
));
if
(
!
u
s
->
host
)
{
printk
(
KERN_WARNING
USB_STORAGE
"Unable to register the scsi host
\n
"
);
/* tell the control thread to exit */
s
s
->
srb
=
NULL
;
up
(
&
s
s
->
sema
);
wait_for_completion
(
&
s
s
->
notify
);
u
s
->
srb
=
NULL
;
up
(
&
u
s
->
sema
);
wait_for_completion
(
&
u
s
->
notify
);
/* re-lock the device pointers */
down
(
&
s
s
->
dev_semaphore
);
down
(
&
u
s
->
dev_semaphore
);
goto
BadDevice
;
}
/* set the hostdata to prepare for scanning */
ss
->
host
->
hostdata
[
0
]
=
(
unsigned
long
)
s
s
;
us
->
host
->
hostdata
[
0
]
=
(
unsigned
long
)
u
s
;
/* associate this host with our interface */
scsi_set_device
(
s
s
->
host
,
&
intf
->
dev
);
scsi_set_device
(
u
s
->
host
,
&
intf
->
dev
);
/* now add the host */
result
=
scsi_add_host
(
s
s
->
host
,
NULL
);
result
=
scsi_add_host
(
u
s
->
host
,
NULL
);
if
(
result
)
{
printk
(
KERN_WARNING
USB_STORAGE
"Unable to add the scsi host
\n
"
);
/* tell the control thread to exit */
s
s
->
srb
=
NULL
;
up
(
&
s
s
->
sema
);
wait_for_completion
(
&
s
s
->
notify
);
u
s
->
srb
=
NULL
;
up
(
&
u
s
->
sema
);
wait_for_completion
(
&
u
s
->
notify
);
/* re-lock the device pointers */
down
(
&
s
s
->
dev_semaphore
);
down
(
&
u
s
->
dev_semaphore
);
goto
BadDevice
;
}
...
...
@@ -911,66 +911,61 @@ static int storage_probe(struct usb_interface *intf,
"USB Mass Storage device found at %d
\n
"
,
dev
->
devnum
);
/* save a pointer to our structure */
usb_set_intfdata
(
intf
,
s
s
);
usb_set_intfdata
(
intf
,
u
s
);
return
0
;
/* we come here if there are any problems */
/*
s
s->dev_semaphore must be locked */
/*
u
s->dev_semaphore must be locked */
BadDevice:
US_DEBUGP
(
"storage_probe() failed
\n
"
);
usb_stor_deallocate_urbs
(
s
s
);
up
(
&
s
s
->
dev_semaphore
);
kfree
(
s
s
);
usb_stor_deallocate_urbs
(
u
s
);
up
(
&
u
s
->
dev_semaphore
);
kfree
(
u
s
);
return
-
EIO
;
}
/* Handle a disconnect event from the USB core */
static
void
storage_disconnect
(
struct
usb_interface
*
intf
)
{
struct
us_data
*
s
s
;
struct
us_data
*
u
s
;
struct
scsi_device
*
sdev
;
US_DEBUGP
(
"storage_disconnect() called
\n
"
);
s
s
=
usb_get_intfdata
(
intf
);
u
s
=
usb_get_intfdata
(
intf
);
usb_set_intfdata
(
intf
,
NULL
);
/* serious error -- we're attempting to disconnect an interface but
* cannot locate the local data structure
*/
BUG_ON
(
ss
==
NULL
);
/* set devices offline -- need host lock for this */
scsi_lock
(
s
s
->
host
);
list_for_each_entry
(
sdev
,
&
s
s
->
host
->
my_devices
,
siblings
)
scsi_lock
(
u
s
->
host
);
list_for_each_entry
(
sdev
,
&
u
s
->
host
->
my_devices
,
siblings
)
sdev
->
online
=
0
;
scsi_unlock
(
s
s
->
host
);
scsi_unlock
(
u
s
->
host
);
/* lock device access -- no need to unlock, as we're going away */
down
(
&
(
s
s
->
dev_semaphore
));
down
(
&
(
u
s
->
dev_semaphore
));
/* Complete all pending commands with * cmd->result = DID_ERROR << 16.
* Since we only queue one command at a time, this is pretty easy. */
if
(
s
s
->
srb
)
{
s
s
->
srb
->
result
=
DID_ERROR
<<
16
;
ss
->
srb
->
scsi_done
(
s
s
->
srb
);
if
(
u
s
->
srb
)
{
u
s
->
srb
->
result
=
DID_ERROR
<<
16
;
us
->
srb
->
scsi_done
(
u
s
->
srb
);
}
/* TODO: somehow, wait for the device to
* be 'idle' (tasklet completion) */
/* remove the pointer to the data structure we were using */
(
struct
us_data
*
)
s
s
->
host
->
hostdata
[
0
]
=
NULL
;
(
struct
us_data
*
)
u
s
->
host
->
hostdata
[
0
]
=
NULL
;
/* begin SCSI host removal sequence */
if
(
scsi_remove_host
(
s
s
->
host
))
{
if
(
scsi_remove_host
(
u
s
->
host
))
{
US_DEBUGP
(
"-- SCSI refused to unregister
\n
"
);
BUG
();
return
;
};
/* finish SCSI host removal sequence */
scsi_unregister
(
s
s
->
host
);
scsi_unregister
(
u
s
->
host
);
/* Kill the control threads
*
...
...
@@ -978,34 +973,34 @@ static void storage_disconnect(struct usb_interface *intf)
* notification that it has exited.
*/
US_DEBUGP
(
"-- sending exit command to thread
\n
"
);
BUG_ON
(
atomic_read
(
&
s
s
->
sm_state
)
!=
US_STATE_IDLE
);
s
s
->
srb
=
NULL
;
up
(
&
(
s
s
->
sema
));
wait_for_completion
(
&
(
s
s
->
notify
));
BUG_ON
(
atomic_read
(
&
u
s
->
sm_state
)
!=
US_STATE_IDLE
);
u
s
->
srb
=
NULL
;
up
(
&
(
u
s
->
sema
));
wait_for_completion
(
&
(
u
s
->
notify
));
/* free allocated urbs */
usb_stor_deallocate_urbs
(
s
s
);
usb_stor_deallocate_urbs
(
u
s
);
/* If there's extra data in the us_data structure then
* free that first */
if
(
s
s
->
extra
)
{
if
(
u
s
->
extra
)
{
/* call the destructor routine, if it exists */
if
(
s
s
->
extra_destructor
)
{
if
(
u
s
->
extra_destructor
)
{
US_DEBUGP
(
"-- calling extra_destructor()
\n
"
);
ss
->
extra_destructor
(
s
s
->
extra
);
us
->
extra_destructor
(
u
s
->
extra
);
}
/* destroy the extra data */
US_DEBUGP
(
"-- freeing the data structure
\n
"
);
kfree
(
s
s
->
extra
);
kfree
(
u
s
->
extra
);
}
/* up the semaphore so auto-code-checkers won't complain about
* the down/up imbalance */
up
(
&
(
s
s
->
dev_semaphore
));
up
(
&
(
u
s
->
dev_semaphore
));
/* free the structure itself */
kfree
(
s
s
);
kfree
(
u
s
);
}
/***********************************************************************
...
...
fs/filesystems.c
View file @
6c7a3c95
...
...
@@ -61,7 +61,7 @@ static struct file_system_type **find_filesystem(const char *name)
/* define fs_subsys */
static
decl_subsys
(
fs
,
NULL
);
static
decl_subsys
(
fs
,
NULL
,
NULL
);
static
int
register_fs_subsys
(
struct
file_system_type
*
fs
)
{
...
...
fs/partitions/check.c
View file @
6c7a3c95
...
...
@@ -248,7 +248,7 @@ static struct attribute * default_attrs[] = {
extern
struct
subsystem
block_subsys
;
st
atic
st
ruct
kobj_type
ktype_part
=
{
struct
kobj_type
ktype_part
=
{
.
default_attrs
=
default_attrs
,
.
sysfs_ops
=
&
part_sysfs_ops
,
};
...
...
include/linux/kobject.h
View file @
6c7a3c95
...
...
@@ -57,12 +57,24 @@ struct kobj_type {
* of object; multiple ksets can belong to one subsystem. All
* ksets of a subsystem share the subsystem's lock.
*
* Each kset can support hotplugging; if it does, it will be given
* the opportunity to filter out specific kobjects from being
* reported, as well as to add its own "data" elements to the
* environment being passed to the hotplug helper.
*/
struct
kset_hotplug_ops
{
int
(
*
filter
)(
struct
kset
*
kset
,
struct
kobject
*
kobj
);
char
*
(
*
name
)(
struct
kset
*
kset
,
struct
kobject
*
kobj
);
int
(
*
hotplug
)(
struct
kset
*
kset
,
struct
kobject
*
kobj
,
char
**
envp
,
int
num_envp
,
char
*
buffer
,
int
buffer_size
);
};
struct
kset
{
struct
subsystem
*
subsys
;
struct
kobj_type
*
ktype
;
struct
list_head
list
;
struct
kobject
kobj
;
struct
kset_hotplug_ops
*
hotplug_ops
;
};
...
...
@@ -86,6 +98,13 @@ static inline void kset_put(struct kset * k)
kobject_put
(
&
k
->
kobj
);
}
static
inline
struct
kobj_type
*
get_ktype
(
struct
kobject
*
k
)
{
if
(
k
->
kset
&&
k
->
kset
->
ktype
)
return
k
->
kset
->
ktype
;
else
return
k
->
ktype
;
}
extern
struct
kobject
*
kset_find_obj
(
struct
kset
*
,
const
char
*
);
...
...
@@ -95,11 +114,12 @@ struct subsystem {
struct
rw_semaphore
rwsem
;
};
#define decl_subsys(_name,_type) \
#define decl_subsys(_name,_type
,_hotplug_ops
) \
struct subsystem _name##_subsys = { \
.kset = { \
.kobj = { .name = __stringify(_name) }, \
.ktype = _type, \
.hotplug_ops =_hotplug_ops, \
} \
}
...
...
lib/kobject.c
View file @
6c7a3c95
...
...
@@ -11,14 +11,6 @@
static
spinlock_t
kobj_lock
=
SPIN_LOCK_UNLOCKED
;
static
inline
struct
kobj_type
*
get_ktype
(
struct
kobject
*
k
)
{
if
(
k
->
kset
&&
k
->
kset
->
ktype
)
return
k
->
kset
->
ktype
;
else
return
k
->
ktype
;
}
/**
* populate_dir - populate directory with attributes.
* @kobj: object we're working on.
...
...
@@ -67,6 +59,140 @@ static inline struct kobject * to_kobj(struct list_head * entry)
}
#ifdef CONFIG_HOTPLUG
static
int
get_kobj_path_length
(
struct
kset
*
kset
,
struct
kobject
*
kobj
)
{
int
length
=
1
;
struct
kobject
*
parent
=
kobj
;
/* walk up the ancestors until we hit the one pointing to the
* root.
* Add 1 to strlen for leading '/' of each level.
*/
do
{
length
+=
strlen
(
parent
->
name
)
+
1
;
parent
=
parent
->
parent
;
}
while
(
parent
);
return
length
;
}
static
void
fill_kobj_path
(
struct
kset
*
kset
,
struct
kobject
*
kobj
,
char
*
path
,
int
length
)
{
struct
kobject
*
parent
;
--
length
;
for
(
parent
=
kobj
;
parent
;
parent
=
parent
->
parent
)
{
int
cur
=
strlen
(
parent
->
name
);
/* back up enough to print this name with '/' */
length
-=
cur
;
strncpy
(
path
+
length
,
parent
->
name
,
cur
);
*
(
path
+
--
length
)
=
'/'
;
}
pr_debug
(
"%s: path = '%s'
\n
"
,
__FUNCTION__
,
path
);
}
#define BUFFER_SIZE 1024
/* should be enough memory for the env */
#define NUM_ENVP 32
/* number of env pointers */
static
void
kset_hotplug
(
const
char
*
action
,
struct
kset
*
kset
,
struct
kobject
*
kobj
)
{
char
*
argv
[
3
];
char
**
envp
;
char
*
buffer
;
char
*
scratch
;
int
i
=
0
;
int
retval
;
int
kobj_path_length
;
char
*
kobj_path
;
char
*
name
=
NULL
;
/* If the kset has a filter operation, call it. If it returns
failure, no hotplug event is required. */
if
(
kset
->
hotplug_ops
->
filter
)
{
if
(
!
kset
->
hotplug_ops
->
filter
(
kset
,
kobj
))
return
;
}
pr_debug
(
"%s
\n
"
,
__FUNCTION__
);
if
(
!
hotplug_path
[
0
])
return
;
envp
=
(
char
**
)
kmalloc
(
NUM_ENVP
*
sizeof
(
char
*
),
GFP_KERNEL
);
if
(
!
envp
)
return
;
memset
(
envp
,
0x00
,
NUM_ENVP
*
sizeof
(
char
*
));
buffer
=
kmalloc
(
BUFFER_SIZE
,
GFP_KERNEL
);
if
(
!
buffer
)
{
kfree
(
envp
);
return
;
}
if
(
kset
->
hotplug_ops
->
name
)
name
=
kset
->
hotplug_ops
->
name
(
kset
,
kobj
);
if
(
name
==
NULL
)
name
=
kset
->
kobj
.
name
;
argv
[
0
]
=
hotplug_path
;
argv
[
1
]
=
name
;
argv
[
2
]
=
0
;
/* minimal command environment */
envp
[
i
++
]
=
"HOME=/"
;
envp
[
i
++
]
=
"PATH=/sbin:/bin:/usr/sbin:/usr/bin"
;
scratch
=
buffer
;
envp
[
i
++
]
=
scratch
;
scratch
+=
sprintf
(
scratch
,
"ACTION=%s"
,
action
)
+
1
;
kobj_path_length
=
get_kobj_path_length
(
kset
,
kobj
);
kobj_path
=
kmalloc
(
kobj_path_length
,
GFP_KERNEL
);
if
(
!
kobj_path
)
{
kfree
(
buffer
);
kfree
(
envp
);
return
;
}
memset
(
kobj_path
,
0x00
,
kobj_path_length
);
fill_kobj_path
(
kset
,
kobj
,
kobj_path
,
kobj_path_length
);
envp
[
i
++
]
=
scratch
;
scratch
+=
sprintf
(
scratch
,
"DEVPATH=%s"
,
kobj_path
)
+
1
;
if
(
kset
->
hotplug_ops
->
hotplug
)
{
/* have the kset specific function add its stuff */
retval
=
kset
->
hotplug_ops
->
hotplug
(
kset
,
kobj
,
&
envp
[
i
],
NUM_ENVP
-
i
,
scratch
,
BUFFER_SIZE
-
(
scratch
-
buffer
));
if
(
retval
)
{
pr_debug
(
"%s - hotplug() returned %d
\n
"
,
__FUNCTION__
,
retval
);
goto
exit
;
}
}
pr_debug
(
"%s: %s %s %s %s %s %s
\n
"
,
__FUNCTION__
,
argv
[
0
],
argv
[
1
],
envp
[
0
],
envp
[
1
],
envp
[
2
],
envp
[
3
]);
retval
=
call_usermodehelper
(
argv
[
0
],
argv
,
envp
,
0
);
if
(
retval
)
pr_debug
(
"%s - call_usermodehelper returned %d
\n
"
,
__FUNCTION__
,
retval
);
exit:
kfree
(
kobj_path
);
kfree
(
buffer
);
return
;
}
#else
static
void
kset_hotplug
(
const
char
*
action
,
struct
kset
*
kset
,
struct
kobject
*
kobj
)
{
return
0
;
}
#endif
/* CONFIG_HOTPLUG */
/**
* kobject_init - initialize object.
* @kobj: object in question.
...
...
@@ -111,6 +237,7 @@ int kobject_add(struct kobject * kobj)
{
int
error
=
0
;
struct
kobject
*
parent
;
struct
kobject
*
top_kobj
;
if
(
!
(
kobj
=
kobject_get
(
kobj
)))
return
-
ENOENT
;
...
...
@@ -134,6 +261,19 @@ int kobject_add(struct kobject * kobj)
error
=
create_dir
(
kobj
);
if
(
error
)
unlink
(
kobj
);
else
{
/* If this kobj does not belong to a kset,
try to find a parent that does. */
top_kobj
=
kobj
;
if
(
!
top_kobj
->
kset
&&
top_kobj
->
parent
)
{
do
{
top_kobj
=
top_kobj
->
parent
;
}
while
(
!
top_kobj
->
kset
&&
top_kobj
->
parent
);
}
if
(
top_kobj
->
kset
&&
top_kobj
->
kset
->
hotplug_ops
)
kset_hotplug
(
"add"
,
top_kobj
->
kset
,
kobj
);
}
return
error
;
}
...
...
@@ -162,6 +302,20 @@ int kobject_register(struct kobject * kobj)
void
kobject_del
(
struct
kobject
*
kobj
)
{
struct
kobject
*
top_kobj
;
/* If this kobj does not belong to a kset,
try to find a parent that does. */
top_kobj
=
kobj
;
if
(
!
top_kobj
->
kset
&&
top_kobj
->
parent
)
{
do
{
top_kobj
=
top_kobj
->
parent
;
}
while
(
!
top_kobj
->
kset
&&
top_kobj
->
parent
);
}
if
(
top_kobj
->
kset
&&
top_kobj
->
kset
->
hotplug_ops
)
kset_hotplug
(
"remove"
,
top_kobj
->
kset
,
kobj
);
sysfs_remove_dir
(
kobj
);
unlink
(
kobj
);
}
...
...
net/core/dev.c
View file @
6c7a3c95
...
...
@@ -2815,7 +2815,7 @@ extern void ip_auto_config(void);
extern
void
dv_init
(
void
);
#endif
/* CONFIG_NET_DIVERT */
static
decl_subsys
(
net
,
NULL
);
static
decl_subsys
(
net
,
NULL
,
NULL
);
/*
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment