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
nexedi
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
Show 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 @@
...
@@ -100,7 +100,8 @@
<chapter
id=
"host"
>
<chapter
id=
"host"
>
<title>
USB Host-Side API Model
</title>
<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
There are two types of public "usbcore" APIs, targetted at two different
layers of USB driver. Those are
layers of USB driver. Those are
<emphasis>
general purpose
</emphasis>
drivers, exposed through
<emphasis>
general purpose
</emphasis>
drivers, exposed through
...
@@ -289,6 +290,684 @@
...
@@ -289,6 +290,684 @@
!Edrivers/usb/core/buffer.c
!Edrivers/usb/core/buffer.c
</chapter>
</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>
</book>
<!-- vim:syntax=sgml:sw=4
<!-- vim:syntax=sgml:sw=4
-->
-->
arch/i386/kernel/edd.c
View file @
6c7a3c95
...
@@ -598,7 +598,7 @@ static struct kobj_type ktype_edd = {
...
@@ -598,7 +598,7 @@ static struct kobj_type ktype_edd = {
.
default_attrs
=
def_attrs
,
.
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)
...
@@ -676,7 +676,7 @@ acpi_bus_init (void)
return_VALUE
(
-
ENODEV
);
return_VALUE
(
-
ENODEV
);
}
}
decl_subsys
(
acpi
,
NULL
);
decl_subsys
(
acpi
,
NULL
,
NULL
);
static
int
__init
acpi_init
(
void
)
static
int
__init
acpi_init
(
void
)
{
{
...
...
drivers/base/base.h
View file @
6c7a3c95
...
@@ -18,13 +18,8 @@ extern void interface_remove_dev(struct device *);
...
@@ -18,13 +18,8 @@ extern void interface_remove_dev(struct device *);
#ifdef CONFIG_HOTPLUG
#ifdef CONFIG_HOTPLUG
extern
int
dev_hotplug
(
struct
device
*
dev
,
const
char
*
action
);
extern
int
class_hotplug
(
struct
device
*
dev
,
const
char
*
action
);
extern
int
class_hotplug
(
struct
device
*
dev
,
const
char
*
action
);
#else
#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
)
static
inline
int
class_hotplug
(
struct
device
*
dev
,
const
char
*
action
)
{
{
return
0
;
return
0
;
...
...
drivers/base/bus.c
View file @
6c7a3c95
...
@@ -132,7 +132,7 @@ static struct kobj_type ktype_bus = {
...
@@ -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.
* bus_for_each_dev - device iterator.
...
...
drivers/base/class.c
View file @
6c7a3c95
...
@@ -49,7 +49,9 @@ static struct kobj_type ktype_devclass = {
...
@@ -49,7 +49,9 @@ static struct kobj_type ktype_devclass = {
.
sysfs_ops
=
&
class_sysfs_ops
,
.
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
)
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;
...
@@ -23,13 +23,12 @@ int (*platform_notify_remove)(struct device * dev) = NULL;
DECLARE_MUTEX
(
device_sem
);
DECLARE_MUTEX
(
device_sem
);
#define to_dev(obj) container_of(obj,struct device,kobj)
/*
/*
* sysfs bindings for devices.
* 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)
#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr)
extern
struct
attribute
*
dev_default_attrs
[];
extern
struct
attribute
*
dev_default_attrs
[];
...
@@ -86,11 +85,55 @@ static struct kobj_type ktype_device = {
...
@@ -86,11 +85,55 @@ static struct kobj_type ktype_device = {
.
default_attrs
=
dev_default_attrs
,
.
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.
* 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)
...
@@ -192,9 +235,6 @@ int device_add(struct device *dev)
if
(
platform_notify
)
if
(
platform_notify
)
platform_notify
(
dev
);
platform_notify
(
dev
);
/* notify userspace of device entry */
dev_hotplug
(
dev
,
"add"
);
devclass_add_device
(
dev
);
devclass_add_device
(
dev
);
register_done:
register_done:
if
(
error
&&
parent
)
if
(
error
&&
parent
)
...
@@ -278,9 +318,6 @@ void device_del(struct device * dev)
...
@@ -278,9 +318,6 @@ void device_del(struct device * dev)
if
(
platform_notify_remove
)
if
(
platform_notify_remove
)
platform_notify_remove
(
dev
);
platform_notify_remove
(
dev
);
/* notify userspace that this device is about to disappear */
dev_hotplug
(
dev
,
"remove"
);
bus_remove_device
(
dev
);
bus_remove_device
(
dev
);
kobject_del
(
&
dev
->
kobj
);
kobject_del
(
&
dev
->
kobj
);
...
...
drivers/base/firmware.c
View file @
6c7a3c95
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
#include <linux/module.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/init.h>
static
decl_subsys
(
firmware
,
NULL
);
static
decl_subsys
(
firmware
,
NULL
,
NULL
);
int
firmware_register
(
struct
subsystem
*
s
)
int
firmware_register
(
struct
subsystem
*
s
)
{
{
...
...
drivers/base/hotplug.c
View file @
6c7a3c95
...
@@ -2,8 +2,8 @@
...
@@ -2,8 +2,8 @@
* drivers/base/hotplug.c - hotplug call code
* drivers/base/hotplug.c - hotplug call code
*
*
* Copyright (c) 2000-2001 David Brownell
* Copyright (c) 2000-2001 David Brownell
* Copyright (c) 2002 Greg Kroah-Hartman
* Copyright (c) 2002
-2003
Greg Kroah-Hartman
* Copyright (c) 2002 IBM Corp.
* Copyright (c) 2002
-2003
IBM Corp.
*
*
* Based off of drivers/usb/core/usb.c:call_agent(), which was
* Based off of drivers/usb/core/usb.c:call_agent(), which was
* written by David Brownell.
* written by David Brownell.
...
@@ -53,17 +53,6 @@ static int do_hotplug (struct device *dev, char *argv1, const char *action,
...
@@ -53,17 +53,6 @@ static int do_hotplug (struct device *dev, char *argv1, const char *action,
if
(
!
hotplug_path
[
0
])
if
(
!
hotplug_path
[
0
])
return
-
ENODEV
;
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
);
envp
=
(
char
**
)
kmalloc
(
NUM_ENVP
*
sizeof
(
char
*
),
GFP_KERNEL
);
if
(
!
envp
)
if
(
!
envp
)
return
-
ENOMEM
;
return
-
ENOMEM
;
...
@@ -128,23 +117,6 @@ static int do_hotplug (struct device *dev, char *argv1, const char *action,
...
@@ -128,23 +117,6 @@ static int do_hotplug (struct device *dev, char *argv1, const char *action,
return
retval
;
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
* 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 = {
...
@@ -525,9 +525,21 @@ static struct kobj_type ktype_block = {
.
default_attrs
=
default_attrs
,
.
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. */
/* declare block_subsys. */
static
decl_subsys
(
block
,
&
ktype_block
);
static
decl_subsys
(
block
,
&
ktype_block
,
&
block_hotplug_ops
);
struct
gendisk
*
alloc_disk
(
int
minors
)
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 = {
...
@@ -100,7 +100,7 @@ static struct kobj_type hotplug_slot_ktype = {
.
sysfs_ops
=
&
hotplug_slot_sysfs_ops
.
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 */
/* 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
...
@@ -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
"
,
printk
(
KERN_INFO
"usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d
\n
"
,
d
->
descriptor
.
idVendor
,
d
->
descriptor
.
idProduct
,
ifnum
);
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
);
ret
=
usb_get_descriptor
(
d
,
USB_DT_CONFIG
,
i
,
buf
,
USB_DT_CONFIG_SIZE
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
printk
(
KERN_INFO
"usb-midi: Could not get config (error=%d).
\n
"
,
ret
);
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
...
@@ -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
"
,
printk
(
KERN_INFO
"usb-midi: Found MIDISTREAMING on dev %04x:%04x, iface %d
\n
"
,
d
->
descriptor
.
idVendor
,
d
->
descriptor
.
idProduct
,
ifnum
);
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.
/* From USB Spec v2.0, Section 9.5.
If the class or vendor specific descriptors use the same format
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)
...
@@ -1175,8 +1175,10 @@ void usb_hub_cleanup(void)
*
*
* Take a look at proc_resetdevice in devio.c for some sample code to
* Take a look at proc_resetdevice in devio.c for some sample code to
* do this.
* 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
*
parent
=
dev
->
parent
;
struct
usb_device_descriptor
*
descriptor
;
struct
usb_device_descriptor
*
descriptor
;
...
@@ -1306,3 +1308,16 @@ int usb_reset_device(struct usb_device *dev)
...
@@ -1306,3 +1308,16 @@ int usb_reset_device(struct usb_device *dev)
return
0
;
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)
...
@@ -930,6 +930,8 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
/* reset more hc/hcd endpoint state */
/* reset more hc/hcd endpoint state */
dev
->
toggle
[
0
]
=
0
;
dev
->
toggle
[
0
]
=
0
;
dev
->
toggle
[
1
]
=
0
;
dev
->
toggle
[
1
]
=
0
;
dev
->
halted
[
0
]
=
0
;
dev
->
halted
[
1
]
=
0
;
usb_set_maxpacket
(
dev
);
usb_set_maxpacket
(
dev
);
return
0
;
return
0
;
...
...
drivers/usb/core/usb.c
View file @
6c7a3c95
...
@@ -89,11 +89,6 @@ int usb_device_probe(struct device *dev)
...
@@ -89,11 +89,6 @@ int usb_device_probe(struct device *dev)
if
(
!
driver
->
probe
)
if
(
!
driver
->
probe
)
return
error
;
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
);
id
=
usb_match_id
(
intf
,
driver
->
id_table
);
if
(
id
)
{
if
(
id
)
{
dev_dbg
(
dev
,
"%s - got id
\n
"
,
__FUNCTION__
);
dev_dbg
(
dev
,
"%s - got id
\n
"
,
__FUNCTION__
);
...
@@ -104,8 +99,6 @@ int usb_device_probe(struct device *dev)
...
@@ -104,8 +99,6 @@ int usb_device_probe(struct device *dev)
if
(
!
error
)
if
(
!
error
)
intf
->
driver
=
driver
;
intf
->
driver
=
driver
;
module_put
(
driver
->
owner
);
return
error
;
return
error
;
}
}
...
@@ -117,22 +110,6 @@ int usb_device_remove(struct device *dev)
...
@@ -117,22 +110,6 @@ int usb_device_remove(struct device *dev)
intf
=
list_entry
(
dev
,
struct
usb_interface
,
dev
);
intf
=
list_entry
(
dev
,
struct
usb_interface
,
dev
);
driver
=
to_usb_driver
(
dev
->
driver
);
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
);
down
(
&
driver
->
serialize
);
if
(
intf
->
driver
&&
intf
->
driver
->
disconnect
)
if
(
intf
->
driver
&&
intf
->
driver
->
disconnect
)
...
@@ -143,7 +120,6 @@ int usb_device_remove(struct device *dev)
...
@@ -143,7 +120,6 @@ int usb_device_remove(struct device *dev)
usb_driver_release_interface
(
driver
,
intf
);
usb_driver_release_interface
(
driver
,
intf
);
up
(
&
driver
->
serialize
);
up
(
&
driver
->
serialize
);
module_put
(
driver
->
owner
);
return
0
;
return
0
;
}
}
...
@@ -498,9 +474,6 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, kdev_t kdev)
...
@@ -498,9 +474,6 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, kdev_t kdev)
continue
;
continue
;
intf
=
to_usb_interface
(
dev
);
intf
=
to_usb_interface
(
dev
);
if
(
!
intf
)
continue
;
if
(
kdev_same
(
intf
->
kdev
,
kdev
))
{
if
(
kdev_same
(
intf
->
kdev
,
kdev
))
{
return
intf
;
return
intf
;
}
}
...
@@ -566,12 +539,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
...
@@ -566,12 +539,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
return
0
;
return
0
;
intf
=
to_usb_interface
(
dev
);
intf
=
to_usb_interface
(
dev
);
if
(
!
intf
)
return
-
ENODEV
;
usb_dev
=
interface_to_usbdev
(
intf
);
usb_dev
=
interface_to_usbdev
(
intf
);
if
(
!
usb_dev
)
return
-
ENODEV
;
if
(
usb_dev
->
devnum
<
0
)
{
if
(
usb_dev
->
devnum
<
0
)
{
dbg
(
"device already deleted ??"
);
dbg
(
"device already deleted ??"
);
...
@@ -748,8 +716,6 @@ static void usb_release_dev(struct device *dev)
...
@@ -748,8 +716,6 @@ static void usb_release_dev(struct device *dev)
struct
usb_device
*
udev
;
struct
usb_device
*
udev
;
udev
=
to_usb_device
(
dev
);
udev
=
to_usb_device
(
dev
);
if
(
!
udev
)
return
;
if
(
udev
->
bus
&&
udev
->
bus
->
op
&&
udev
->
bus
->
op
->
deallocate
)
if
(
udev
->
bus
&&
udev
->
bus
->
op
&&
udev
->
bus
->
op
->
deallocate
)
udev
->
bus
->
op
->
deallocate
(
udev
);
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)
...
@@ -62,6 +62,7 @@ static inline void ehci_qtd_init (struct ehci_qtd *qtd, dma_addr_t dma)
{
{
memset
(
qtd
,
0
,
sizeof
*
qtd
);
memset
(
qtd
,
0
,
sizeof
*
qtd
);
qtd
->
qtd_dma
=
dma
;
qtd
->
qtd_dma
=
dma
;
qtd
->
hw_token
=
cpu_to_le32
(
QTD_STS_HALT
);
qtd
->
hw_next
=
EHCI_LIST_END
;
qtd
->
hw_next
=
EHCI_LIST_END
;
qtd
->
hw_alt_next
=
EHCI_LIST_END
;
qtd
->
hw_alt_next
=
EHCI_LIST_END
;
INIT_LIST_HEAD
(
&
qtd
->
qtd_list
);
INIT_LIST_HEAD
(
&
qtd
->
qtd_list
);
...
...
drivers/usb/host/ehci-q.c
View file @
6c7a3c95
...
@@ -137,7 +137,10 @@ static void qtd_copy_status (
...
@@ -137,7 +137,10 @@ static void qtd_copy_status (
if
(
QTD_CERR
(
token
))
if
(
QTD_CERR
(
token
))
urb
->
status
=
-
EPIPE
;
urb
->
status
=
-
EPIPE
;
else
{
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
;
urb
->
status
=
-
EPROTO
;
}
}
/* CERR nonzero + no errors + halt --> stall */
/* CERR nonzero + no errors + halt --> stall */
...
@@ -213,7 +216,6 @@ ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
...
@@ -213,7 +216,6 @@ ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
/* complete() can reenter this HCD */
/* complete() can reenter this HCD */
spin_unlock
(
&
ehci
->
lock
);
spin_unlock
(
&
ehci
->
lock
);
usb_hcd_giveback_urb
(
&
ehci
->
hcd
,
urb
,
regs
);
usb_hcd_giveback_urb
(
&
ehci
->
hcd
,
urb
,
regs
);
spin_lock
(
&
ehci
->
lock
);
spin_lock
(
&
ehci
->
lock
);
}
}
...
@@ -827,7 +829,7 @@ static struct ehci_qh *qh_append_tds (
...
@@ -827,7 +829,7 @@ static struct ehci_qh *qh_append_tds (
* HC is allowed to fetch the old dummy (4.10.2).
* HC is allowed to fetch the old dummy (4.10.2).
*/
*/
token
=
qtd
->
hw_token
;
token
=
qtd
->
hw_token
;
qtd
->
hw_token
=
0
;
qtd
->
hw_token
=
cpu_to_le32
(
QTD_STS_HALT
)
;
wmb
();
wmb
();
dummy
=
qh
->
dummy
;
dummy
=
qh
->
dummy
;
...
@@ -879,8 +881,7 @@ submit_async (
...
@@ -879,8 +881,7 @@ submit_async (
if
(
usb_pipein
(
urb
->
pipe
)
&&
!
usb_pipecontrol
(
urb
->
pipe
))
if
(
usb_pipein
(
urb
->
pipe
)
&&
!
usb_pipecontrol
(
urb
->
pipe
))
epnum
|=
0x10
;
epnum
|=
0x10
;
vdbg
(
"%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]"
,
ehci_vdbg
(
ehci
,
"submit_async urb %p len %d ep%d%s qtd %p [qh %p]
\n
"
,
hcd_to_bus
(
&
ehci
->
hcd
)
->
bus_name
,
urb
,
urb
->
transfer_buffer_length
,
urb
,
urb
->
transfer_buffer_length
,
epnum
&
0x0f
,
(
epnum
&
0x10
)
?
"in"
:
"out"
,
epnum
&
0x0f
,
(
epnum
&
0x10
)
?
"in"
:
"out"
,
qtd
,
dev
?
dev
->
ep
[
epnum
]
:
(
void
*
)
~
0
);
qtd
,
dev
?
dev
->
ep
[
epnum
]
:
(
void
*
)
~
0
);
...
@@ -916,7 +917,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
...
@@ -916,7 +917,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
del_timer
(
&
ehci
->
watchdog
);
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_state
=
QH_STATE_IDLE
;
qh
->
qh_next
.
qh
=
0
;
qh
->
qh_next
.
qh
=
0
;
qh_put
(
ehci
,
qh
);
// refcount from reclaim
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)
...
@@ -429,6 +429,8 @@ static int hc_reset (struct ohci_hcd *ohci)
ohci
->
hc_control
=
readl
(
&
ohci
->
regs
->
control
);
ohci
->
hc_control
=
readl
(
&
ohci
->
regs
->
control
);
ohci
->
hc_control
&=
OHCI_CTRL_RWC
;
/* hcfs 0 = RESET */
ohci
->
hc_control
&=
OHCI_CTRL_RWC
;
/* hcfs 0 = RESET */
writel
(
ohci
->
hc_control
,
&
ohci
->
regs
->
control
);
writel
(
ohci
->
hc_control
,
&
ohci
->
regs
->
control
);
// flush those pci writes
(
void
)
readl
(
&
ohci
->
regs
->
control
);
wait_ms
(
50
);
wait_ms
(
50
);
/* HC Reset requires max 10 us delay */
/* HC Reset requires max 10 us delay */
...
@@ -450,6 +452,8 @@ static int hc_reset (struct ohci_hcd *ohci)
...
@@ -450,6 +452,8 @@ static int hc_reset (struct ohci_hcd *ohci)
* this if we write fmInterval after we're OPERATIONAL.
* this if we write fmInterval after we're OPERATIONAL.
*/
*/
writel
(
ohci
->
hc_control
,
&
ohci
->
regs
->
control
);
writel
(
ohci
->
hc_control
,
&
ohci
->
regs
->
control
);
// flush those pci writes
(
void
)
readl
(
&
ohci
->
regs
->
control
);
return
0
;
return
0
;
}
}
...
@@ -524,6 +528,8 @@ static int hc_start (struct ohci_hcd *ohci)
...
@@ -524,6 +528,8 @@ static int hc_start (struct ohci_hcd *ohci)
writel
(
tmp
,
&
ohci
->
regs
->
roothub
.
a
);
writel
(
tmp
,
&
ohci
->
regs
->
roothub
.
a
);
writel
(
RH_HS_LPSC
,
&
ohci
->
regs
->
roothub
.
status
);
writel
(
RH_HS_LPSC
,
&
ohci
->
regs
->
roothub
.
status
);
writel
(
0
,
&
ohci
->
regs
->
roothub
.
b
);
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.
// POTPGT delay is bits 24-31, in 2 ms units.
mdelay
((
roothub_a
(
ohci
)
>>
23
)
&
0x1fe
);
mdelay
((
roothub_a
(
ohci
)
>>
23
)
&
0x1fe
);
...
@@ -610,6 +616,8 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
...
@@ -610,6 +616,8 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
writel
(
ints
,
&
regs
->
intrstatus
);
writel
(
ints
,
&
regs
->
intrstatus
);
writel
(
OHCI_INTR_MIE
,
&
regs
->
intrenable
);
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)
...
@@ -446,6 +446,8 @@ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
if
(
!
ohci
->
sleeping
)
{
if
(
!
ohci
->
sleeping
)
{
writel
(
OHCI_INTR_SF
,
&
ohci
->
regs
->
intrstatus
);
writel
(
OHCI_INTR_SF
,
&
ohci
->
regs
->
intrstatus
);
writel
(
OHCI_INTR_SF
,
&
ohci
->
regs
->
intrenable
);
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 = {
...
@@ -1664,6 +1664,9 @@ static struct usb_driver hid_driver = {
.
probe
=
hid_probe
,
.
probe
=
hid_probe
,
.
disconnect
=
hid_disconnect
,
.
disconnect
=
hid_disconnect
,
.
id_table
=
hid_usb_ids
,
.
id_table
=
hid_usb_ids
,
.
driver
=
{
.
devclass
=
&
input_devclass
,
},
};
};
static
int
__init
hid_init
(
void
)
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)
...
@@ -91,7 +91,7 @@ static void kbtab_irq(struct urb *urb, struct pt_regs *regs)
}
}
struct
usb_device_id
kbtab_ids
[]
=
{
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 = {
...
@@ -359,6 +359,9 @@ static struct usb_driver usb_kbd_driver = {
.
probe
=
usb_kbd_probe
,
.
probe
=
usb_kbd_probe
,
.
disconnect
=
usb_kbd_disconnect
,
.
disconnect
=
usb_kbd_disconnect
,
.
id_table
=
usb_kbd_id_table
,
.
id_table
=
usb_kbd_id_table
,
.
driver
=
{
.
devclass
=
&
input_devclass
,
},
};
};
static
int
__init
usb_kbd_init
(
void
)
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 = {
...
@@ -242,6 +242,9 @@ static struct usb_driver usb_mouse_driver = {
.
probe
=
usb_mouse_probe
,
.
probe
=
usb_mouse_probe
,
.
disconnect
=
usb_mouse_disconnect
,
.
disconnect
=
usb_mouse_disconnect
,
.
id_table
=
usb_mouse_id_table
,
.
id_table
=
usb_mouse_id_table
,
.
driver
=
{
.
devclass
=
&
input_devclass
,
},
};
};
static
int
__init
usb_mouse_init
(
void
)
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)
...
@@ -1034,6 +1034,23 @@ static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
** USB **
** 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
)
static
int
udsl_usb_ioctl
(
struct
usb_interface
*
intf
,
unsigned
int
code
,
void
*
user_data
)
{
{
struct
udsl_instance_data
*
instance
=
usb_get_intfdata
(
intf
);
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 *
...
@@ -1048,14 +1065,7 @@ static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *
switch
(
code
)
{
switch
(
code
)
{
case
UDSL_IOCTL_START
:
case
UDSL_IOCTL_START
:
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_FOUND
;
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_FOUND
;
down
(
&
instance
->
serialize
);
/* vs self */
return
udsl_set_alternate
(
instance
);
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
;
case
UDSL_IOCTL_STOP
:
case
UDSL_IOCTL_STOP
:
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_LOST
;
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_LOST
;
return
0
;
return
0
;
...
...
drivers/usb/net/pegasus.c
View file @
6c7a3c95
...
@@ -45,7 +45,7 @@
...
@@ -45,7 +45,7 @@
/*
/*
* Version Information
* 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_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
...
@@ -121,7 +121,7 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
...
@@ -121,7 +121,7 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
char
*
buffer
;
char
*
buffer
;
DECLARE_WAITQUEUE
(
wait
,
current
);
DECLARE_WAITQUEUE
(
wait
,
current
);
buffer
=
kmalloc
(
size
,
GFP_
KERNEL
);
buffer
=
kmalloc
(
size
,
GFP_
DMA
);
if
(
!
buffer
)
{
if
(
!
buffer
)
{
warn
(
"%s: looks like we're out of memory"
,
__FUNCTION__
);
warn
(
"%s: looks like we're out of memory"
,
__FUNCTION__
);
return
-
ENOMEM
;
return
-
ENOMEM
;
...
@@ -170,7 +170,7 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
...
@@ -170,7 +170,7 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
char
*
buffer
;
char
*
buffer
;
DECLARE_WAITQUEUE
(
wait
,
current
);
DECLARE_WAITQUEUE
(
wait
,
current
);
buffer
=
kmalloc
(
size
,
GFP_
KERNEL
);
buffer
=
kmalloc
(
size
,
GFP_
DMA
);
if
(
!
buffer
)
{
if
(
!
buffer
)
{
warn
(
"%s: looks like we're out of memory"
,
__FUNCTION__
);
warn
(
"%s: looks like we're out of memory"
,
__FUNCTION__
);
return
-
ENOMEM
;
return
-
ENOMEM
;
...
@@ -218,7 +218,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
...
@@ -218,7 +218,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
char
*
tmp
;
char
*
tmp
;
DECLARE_WAITQUEUE
(
wait
,
current
);
DECLARE_WAITQUEUE
(
wait
,
current
);
tmp
=
kmalloc
(
1
,
GFP_
KERNEL
);
tmp
=
kmalloc
(
1
,
GFP_
DMA
);
if
(
!
tmp
)
{
if
(
!
tmp
)
{
warn
(
"%s: looks like we're out of memory"
,
__FUNCTION__
);
warn
(
"%s: looks like we're out of memory"
,
__FUNCTION__
);
return
-
ENOMEM
;
return
-
ENOMEM
;
...
@@ -233,7 +233,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
...
@@ -233,7 +233,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
pegasus
->
dr
.
bRequestType
=
PEGASUS_REQT_WRITE
;
pegasus
->
dr
.
bRequestType
=
PEGASUS_REQT_WRITE
;
pegasus
->
dr
.
bRequest
=
PEGASUS_REQ_SET_REG
;
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
.
wIndex
=
cpu_to_le16p
(
&
indx
);
pegasus
->
dr
.
wLength
=
cpu_to_le16
(
1
);
pegasus
->
dr
.
wLength
=
cpu_to_le16
(
1
);
pegasus
->
ctrl_urb
->
transfer_buffer_length
=
1
;
pegasus
->
ctrl_urb
->
transfer_buffer_length
=
1
;
...
@@ -711,11 +711,11 @@ static void intr_callback(struct urb *urb, struct pt_regs *regs)
...
@@ -711,11 +711,11 @@ static void intr_callback(struct urb *urb, struct pt_regs *regs)
pegasus
->
stats
.
tx_aborted_errors
++
;
pegasus
->
stats
.
tx_aborted_errors
++
;
if
(
d
[
0
]
&
LATE_COL
)
if
(
d
[
0
]
&
LATE_COL
)
pegasus
->
stats
.
tx_window_errors
++
;
pegasus
->
stats
.
tx_window_errors
++
;
if
(
d
[
0
]
&
(
NO_CARRIER
|
LOSS_CARRIER
))
{
if
(
d
[
5
]
&
LINK_STATUS
)
{
netif_carrier_on
(
net
);
}
else
{
pegasus
->
stats
.
tx_carrier_errors
++
;
pegasus
->
stats
.
tx_carrier_errors
++
;
netif_carrier_off
(
net
);
netif_carrier_off
(
net
);
}
else
{
netif_carrier_on
(
net
);
}
}
}
}
...
...
drivers/usb/net/pegasus.h
View file @
6c7a3c95
...
@@ -52,6 +52,8 @@
...
@@ -52,6 +52,8 @@
#define LOSS_CARRIER 0x08
#define LOSS_CARRIER 0x08
#define JABBER_TIMEOUT 0x04
#define JABBER_TIMEOUT 0x04
#define LINK_STATUS 0x01
#define PEGASUS_REQT_READ 0xc0
#define PEGASUS_REQT_READ 0xc0
#define PEGASUS_REQT_WRITE 0x40
#define PEGASUS_REQT_WRITE 0x40
#define PEGASUS_REQ_GET_REGS 0xf0
#define PEGASUS_REQ_GET_REGS 0xf0
...
...
drivers/usb/net/usbnet.c
View file @
6c7a3c95
...
@@ -122,6 +122,11 @@
...
@@ -122,6 +122,11 @@
* cleanups and stubbed PXA-250 support (db), fix for framing
* cleanups and stubbed PXA-250 support (db), fix for framing
* issues on Z, net1080, and gl620a (Toby Milne)
* 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>
#include <linux/config.h>
...
@@ -155,16 +160,17 @@
...
@@ -155,16 +160,17 @@
/* minidrivers _could_ be individually configured */
/* minidrivers _could_ be individually configured */
#define CONFIG_USB_AN2720
#define CONFIG_USB_AN2720
#define CONFIG_USB_BELKIN
#define CONFIG_USB_BELKIN
#undef CONFIG_USB_CDCETHER
//#define CONFIG_USB_CDCETHER /* NYET */
#define CONFIG_USB_EPSON2888
#define CONFIG_USB_EPSON2888
#define CONFIG_USB_GENESYS
#define CONFIG_USB_GENESYS
#define CONFIG_USB_NET1080
#define CONFIG_USB_NET1080
#define CONFIG_USB_PL2301
#define CONFIG_USB_PL2301
// #define CONFIG_USB_PXA
#define CONFIG_USB_ARMLINUX
#define CONFIG_USB_SA1100
#define CONFIG_USB_ZAURUS
#define CONFIG_USB_ZAURUS
#define DRIVER_VERSION "
18-Oct-2002
"
#define DRIVER_VERSION "
31-Mar-2003
"
/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
...
@@ -176,11 +182,11 @@
...
@@ -176,11 +182,11 @@
* Ethernet packets (so queues should be bigger).
* Ethernet packets (so queues should be bigger).
*/
*/
#ifdef REALLY_QUEUE
#ifdef REALLY_QUEUE
#define RX_QLEN
4
#define RX_QLEN
(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
#define TX_QLEN
4
#define TX_QLEN
(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
#else
#else
#define RX_QLEN 1
#define RX_QLEN
(dev)
1
#define TX_QLEN 1
#define TX_QLEN
(dev)
1
#endif
#endif
// packets are always ethernet inside
// packets are always ethernet inside
...
@@ -191,6 +197,10 @@
...
@@ -191,6 +197,10 @@
// reawaken network queue this soon after stopping; else watchdog barks
// reawaken network queue this soon after stopping; else watchdog barks
#define TX_TIMEOUT_JIFFIES (5*HZ)
#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
// for vendor-specific control operations
#define CONTROL_TIMEOUT_MS (500)
/* msec */
#define CONTROL_TIMEOUT_MS (500)
/* msec */
#define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000)
#define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000)
...
@@ -200,10 +210,6 @@
...
@@ -200,10 +210,6 @@
/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
// list of all devices we manage
static
DECLARE_MUTEX
(
usbnet_mutex
);
static
LIST_HEAD
(
usbnet_list
);
// randomly generated ethernet address
// randomly generated ethernet address
static
u8
node_id
[
ETH_ALEN
];
static
u8
node_id
[
ETH_ALEN
];
...
@@ -213,17 +219,18 @@ struct usbnet {
...
@@ -213,17 +219,18 @@ struct usbnet {
struct
usb_device
*
udev
;
struct
usb_device
*
udev
;
struct
driver_info
*
driver_info
;
struct
driver_info
*
driver_info
;
struct
semaphore
mutex
;
struct
semaphore
mutex
;
struct
list_head
dev_list
;
wait_queue_head_t
*
wait
;
wait_queue_head_t
*
wait
;
// i/o info: pipes etc
unsigned
in
,
out
;
unsigned
maxpacket
;
struct
timer_list
delay
;
// protocol/interface state
// protocol/interface state
struct
net_device
net
;
struct
net_device
net
;
struct
net_device_stats
stats
;
struct
net_device_stats
stats
;
int
msg_level
;
int
msg_level
;
unsigned
long
data
[
5
];
#ifdef CONFIG_USB_NET1080
u16
packet_id
;
#endif
// various kinds of pending driver work
// various kinds of pending driver work
struct
sk_buff_head
rxq
;
struct
sk_buff_head
rxq
;
...
@@ -243,11 +250,19 @@ struct driver_info {
...
@@ -243,11 +250,19 @@ struct driver_info {
char
*
description
;
char
*
description
;
int
flags
;
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_NC 0x0001
/* guard against device dropouts */
#define FLAG_FRAMING_GL 0x0002
/* genelink batches packets */
#define FLAG_FRAMING_GL 0x0002
/* genelink batches packets */
#define FLAG_FRAMING_Z 0x0004
/* zaurus adds a trailer */
#define FLAG_FRAMING_Z 0x0004
/* zaurus adds a trailer */
#define FLAG_NO_SETINT 0x0010
/* device can't set_interface() */
#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 */
/* reset device ... can sleep */
int
(
*
reset
)(
struct
usbnet
*
);
int
(
*
reset
)(
struct
usbnet
*
);
...
@@ -263,15 +278,13 @@ struct driver_info {
...
@@ -263,15 +278,13 @@ struct driver_info {
// FIXME -- also an interrupt mechanism
// FIXME -- also an interrupt mechanism
// useful for at least PL2301/2302 and GL620USB-A
// 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
in
;
/* rx endpoint */
int
out
;
/* tx 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
// we record the state for each of our queued skbs
enum
skb_state
{
enum
skb_state
{
illegal
=
0
,
illegal
=
0
,
...
@@ -300,14 +313,6 @@ MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)");
...
@@ -300,14 +313,6 @@ MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)");
#define RUN_CONTEXT (in_irq () ? "in_irq" \
#define RUN_CONTEXT (in_irq () ? "in_irq" \
: (in_interrupt () ? "in_interrupt" : "can sleep"))
: (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
#ifdef DEBUG
#define devdbg(usbnet, fmt, arg...) \
#define devdbg(usbnet, fmt, arg...) \
printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net.name, ## arg)
printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net.name, ## arg)
...
@@ -315,11 +320,76 @@ static int always_connected (struct usbnet *dev)
...
@@ -315,11 +320,76 @@ static int always_connected (struct usbnet *dev)
#define devdbg(usbnet, fmt, arg...) do {} while(0)
#define devdbg(usbnet, fmt, arg...) do {} while(0)
#endif
#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...) \
#define devinfo(usbnet, fmt, arg...) \
do { if ((usbnet)->msg_level >= 1) \
do { if ((usbnet)->msg_level >= 1) \
printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg); \
printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg); \
} while (0)
} 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
#ifdef CONFIG_USB_AN2720
...
@@ -340,7 +410,6 @@ static const struct driver_info an2720_info = {
...
@@ -340,7 +410,6 @@ static const struct driver_info an2720_info = {
// no check_connect available!
// no check_connect available!
.
in
=
2
,
.
out
=
2
,
// direction distinguishes these
.
in
=
2
,
.
out
=
2
,
// direction distinguishes these
.
epsize
=
64
,
};
};
#endif
/* CONFIG_USB_AN2720 */
#endif
/* CONFIG_USB_AN2720 */
...
@@ -359,14 +428,225 @@ static const struct driver_info an2720_info = {
...
@@ -359,14 +428,225 @@ static const struct driver_info an2720_info = {
static
const
struct
driver_info
belkin_info
=
{
static
const
struct
driver_info
belkin_info
=
{
.
description
=
"Belkin, eTEK, or compatible"
,
.
description
=
"Belkin, eTEK, or compatible"
,
.
in
=
1
,
.
out
=
1
,
// direction distinguishes these
.
epsize
=
64
,
};
};
#endif
/* CONFIG_USB_BELKIN */
#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
#ifdef CONFIG_USB_EPSON2888
...
@@ -386,7 +666,6 @@ static const struct driver_info epson2888_info = {
...
@@ -386,7 +666,6 @@ static const struct driver_info epson2888_info = {
.
check_connect
=
always_connected
,
.
check_connect
=
always_connected
,
.
in
=
4
,
.
out
=
3
,
.
in
=
4
,
.
out
=
3
,
.
epsize
=
64
,
};
};
#endif
/* CONFIG_USB_EPSON2888 */
#endif
/* CONFIG_USB_EPSON2888 */
...
@@ -704,7 +983,7 @@ genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
...
@@ -704,7 +983,7 @@ genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
*
packet_len
=
length
;
*
packet_len
=
length
;
// add padding byte
// add padding byte
if
((
skb
->
len
%
EP_SIZE
(
dev
)
)
==
0
)
if
((
skb
->
len
%
dev
->
maxpacket
)
==
0
)
skb_put
(
skb
,
1
);
skb_put
(
skb
,
1
);
return
skb
;
return
skb
;
...
@@ -717,7 +996,6 @@ static const struct driver_info genelink_info = {
...
@@ -717,7 +996,6 @@ static const struct driver_info genelink_info = {
.
tx_fixup
=
genelink_tx_fixup
,
.
tx_fixup
=
genelink_tx_fixup
,
.
in
=
1
,
.
out
=
2
,
.
in
=
1
,
.
out
=
2
,
.
epsize
=
64
,
#ifdef GENELINK_ACK
#ifdef GENELINK_ACK
.
check_connect
=
genelink_check_connect
,
.
check_connect
=
genelink_check_connect
,
...
@@ -737,6 +1015,9 @@ static const struct driver_info genelink_info = {
...
@@ -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
* NetChip framing of ethernet packets, supporting additional error
* checks for links that may drop bulk packets from inside messages.
* checks for links that may drop bulk packets from inside messages.
...
@@ -1064,6 +1345,60 @@ static int net1080_check_connect (struct usbnet *dev)
...
@@ -1064,6 +1345,60 @@ static int net1080_check_connect (struct usbnet *dev)
return
0
;
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
)
static
int
net1080_rx_fixup
(
struct
usbnet
*
dev
,
struct
sk_buff
*
skb
)
{
{
struct
nc_header
*
header
;
struct
nc_header
*
header
;
...
@@ -1076,6 +1411,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
...
@@ -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
,
dbg
(
"rx framesize %d range %d..%d mtu %d"
,
skb
->
len
,
(
int
)
MIN_FRAMED
,
(
int
)
FRAMED_SIZE
(
dev
->
net
.
mtu
),
(
int
)
MIN_FRAMED
,
(
int
)
FRAMED_SIZE
(
dev
->
net
.
mtu
),
dev
->
net
.
mtu
);
dev
->
net
.
mtu
);
nc_ensure_sync
(
dev
);
return
0
;
return
0
;
}
}
...
@@ -1085,15 +1421,18 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
...
@@ -1085,15 +1421,18 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
if
(
FRAMED_SIZE
(
header
->
packet_len
)
>
MAX_PACKET
)
{
if
(
FRAMED_SIZE
(
header
->
packet_len
)
>
MAX_PACKET
)
{
dev
->
stats
.
rx_frame_errors
++
;
dev
->
stats
.
rx_frame_errors
++
;
dbg
(
"packet too big, %d"
,
header
->
packet_len
);
dbg
(
"packet too big, %d"
,
header
->
packet_len
);
nc_ensure_sync
(
dev
);
return
0
;
return
0
;
}
else
if
(
header
->
hdr_len
<
MIN_HEADER
)
{
}
else
if
(
header
->
hdr_len
<
MIN_HEADER
)
{
dev
->
stats
.
rx_frame_errors
++
;
dev
->
stats
.
rx_frame_errors
++
;
dbg
(
"header too short, %d"
,
header
->
hdr_len
);
dbg
(
"header too short, %d"
,
header
->
hdr_len
);
nc_ensure_sync
(
dev
);
return
0
;
return
0
;
}
else
if
(
header
->
hdr_len
>
MIN_HEADER
)
{
}
else
if
(
header
->
hdr_len
>
MIN_HEADER
)
{
// out of band data for us?
// out of band data for us?
dbg
(
"header OOB, %d bytes"
,
dbg
(
"header OOB, %d bytes"
,
header
->
hdr_len
-
MIN_HEADER
);
header
->
hdr_len
-
MIN_HEADER
);
nc_ensure_sync
(
dev
);
// switch (vendor/product ids) { ... }
// switch (vendor/product ids) { ... }
}
}
skb_pull
(
skb
,
header
->
hdr_len
);
skb_pull
(
skb
,
header
->
hdr_len
);
...
@@ -1114,6 +1453,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
...
@@ -1114,6 +1453,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
dev
->
stats
.
rx_frame_errors
++
;
dev
->
stats
.
rx_frame_errors
++
;
dbg
(
"bad packet len %d (expected %d)"
,
dbg
(
"bad packet len %d (expected %d)"
,
skb
->
len
,
header
->
packet_len
);
skb
->
len
,
header
->
packet_len
);
nc_ensure_sync
(
dev
);
return
0
;
return
0
;
}
}
if
(
header
->
packet_id
!=
get_unaligned
(
&
trailer
->
packet_id
))
{
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)
...
@@ -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,
devdbg (dev, "frame <rx h %d p %d id %d", header->hdr_len,
header->packet_len, header->packet_id);
header->packet_len, header->packet_id);
#endif
#endif
dev
->
frame_errors
=
0
;
return
1
;
return
1
;
}
}
...
@@ -1143,11 +1484,13 @@ net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
...
@@ -1143,11 +1484,13 @@ net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
if
((
padlen
+
sizeof
(
struct
nc_trailer
))
<=
tailroom
if
((
padlen
+
sizeof
(
struct
nc_trailer
))
<=
tailroom
&&
sizeof
(
struct
nc_header
)
<=
headroom
)
&&
sizeof
(
struct
nc_header
)
<=
headroom
)
/* There's enough head and tail room */
return
skb
;
return
skb
;
if
((
sizeof
(
struct
nc_header
)
+
padlen
if
((
sizeof
(
struct
nc_header
)
+
padlen
+
sizeof
(
struct
nc_trailer
))
<
+
sizeof
(
struct
nc_trailer
))
<
(
headroom
+
tailroom
))
{
(
headroom
+
tailroom
))
{
/* There's enough total room, so just readjust */
skb
->
data
=
memmove
(
skb
->
head
skb
->
data
=
memmove
(
skb
->
head
+
sizeof
(
struct
nc_header
),
+
sizeof
(
struct
nc_header
),
skb
->
data
,
skb
->
len
);
skb
->
data
,
skb
->
len
);
...
@@ -1155,6 +1498,8 @@ net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
...
@@ -1155,6 +1498,8 @@ net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
return
skb
;
return
skb
;
}
}
}
}
/* Create a new skb to use with the correct size */
skb2
=
skb_copy_expand
(
skb
,
skb2
=
skb_copy_expand
(
skb
,
sizeof
(
struct
nc_header
),
sizeof
(
struct
nc_header
),
sizeof
(
struct
nc_trailer
)
+
padlen
,
sizeof
(
struct
nc_trailer
)
+
padlen
,
...
@@ -1170,9 +1515,6 @@ static const struct driver_info net1080_info = {
...
@@ -1170,9 +1515,6 @@ static const struct driver_info net1080_info = {
.
check_connect
=
net1080_check_connect
,
.
check_connect
=
net1080_check_connect
,
.
rx_fixup
=
net1080_rx_fixup
,
.
rx_fixup
=
net1080_rx_fixup
,
.
tx_fixup
=
net1080_tx_fixup
,
.
tx_fixup
=
net1080_tx_fixup
,
.
in
=
1
,
.
out
=
1
,
// direction distinguishes these
.
epsize
=
64
,
};
};
#endif
/* CONFIG_USB_NET1080 */
#endif
/* CONFIG_USB_NET1080 */
...
@@ -1237,37 +1579,13 @@ static const struct driver_info prolific_info = {
...
@@ -1237,37 +1579,13 @@ static const struct driver_info prolific_info = {
.
flags
=
FLAG_NO_SETINT
,
.
flags
=
FLAG_NO_SETINT
,
/* some PL-2302 versions seem to fail usb_set_interface() */
/* some PL-2302 versions seem to fail usb_set_interface() */
.
reset
=
pl_reset
,
.
reset
=
pl_reset
,
.
in
=
3
,
.
out
=
2
,
.
epsize
=
64
,
};
};
#endif
/* CONFIG_USB_PL2301 */
#endif
/* CONFIG_USB_PL2301 */
#ifdef CONFIG_USB_PXA
#ifdef CONFIG_USB_ARMLINUX
/*-------------------------------------------------------------------------
*
* 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
/*-------------------------------------------------------------------------
/*-------------------------------------------------------------------------
*
*
...
@@ -1279,25 +1597,24 @@ static const struct driver_info pxa_info = {
...
@@ -1279,25 +1597,24 @@ static const struct driver_info pxa_info = {
* This describes the driver currently in standard ARM Linux kernels.
* This describes the driver currently in standard ARM Linux kernels.
* The Zaurus uses a different driver (see later).
* 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
=
{
static
const
struct
driver_info
linuxdev_info
=
{
.
description
=
"
SA-1100
Linux Device"
,
.
description
=
"Linux Device"
,
.
check_connect
=
always_connected
,
.
check_connect
=
always_connected
,
.
in
=
2
,
.
out
=
1
,
.
epsize
=
64
,
};
};
static
const
struct
driver_info
yopy_info
=
{
static
const
struct
driver_info
yopy_info
=
{
.
description
=
"Yopy"
,
.
description
=
"Yopy"
,
.
check_connect
=
always_connected
,
.
check_connect
=
always_connected
,
.
in
=
2
,
.
out
=
1
,
.
epsize
=
64
,
};
};
#endif
/* CONFIG_USB_
SA1100
*/
#endif
/* CONFIG_USB_
ARMLINUX
*/
#ifdef CONFIG_USB_ZAURUS
#ifdef CONFIG_USB_ZAURUS
...
@@ -1349,10 +1666,9 @@ static const struct driver_info zaurus_sl5x00_info = {
...
@@ -1349,10 +1666,9 @@ static const struct driver_info zaurus_sl5x00_info = {
.
description
=
"Sharp Zaurus SL-5x00"
,
.
description
=
"Sharp Zaurus SL-5x00"
,
.
flags
=
FLAG_FRAMING_Z
,
.
flags
=
FLAG_FRAMING_Z
,
.
check_connect
=
always_connected
,
.
check_connect
=
always_connected
,
.
bind
=
cdc_bind
,
.
unbind
=
cdc_unbind
,
.
tx_fixup
=
zaurus_tx_fixup
,
.
tx_fixup
=
zaurus_tx_fixup
,
.
in
=
2
,
.
out
=
1
,
.
epsize
=
64
,
};
};
static
const
struct
driver_info
zaurus_sla300_info
=
{
static
const
struct
driver_info
zaurus_sla300_info
=
{
.
description
=
"Sharp Zaurus SL-A300"
,
.
description
=
"Sharp Zaurus SL-A300"
,
...
@@ -1361,7 +1677,6 @@ static const struct driver_info zaurus_sla300_info = {
...
@@ -1361,7 +1677,6 @@ static const struct driver_info zaurus_sla300_info = {
.
tx_fixup
=
zaurus_tx_fixup
,
.
tx_fixup
=
zaurus_tx_fixup
,
.
in
=
1
,
.
out
=
2
,
.
in
=
1
,
.
out
=
2
,
.
epsize
=
64
,
};
};
static
const
struct
driver_info
zaurus_slb500_info
=
{
static
const
struct
driver_info
zaurus_slb500_info
=
{
/* Japanese B500 ~= US SL-5600 */
/* Japanese B500 ~= US SL-5600 */
...
@@ -1371,7 +1686,6 @@ static const struct driver_info zaurus_slb500_info = {
...
@@ -1371,7 +1686,6 @@ static const struct driver_info zaurus_slb500_info = {
.
tx_fixup
=
zaurus_tx_fixup
,
.
tx_fixup
=
zaurus_tx_fixup
,
.
in
=
1
,
.
out
=
2
,
.
in
=
1
,
.
out
=
2
,
.
epsize
=
64
,
};
};
// SL-5600 and C-700 are PXA based; should resemble A300
// 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)
...
@@ -1403,7 +1717,7 @@ static int usbnet_change_mtu (struct net_device *net, int new_mtu)
return
-
EINVAL
;
return
-
EINVAL
;
#endif
#endif
// no second zero-length packet read wanted after mtu-sized packets
// 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
;
return
-
EDOM
;
net
->
mtu
=
new_mtu
;
net
->
mtu
=
new_mtu
;
return
0
;
return
0
;
...
@@ -1444,10 +1758,9 @@ static void defer_kevent (struct usbnet *dev, int work)
...
@@ -1444,10 +1758,9 @@ static void defer_kevent (struct usbnet *dev, int work)
{
{
set_bit
(
work
,
&
dev
->
flags
);
set_bit
(
work
,
&
dev
->
flags
);
if
(
!
schedule_work
(
&
dev
->
kevent
))
if
(
!
schedule_work
(
&
dev
->
kevent
))
err
(
"%s: kevent %d may have been dropped"
,
deverr
(
dev
,
"kevent %d may have been dropped"
,
work
);
dev
->
net
.
name
,
work
);
else
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)
...
@@ -1480,7 +1793,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
size
=
(
sizeof
(
struct
ethhdr
)
+
dev
->
net
.
mtu
);
size
=
(
sizeof
(
struct
ethhdr
)
+
dev
->
net
.
mtu
);
if
((
skb
=
alloc_skb
(
size
,
flags
))
==
0
)
{
if
((
skb
=
alloc_skb
(
size
,
flags
))
==
0
)
{
d
bg
(
"no rx skb"
);
d
evdbg
(
dev
,
"no rx skb"
);
defer_kevent
(
dev
,
EVENT_RX_MEMORY
);
defer_kevent
(
dev
,
EVENT_RX_MEMORY
);
usb_free_urb
(
urb
);
usb_free_urb
(
urb
);
return
;
return
;
...
@@ -1492,14 +1805,14 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
...
@@ -1492,14 +1805,14 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
entry
->
state
=
rx_start
;
entry
->
state
=
rx_start
;
entry
->
length
=
0
;
entry
->
length
=
0
;
usb_fill_bulk_urb
(
urb
,
dev
->
udev
,
usb_fill_bulk_urb
(
urb
,
dev
->
udev
,
dev
->
in
,
usb_rcvbulkpipe
(
dev
->
udev
,
dev
->
driver_info
->
in
),
skb
->
data
,
size
,
rx_complete
,
skb
);
skb
->
data
,
size
,
rx_complete
,
skb
);
urb
->
transfer_flags
|=
URB_ASYNC_UNLINK
;
urb
->
transfer_flags
|=
URB_ASYNC_UNLINK
;
spin_lock_irqsave
(
&
dev
->
rxq
.
lock
,
lockflags
);
spin_lock_irqsave
(
&
dev
->
rxq
.
lock
,
lockflags
);
if
(
netif_running
(
&
dev
->
net
)
if
(
netif_running
(
&
dev
->
net
)
&&
netif_device_present
(
&
dev
->
net
)
&&
!
test_bit
(
EVENT_RX_HALT
,
&
dev
->
flags
))
{
&&
!
test_bit
(
EVENT_RX_HALT
,
&
dev
->
flags
))
{
switch
(
retval
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
)){
switch
(
retval
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
)){
case
-
EPIPE
:
case
-
EPIPE
:
...
@@ -1508,15 +1821,19 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
...
@@ -1508,15 +1821,19 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
case
-
ENOMEM
:
case
-
ENOMEM
:
defer_kevent
(
dev
,
EVENT_RX_MEMORY
);
defer_kevent
(
dev
,
EVENT_RX_MEMORY
);
break
;
break
;
case
-
ENODEV
:
devdbg
(
dev
,
"device gone"
);
netif_device_detach
(
&
dev
->
net
);
break
;
default:
default:
d
bg
(
"%s rx submit, %d"
,
dev
->
net
.
name
,
retval
);
d
evdbg
(
dev
,
"rx submit, %d"
,
retval
);
tasklet_schedule
(
&
dev
->
bh
);
tasklet_schedule
(
&
dev
->
bh
);
break
;
break
;
case
0
:
case
0
:
__skb_queue_tail
(
&
dev
->
rxq
,
skb
);
__skb_queue_tail
(
&
dev
->
rxq
,
skb
);
}
}
}
else
{
}
else
{
d
bg
(
"rx: stopped"
);
d
evdbg
(
dev
,
"rx: stopped"
);
retval
=
-
ENOLINK
;
retval
=
-
ENOLINK
;
}
}
spin_unlock_irqrestore
(
&
dev
->
rxq
.
lock
,
lockflags
);
spin_unlock_irqrestore
(
&
dev
->
rxq
.
lock
,
lockflags
);
...
@@ -1553,7 +1870,7 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
...
@@ -1553,7 +1870,7 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
if
(
status
!=
NET_RX_SUCCESS
)
if
(
status
!=
NET_RX_SUCCESS
)
devdbg
(
dev
,
"netif_rx status %d"
,
status
);
devdbg
(
dev
,
"netif_rx status %d"
,
status
);
}
else
{
}
else
{
d
bg
(
"drop"
);
d
evdbg
(
dev
,
"drop"
);
error:
error:
dev
->
stats
.
rx_errors
++
;
dev
->
stats
.
rx_errors
++
;
skb_queue_tail
(
&
dev
->
done
,
skb
);
skb_queue_tail
(
&
dev
->
done
,
skb
);
...
@@ -1580,7 +1897,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
...
@@ -1580,7 +1897,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
entry
->
state
=
rx_cleanup
;
entry
->
state
=
rx_cleanup
;
dev
->
stats
.
rx_errors
++
;
dev
->
stats
.
rx_errors
++
;
dev
->
stats
.
rx_length_errors
++
;
dev
->
stats
.
rx_length_errors
++
;
d
bg
(
"rx length %d"
,
skb
->
len
);
d
evdbg
(
dev
,
"rx length %d"
,
skb
->
len
);
}
}
break
;
break
;
...
@@ -1589,15 +1906,31 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
...
@@ -1589,15 +1906,31 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
// we avoid the highspeed version of the ETIMEOUT/EILSEQ
// we avoid the highspeed version of the ETIMEOUT/EILSEQ
// storm, recovering as needed.
// storm, recovering as needed.
case
-
EPIPE
:
case
-
EPIPE
:
dev
->
stats
.
rx_errors
++
;
defer_kevent
(
dev
,
EVENT_RX_HALT
);
defer_kevent
(
dev
,
EVENT_RX_HALT
);
// FALLTHROUGH
// FALLTHROUGH
// software-driven interface shutdown
// software-driven interface shutdown
case
-
ECONNRESET
:
// according to API spec
case
-
ECONNRESET
:
// async unlink
case
-
ECONNABORTED
:
// some (now fixed?) UHCI bugs
case
-
ESHUTDOWN
:
// hardware gone
dbg
(
"%s rx shutdown, code %d"
,
dev
->
net
.
name
,
urb_status
);
#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
;
entry
->
state
=
rx_cleanup
;
// do urb frees only in the tasklet (UHCI has oopsed ...)
entry
->
urb
=
urb
;
entry
->
urb
=
urb
;
urb
=
0
;
urb
=
0
;
break
;
break
;
...
@@ -1608,12 +1941,9 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
...
@@ -1608,12 +1941,9 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
// FALLTHROUGH
// FALLTHROUGH
default:
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
;
entry
->
state
=
rx_cleanup
;
dev
->
stats
.
rx_errors
++
;
dev
->
stats
.
rx_errors
++
;
d
bg
(
"%s rx: status %d"
,
dev
->
net
.
name
,
urb_status
);
d
evdbg
(
dev
,
"rx status %d"
,
urb_status
);
break
;
break
;
}
}
...
@@ -1628,7 +1958,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
...
@@ -1628,7 +1958,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
usb_free_urb
(
urb
);
usb_free_urb
(
urb
);
}
}
#ifdef VERBOSE
#ifdef VERBOSE
d
bg
(
"no read resubmitted"
);
d
evdbg
(
dev
,
"no read resubmitted"
);
#endif
/* VERBOSE */
#endif
/* VERBOSE */
}
}
...
@@ -1636,7 +1966,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
...
@@ -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
// 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
;
unsigned
long
flags
;
struct
sk_buff
*
skb
,
*
skbnext
;
struct
sk_buff
*
skb
,
*
skbnext
;
...
@@ -1656,7 +1986,7 @@ static int unlink_urbs (struct sk_buff_head *q)
...
@@ -1656,7 +1986,7 @@ static int unlink_urbs (struct sk_buff_head *q)
// these (async) unlinks complete immediately
// these (async) unlinks complete immediately
retval
=
usb_unlink_urb
(
urb
);
retval
=
usb_unlink_urb
(
urb
);
if
(
retval
!=
-
EINPROGRESS
&&
retval
!=
0
)
if
(
retval
!=
-
EINPROGRESS
&&
retval
!=
0
)
d
bg
(
"unlink urb err, %d"
,
retval
);
d
evdbg
(
dev
,
"unlink urb err, %d"
,
retval
);
else
else
count
++
;
count
++
;
}
}
...
@@ -1688,7 +2018,7 @@ static int usbnet_stop (struct net_device *net)
...
@@ -1688,7 +2018,7 @@ static int usbnet_stop (struct net_device *net)
// ensure there are no more active urbs
// ensure there are no more active urbs
add_wait_queue
(
&
unlink_wakeup
,
&
wait
);
add_wait_queue
(
&
unlink_wakeup
,
&
wait
);
dev
->
wait
=
&
unlink_wakeup
;
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.
// maybe wait for deletions to finish.
while
(
skb_queue_len
(
&
dev
->
rxq
)
while
(
skb_queue_len
(
&
dev
->
rxq
)
...
@@ -1696,11 +2026,16 @@ static int usbnet_stop (struct net_device *net)
...
@@ -1696,11 +2026,16 @@ static int usbnet_stop (struct net_device *net)
&&
skb_queue_len
(
&
dev
->
done
))
{
&&
skb_queue_len
(
&
dev
->
done
))
{
set_current_state
(
TASK_UNINTERRUPTIBLE
);
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
UNLINK_TIMEOUT_JIFFIES
);
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
;
dev
->
wait
=
0
;
remove_wait_queue
(
&
unlink_wakeup
,
&
wait
);
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
);
mutex_unlock
(
&
dev
->
mutex
);
return
0
;
return
0
;
}
}
...
@@ -1738,7 +2073,7 @@ static int usbnet_open (struct net_device *net)
...
@@ -1738,7 +2073,7 @@ static int usbnet_open (struct net_device *net)
if
(
dev
->
msg_level
>=
2
)
if
(
dev
->
msg_level
>=
2
)
devinfo
(
dev
,
"open: enable queueing "
devinfo
(
dev
,
"open: enable queueing "
"(rx %d, tx %d) mtu %d %s framing"
,
"(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
|
FLAG_FRAMING_GL
))
?
((
info
->
flags
&
FLAG_FRAMING_NC
)
?
((
info
->
flags
&
FLAG_FRAMING_NC
)
?
"NetChip"
?
"NetChip"
...
@@ -1755,7 +2090,8 @@ static int usbnet_open (struct net_device *net)
...
@@ -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
;
struct
usbnet
*
dev
=
(
struct
usbnet
*
)
net
->
priv
;
u32
cmd
;
u32
cmd
;
...
@@ -1829,9 +2165,8 @@ static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int 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.
/* work that cannot be done in interrupt context uses keventd.
*
*
* NOTE: "uhci" and "usb-uhci" may have trouble with this since they don't
* NOTE: with 2.5 we could do more of this using completion callbacks,
* queue control transfers to individual devices, and other threads could
* especially now that control transfers can be queued.
* trigger control requests concurrently. hope that's rare.
*/
*/
static
void
static
void
kevent
(
void
*
data
)
kevent
(
void
*
data
)
...
@@ -1841,24 +2176,22 @@ kevent (void *data)
...
@@ -1841,24 +2176,22 @@ kevent (void *data)
/* usb_clear_halt() needs a thread context */
/* usb_clear_halt() needs a thread context */
if
(
test_bit
(
EVENT_TX_HALT
,
&
dev
->
flags
))
{
if
(
test_bit
(
EVENT_TX_HALT
,
&
dev
->
flags
))
{
unlink_urbs
(
&
dev
->
txq
);
unlink_urbs
(
dev
,
&
dev
->
txq
);
status
=
usb_clear_halt
(
dev
->
udev
,
status
=
usb_clear_halt
(
dev
->
udev
,
dev
->
out
);
usb_sndbulkpipe
(
dev
->
udev
,
dev
->
driver_info
->
out
));
if
(
status
<
0
)
if
(
status
<
0
)
err
(
"%s:
can't clear tx halt, status %d"
,
deverr
(
dev
,
"
can't clear tx halt, status %d"
,
dev
->
net
.
name
,
status
);
status
);
else
{
else
{
clear_bit
(
EVENT_TX_HALT
,
&
dev
->
flags
);
clear_bit
(
EVENT_TX_HALT
,
&
dev
->
flags
);
netif_wake_queue
(
&
dev
->
net
);
netif_wake_queue
(
&
dev
->
net
);
}
}
}
}
if
(
test_bit
(
EVENT_RX_HALT
,
&
dev
->
flags
))
{
if
(
test_bit
(
EVENT_RX_HALT
,
&
dev
->
flags
))
{
unlink_urbs
(
&
dev
->
rxq
);
unlink_urbs
(
dev
,
&
dev
->
rxq
);
status
=
usb_clear_halt
(
dev
->
udev
,
status
=
usb_clear_halt
(
dev
->
udev
,
dev
->
in
);
usb_rcvbulkpipe
(
dev
->
udev
,
dev
->
driver_info
->
in
));
if
(
status
<
0
)
if
(
status
<
0
)
err
(
"%s:
can't clear rx halt, status %d"
,
deverr
(
dev
,
"
can't clear rx halt, status %d"
,
dev
->
net
.
name
,
status
);
status
);
else
{
else
{
clear_bit
(
EVENT_RX_HALT
,
&
dev
->
flags
);
clear_bit
(
EVENT_RX_HALT
,
&
dev
->
flags
);
tasklet_schedule
(
&
dev
->
bh
);
tasklet_schedule
(
&
dev
->
bh
);
...
@@ -1881,8 +2214,8 @@ kevent (void *data)
...
@@ -1881,8 +2214,8 @@ kevent (void *data)
}
}
if
(
dev
->
flags
)
if
(
dev
->
flags
)
d
bg
(
"%s:
kevent done, flags = 0x%lx"
,
d
evdbg
(
dev
,
"
kevent done, flags = 0x%lx"
,
dev
->
net
.
name
,
dev
->
flags
);
dev
->
flags
);
}
}
/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
...
@@ -1893,8 +2226,35 @@ static void tx_complete (struct urb *urb, struct pt_regs *regs)
...
@@ -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
skb_data
*
entry
=
(
struct
skb_data
*
)
skb
->
cb
;
struct
usbnet
*
dev
=
entry
->
dev
;
struct
usbnet
*
dev
=
entry
->
dev
;
if
(
urb
->
status
==
-
EPIPE
)
if
(
urb
->
status
==
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
);
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
;
urb
->
dev
=
0
;
entry
->
state
=
tx_done
;
entry
->
state
=
tx_done
;
defer_bh
(
dev
,
skb
);
defer_bh
(
dev
,
skb
);
...
@@ -1906,7 +2266,7 @@ static void usbnet_tx_timeout (struct net_device *net)
...
@@ -1906,7 +2266,7 @@ static void usbnet_tx_timeout (struct net_device *net)
{
{
struct
usbnet
*
dev
=
(
struct
usbnet
*
)
net
->
priv
;
struct
usbnet
*
dev
=
(
struct
usbnet
*
)
net
->
priv
;
unlink_urbs
(
&
dev
->
txq
);
unlink_urbs
(
dev
,
&
dev
->
txq
);
tasklet_schedule
(
&
dev
->
bh
);
tasklet_schedule
(
&
dev
->
bh
);
// FIXME: device recovery -- reset?
// FIXME: device recovery -- reset?
...
@@ -1933,14 +2293,14 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
...
@@ -1933,14 +2293,14 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
if
(
info
->
tx_fixup
)
{
if
(
info
->
tx_fixup
)
{
skb
=
info
->
tx_fixup
(
dev
,
skb
,
GFP_ATOMIC
);
skb
=
info
->
tx_fixup
(
dev
,
skb
,
GFP_ATOMIC
);
if
(
!
skb
)
{
if
(
!
skb
)
{
d
bg
(
"can't tx_fixup skb"
);
d
evdbg
(
dev
,
"can't tx_fixup skb"
);
goto
drop
;
goto
drop
;
}
}
}
}
length
=
skb
->
len
;
length
=
skb
->
len
;
if
(
!
(
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
)))
{
if
(
!
(
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
)))
{
d
bg
(
"no urb"
);
d
evdbg
(
dev
,
"no urb"
);
goto
drop
;
goto
drop
;
}
}
...
@@ -1965,20 +2325,24 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
...
@@ -1965,20 +2325,24 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
}
else
}
else
#endif
/* CONFIG_USB_NET1080 */
#endif
/* CONFIG_USB_NET1080 */
/* don't assume the hardware handles USB_ZERO_PACKET */
usb_fill_bulk_urb
(
urb
,
dev
->
udev
,
dev
->
out
,
if
((
length
%
EP_SIZE
(
dev
))
==
0
)
skb
->
len
++
;
usb_fill_bulk_urb
(
urb
,
dev
->
udev
,
usb_sndbulkpipe
(
dev
->
udev
,
info
->
out
),
skb
->
data
,
skb
->
len
,
tx_complete
,
skb
);
skb
->
data
,
skb
->
len
,
tx_complete
,
skb
);
urb
->
transfer_flags
|=
URB_ASYNC_UNLINK
;
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
);
spin_lock_irqsave
(
&
dev
->
txq
.
lock
,
flags
);
#ifdef CONFIG_USB_NET1080
#ifdef CONFIG_USB_NET1080
if
(
info
->
flags
&
FLAG_FRAMING_NC
)
{
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
);
put_unaligned
(
header
->
packet_id
,
&
trailer
->
packet_id
);
#if 0
#if 0
devdbg (dev, "frame >tx h %d p %d id %d",
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)
...
@@ -1994,12 +2358,12 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
defer_kevent
(
dev
,
EVENT_TX_HALT
);
defer_kevent
(
dev
,
EVENT_TX_HALT
);
break
;
break
;
default:
default:
d
bg
(
"%s tx: submit urb err %d"
,
net
->
name
,
retval
);
d
evdbg
(
dev
,
"tx: submit urb err %d"
,
retval
);
break
;
break
;
case
0
:
case
0
:
net
->
trans_start
=
jiffies
;
net
->
trans_start
=
jiffies
;
__skb_queue_tail
(
&
dev
->
txq
,
skb
);
__skb_queue_tail
(
&
dev
->
txq
,
skb
);
if
(
dev
->
txq
.
qlen
>=
TX_QLEN
)
if
(
dev
->
txq
.
qlen
>=
TX_QLEN
(
dev
)
)
netif_stop_queue
(
net
);
netif_stop_queue
(
net
);
}
}
spin_unlock_irqrestore
(
&
dev
->
txq
.
lock
,
flags
);
spin_unlock_irqrestore
(
&
dev
->
txq
.
lock
,
flags
);
...
@@ -2024,7 +2388,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
...
@@ -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
)
static
void
usbnet_bh
(
unsigned
long
param
)
{
{
...
@@ -2040,23 +2404,12 @@ static void usbnet_bh (unsigned long param)
...
@@ -2040,23 +2404,12 @@ static void usbnet_bh (unsigned long param)
rx_process
(
dev
,
skb
);
rx_process
(
dev
,
skb
);
continue
;
continue
;
case
tx_done
:
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
:
case
rx_cleanup
:
usb_free_urb
(
entry
->
urb
);
usb_free_urb
(
entry
->
urb
);
dev_kfree_skb
(
skb
);
dev_kfree_skb
(
skb
);
continue
;
continue
;
default:
default:
dbg
(
"%s: bogus skb state %d"
,
devdbg
(
dev
,
"bogus skb state %d"
,
entry
->
state
);
dev
->
net
.
name
,
entry
->
state
);
}
}
}
}
...
@@ -2068,23 +2421,28 @@ static void usbnet_bh (unsigned long param)
...
@@ -2068,23 +2421,28 @@ static void usbnet_bh (unsigned long param)
// or are we maybe short a few urbs?
// or are we maybe short a few urbs?
}
else
if
(
netif_running
(
&
dev
->
net
)
}
else
if
(
netif_running
(
&
dev
->
net
)
&&
netif_device_present
(
&
dev
->
net
)
&&
!
timer_pending
(
&
dev
->
delay
)
&&
!
test_bit
(
EVENT_RX_HALT
,
&
dev
->
flags
))
{
&&
!
test_bit
(
EVENT_RX_HALT
,
&
dev
->
flags
))
{
int
temp
=
dev
->
rxq
.
qlen
;
int
temp
=
dev
->
rxq
.
qlen
;
int
qlen
=
RX_QLEN
(
dev
);
if
(
temp
<
RX_QLEN
)
{
if
(
temp
<
qlen
)
{
struct
urb
*
urb
;
struct
urb
*
urb
;
int
i
;
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
)
if
((
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
))
!=
0
)
rx_submit
(
dev
,
urb
,
GFP_ATOMIC
);
rx_submit
(
dev
,
urb
,
GFP_ATOMIC
);
}
}
if
(
temp
!=
dev
->
rxq
.
qlen
)
if
(
temp
!=
dev
->
rxq
.
qlen
)
devdbg
(
dev
,
"rxqlen %d --> %d"
,
devdbg
(
dev
,
"rxqlen %d --> %d"
,
temp
,
dev
->
rxq
.
qlen
);
temp
,
dev
->
rxq
.
qlen
);
if
(
dev
->
rxq
.
qlen
<
RX_QLEN
)
if
(
dev
->
rxq
.
qlen
<
qlen
)
tasklet_schedule
(
&
dev
->
bh
);
tasklet_schedule
(
&
dev
->
bh
);
}
}
if
(
dev
->
txq
.
qlen
<
TX_QLEN
)
if
(
dev
->
txq
.
qlen
<
TX_QLEN
(
dev
)
)
netif_wake_queue
(
&
dev
->
net
);
netif_wake_queue
(
&
dev
->
net
);
}
}
}
}
...
@@ -2117,13 +2475,8 @@ static void usbnet_disconnect (struct usb_interface *intf)
...
@@ -2117,13 +2475,8 @@ static void usbnet_disconnect (struct usb_interface *intf)
unregister_netdev
(
&
dev
->
net
);
unregister_netdev
(
&
dev
->
net
);
mutex_lock
(
&
usbnet_mutex
);
if
(
dev
->
driver_info
->
unbind
)
mutex_lock
(
&
dev
->
mutex
);
dev
->
driver_info
->
unbind
(
dev
,
intf
);
list_del
(
&
dev
->
dev_list
);
mutex_unlock
(
&
usbnet_mutex
);
// assuming we used keventd, it must quiesce too
flush_scheduled_work
();
kfree
(
dev
);
kfree
(
dev
);
usb_put_dev
(
xdev
);
usb_put_dev
(
xdev
);
...
@@ -2142,20 +2495,12 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
...
@@ -2142,20 +2495,12 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
struct
usb_host_interface
*
interface
;
struct
usb_host_interface
*
interface
;
struct
driver_info
*
info
;
struct
driver_info
*
info
;
struct
usb_device
*
xdev
;
struct
usb_device
*
xdev
;
int
status
;
info
=
(
struct
driver_info
*
)
prod
->
driver_info
;
info
=
(
struct
driver_info
*
)
prod
->
driver_info
;
xdev
=
interface_to_usbdev
(
udev
);
xdev
=
interface_to_usbdev
(
udev
);
interface
=
&
udev
->
altsetting
[
udev
->
act_altsetting
];
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
// set up our own records
if
(
!
(
dev
=
kmalloc
(
sizeof
*
dev
,
GFP_KERNEL
)))
{
if
(
!
(
dev
=
kmalloc
(
sizeof
*
dev
,
GFP_KERNEL
)))
{
dbg
(
"can't kmalloc dev"
);
dbg
(
"can't kmalloc dev"
);
...
@@ -2168,13 +2513,15 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
...
@@ -2168,13 +2513,15 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev
->
udev
=
xdev
;
dev
->
udev
=
xdev
;
dev
->
driver_info
=
info
;
dev
->
driver_info
=
info
;
dev
->
msg_level
=
msg_level
;
dev
->
msg_level
=
msg_level
;
INIT_LIST_HEAD
(
&
dev
->
dev_list
);
skb_queue_head_init
(
&
dev
->
rxq
);
skb_queue_head_init
(
&
dev
->
rxq
);
skb_queue_head_init
(
&
dev
->
txq
);
skb_queue_head_init
(
&
dev
->
txq
);
skb_queue_head_init
(
&
dev
->
done
);
skb_queue_head_init
(
&
dev
->
done
);
dev
->
bh
.
func
=
usbnet_bh
;
dev
->
bh
.
func
=
usbnet_bh
;
dev
->
bh
.
data
=
(
unsigned
long
)
dev
;
dev
->
bh
.
data
=
(
unsigned
long
)
dev
;
INIT_WORK
(
&
dev
->
kevent
,
kevent
,
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
// set up network interface records
net
=
&
dev
->
net
;
net
=
&
dev
->
net
;
...
@@ -2200,31 +2547,41 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
...
@@ -2200,31 +2547,41 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
net
->
tx_timeout
=
usbnet_tx_timeout
;
net
->
tx_timeout
=
usbnet_tx_timeout
;
net
->
do_ioctl
=
usbnet_ioctl
;
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
);
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
,
xdev
->
bus
->
bus_name
,
xdev
->
devpath
,
dev
->
driver_info
->
description
);
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.
// ok, it's ready to go.
usb_set_intfdata
(
udev
,
dev
);
usb_set_intfdata
(
udev
,
dev
);
mutex_lock
(
&
usbnet_mutex
);
list_add
(
&
dev
->
dev_list
,
&
usbnet_list
);
mutex_unlock
(
&
dev
->
mutex
);
mutex_unlock
(
&
dev
->
mutex
);
// start as if the link is up
// start as if the link is up
netif_device_attach
(
&
dev
->
net
);
netif_device_attach
(
&
dev
->
net
);
mutex_unlock
(
&
usbnet_mutex
);
return
0
;
return
0
;
}
}
...
@@ -2298,28 +2655,19 @@ static const struct usb_device_id products [] = {
...
@@ -2298,28 +2655,19 @@ static const struct usb_device_id products [] = {
},
},
#endif
#endif
#ifdef CONFIG_USB_PXA
#ifdef CONFIG_USB_ARMLINUX
/*
* 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
/*
/*
* SA-1100 using standard ARM Linux kernels, or compatible.
* SA-1100 using standard ARM Linux kernels, or compatible.
* Often used when talking to Linux PDAs (iPaq, Yopy, etc).
* Often used when talking to Linux PDAs (iPaq, Yopy, etc).
* The sa-1100 "usb-eth" driver handles the basic framing.
* 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?
// 1183 = 0x049F, both used as hex values?
// Compaq "Itsy" vendor/product id
, version "0.0"
// Compaq "Itsy" vendor/product id
USB_DEVICE
_VER
(
0x049F
,
0x505A
,
0
,
0
),
USB_DEVICE
(
0x049F
,
0x505A
),
.
driver_info
=
(
unsigned
long
)
&
linuxdev_info
,
.
driver_info
=
(
unsigned
long
)
&
linuxdev_info
,
},
{
},
{
USB_DEVICE
(
0x0E7E
,
0x1001
),
// G.Mate "Yopy"
USB_DEVICE
(
0x0E7E
,
0x1001
),
// G.Mate "Yopy"
...
@@ -2337,9 +2685,10 @@ static const struct usb_device_id products [] = {
...
@@ -2337,9 +2685,10 @@ static const struct usb_device_id products [] = {
|
USB_DEVICE_ID_MATCH_DEVICE
,
|
USB_DEVICE_ID_MATCH_DEVICE
,
.
idVendor
=
0x04DD
,
.
idVendor
=
0x04DD
,
.
idProduct
=
0x8004
,
.
idProduct
=
0x8004
,
.
bInterfaceClass
=
0x0a
,
/* match the master interface */
.
bInterfaceSubClass
=
0x00
,
.
bInterfaceClass
=
USB_CLASS_COMM
,
.
bInterfaceProtocol
=
0x00
,
.
bInterfaceSubClass
=
6
/* Ethernet model */
,
.
bInterfaceProtocol
=
0
,
.
driver_info
=
(
unsigned
long
)
&
zaurus_sl5x00_info
,
.
driver_info
=
(
unsigned
long
)
&
zaurus_sl5x00_info
,
},
{
},
{
.
match_flags
=
USB_DEVICE_ID_MATCH_INT_INFO
.
match_flags
=
USB_DEVICE_ID_MATCH_INT_INFO
...
@@ -2360,6 +2709,24 @@ static const struct usb_device_id products [] = {
...
@@ -2360,6 +2709,24 @@ static const struct usb_device_id products [] = {
.
bInterfaceProtocol
=
0x00
,
.
bInterfaceProtocol
=
0x00
,
.
driver_info
=
(
unsigned
long
)
&
zaurus_slb500_info
,
.
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
#endif
{
},
// END
{
},
// END
...
...
drivers/usb/serial/keyspan.h
View file @
6c7a3c95
...
@@ -411,19 +411,19 @@ static const struct keyspan_device_details usa49w_device_details = {
...
@@ -411,19 +411,19 @@ static const struct keyspan_device_details usa49w_device_details = {
};
};
static
const
struct
keyspan_device_details
usa49wlc_device_details
=
{
static
const
struct
keyspan_device_details
usa49wlc_device_details
=
{
product_id:
keyspan_usa49wlc_product_id
,
.
product_id
=
keyspan_usa49wlc_product_id
,
msg_format:
msg_usa49
,
.
msg_format
=
msg_usa49
,
num_ports:
4
,
.
num_ports
=
4
,
indat_endp_flip:
0
,
.
indat_endp_flip
=
0
,
outdat_endp_flip:
0
,
.
outdat_endp_flip
=
0
,
indat_endpoints:
{
0x81
,
0x82
,
0x83
,
0x84
},
.
indat_endpoints
=
{
0x81
,
0x82
,
0x83
,
0x84
},
outdat_endpoints:
{
0x01
,
0x02
,
0x03
,
0x04
},
.
outdat_endpoints
=
{
0x01
,
0x02
,
0x03
,
0x04
},
inack_endpoints:
{
-
1
,
-
1
,
-
1
,
-
1
},
.
inack_endpoints
=
{
-
1
,
-
1
,
-
1
,
-
1
},
outcont_endpoints:
{
-
1
,
-
1
,
-
1
,
-
1
},
.
outcont_endpoints
=
{
-
1
,
-
1
,
-
1
,
-
1
},
instat_endpoint:
0x87
,
.
instat_endpoint
=
0x87
,
glocont_endpoint:
0x07
,
.
glocont_endpoint
=
0x07
,
calculate_baud_rate:
keyspan_usa19w_calc_baud
,
.
calculate_baud_rate
=
keyspan_usa19w_calc_baud
,
baudclk:
KEYSPAN_USA19W_BAUDCLK
,
.
baudclk
=
KEYSPAN_USA19W_BAUDCLK
,
};
};
static
const
struct
keyspan_device_details
*
keyspan_devices
[]
=
{
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)
...
@@ -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
*
))
static
int
usb_storage_queuecommand
(
Scsi_Cmnd
*
srb
,
void
(
*
done
)(
Scsi_Cmnd
*
))
{
{
struct
us_data
*
us
=
(
struct
us_data
*
)
srb
->
device
->
host
->
hostdata
[
0
];
struct
us_data
*
us
=
(
struct
us_data
*
)
srb
->
device
->
host
->
hostdata
[
0
];
int
state
=
atomic_read
(
&
us
->
sm_state
);
US_DEBUGP
(
"queuecommand() called
\n
"
);
US_DEBUGP
(
"queuecommand() called
\n
"
);
srb
->
host_scribble
=
(
unsigned
char
*
)
us
;
srb
->
host_scribble
=
(
unsigned
char
*
)
us
;
/* enqueue the command */
/* enqueue the command */
BUG_ON
(
atomic_read
(
&
us
->
sm_state
)
!=
US_STATE_IDLE
);
if
(
state
!=
US_STATE_IDLE
||
us
->
srb
!=
NULL
)
{
BUG_ON
(
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
;
srb
->
scsi_done
=
done
;
us
->
srb
=
srb
;
us
->
srb
=
srb
;
...
@@ -175,8 +181,7 @@ static int usb_storage_command_abort( Scsi_Cmnd *srb )
...
@@ -175,8 +181,7 @@ static int usb_storage_command_abort( Scsi_Cmnd *srb )
return
FAILED
;
return
FAILED
;
}
}
usb_stor_abort_transport
(
us
);
return
usb_stor_abort_transport
(
us
);
return
SUCCESS
;
}
}
/* This invokes the transport reset mechanism to reset the state of the
/* 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 )
...
@@ -185,10 +190,15 @@ static int usb_storage_command_abort( Scsi_Cmnd *srb )
static
int
usb_storage_device_reset
(
Scsi_Cmnd
*
srb
)
static
int
usb_storage_device_reset
(
Scsi_Cmnd
*
srb
)
{
{
struct
us_data
*
us
=
(
struct
us_data
*
)
srb
->
device
->
host
->
hostdata
[
0
];
struct
us_data
*
us
=
(
struct
us_data
*
)
srb
->
device
->
host
->
hostdata
[
0
];
int
state
=
atomic_read
(
&
us
->
sm_state
);
int
result
;
int
result
;
US_DEBUGP
(
"device_reset() called
\n
"
);
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 */
/* set the state and release the lock */
atomic_set
(
&
us
->
sm_state
,
US_STATE_RESETTING
);
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,
...
@@ -260,6 +270,7 @@ static int usb_storage_proc_info (char *buffer, char **start, off_t offset,
struct
us_data
*
us
;
struct
us_data
*
us
;
char
*
pos
=
buffer
;
char
*
pos
=
buffer
;
struct
Scsi_Host
*
hostptr
;
struct
Scsi_Host
*
hostptr
;
unsigned
long
f
;
/* if someone is sending us data, just throw it away */
/* if someone is sending us data, just throw it away */
if
(
inout
)
if
(
inout
)
...
@@ -274,6 +285,7 @@ static int usb_storage_proc_info (char *buffer, char **start, off_t offset,
...
@@ -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 we couldn't find it, we return an error */
if
(
!
us
)
{
if
(
!
us
)
{
scsi_host_put
(
hostptr
);
return
-
ESRCH
;
return
-
ESRCH
;
}
}
...
@@ -289,6 +301,24 @@ static int usb_storage_proc_info (char *buffer, char **start, off_t offset,
...
@@ -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
(
" Protocol: %s
\n
"
,
us
->
protocol_name
);
SPRINTF
(
" Transport: %s
\n
"
,
us
->
transport_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 */
/* release the reference count on this host */
scsi_host_put
(
hostptr
);
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,
...
@@ -297,10 +297,11 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe,
/* stalled */
/* stalled */
case
-
EPIPE
:
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
))
{
if
(
usb_pipecontrol
(
pipe
))
{
US_DEBUGP
(
"-- stall on control pipe
\n
"
);
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 */
/* for other sorts of endpoint, clear the stall */
...
@@ -691,7 +692,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
...
@@ -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.
/* Abort the currently running scsi command or device reset.
* This must be called with scsi_lock(us->srb->host) held */
* 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
;
struct
Scsi_Host
*
host
;
int
state
=
atomic_read
(
&
us
->
sm_state
);
int
state
=
atomic_read
(
&
us
->
sm_state
);
...
@@ -701,7 +702,11 @@ void usb_stor_abort_transport(struct us_data *us)
...
@@ -701,7 +702,11 @@ void usb_stor_abort_transport(struct us_data *us)
/* Normally the current state is RUNNING. If the control thread
/* Normally the current state is RUNNING. If the control thread
* hasn't even started processing this command, the state will be
* hasn't even started processing this command, the state will be
* IDLE. Anything else is a bug. */
* 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 */
/* set state to abort and release the lock */
atomic_set
(
&
us
->
sm_state
,
US_STATE_ABORTING
);
atomic_set
(
&
us
->
sm_state
,
US_STATE_ABORTING
);
...
@@ -730,6 +735,7 @@ void usb_stor_abort_transport(struct us_data *us)
...
@@ -730,6 +735,7 @@ void usb_stor_abort_transport(struct us_data *us)
/* Reacquire the lock: note that us->srb is now NULL */
/* Reacquire the lock: note that us->srb is now NULL */
scsi_lock
(
host
);
scsi_lock
(
host
);
return
SUCCESS
;
}
}
/*
/*
...
@@ -750,8 +756,14 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
...
@@ -750,8 +756,14 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* check the return code for the command */
/* check the return code for the command */
US_DEBUGP
(
"Call to usb_stor_ctrl_transfer() returned %d
\n
"
,
result
);
US_DEBUGP
(
"Call to usb_stor_ctrl_transfer() returned %d
\n
"
,
result
);
if
(
result
!=
USB_STOR_XFER_GOOD
)
{
/* 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 */
/* Uh oh... serious problem here */
if
(
result
!=
USB_STOR_XFER_GOOD
)
{
return
USB_STOR_TRANSPORT_ERROR
;
return
USB_STOR_TRANSPORT_ERROR
;
}
}
...
@@ -834,8 +846,14 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
...
@@ -834,8 +846,14 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
/* check the return code for the command */
/* check the return code for the command */
US_DEBUGP
(
"Call to usb_stor_ctrl_transfer() returned %d
\n
"
,
result
);
US_DEBUGP
(
"Call to usb_stor_ctrl_transfer() returned %d
\n
"
,
result
);
if
(
result
!=
USB_STOR_XFER_GOOD
)
{
/* 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 */
/* Uh oh... serious problem here */
if
(
result
!=
USB_STOR_XFER_GOOD
)
{
return
USB_STOR_TRANSPORT_ERROR
;
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*);
...
@@ -154,7 +154,7 @@ extern int usb_stor_Bulk_max_lun(struct us_data*);
extern
int
usb_stor_Bulk_reset
(
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_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
,
extern
int
usb_stor_bulk_msg
(
struct
us_data
*
us
,
void
*
data
,
unsigned
int
pipe
,
unsigned
int
len
,
unsigned
int
*
act_len
);
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)
...
@@ -430,39 +430,39 @@ static int usb_stor_control_thread(void * __us)
}
}
/* Set up the URB and the usb_ctrlrequest.
/* 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
* Note that this function assumes that all the data in the us_data
* structure is current.
* structure is current.
* Returns non-zero on failure, zero on success
* 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 */
/* calculate and store the pipe values */
ss
->
send_ctrl_pipe
=
usb_sndctrlpipe
(
s
s
->
pusb_dev
,
0
);
us
->
send_ctrl_pipe
=
usb_sndctrlpipe
(
u
s
->
pusb_dev
,
0
);
ss
->
recv_ctrl_pipe
=
usb_rcvctrlpipe
(
s
s
->
pusb_dev
,
0
);
us
->
recv_ctrl_pipe
=
usb_rcvctrlpipe
(
u
s
->
pusb_dev
,
0
);
ss
->
send_bulk_pipe
=
usb_sndbulkpipe
(
ss
->
pusb_dev
,
s
s
->
ep_out
);
us
->
send_bulk_pipe
=
usb_sndbulkpipe
(
us
->
pusb_dev
,
u
s
->
ep_out
);
ss
->
recv_bulk_pipe
=
usb_rcvbulkpipe
(
ss
->
pusb_dev
,
s
s
->
ep_in
);
us
->
recv_bulk_pipe
=
usb_rcvbulkpipe
(
us
->
pusb_dev
,
u
s
->
ep_in
);
ss
->
recv_intr_pipe
=
usb_rcvintpipe
(
ss
->
pusb_dev
,
s
s
->
ep_int
);
us
->
recv_intr_pipe
=
usb_rcvintpipe
(
us
->
pusb_dev
,
u
s
->
ep_int
);
/* allocate the usb_ctrlrequest for control packets */
/* allocate the usb_ctrlrequest for control packets */
US_DEBUGP
(
"Allocating usb_ctrlrequest
\n
"
);
US_DEBUGP
(
"Allocating usb_ctrlrequest
\n
"
);
s
s
->
dr
=
kmalloc
(
sizeof
(
struct
usb_ctrlrequest
),
GFP_NOIO
);
u
s
->
dr
=
kmalloc
(
sizeof
(
struct
usb_ctrlrequest
),
GFP_NOIO
);
if
(
!
s
s
->
dr
)
{
if
(
!
u
s
->
dr
)
{
US_DEBUGP
(
"allocation failed
\n
"
);
US_DEBUGP
(
"allocation failed
\n
"
);
return
1
;
return
1
;
}
}
/* allocate the URB we're going to use */
/* allocate the URB we're going to use */
US_DEBUGP
(
"Allocating URB
\n
"
);
US_DEBUGP
(
"Allocating URB
\n
"
);
s
s
->
current_urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
u
s
->
current_urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
s
s
->
current_urb
)
{
if
(
!
u
s
->
current_urb
)
{
US_DEBUGP
(
"allocation failed
\n
"
);
US_DEBUGP
(
"allocation failed
\n
"
);
return
2
;
return
2
;
}
}
US_DEBUGP
(
"Allocating scatter-gather request block
\n
"
);
US_DEBUGP
(
"Allocating scatter-gather request block
\n
"
);
ss
->
current_sg
=
kmalloc
(
sizeof
(
*
s
s
->
current_sg
),
GFP_KERNEL
);
us
->
current_sg
=
kmalloc
(
sizeof
(
*
u
s
->
current_sg
),
GFP_KERNEL
);
if
(
!
s
s
->
current_sg
)
{
if
(
!
u
s
->
current_sg
)
{
US_DEBUGP
(
"allocation failed
\n
"
);
US_DEBUGP
(
"allocation failed
\n
"
);
return
5
;
return
5
;
}
}
...
@@ -471,32 +471,32 @@ static int usb_stor_allocate_urbs(struct us_data *ss)
...
@@ -471,32 +471,32 @@ static int usb_stor_allocate_urbs(struct us_data *ss)
}
}
/* Deallocate the URB, the usb_ctrlrequest, and the IRQ pipe.
/* 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 */
/* free the scatter-gather request block */
if
(
s
s
->
current_sg
)
{
if
(
u
s
->
current_sg
)
{
kfree
(
s
s
->
current_sg
);
kfree
(
u
s
->
current_sg
);
s
s
->
current_sg
=
NULL
;
u
s
->
current_sg
=
NULL
;
}
}
/* free up the main URB for this device */
/* free up the main URB for this device */
if
(
s
s
->
current_urb
)
{
if
(
u
s
->
current_urb
)
{
US_DEBUGP
(
"-- releasing main URB
\n
"
);
US_DEBUGP
(
"-- releasing main URB
\n
"
);
usb_free_urb
(
s
s
->
current_urb
);
usb_free_urb
(
u
s
->
current_urb
);
s
s
->
current_urb
=
NULL
;
u
s
->
current_urb
=
NULL
;
}
}
/* free the usb_ctrlrequest buffer */
/* free the usb_ctrlrequest buffer */
if
(
s
s
->
dr
)
{
if
(
u
s
->
dr
)
{
kfree
(
s
s
->
dr
);
kfree
(
u
s
->
dr
);
s
s
->
dr
=
NULL
;
u
s
->
dr
=
NULL
;
}
}
/* mark the device as gone */
/* mark the device as gone */
usb_put_dev
(
s
s
->
pusb_dev
);
usb_put_dev
(
u
s
->
pusb_dev
);
s
s
->
pusb_dev
=
NULL
;
u
s
->
pusb_dev
=
NULL
;
}
}
/* Probe to see if a new device is actually a SCSI device */
/* Probe to see if a new device is actually a SCSI device */
...
@@ -512,7 +512,7 @@ static int storage_probe(struct usb_interface *intf,
...
@@ -512,7 +512,7 @@ static int storage_probe(struct usb_interface *intf,
char
serial
[
USB_STOR_STRING_LEN
];
/* serial number */
char
serial
[
USB_STOR_STRING_LEN
];
/* serial number */
unsigned
int
flags
;
unsigned
int
flags
;
struct
us_unusual_dev
*
unusual_dev
;
struct
us_unusual_dev
*
unusual_dev
;
struct
us_data
*
s
s
=
NULL
;
struct
us_data
*
u
s
=
NULL
;
int
result
;
int
result
;
/* these are temporary copies -- we test on these, then put them
/* these are temporary copies -- we test on these, then put them
...
@@ -633,212 +633,212 @@ static int storage_probe(struct usb_interface *intf,
...
@@ -633,212 +633,212 @@ static int storage_probe(struct usb_interface *intf,
serial
,
sizeof
(
serial
));
serial
,
sizeof
(
serial
));
/* New device -- allocate memory and initialize */
/* 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
)
{
GFP_KERNEL
))
==
NULL
)
{
printk
(
KERN_WARNING
USB_STORAGE
"Out of memory
\n
"
);
printk
(
KERN_WARNING
USB_STORAGE
"Out of memory
\n
"
);
usb_put_dev
(
dev
);
usb_put_dev
(
dev
);
return
-
ENOMEM
;
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 */
/* Initialize the mutexes only when the struct is new */
init_completion
(
&
(
s
s
->
notify
));
init_completion
(
&
(
u
s
->
notify
));
init_MUTEX_LOCKED
(
&
(
s
s
->
dev_semaphore
));
init_MUTEX_LOCKED
(
&
(
u
s
->
dev_semaphore
));
/* copy over the subclass and protocol data */
/* copy over the subclass and protocol data */
s
s
->
subclass
=
subclass
;
u
s
->
subclass
=
subclass
;
s
s
->
protocol
=
protocol
;
u
s
->
protocol
=
protocol
;
s
s
->
flags
=
flags
;
u
s
->
flags
=
flags
;
s
s
->
unusual_dev
=
unusual_dev
;
u
s
->
unusual_dev
=
unusual_dev
;
/* copy over the endpoint data */
/* copy over the endpoint data */
s
s
->
ep_in
=
ep_in
->
bEndpointAddress
&
u
s
->
ep_in
=
ep_in
->
bEndpointAddress
&
USB_ENDPOINT_NUMBER_MASK
;
USB_ENDPOINT_NUMBER_MASK
;
s
s
->
ep_out
=
ep_out
->
bEndpointAddress
&
u
s
->
ep_out
=
ep_out
->
bEndpointAddress
&
USB_ENDPOINT_NUMBER_MASK
;
USB_ENDPOINT_NUMBER_MASK
;
if
(
ep_int
)
{
if
(
ep_int
)
{
s
s
->
ep_int
=
ep_int
->
bEndpointAddress
&
u
s
->
ep_int
=
ep_int
->
bEndpointAddress
&
USB_ENDPOINT_NUMBER_MASK
;
USB_ENDPOINT_NUMBER_MASK
;
s
s
->
ep_bInterval
=
ep_int
->
bInterval
;
u
s
->
ep_bInterval
=
ep_int
->
bInterval
;
}
}
else
else
ss
->
ep_int
=
s
s
->
ep_bInterval
=
0
;
us
->
ep_int
=
u
s
->
ep_bInterval
=
0
;
/* establish the connection to the new device */
/* establish the connection to the new device */
s
s
->
ifnum
=
ifnum
;
u
s
->
ifnum
=
ifnum
;
s
s
->
pusb_dev
=
dev
;
u
s
->
pusb_dev
=
dev
;
/* copy over the identifiying strings */
/* copy over the identifiying strings */
strncpy
(
s
s
->
vendor
,
mf
,
USB_STOR_STRING_LEN
);
strncpy
(
u
s
->
vendor
,
mf
,
USB_STOR_STRING_LEN
);
strncpy
(
s
s
->
product
,
prod
,
USB_STOR_STRING_LEN
);
strncpy
(
u
s
->
product
,
prod
,
USB_STOR_STRING_LEN
);
strncpy
(
s
s
->
serial
,
serial
,
USB_STOR_STRING_LEN
);
strncpy
(
u
s
->
serial
,
serial
,
USB_STOR_STRING_LEN
);
if
(
strlen
(
s
s
->
vendor
)
==
0
)
{
if
(
strlen
(
u
s
->
vendor
)
==
0
)
{
if
(
unusual_dev
->
vendorName
)
if
(
unusual_dev
->
vendorName
)
strncpy
(
s
s
->
vendor
,
unusual_dev
->
vendorName
,
strncpy
(
u
s
->
vendor
,
unusual_dev
->
vendorName
,
USB_STOR_STRING_LEN
);
USB_STOR_STRING_LEN
);
else
else
strncpy
(
s
s
->
vendor
,
"Unknown"
,
strncpy
(
u
s
->
vendor
,
"Unknown"
,
USB_STOR_STRING_LEN
);
USB_STOR_STRING_LEN
);
}
}
if
(
strlen
(
s
s
->
product
)
==
0
)
{
if
(
strlen
(
u
s
->
product
)
==
0
)
{
if
(
unusual_dev
->
productName
)
if
(
unusual_dev
->
productName
)
strncpy
(
s
s
->
product
,
unusual_dev
->
productName
,
strncpy
(
u
s
->
product
,
unusual_dev
->
productName
,
USB_STOR_STRING_LEN
);
USB_STOR_STRING_LEN
);
else
else
strncpy
(
s
s
->
product
,
"Unknown"
,
strncpy
(
u
s
->
product
,
"Unknown"
,
USB_STOR_STRING_LEN
);
USB_STOR_STRING_LEN
);
}
}
if
(
strlen
(
s
s
->
serial
)
==
0
)
if
(
strlen
(
u
s
->
serial
)
==
0
)
strncpy
(
s
s
->
serial
,
"None"
,
USB_STOR_STRING_LEN
);
strncpy
(
u
s
->
serial
,
"None"
,
USB_STOR_STRING_LEN
);
/*
/*
* Set the handler pointers based on the protocol
* Set the handler pointers based on the protocol
* Again, this data is persistent across reattachments
* Again, this data is persistent across reattachments
*/
*/
switch
(
s
s
->
protocol
)
{
switch
(
u
s
->
protocol
)
{
case
US_PR_CB
:
case
US_PR_CB
:
s
s
->
transport_name
=
"Control/Bulk"
;
u
s
->
transport_name
=
"Control/Bulk"
;
s
s
->
transport
=
usb_stor_CB_transport
;
u
s
->
transport
=
usb_stor_CB_transport
;
s
s
->
transport_reset
=
usb_stor_CB_reset
;
u
s
->
transport_reset
=
usb_stor_CB_reset
;
s
s
->
max_lun
=
7
;
u
s
->
max_lun
=
7
;
break
;
break
;
case
US_PR_CBI
:
case
US_PR_CBI
:
s
s
->
transport_name
=
"Control/Bulk/Interrupt"
;
u
s
->
transport_name
=
"Control/Bulk/Interrupt"
;
s
s
->
transport
=
usb_stor_CBI_transport
;
u
s
->
transport
=
usb_stor_CBI_transport
;
s
s
->
transport_reset
=
usb_stor_CB_reset
;
u
s
->
transport_reset
=
usb_stor_CB_reset
;
s
s
->
max_lun
=
7
;
u
s
->
max_lun
=
7
;
break
;
break
;
case
US_PR_BULK
:
case
US_PR_BULK
:
s
s
->
transport_name
=
"Bulk"
;
u
s
->
transport_name
=
"Bulk"
;
s
s
->
transport
=
usb_stor_Bulk_transport
;
u
s
->
transport
=
usb_stor_Bulk_transport
;
s
s
->
transport_reset
=
usb_stor_Bulk_reset
;
u
s
->
transport_reset
=
usb_stor_Bulk_reset
;
ss
->
max_lun
=
usb_stor_Bulk_max_lun
(
s
s
);
us
->
max_lun
=
usb_stor_Bulk_max_lun
(
u
s
);
break
;
break
;
#ifdef CONFIG_USB_STORAGE_HP8200e
#ifdef CONFIG_USB_STORAGE_HP8200e
case
US_PR_SCM_ATAPI
:
case
US_PR_SCM_ATAPI
:
s
s
->
transport_name
=
"SCM/ATAPI"
;
u
s
->
transport_name
=
"SCM/ATAPI"
;
s
s
->
transport
=
hp8200e_transport
;
u
s
->
transport
=
hp8200e_transport
;
s
s
->
transport_reset
=
usb_stor_CB_reset
;
u
s
->
transport_reset
=
usb_stor_CB_reset
;
s
s
->
max_lun
=
1
;
u
s
->
max_lun
=
1
;
break
;
break
;
#endif
#endif
#ifdef CONFIG_USB_STORAGE_SDDR09
#ifdef CONFIG_USB_STORAGE_SDDR09
case
US_PR_EUSB_SDDR09
:
case
US_PR_EUSB_SDDR09
:
s
s
->
transport_name
=
"EUSB/SDDR09"
;
u
s
->
transport_name
=
"EUSB/SDDR09"
;
s
s
->
transport
=
sddr09_transport
;
u
s
->
transport
=
sddr09_transport
;
s
s
->
transport_reset
=
usb_stor_CB_reset
;
u
s
->
transport_reset
=
usb_stor_CB_reset
;
s
s
->
max_lun
=
0
;
u
s
->
max_lun
=
0
;
break
;
break
;
#endif
#endif
#ifdef CONFIG_USB_STORAGE_SDDR55
#ifdef CONFIG_USB_STORAGE_SDDR55
case
US_PR_SDDR55
:
case
US_PR_SDDR55
:
s
s
->
transport_name
=
"SDDR55"
;
u
s
->
transport_name
=
"SDDR55"
;
s
s
->
transport
=
sddr55_transport
;
u
s
->
transport
=
sddr55_transport
;
s
s
->
transport_reset
=
sddr55_reset
;
u
s
->
transport_reset
=
sddr55_reset
;
s
s
->
max_lun
=
0
;
u
s
->
max_lun
=
0
;
break
;
break
;
#endif
#endif
#ifdef CONFIG_USB_STORAGE_DPCM
#ifdef CONFIG_USB_STORAGE_DPCM
case
US_PR_DPCM_USB
:
case
US_PR_DPCM_USB
:
s
s
->
transport_name
=
"Control/Bulk-EUSB/SDDR09"
;
u
s
->
transport_name
=
"Control/Bulk-EUSB/SDDR09"
;
s
s
->
transport
=
dpcm_transport
;
u
s
->
transport
=
dpcm_transport
;
s
s
->
transport_reset
=
usb_stor_CB_reset
;
u
s
->
transport_reset
=
usb_stor_CB_reset
;
s
s
->
max_lun
=
1
;
u
s
->
max_lun
=
1
;
break
;
break
;
#endif
#endif
#ifdef CONFIG_USB_STORAGE_FREECOM
#ifdef CONFIG_USB_STORAGE_FREECOM
case
US_PR_FREECOM
:
case
US_PR_FREECOM
:
s
s
->
transport_name
=
"Freecom"
;
u
s
->
transport_name
=
"Freecom"
;
s
s
->
transport
=
freecom_transport
;
u
s
->
transport
=
freecom_transport
;
s
s
->
transport_reset
=
usb_stor_freecom_reset
;
u
s
->
transport_reset
=
usb_stor_freecom_reset
;
s
s
->
max_lun
=
0
;
u
s
->
max_lun
=
0
;
break
;
break
;
#endif
#endif
#ifdef CONFIG_USB_STORAGE_DATAFAB
#ifdef CONFIG_USB_STORAGE_DATAFAB
case
US_PR_DATAFAB
:
case
US_PR_DATAFAB
:
s
s
->
transport_name
=
"Datafab Bulk-Only"
;
u
s
->
transport_name
=
"Datafab Bulk-Only"
;
s
s
->
transport
=
datafab_transport
;
u
s
->
transport
=
datafab_transport
;
s
s
->
transport_reset
=
usb_stor_Bulk_reset
;
u
s
->
transport_reset
=
usb_stor_Bulk_reset
;
s
s
->
max_lun
=
1
;
u
s
->
max_lun
=
1
;
break
;
break
;
#endif
#endif
#ifdef CONFIG_USB_STORAGE_JUMPSHOT
#ifdef CONFIG_USB_STORAGE_JUMPSHOT
case
US_PR_JUMPSHOT
:
case
US_PR_JUMPSHOT
:
s
s
->
transport_name
=
"Lexar Jumpshot Control/Bulk"
;
u
s
->
transport_name
=
"Lexar Jumpshot Control/Bulk"
;
s
s
->
transport
=
jumpshot_transport
;
u
s
->
transport
=
jumpshot_transport
;
s
s
->
transport_reset
=
usb_stor_Bulk_reset
;
u
s
->
transport_reset
=
usb_stor_Bulk_reset
;
s
s
->
max_lun
=
1
;
u
s
->
max_lun
=
1
;
break
;
break
;
#endif
#endif
default:
default:
/*
s
s->transport_name = "Unknown"; */
/*
u
s->transport_name = "Unknown"; */
goto
BadDevice
;
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 */
/* fix for single-lun devices */
if
(
s
s
->
flags
&
US_FL_SINGLE_LUN
)
if
(
u
s
->
flags
&
US_FL_SINGLE_LUN
)
s
s
->
max_lun
=
0
;
u
s
->
max_lun
=
0
;
switch
(
s
s
->
subclass
)
{
switch
(
u
s
->
subclass
)
{
case
US_SC_RBC
:
case
US_SC_RBC
:
s
s
->
protocol_name
=
"Reduced Block Commands (RBC)"
;
u
s
->
protocol_name
=
"Reduced Block Commands (RBC)"
;
s
s
->
proto_handler
=
usb_stor_transparent_scsi_command
;
u
s
->
proto_handler
=
usb_stor_transparent_scsi_command
;
break
;
break
;
case
US_SC_8020
:
case
US_SC_8020
:
s
s
->
protocol_name
=
"8020i"
;
u
s
->
protocol_name
=
"8020i"
;
s
s
->
proto_handler
=
usb_stor_ATAPI_command
;
u
s
->
proto_handler
=
usb_stor_ATAPI_command
;
s
s
->
max_lun
=
0
;
u
s
->
max_lun
=
0
;
break
;
break
;
case
US_SC_QIC
:
case
US_SC_QIC
:
s
s
->
protocol_name
=
"QIC-157"
;
u
s
->
protocol_name
=
"QIC-157"
;
s
s
->
proto_handler
=
usb_stor_qic157_command
;
u
s
->
proto_handler
=
usb_stor_qic157_command
;
s
s
->
max_lun
=
0
;
u
s
->
max_lun
=
0
;
break
;
break
;
case
US_SC_8070
:
case
US_SC_8070
:
s
s
->
protocol_name
=
"8070i"
;
u
s
->
protocol_name
=
"8070i"
;
s
s
->
proto_handler
=
usb_stor_ATAPI_command
;
u
s
->
proto_handler
=
usb_stor_ATAPI_command
;
s
s
->
max_lun
=
0
;
u
s
->
max_lun
=
0
;
break
;
break
;
case
US_SC_SCSI
:
case
US_SC_SCSI
:
s
s
->
protocol_name
=
"Transparent SCSI"
;
u
s
->
protocol_name
=
"Transparent SCSI"
;
s
s
->
proto_handler
=
usb_stor_transparent_scsi_command
;
u
s
->
proto_handler
=
usb_stor_transparent_scsi_command
;
break
;
break
;
case
US_SC_UFI
:
case
US_SC_UFI
:
s
s
->
protocol_name
=
"Uniform Floppy Interface (UFI)"
;
u
s
->
protocol_name
=
"Uniform Floppy Interface (UFI)"
;
s
s
->
proto_handler
=
usb_stor_ufi_command
;
u
s
->
proto_handler
=
usb_stor_ufi_command
;
break
;
break
;
#ifdef CONFIG_USB_STORAGE_ISD200
#ifdef CONFIG_USB_STORAGE_ISD200
case
US_SC_ISD200
:
case
US_SC_ISD200
:
s
s
->
protocol_name
=
"ISD200 ATA/ATAPI"
;
u
s
->
protocol_name
=
"ISD200 ATA/ATAPI"
;
s
s
->
proto_handler
=
isd200_ata_command
;
u
s
->
proto_handler
=
isd200_ata_command
;
break
;
break
;
#endif
#endif
default:
default:
/*
s
s->protocol_name = "Unknown"; */
/*
u
s->protocol_name = "Unknown"; */
goto
BadDevice
;
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 */
/* 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
;
goto
BadDevice
;
/*
/*
...
@@ -849,59 +849,59 @@ static int storage_probe(struct usb_interface *intf,
...
@@ -849,59 +849,59 @@ static int storage_probe(struct usb_interface *intf,
/* Just before we start our control thread, initialize
/* Just before we start our control thread, initialize
* the device if it needs initialization */
* the device if it needs initialization */
if
(
unusual_dev
&&
unusual_dev
->
initFunction
)
if
(
unusual_dev
&&
unusual_dev
->
initFunction
)
unusual_dev
->
initFunction
(
s
s
);
unusual_dev
->
initFunction
(
u
s
);
/* start up our control thread */
/* start up our control thread */
atomic_set
(
&
s
s
->
sm_state
,
US_STATE_IDLE
);
atomic_set
(
&
u
s
->
sm_state
,
US_STATE_IDLE
);
ss
->
pid
=
kernel_thread
(
usb_stor_control_thread
,
s
s
,
us
->
pid
=
kernel_thread
(
usb_stor_control_thread
,
u
s
,
CLONE_VM
);
CLONE_VM
);
if
(
s
s
->
pid
<
0
)
{
if
(
u
s
->
pid
<
0
)
{
printk
(
KERN_WARNING
USB_STORAGE
printk
(
KERN_WARNING
USB_STORAGE
"Unable to start control thread
\n
"
);
"Unable to start control thread
\n
"
);
goto
BadDevice
;
goto
BadDevice
;
}
}
/* wait for the thread to start */
/* wait for the thread to start */
wait_for_completion
(
&
(
s
s
->
notify
));
wait_for_completion
(
&
(
u
s
->
notify
));
/* unlock the device pointers */
/* unlock the device pointers */
up
(
&
(
s
s
->
dev_semaphore
));
up
(
&
(
u
s
->
dev_semaphore
));
/* now register */
/* now register */
ss
->
host
=
scsi_register
(
&
usb_stor_host_template
,
sizeof
(
s
s
));
us
->
host
=
scsi_register
(
&
usb_stor_host_template
,
sizeof
(
u
s
));
if
(
!
s
s
->
host
)
{
if
(
!
u
s
->
host
)
{
printk
(
KERN_WARNING
USB_STORAGE
printk
(
KERN_WARNING
USB_STORAGE
"Unable to register the scsi host
\n
"
);
"Unable to register the scsi host
\n
"
);
/* tell the control thread to exit */
/* tell the control thread to exit */
s
s
->
srb
=
NULL
;
u
s
->
srb
=
NULL
;
up
(
&
s
s
->
sema
);
up
(
&
u
s
->
sema
);
wait_for_completion
(
&
s
s
->
notify
);
wait_for_completion
(
&
u
s
->
notify
);
/* re-lock the device pointers */
/* re-lock the device pointers */
down
(
&
s
s
->
dev_semaphore
);
down
(
&
u
s
->
dev_semaphore
);
goto
BadDevice
;
goto
BadDevice
;
}
}
/* set the hostdata to prepare for scanning */
/* 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 */
/* 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 */
/* now add the host */
result
=
scsi_add_host
(
s
s
->
host
,
NULL
);
result
=
scsi_add_host
(
u
s
->
host
,
NULL
);
if
(
result
)
{
if
(
result
)
{
printk
(
KERN_WARNING
USB_STORAGE
printk
(
KERN_WARNING
USB_STORAGE
"Unable to add the scsi host
\n
"
);
"Unable to add the scsi host
\n
"
);
/* tell the control thread to exit */
/* tell the control thread to exit */
s
s
->
srb
=
NULL
;
u
s
->
srb
=
NULL
;
up
(
&
s
s
->
sema
);
up
(
&
u
s
->
sema
);
wait_for_completion
(
&
s
s
->
notify
);
wait_for_completion
(
&
u
s
->
notify
);
/* re-lock the device pointers */
/* re-lock the device pointers */
down
(
&
s
s
->
dev_semaphore
);
down
(
&
u
s
->
dev_semaphore
);
goto
BadDevice
;
goto
BadDevice
;
}
}
...
@@ -911,66 +911,61 @@ static int storage_probe(struct usb_interface *intf,
...
@@ -911,66 +911,61 @@ static int storage_probe(struct usb_interface *intf,
"USB Mass Storage device found at %d
\n
"
,
dev
->
devnum
);
"USB Mass Storage device found at %d
\n
"
,
dev
->
devnum
);
/* save a pointer to our structure */
/* save a pointer to our structure */
usb_set_intfdata
(
intf
,
s
s
);
usb_set_intfdata
(
intf
,
u
s
);
return
0
;
return
0
;
/* we come here if there are any problems */
/* we come here if there are any problems */
/*
s
s->dev_semaphore must be locked */
/*
u
s->dev_semaphore must be locked */
BadDevice:
BadDevice:
US_DEBUGP
(
"storage_probe() failed
\n
"
);
US_DEBUGP
(
"storage_probe() failed
\n
"
);
usb_stor_deallocate_urbs
(
s
s
);
usb_stor_deallocate_urbs
(
u
s
);
up
(
&
s
s
->
dev_semaphore
);
up
(
&
u
s
->
dev_semaphore
);
kfree
(
s
s
);
kfree
(
u
s
);
return
-
EIO
;
return
-
EIO
;
}
}
/* Handle a disconnect event from the USB core */
/* Handle a disconnect event from the USB core */
static
void
storage_disconnect
(
struct
usb_interface
*
intf
)
static
void
storage_disconnect
(
struct
usb_interface
*
intf
)
{
{
struct
us_data
*
s
s
;
struct
us_data
*
u
s
;
struct
scsi_device
*
sdev
;
struct
scsi_device
*
sdev
;
US_DEBUGP
(
"storage_disconnect() called
\n
"
);
US_DEBUGP
(
"storage_disconnect() called
\n
"
);
s
s
=
usb_get_intfdata
(
intf
);
u
s
=
usb_get_intfdata
(
intf
);
usb_set_intfdata
(
intf
,
NULL
);
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 */
/* set devices offline -- need host lock for this */
scsi_lock
(
s
s
->
host
);
scsi_lock
(
u
s
->
host
);
list_for_each_entry
(
sdev
,
&
s
s
->
host
->
my_devices
,
siblings
)
list_for_each_entry
(
sdev
,
&
u
s
->
host
->
my_devices
,
siblings
)
sdev
->
online
=
0
;
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 */
/* 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.
/* Complete all pending commands with * cmd->result = DID_ERROR << 16.
* Since we only queue one command at a time, this is pretty easy. */
* Since we only queue one command at a time, this is pretty easy. */
if
(
s
s
->
srb
)
{
if
(
u
s
->
srb
)
{
s
s
->
srb
->
result
=
DID_ERROR
<<
16
;
u
s
->
srb
->
result
=
DID_ERROR
<<
16
;
ss
->
srb
->
scsi_done
(
s
s
->
srb
);
us
->
srb
->
scsi_done
(
u
s
->
srb
);
}
}
/* TODO: somehow, wait for the device to
/* TODO: somehow, wait for the device to
* be 'idle' (tasklet completion) */
* be 'idle' (tasklet completion) */
/* remove the pointer to the data structure we were using */
/* 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 */
/* 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
"
);
US_DEBUGP
(
"-- SCSI refused to unregister
\n
"
);
BUG
();
BUG
();
return
;
return
;
};
};
/* finish SCSI host removal sequence */
/* finish SCSI host removal sequence */
scsi_unregister
(
s
s
->
host
);
scsi_unregister
(
u
s
->
host
);
/* Kill the control threads
/* Kill the control threads
*
*
...
@@ -978,34 +973,34 @@ static void storage_disconnect(struct usb_interface *intf)
...
@@ -978,34 +973,34 @@ static void storage_disconnect(struct usb_interface *intf)
* notification that it has exited.
* notification that it has exited.
*/
*/
US_DEBUGP
(
"-- sending exit command to thread
\n
"
);
US_DEBUGP
(
"-- sending exit command to thread
\n
"
);
BUG_ON
(
atomic_read
(
&
s
s
->
sm_state
)
!=
US_STATE_IDLE
);
BUG_ON
(
atomic_read
(
&
u
s
->
sm_state
)
!=
US_STATE_IDLE
);
s
s
->
srb
=
NULL
;
u
s
->
srb
=
NULL
;
up
(
&
(
s
s
->
sema
));
up
(
&
(
u
s
->
sema
));
wait_for_completion
(
&
(
s
s
->
notify
));
wait_for_completion
(
&
(
u
s
->
notify
));
/* free allocated urbs */
/* 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
/* If there's extra data in the us_data structure then
* free that first */
* free that first */
if
(
s
s
->
extra
)
{
if
(
u
s
->
extra
)
{
/* call the destructor routine, if it exists */
/* call the destructor routine, if it exists */
if
(
s
s
->
extra_destructor
)
{
if
(
u
s
->
extra_destructor
)
{
US_DEBUGP
(
"-- calling extra_destructor()
\n
"
);
US_DEBUGP
(
"-- calling extra_destructor()
\n
"
);
ss
->
extra_destructor
(
s
s
->
extra
);
us
->
extra_destructor
(
u
s
->
extra
);
}
}
/* destroy the extra data */
/* destroy the extra data */
US_DEBUGP
(
"-- freeing the data structure
\n
"
);
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
/* up the semaphore so auto-code-checkers won't complain about
* the down/up imbalance */
* the down/up imbalance */
up
(
&
(
s
s
->
dev_semaphore
));
up
(
&
(
u
s
->
dev_semaphore
));
/* free the structure itself */
/* 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)
...
@@ -61,7 +61,7 @@ static struct file_system_type **find_filesystem(const char *name)
/* define fs_subsys */
/* define fs_subsys */
static
decl_subsys
(
fs
,
NULL
);
static
decl_subsys
(
fs
,
NULL
,
NULL
);
static
int
register_fs_subsys
(
struct
file_system_type
*
fs
)
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[] = {
...
@@ -248,7 +248,7 @@ static struct attribute * default_attrs[] = {
extern
struct
subsystem
block_subsys
;
extern
struct
subsystem
block_subsys
;
st
atic
st
ruct
kobj_type
ktype_part
=
{
struct
kobj_type
ktype_part
=
{
.
default_attrs
=
default_attrs
,
.
default_attrs
=
default_attrs
,
.
sysfs_ops
=
&
part_sysfs_ops
,
.
sysfs_ops
=
&
part_sysfs_ops
,
};
};
...
...
include/linux/kobject.h
View file @
6c7a3c95
...
@@ -57,12 +57,24 @@ struct kobj_type {
...
@@ -57,12 +57,24 @@ struct kobj_type {
* of object; multiple ksets can belong to one subsystem. All
* of object; multiple ksets can belong to one subsystem. All
* ksets of a subsystem share the subsystem's lock.
* 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
kset
{
struct
subsystem
*
subsys
;
struct
subsystem
*
subsys
;
struct
kobj_type
*
ktype
;
struct
kobj_type
*
ktype
;
struct
list_head
list
;
struct
list_head
list
;
struct
kobject
kobj
;
struct
kobject
kobj
;
struct
kset_hotplug_ops
*
hotplug_ops
;
};
};
...
@@ -86,6 +98,13 @@ static inline void kset_put(struct kset * k)
...
@@ -86,6 +98,13 @@ static inline void kset_put(struct kset * k)
kobject_put
(
&
k
->
kobj
);
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
*
);
extern
struct
kobject
*
kset_find_obj
(
struct
kset
*
,
const
char
*
);
...
@@ -95,11 +114,12 @@ struct subsystem {
...
@@ -95,11 +114,12 @@ struct subsystem {
struct
rw_semaphore
rwsem
;
struct
rw_semaphore
rwsem
;
};
};
#define decl_subsys(_name,_type) \
#define decl_subsys(_name,_type
,_hotplug_ops
) \
struct subsystem _name##_subsys = { \
struct subsystem _name##_subsys = { \
.kset = { \
.kset = { \
.kobj = { .name = __stringify(_name) }, \
.kobj = { .name = __stringify(_name) }, \
.ktype = _type, \
.ktype = _type, \
.hotplug_ops =_hotplug_ops, \
} \
} \
}
}
...
...
lib/kobject.c
View file @
6c7a3c95
...
@@ -11,14 +11,6 @@
...
@@ -11,14 +11,6 @@
static
spinlock_t
kobj_lock
=
SPIN_LOCK_UNLOCKED
;
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.
* populate_dir - populate directory with attributes.
* @kobj: object we're working on.
* @kobj: object we're working on.
...
@@ -67,6 +59,140 @@ static inline struct kobject * to_kobj(struct list_head * entry)
...
@@ -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.
* kobject_init - initialize object.
* @kobj: object in question.
* @kobj: object in question.
...
@@ -111,6 +237,7 @@ int kobject_add(struct kobject * kobj)
...
@@ -111,6 +237,7 @@ int kobject_add(struct kobject * kobj)
{
{
int
error
=
0
;
int
error
=
0
;
struct
kobject
*
parent
;
struct
kobject
*
parent
;
struct
kobject
*
top_kobj
;
if
(
!
(
kobj
=
kobject_get
(
kobj
)))
if
(
!
(
kobj
=
kobject_get
(
kobj
)))
return
-
ENOENT
;
return
-
ENOENT
;
...
@@ -134,6 +261,19 @@ int kobject_add(struct kobject * kobj)
...
@@ -134,6 +261,19 @@ int kobject_add(struct kobject * kobj)
error
=
create_dir
(
kobj
);
error
=
create_dir
(
kobj
);
if
(
error
)
if
(
error
)
unlink
(
kobj
);
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
;
return
error
;
}
}
...
@@ -162,6 +302,20 @@ int kobject_register(struct kobject * kobj)
...
@@ -162,6 +302,20 @@ int kobject_register(struct kobject * kobj)
void
kobject_del
(
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
);
sysfs_remove_dir
(
kobj
);
unlink
(
kobj
);
unlink
(
kobj
);
}
}
...
...
net/core/dev.c
View file @
6c7a3c95
...
@@ -2815,7 +2815,7 @@ extern void ip_auto_config(void);
...
@@ -2815,7 +2815,7 @@ extern void ip_auto_config(void);
extern
void
dv_init
(
void
);
extern
void
dv_init
(
void
);
#endif
/* CONFIG_NET_DIVERT */
#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