You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (120 commits) usb: don't update devnum for wusb devices wusb: make ep0_reinit available for modules wusb: devices dont use a set address wusb: teach choose_address() about wireless devices wusb: add link wusb-usb device wusb: add authenticathed bit to usb_dev USB: remove unnecessary type casting of urb->context usb serial: more fixes and groundwork for tty changes USB: replace remaining __FUNCTION__ occurrences USB: usbfs: export the URB_NO_INTERRUPT flag to userspace USB: fix compile problems in ehci-hcd USB: ehci: qh_completions cleanup and bugfix USB: cdc-acm: signedness fix USB: add documentation about callbacks USB: don't explicitly reenable root-hub status interrupts USB: OHCI: turn off RD when remote wakeup is disabled USB: HCDs use the do_remote_wakeup flag USB: g_file_storage: ignore bulk-out data after invalid CBW USB: serial: remove endpoints setting checks from core and header USB: serial: remove unneeded number endpoints settings ...
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
What is anchor?
|
||||
===============
|
||||
|
||||
A USB driver needs to support some callbacks requiring
|
||||
a driver to cease all IO to an interface. To do so, a
|
||||
driver has to keep track of the URBs it has submitted
|
||||
to know they've all completed or to call usb_kill_urb
|
||||
for them. The anchor is a data structure takes care of
|
||||
keeping track of URBs and provides methods to deal with
|
||||
multiple URBs.
|
||||
|
||||
Allocation and Initialisation
|
||||
=============================
|
||||
|
||||
There's no API to allocate an anchor. It is simply declared
|
||||
as struct usb_anchor. init_usb_anchor() must be called to
|
||||
initialise the data structure.
|
||||
|
||||
Deallocation
|
||||
============
|
||||
|
||||
Once it has no more URBs associated with it, the anchor can be
|
||||
freed with normal memory management operations.
|
||||
|
||||
Association and disassociation of URBs with anchors
|
||||
===================================================
|
||||
|
||||
An association of URBs to an anchor is made by an explicit
|
||||
call to usb_anchor_urb(). The association is maintained until
|
||||
an URB is finished by (successfull) completion. Thus disassociation
|
||||
is automatic. A function is provided to forcibly finish (kill)
|
||||
all URBs associated with an anchor.
|
||||
Furthermore, disassociation can be made with usb_unanchor_urb()
|
||||
|
||||
Operations on multitudes of URBs
|
||||
================================
|
||||
|
||||
usb_kill_anchored_urbs()
|
||||
------------------------
|
||||
|
||||
This function kills all URBs associated with an anchor. The URBs
|
||||
are called in the reverse temporal order they were submitted.
|
||||
This way no data can be reordered.
|
||||
|
||||
usb_wait_anchor_empty_timeout()
|
||||
-------------------------------
|
||||
|
||||
This function waits for all URBs associated with an anchor to finish
|
||||
or a timeout, whichever comes first. Its return value will tell you
|
||||
whether the timeout was reached.
|
||||
@@ -0,0 +1,132 @@
|
||||
What callbacks will usbcore do?
|
||||
===============================
|
||||
|
||||
Usbcore will call into a driver through callbacks defined in the driver
|
||||
structure and through the completion handler of URBs a driver submits.
|
||||
Only the former are in the scope of this document. These two kinds of
|
||||
callbacks are completely independent of each other. Information on the
|
||||
completion callback can be found in Documentation/usb/URB.txt.
|
||||
|
||||
The callbacks defined in the driver structure are:
|
||||
|
||||
1. Hotplugging callbacks:
|
||||
|
||||
* @probe: Called to see if the driver is willing to manage a particular
|
||||
* interface on a device.
|
||||
* @disconnect: Called when the interface is no longer accessible, usually
|
||||
* because its device has been (or is being) disconnected or the
|
||||
* driver module is being unloaded.
|
||||
|
||||
2. Odd backdoor through usbfs:
|
||||
|
||||
* @ioctl: Used for drivers that want to talk to userspace through
|
||||
* the "usbfs" filesystem. This lets devices provide ways to
|
||||
* expose information to user space regardless of where they
|
||||
* do (or don't) show up otherwise in the filesystem.
|
||||
|
||||
3. Power management (PM) callbacks:
|
||||
|
||||
* @suspend: Called when the device is going to be suspended.
|
||||
* @resume: Called when the device is being resumed.
|
||||
* @reset_resume: Called when the suspended device has been reset instead
|
||||
* of being resumed.
|
||||
|
||||
4. Device level operations:
|
||||
|
||||
* @pre_reset: Called when the device is about to be reset.
|
||||
* @post_reset: Called after the device has been reset
|
||||
|
||||
The ioctl interface (2) should be used only if you have a very good
|
||||
reason. Sysfs is preferred these days. The PM callbacks are covered
|
||||
separately in Documentation/usb/power-management.txt.
|
||||
|
||||
Calling conventions
|
||||
===================
|
||||
|
||||
All callbacks are mutually exclusive. There's no need for locking
|
||||
against other USB callbacks. All callbacks are called from a task
|
||||
context. You may sleep. However, it is important that all sleeps have a
|
||||
small fixed upper limit in time. In particular you must not call out to
|
||||
user space and await results.
|
||||
|
||||
Hotplugging callbacks
|
||||
=====================
|
||||
|
||||
These callbacks are intended to associate and disassociate a driver with
|
||||
an interface. A driver's bond to an interface is exclusive.
|
||||
|
||||
The probe() callback
|
||||
--------------------
|
||||
|
||||
int (*probe) (struct usb_interface *intf,
|
||||
const struct usb_device_id *id);
|
||||
|
||||
Accept or decline an interface. If you accept the device return 0,
|
||||
otherwise -ENODEV or -ENXIO. Other error codes should be used only if a
|
||||
genuine error occurred during initialisation which prevented a driver
|
||||
from accepting a device that would else have been accepted.
|
||||
You are strongly encouraged to use usbcore'sfacility,
|
||||
usb_set_intfdata(), to associate a data structure with an interface, so
|
||||
that you know which internal state and identity you associate with a
|
||||
particular interface. The device will not be suspended and you may do IO
|
||||
to the interface you are called for and endpoint 0 of the device. Device
|
||||
initialisation that doesn't take too long is a good idea here.
|
||||
|
||||
The disconnect() callback
|
||||
-------------------------
|
||||
|
||||
void (*disconnect) (struct usb_interface *intf);
|
||||
|
||||
This callback is a signal to break any connection with an interface.
|
||||
You are not allowed any IO to a device after returning from this
|
||||
callback. You also may not do any other operation that may interfere
|
||||
with another driver bound the interface, eg. a power management
|
||||
operation.
|
||||
If you are called due to a physical disconnection, all your URBs will be
|
||||
killed by usbcore. Note that in this case disconnect will be called some
|
||||
time after the physical disconnection. Thus your driver must be prepared
|
||||
to deal with failing IO even prior to the callback.
|
||||
|
||||
Device level callbacks
|
||||
======================
|
||||
|
||||
pre_reset
|
||||
---------
|
||||
|
||||
int (*pre_reset)(struct usb_interface *intf);
|
||||
|
||||
Another driver or user space is triggering a reset on the device which
|
||||
contains the interface passed as an argument. Cease IO and save any
|
||||
device state you need to restore.
|
||||
|
||||
If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if you
|
||||
are in atomic context.
|
||||
|
||||
post_reset
|
||||
----------
|
||||
|
||||
int (*post_reset)(struct usb_interface *intf);
|
||||
|
||||
The reset has completed. Restore any saved device state and begin
|
||||
using the device again.
|
||||
|
||||
If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if you
|
||||
are in atomic context.
|
||||
|
||||
Call sequences
|
||||
==============
|
||||
|
||||
No callbacks other than probe will be invoked for an interface
|
||||
that isn't bound to your driver.
|
||||
|
||||
Probe will never be called for an interface bound to a driver.
|
||||
Hence following a successful probe, disconnect will be called
|
||||
before there is another probe for the same interface.
|
||||
|
||||
Once your driver is bound to an interface, disconnect can be
|
||||
called at any time except in between pre_reset and post_reset.
|
||||
pre_reset is always followed by post_reset, even if the reset
|
||||
failed or the device has been unplugged.
|
||||
|
||||
suspend is always followed by one of: resume, reset_resume, or
|
||||
disconnect.
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Alan Stern <stern@rowland.harvard.edu>
|
||||
|
||||
September 2, 2006 (Updated May 29, 2007)
|
||||
September 2, 2006 (Updated February 25, 2008)
|
||||
|
||||
|
||||
What is the problem?
|
||||
@@ -65,9 +65,10 @@ much better.)
|
||||
|
||||
What is the solution?
|
||||
|
||||
Setting CONFIG_USB_PERSIST will cause the kernel to work around these
|
||||
issues. It enables a mode in which the core USB device data
|
||||
structures are allowed to persist across a power-session disruption.
|
||||
The kernel includes a feature called USB-persist. It tries to work
|
||||
around these issues by allowing the core USB device data structures to
|
||||
persist across a power-session disruption.
|
||||
|
||||
It works like this. If the kernel sees that a USB host controller is
|
||||
not in the expected state during resume (i.e., if the controller was
|
||||
reset or otherwise had lost power) then it applies a persistence check
|
||||
@@ -80,28 +81,30 @@ re-enumeration shows that the device now attached to that port has the
|
||||
same descriptors as before, including the Vendor and Product IDs, then
|
||||
the kernel continues to use the same device structure. In effect, the
|
||||
kernel treats the device as though it had merely been reset instead of
|
||||
unplugged.
|
||||
unplugged. The same thing happens if the host controller is in the
|
||||
expected state but a USB device was unplugged and then replugged.
|
||||
|
||||
If no device is now attached to the port, or if the descriptors are
|
||||
different from what the kernel remembers, then the treatment is what
|
||||
you would expect. The kernel destroys the old device structure and
|
||||
behaves as though the old device had been unplugged and a new device
|
||||
plugged in, just as it would without the CONFIG_USB_PERSIST option.
|
||||
plugged in.
|
||||
|
||||
The end result is that the USB device remains available and usable.
|
||||
Filesystem mounts and memory mappings are unaffected, and the world is
|
||||
now a good and happy place.
|
||||
|
||||
Note that even when CONFIG_USB_PERSIST is set, the "persist" feature
|
||||
will be applied only to those devices for which it is enabled. You
|
||||
can enable the feature by doing (as root):
|
||||
Note that the "USB-persist" feature will be applied only to those
|
||||
devices for which it is enabled. You can enable the feature by doing
|
||||
(as root):
|
||||
|
||||
echo 1 >/sys/bus/usb/devices/.../power/persist
|
||||
|
||||
where the "..." should be filled in the with the device's ID. Disable
|
||||
the feature by writing 0 instead of 1. For hubs the feature is
|
||||
automatically and permanently enabled, so you only have to worry about
|
||||
setting it for devices where it really matters.
|
||||
automatically and permanently enabled and the power/persist file
|
||||
doesn't even exist, so you only have to worry about setting it for
|
||||
devices where it really matters.
|
||||
|
||||
|
||||
Is this the best solution?
|
||||
@@ -112,19 +115,19 @@ centralized Logical Volume Manager. Such a solution would allow you
|
||||
to plug in a USB flash device, create a persistent volume associated
|
||||
with it, unplug the flash device, plug it back in later, and still
|
||||
have the same persistent volume associated with the device. As such
|
||||
it would be more far-reaching than CONFIG_USB_PERSIST.
|
||||
it would be more far-reaching than USB-persist.
|
||||
|
||||
On the other hand, writing a persistent volume manager would be a big
|
||||
job and using it would require significant input from the user. This
|
||||
solution is much quicker and easier -- and it exists now, a giant
|
||||
point in its favor!
|
||||
|
||||
Furthermore, the USB_PERSIST option applies to _all_ USB devices, not
|
||||
Furthermore, the USB-persist feature applies to _all_ USB devices, not
|
||||
just mass-storage devices. It might turn out to be equally useful for
|
||||
other device types, such as network interfaces.
|
||||
|
||||
|
||||
WARNING: Using CONFIG_USB_PERSIST can be dangerous!!
|
||||
WARNING: USB-persist can be dangerous!!
|
||||
|
||||
When recovering an interrupted power session the kernel does its best
|
||||
to make sure the USB device hasn't been changed; that is, the same
|
||||
@@ -133,10 +136,10 @@ aren't guaranteed to be 100% accurate.
|
||||
|
||||
If you replace one USB device with another of the same type (same
|
||||
manufacturer, same IDs, and so on) there's an excellent chance the
|
||||
kernel won't detect the change. Serial numbers and other strings are
|
||||
not compared. In many cases it wouldn't help if they were, because
|
||||
manufacturers frequently omit serial numbers entirely in their
|
||||
devices.
|
||||
kernel won't detect the change. The serial number string and other
|
||||
descriptors are compared with the kernel's stored values, but this
|
||||
might not help since manufacturers frequently omit serial numbers
|
||||
entirely in their devices.
|
||||
|
||||
Furthermore it's quite possible to leave a USB device exactly the same
|
||||
while changing its media. If you replace the flash memory card in a
|
||||
@@ -152,5 +155,5 @@ but yourself.
|
||||
YOU HAVE BEEN WARNED! USE AT YOUR OWN RISK!
|
||||
|
||||
That having been said, most of the time there shouldn't be any trouble
|
||||
at all. The "persist" feature can be extremely useful. Make the most
|
||||
of it.
|
||||
at all. The USB-persist feature can be extremely useful. Make the
|
||||
most of it.
|
||||
|
||||
@@ -192,12 +192,9 @@ Keyspan USA-series Serial Adapters
|
||||
|
||||
FTDI Single Port Serial Driver
|
||||
|
||||
This is a single port DB-25 serial adapter. More information about this
|
||||
device and the Linux driver can be found at:
|
||||
http://reality.sgi.com/bryder_wellington/ftdi_sio/
|
||||
This is a single port DB-25 serial adapter.
|
||||
|
||||
For any questions or problems with this driver, please contact Bill Ryder
|
||||
at bryder@sgi.com
|
||||
For any questions or problems with this driver, please contact Bill Ryder.
|
||||
|
||||
|
||||
ZyXEL omni.net lcd plus ISDN TA
|
||||
|
||||
@@ -405,9 +405,11 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha
|
||||
static void xpad_irq_in(struct urb *urb)
|
||||
{
|
||||
struct usb_xpad *xpad = urb->context;
|
||||
int retval;
|
||||
int retval, status;
|
||||
|
||||
switch (urb->status) {
|
||||
status = urb->status;
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
/* success */
|
||||
break;
|
||||
@@ -416,11 +418,11 @@ static void xpad_irq_in(struct urb *urb)
|
||||
case -ESHUTDOWN:
|
||||
/* this urb is terminated, clean up */
|
||||
dbg("%s - urb shutting down with status: %d",
|
||||
__FUNCTION__, urb->status);
|
||||
__FUNCTION__, status);
|
||||
return;
|
||||
default:
|
||||
dbg("%s - nonzero urb status received: %d",
|
||||
__FUNCTION__, urb->status);
|
||||
__FUNCTION__, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -445,9 +447,11 @@ exit:
|
||||
#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
|
||||
static void xpad_irq_out(struct urb *urb)
|
||||
{
|
||||
int retval;
|
||||
int retval, status;
|
||||
|
||||
switch (urb->status) {
|
||||
status = urb->status;
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
/* success */
|
||||
break;
|
||||
@@ -456,11 +460,11 @@ static void xpad_irq_out(struct urb *urb)
|
||||
case -ESHUTDOWN:
|
||||
/* this urb is terminated, clean up */
|
||||
dbg("%s - urb shutting down with status: %d",
|
||||
__FUNCTION__, urb->status);
|
||||
__FUNCTION__, status);
|
||||
return;
|
||||
default:
|
||||
dbg("%s - nonzero urb status received: %d",
|
||||
__FUNCTION__, urb->status);
|
||||
__FUNCTION__, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
||||
@@ -444,7 +444,7 @@ CXACRU_ALL_FILES(INIT);
|
||||
/* the following three functions are stolen from drivers/usb/core/message.c */
|
||||
static void cxacru_blocking_completion(struct urb *urb)
|
||||
{
|
||||
complete((struct completion *)urb->context);
|
||||
complete(urb->context);
|
||||
}
|
||||
|
||||
static void cxacru_timeout_kill(unsigned long data)
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
if (debug >= 1) \
|
||||
dev_dbg(&(usb_dev)->dev, \
|
||||
"[ueagle-atm dbg] %s: " format, \
|
||||
__FUNCTION__, ##args); \
|
||||
__func__, ##args); \
|
||||
} while (0)
|
||||
|
||||
#define uea_vdbg(usb_dev, format, args...) \
|
||||
@@ -94,10 +94,10 @@
|
||||
} while (0)
|
||||
|
||||
#define uea_enters(usb_dev) \
|
||||
uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__)
|
||||
uea_vdbg(usb_dev, "entering %s\n", __func__)
|
||||
|
||||
#define uea_leaves(usb_dev) \
|
||||
uea_vdbg(usb_dev, "leaving %s\n", __FUNCTION__)
|
||||
uea_vdbg(usb_dev, "leaving %s\n", __func__)
|
||||
|
||||
#define uea_err(usb_dev, format,args...) \
|
||||
dev_err(&(usb_dev)->dev ,"[UEAGLE-ATM] " format , ##args)
|
||||
|
||||
+14
-11
@@ -80,6 +80,7 @@
|
||||
#include <linux/stat.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
static int usbatm_print_packet(const unsigned char *data, int len);
|
||||
@@ -1014,10 +1015,7 @@ static int usbatm_do_heavy_init(void *arg)
|
||||
struct usbatm_data *instance = arg;
|
||||
int ret;
|
||||
|
||||
daemonize(instance->driver->driver_name);
|
||||
allow_signal(SIGTERM);
|
||||
instance->thread_pid = current->pid;
|
||||
|
||||
complete(&instance->thread_started);
|
||||
|
||||
ret = instance->driver->heavy_init(instance, instance->usb_intf);
|
||||
@@ -1026,7 +1024,7 @@ static int usbatm_do_heavy_init(void *arg)
|
||||
ret = usbatm_atm_init(instance);
|
||||
|
||||
mutex_lock(&instance->serialize);
|
||||
instance->thread_pid = -1;
|
||||
instance->thread = NULL;
|
||||
mutex_unlock(&instance->serialize);
|
||||
|
||||
complete_and_exit(&instance->thread_exited, ret);
|
||||
@@ -1034,13 +1032,18 @@ static int usbatm_do_heavy_init(void *arg)
|
||||
|
||||
static int usbatm_heavy_init(struct usbatm_data *instance)
|
||||
{
|
||||
int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_FS | CLONE_FILES);
|
||||
struct task_struct *t;
|
||||
|
||||
if (ret < 0) {
|
||||
usb_err(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret);
|
||||
return ret;
|
||||
t = kthread_create(usbatm_do_heavy_init, instance,
|
||||
instance->driver->driver_name);
|
||||
if (IS_ERR(t)) {
|
||||
usb_err(instance, "%s: failed to create kernel_thread (%ld)!\n",
|
||||
__func__, PTR_ERR(t));
|
||||
return PTR_ERR(t);
|
||||
}
|
||||
|
||||
instance->thread = t;
|
||||
wake_up_process(t);
|
||||
wait_for_completion(&instance->thread_started);
|
||||
|
||||
return 0;
|
||||
@@ -1124,7 +1127,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
|
||||
kref_init(&instance->refcount); /* dropped in usbatm_usb_disconnect */
|
||||
mutex_init(&instance->serialize);
|
||||
|
||||
instance->thread_pid = -1;
|
||||
instance->thread = NULL;
|
||||
init_completion(&instance->thread_started);
|
||||
init_completion(&instance->thread_exited);
|
||||
|
||||
@@ -1287,8 +1290,8 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
|
||||
|
||||
mutex_lock(&instance->serialize);
|
||||
instance->disconnected = 1;
|
||||
if (instance->thread_pid >= 0)
|
||||
kill_proc(instance->thread_pid, SIGTERM, 1);
|
||||
if (instance->thread != NULL)
|
||||
send_sig(SIGTERM, instance->thread, 1);
|
||||
mutex_unlock(&instance->serialize);
|
||||
|
||||
wait_for_completion(&instance->thread_exited);
|
||||
|
||||
@@ -175,7 +175,7 @@ struct usbatm_data {
|
||||
int disconnected;
|
||||
|
||||
/* heavy init */
|
||||
int thread_pid;
|
||||
struct task_struct *thread;
|
||||
struct completion thread_started;
|
||||
struct completion thread_exited;
|
||||
|
||||
|
||||
+52
-46
@@ -31,6 +31,7 @@
|
||||
* v0.23 - use softirq for rx processing, as needed by tty layer
|
||||
* v0.24 - change probe method to evaluate CDC union descriptor
|
||||
* v0.25 - downstream tasks paralelized to maximize throughput
|
||||
* v0.26 - multiple write urbs, writesize increased
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -72,7 +73,7 @@
|
||||
/*
|
||||
* Version Information
|
||||
*/
|
||||
#define DRIVER_VERSION "v0.25"
|
||||
#define DRIVER_VERSION "v0.26"
|
||||
#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
|
||||
#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
|
||||
|
||||
@@ -118,7 +119,7 @@ static int acm_wb_alloc(struct acm *acm)
|
||||
int i, wbn;
|
||||
struct acm_wb *wb;
|
||||
|
||||
wbn = acm->write_current;
|
||||
wbn = 0;
|
||||
i = 0;
|
||||
for (;;) {
|
||||
wb = &acm->wb[wbn];
|
||||
@@ -132,11 +133,6 @@ static int acm_wb_alloc(struct acm *acm)
|
||||
}
|
||||
}
|
||||
|
||||
static void acm_wb_free(struct acm *acm, int wbn)
|
||||
{
|
||||
acm->wb[wbn].use = 0;
|
||||
}
|
||||
|
||||
static int acm_wb_is_avail(struct acm *acm)
|
||||
{
|
||||
int i, n;
|
||||
@@ -156,26 +152,22 @@ static inline int acm_wb_is_used(struct acm *acm, int wbn)
|
||||
/*
|
||||
* Finish write.
|
||||
*/
|
||||
static void acm_write_done(struct acm *acm)
|
||||
static void acm_write_done(struct acm *acm, struct acm_wb *wb)
|
||||
{
|
||||
unsigned long flags;
|
||||
int wbn;
|
||||
|
||||
spin_lock_irqsave(&acm->write_lock, flags);
|
||||
acm->write_ready = 1;
|
||||
wbn = acm->write_current;
|
||||
acm_wb_free(acm, wbn);
|
||||
acm->write_current = (wbn + 1) % ACM_NW;
|
||||
wb->use = 0;
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Poke write.
|
||||
*/
|
||||
static int acm_write_start(struct acm *acm)
|
||||
static int acm_write_start(struct acm *acm, int wbn)
|
||||
{
|
||||
unsigned long flags;
|
||||
int wbn;
|
||||
struct acm_wb *wb;
|
||||
int rc;
|
||||
|
||||
@@ -190,24 +182,24 @@ static int acm_write_start(struct acm *acm)
|
||||
return 0; /* A white lie */
|
||||
}
|
||||
|
||||
wbn = acm->write_current;
|
||||
if (!acm_wb_is_used(acm, wbn)) {
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
wb = &acm->wb[wbn];
|
||||
|
||||
acm->write_ready = 0;
|
||||
if(acm_wb_is_avail(acm) <= 1)
|
||||
acm->write_ready = 0;
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
|
||||
acm->writeurb->transfer_buffer = wb->buf;
|
||||
acm->writeurb->transfer_dma = wb->dmah;
|
||||
acm->writeurb->transfer_buffer_length = wb->len;
|
||||
acm->writeurb->dev = acm->dev;
|
||||
wb->urb->transfer_buffer = wb->buf;
|
||||
wb->urb->transfer_dma = wb->dmah;
|
||||
wb->urb->transfer_buffer_length = wb->len;
|
||||
wb->urb->dev = acm->dev;
|
||||
|
||||
if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) {
|
||||
if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) {
|
||||
dbg("usb_submit_urb(write bulk) failed: %d", rc);
|
||||
acm_write_done(acm);
|
||||
acm_write_done(acm, wb);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -268,10 +260,10 @@ static void acm_ctrl_irq(struct urb *urb)
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
/* this urb is terminated, clean up */
|
||||
dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
|
||||
dbg("%s - urb shutting down with status: %d", __func__, status);
|
||||
return;
|
||||
default:
|
||||
dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
|
||||
dbg("%s - nonzero urb status received: %d", __func__, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -315,7 +307,7 @@ exit:
|
||||
retval = usb_submit_urb (urb, GFP_ATOMIC);
|
||||
if (retval)
|
||||
err ("%s - usb_submit_urb failed with result %d",
|
||||
__FUNCTION__, retval);
|
||||
__func__, retval);
|
||||
}
|
||||
|
||||
/* data interface returns incoming bytes, or we got unthrottled */
|
||||
@@ -450,12 +442,13 @@ urbs:
|
||||
/* data interface wrote those outgoing bytes */
|
||||
static void acm_write_bulk(struct urb *urb)
|
||||
{
|
||||
struct acm *acm = (struct acm *)urb->context;
|
||||
struct acm *acm;
|
||||
struct acm_wb *wb = urb->context;
|
||||
|
||||
dbg("Entering acm_write_bulk with status %d", urb->status);
|
||||
|
||||
acm_write_done(acm);
|
||||
acm_write_start(acm);
|
||||
acm = wb->instance;
|
||||
acm_write_done(acm, wb);
|
||||
if (ACM_READY(acm))
|
||||
schedule_work(&acm->work);
|
||||
}
|
||||
@@ -489,6 +482,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
else
|
||||
rv = 0;
|
||||
|
||||
set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
|
||||
tty->driver_data = acm;
|
||||
acm->tty = tty;
|
||||
|
||||
@@ -556,7 +550,8 @@ static void acm_tty_unregister(struct acm *acm)
|
||||
usb_put_intf(acm->control);
|
||||
acm_table[acm->minor] = NULL;
|
||||
usb_free_urb(acm->ctrlurb);
|
||||
usb_free_urb(acm->writeurb);
|
||||
for (i = 0; i < ACM_NW; i++)
|
||||
usb_free_urb(acm->wb[i].urb);
|
||||
for (i = 0; i < nr; i++)
|
||||
usb_free_urb(acm->ru[i].urb);
|
||||
kfree(acm->country_codes);
|
||||
@@ -577,7 +572,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
if (acm->dev) {
|
||||
acm_set_control(acm, acm->ctrlout = 0);
|
||||
usb_kill_urb(acm->ctrlurb);
|
||||
usb_kill_urb(acm->writeurb);
|
||||
for (i = 0; i < ACM_NW; i++)
|
||||
usb_kill_urb(acm->wb[i].urb);
|
||||
for (i = 0; i < nr; i++)
|
||||
usb_kill_urb(acm->ru[i].urb);
|
||||
usb_autopm_put_interface(acm->control);
|
||||
@@ -605,7 +601,6 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
|
||||
spin_lock_irqsave(&acm->write_lock, flags);
|
||||
if ((wbn = acm_wb_alloc(acm)) < 0) {
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
acm_write_start(acm);
|
||||
return 0;
|
||||
}
|
||||
wb = &acm->wb[wbn];
|
||||
@@ -616,7 +611,7 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
|
||||
wb->len = count;
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
|
||||
if ((stat = acm_write_start(acm)) < 0)
|
||||
if ((stat = acm_write_start(acm, wbn)) < 0)
|
||||
return stat;
|
||||
return count;
|
||||
}
|
||||
@@ -809,7 +804,7 @@ static int acm_probe (struct usb_interface *intf,
|
||||
{
|
||||
struct usb_cdc_union_desc *union_header = NULL;
|
||||
struct usb_cdc_country_functional_desc *cfd = NULL;
|
||||
char *buffer = intf->altsetting->extra;
|
||||
unsigned char *buffer = intf->altsetting->extra;
|
||||
int buflen = intf->altsetting->extralen;
|
||||
struct usb_interface *control_interface;
|
||||
struct usb_interface *data_interface;
|
||||
@@ -886,9 +881,13 @@ static int acm_probe (struct usb_interface *intf,
|
||||
if ((call_management_function & 3) != 3)
|
||||
err("This device cannot do calls on its own. It is no modem.");
|
||||
break;
|
||||
|
||||
default:
|
||||
err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]);
|
||||
/* there are LOTS more CDC descriptors that
|
||||
* could legitimately be found here.
|
||||
*/
|
||||
dev_dbg(&intf->dev, "Ignoring descriptor: "
|
||||
"type %02x, length %d\n",
|
||||
buffer[2], buffer[0]);
|
||||
break;
|
||||
}
|
||||
next_desc:
|
||||
@@ -976,7 +975,7 @@ skip_normal_probe:
|
||||
|
||||
ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
|
||||
readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
|
||||
acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize);
|
||||
acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
|
||||
acm->control = control_interface;
|
||||
acm->data = data_interface;
|
||||
acm->minor = minor;
|
||||
@@ -1031,10 +1030,19 @@ skip_normal_probe:
|
||||
goto alloc_fail7;
|
||||
}
|
||||
}
|
||||
acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!acm->writeurb) {
|
||||
dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n");
|
||||
goto alloc_fail7;
|
||||
for(i = 0; i < ACM_NW; i++)
|
||||
{
|
||||
struct acm_wb *snd = &(acm->wb[i]);
|
||||
|
||||
if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) {
|
||||
dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)");
|
||||
goto alloc_fail7;
|
||||
}
|
||||
|
||||
usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
|
||||
NULL, acm->writesize, acm_write_bulk, snd);
|
||||
snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
snd->instance = acm;
|
||||
}
|
||||
|
||||
usb_set_intfdata (intf, acm);
|
||||
@@ -1070,10 +1078,6 @@ skip_countries:
|
||||
acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
acm->ctrlurb->transfer_dma = acm->ctrl_dma;
|
||||
|
||||
usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
|
||||
NULL, acm->writesize, acm_write_bulk, acm);
|
||||
acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
|
||||
|
||||
acm_set_control(acm, acm->ctrlout);
|
||||
@@ -1091,7 +1095,8 @@ skip_countries:
|
||||
|
||||
return 0;
|
||||
alloc_fail8:
|
||||
usb_free_urb(acm->writeurb);
|
||||
for (i = 0; i < ACM_NW; i++)
|
||||
usb_free_urb(acm->wb[i].urb);
|
||||
alloc_fail7:
|
||||
for (i = 0; i < num_rx_buf; i++)
|
||||
usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
|
||||
@@ -1115,7 +1120,8 @@ static void stop_data_traffic(struct acm *acm)
|
||||
tasklet_disable(&acm->urb_task);
|
||||
|
||||
usb_kill_urb(acm->ctrlurb);
|
||||
usb_kill_urb(acm->writeurb);
|
||||
for(i = 0; i < ACM_NW; i++)
|
||||
usb_kill_urb(acm->wb[i].urb);
|
||||
for (i = 0; i < acm->rx_buflimit; i++)
|
||||
usb_kill_urb(acm->ru[i].urb);
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
* when processing onlcr, so we only need 2 buffers. These values must be
|
||||
* powers of 2.
|
||||
*/
|
||||
#define ACM_NW 2
|
||||
#define ACM_NW 16
|
||||
#define ACM_NR 16
|
||||
|
||||
struct acm_wb {
|
||||
@@ -67,6 +67,8 @@ struct acm_wb {
|
||||
dma_addr_t dmah;
|
||||
int len;
|
||||
int use;
|
||||
struct urb *urb;
|
||||
struct acm *instance;
|
||||
};
|
||||
|
||||
struct acm_rb {
|
||||
@@ -88,7 +90,7 @@ struct acm {
|
||||
struct usb_interface *control; /* control interface */
|
||||
struct usb_interface *data; /* data interface */
|
||||
struct tty_struct *tty; /* the corresponding tty */
|
||||
struct urb *ctrlurb, *writeurb; /* urbs */
|
||||
struct urb *ctrlurb; /* urbs */
|
||||
u8 *ctrl_buffer; /* buffers of urbs */
|
||||
dma_addr_t ctrl_dma; /* dma handles of buffers */
|
||||
u8 *country_codes; /* country codes from device */
|
||||
@@ -103,7 +105,6 @@ struct acm {
|
||||
struct list_head spare_read_urbs;
|
||||
struct list_head spare_read_bufs;
|
||||
struct list_head filled_read_bufs;
|
||||
int write_current; /* current write buffer */
|
||||
int write_used; /* number of non-empty write buffers */
|
||||
int write_ready; /* write urb is not running */
|
||||
spinlock_t write_lock;
|
||||
|
||||
+10
-32
@@ -76,8 +76,8 @@ config USB_DEVICE_CLASS
|
||||
NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644"
|
||||
|
||||
config USB_DYNAMIC_MINORS
|
||||
bool "Dynamic USB minor allocation (EXPERIMENTAL)"
|
||||
depends on USB && EXPERIMENTAL
|
||||
bool "Dynamic USB minor allocation"
|
||||
depends on USB
|
||||
help
|
||||
If you say Y here, the USB subsystem will use dynamic minor
|
||||
allocation for any device that uses the USB major number.
|
||||
@@ -102,31 +102,6 @@ config USB_SUSPEND
|
||||
|
||||
If you are unsure about this, say N here.
|
||||
|
||||
config USB_PERSIST
|
||||
bool "USB device persistence during system suspend (DANGEROUS)"
|
||||
depends on USB && PM && EXPERIMENTAL
|
||||
default n
|
||||
help
|
||||
|
||||
If you say Y here and enable the "power/persist" attribute
|
||||
for a USB device, the device's data structures will remain
|
||||
persistent across system suspend, even if the USB bus loses
|
||||
power. (This includes hibernation, also known as swsusp or
|
||||
suspend-to-disk.) The devices will reappear as if by magic
|
||||
when the system wakes up, with no need to unmount USB
|
||||
filesystems, rmmod host-controller drivers, or do anything
|
||||
else.
|
||||
|
||||
WARNING: This option can be dangerous!
|
||||
|
||||
If a USB device is replaced by another of the same type while
|
||||
the system is asleep, there's a good chance the kernel won't
|
||||
detect the change. Likewise if the media in a USB storage
|
||||
device is replaced. When this happens it's almost certain to
|
||||
cause data corruption and maybe even crash your system.
|
||||
|
||||
If you are unsure, say N here.
|
||||
|
||||
config USB_OTG
|
||||
bool
|
||||
depends on USB && EXPERIMENTAL
|
||||
@@ -136,14 +111,16 @@ config USB_OTG
|
||||
|
||||
config USB_OTG_WHITELIST
|
||||
bool "Rely on OTG Targeted Peripherals List"
|
||||
depends on USB_OTG
|
||||
default y
|
||||
depends on USB_OTG || EMBEDDED
|
||||
default y if USB_OTG
|
||||
default n if EMBEDDED
|
||||
help
|
||||
If you say Y here, the "otg_whitelist.h" file will be used as a
|
||||
product whitelist, so USB peripherals not listed there will be
|
||||
rejected during enumeration. This behavior is required by the
|
||||
USB OTG specification for all devices not on your product's
|
||||
"Targeted Peripherals List".
|
||||
"Targeted Peripherals List". "Embedded Hosts" are likewise
|
||||
allowed to support only a limited number of peripherals.
|
||||
|
||||
Otherwise, peripherals not listed there will only generate a
|
||||
warning and enumeration will continue. That's more like what
|
||||
@@ -152,9 +129,10 @@ config USB_OTG_WHITELIST
|
||||
|
||||
config USB_OTG_BLACKLIST_HUB
|
||||
bool "Disable external hubs"
|
||||
depends on USB_OTG
|
||||
depends on USB_OTG || EMBEDDED
|
||||
help
|
||||
If you say Y here, then Linux will refuse to enumerate
|
||||
external hubs. OTG hosts are allowed to reduce hardware
|
||||
and software costs by not supporting external hubs.
|
||||
and software costs by not supporting external hubs. So
|
||||
are "Emedded Hosts" that don't offer OTG support.
|
||||
|
||||
|
||||
@@ -145,6 +145,23 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
|
||||
endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some buggy high speed devices have bulk endpoints using
|
||||
* maxpacket sizes other than 512. High speed HCDs may not
|
||||
* be able to handle that particular bug, so let's warn...
|
||||
*/
|
||||
if (to_usb_device(ddev)->speed == USB_SPEED_HIGH
|
||||
&& usb_endpoint_xfer_bulk(d)) {
|
||||
unsigned maxp;
|
||||
|
||||
maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize) & 0x07ff;
|
||||
if (maxp != 512)
|
||||
dev_warn(ddev, "config %d interface %d altsetting %d "
|
||||
"bulk endpoint 0x%X has invalid maxpacket %d\n",
|
||||
cfgno, inum, asnum, d->bEndpointAddress,
|
||||
maxp);
|
||||
}
|
||||
|
||||
/* Skip over any Class Specific or Vendor Specific descriptors;
|
||||
* find the next endpoint or interface descriptor */
|
||||
endpoint->extra = buffer;
|
||||
|
||||
+47
-26
@@ -647,6 +647,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)
|
||||
struct usbdevfs_ctrltransfer ctrl;
|
||||
unsigned int tmo;
|
||||
unsigned char *tbuf;
|
||||
unsigned wLength;
|
||||
int i, j, ret;
|
||||
|
||||
if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
|
||||
@@ -654,7 +655,8 @@ static int proc_control(struct dev_state *ps, void __user *arg)
|
||||
ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ctrl.wLength > PAGE_SIZE)
|
||||
wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */
|
||||
if (wLength > PAGE_SIZE)
|
||||
return -EINVAL;
|
||||
tbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
|
||||
if (!tbuf)
|
||||
@@ -946,8 +948,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
|
||||
int ret, ifnum = -1;
|
||||
int is_in;
|
||||
|
||||
if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
|
||||
URB_NO_FSBR|URB_ZERO_PACKET))
|
||||
if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP |
|
||||
USBDEVFS_URB_SHORT_NOT_OK |
|
||||
USBDEVFS_URB_NO_FSBR |
|
||||
USBDEVFS_URB_ZERO_PACKET |
|
||||
USBDEVFS_URB_NO_INTERRUPT))
|
||||
return -EINVAL;
|
||||
if (!uurb->buffer)
|
||||
return -EINVAL;
|
||||
@@ -1102,8 +1107,24 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
|
||||
as->urb->pipe = (uurb->type << 30) |
|
||||
__create_pipe(ps->dev, uurb->endpoint & 0xf) |
|
||||
(uurb->endpoint & USB_DIR_IN);
|
||||
as->urb->transfer_flags = uurb->flags |
|
||||
(is_in ? URB_DIR_IN : URB_DIR_OUT);
|
||||
|
||||
/* This tedious sequence is necessary because the URB_* flags
|
||||
* are internal to the kernel and subject to change, whereas
|
||||
* the USBDEVFS_URB_* flags are a user API and must not be changed.
|
||||
*/
|
||||
u = (is_in ? URB_DIR_IN : URB_DIR_OUT);
|
||||
if (uurb->flags & USBDEVFS_URB_ISO_ASAP)
|
||||
u |= URB_ISO_ASAP;
|
||||
if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
|
||||
u |= URB_SHORT_NOT_OK;
|
||||
if (uurb->flags & USBDEVFS_URB_NO_FSBR)
|
||||
u |= URB_NO_FSBR;
|
||||
if (uurb->flags & USBDEVFS_URB_ZERO_PACKET)
|
||||
u |= URB_ZERO_PACKET;
|
||||
if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT)
|
||||
u |= URB_NO_INTERRUPT;
|
||||
as->urb->transfer_flags = u;
|
||||
|
||||
as->urb->transfer_buffer_length = uurb->buffer_length;
|
||||
as->urb->setup_packet = (unsigned char *)dr;
|
||||
as->urb->start_frame = uurb->start_frame;
|
||||
@@ -1509,60 +1530,60 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
|
||||
|
||||
switch (cmd) {
|
||||
case USBDEVFS_CONTROL:
|
||||
snoop(&dev->dev, "%s: CONTROL\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: CONTROL\n", __func__);
|
||||
ret = proc_control(ps, p);
|
||||
if (ret >= 0)
|
||||
inode->i_mtime = CURRENT_TIME;
|
||||
break;
|
||||
|
||||
case USBDEVFS_BULK:
|
||||
snoop(&dev->dev, "%s: BULK\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: BULK\n", __func__);
|
||||
ret = proc_bulk(ps, p);
|
||||
if (ret >= 0)
|
||||
inode->i_mtime = CURRENT_TIME;
|
||||
break;
|
||||
|
||||
case USBDEVFS_RESETEP:
|
||||
snoop(&dev->dev, "%s: RESETEP\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: RESETEP\n", __func__);
|
||||
ret = proc_resetep(ps, p);
|
||||
if (ret >= 0)
|
||||
inode->i_mtime = CURRENT_TIME;
|
||||
break;
|
||||
|
||||
case USBDEVFS_RESET:
|
||||
snoop(&dev->dev, "%s: RESET\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: RESET\n", __func__);
|
||||
ret = proc_resetdevice(ps);
|
||||
break;
|
||||
|
||||
case USBDEVFS_CLEAR_HALT:
|
||||
snoop(&dev->dev, "%s: CLEAR_HALT\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: CLEAR_HALT\n", __func__);
|
||||
ret = proc_clearhalt(ps, p);
|
||||
if (ret >= 0)
|
||||
inode->i_mtime = CURRENT_TIME;
|
||||
break;
|
||||
|
||||
case USBDEVFS_GETDRIVER:
|
||||
snoop(&dev->dev, "%s: GETDRIVER\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: GETDRIVER\n", __func__);
|
||||
ret = proc_getdriver(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_CONNECTINFO:
|
||||
snoop(&dev->dev, "%s: CONNECTINFO\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: CONNECTINFO\n", __func__);
|
||||
ret = proc_connectinfo(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_SETINTERFACE:
|
||||
snoop(&dev->dev, "%s: SETINTERFACE\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: SETINTERFACE\n", __func__);
|
||||
ret = proc_setintf(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_SETCONFIGURATION:
|
||||
snoop(&dev->dev, "%s: SETCONFIGURATION\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: SETCONFIGURATION\n", __func__);
|
||||
ret = proc_setconfig(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_SUBMITURB:
|
||||
snoop(&dev->dev, "%s: SUBMITURB\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: SUBMITURB\n", __func__);
|
||||
ret = proc_submiturb(ps, p);
|
||||
if (ret >= 0)
|
||||
inode->i_mtime = CURRENT_TIME;
|
||||
@@ -1571,60 +1592,60 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
case USBDEVFS_SUBMITURB32:
|
||||
snoop(&dev->dev, "%s: SUBMITURB32\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: SUBMITURB32\n", __func__);
|
||||
ret = proc_submiturb_compat(ps, p);
|
||||
if (ret >= 0)
|
||||
inode->i_mtime = CURRENT_TIME;
|
||||
break;
|
||||
|
||||
case USBDEVFS_REAPURB32:
|
||||
snoop(&dev->dev, "%s: REAPURB32\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: REAPURB32\n", __func__);
|
||||
ret = proc_reapurb_compat(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_REAPURBNDELAY32:
|
||||
snoop(&dev->dev, "%s: REAPURBDELAY32\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: REAPURBDELAY32\n", __func__);
|
||||
ret = proc_reapurbnonblock_compat(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_IOCTL32:
|
||||
snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: IOCTL\n", __func__);
|
||||
ret = proc_ioctl_compat(ps, ptr_to_compat(p));
|
||||
break;
|
||||
#endif
|
||||
|
||||
case USBDEVFS_DISCARDURB:
|
||||
snoop(&dev->dev, "%s: DISCARDURB\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: DISCARDURB\n", __func__);
|
||||
ret = proc_unlinkurb(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_REAPURB:
|
||||
snoop(&dev->dev, "%s: REAPURB\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: REAPURB\n", __func__);
|
||||
ret = proc_reapurb(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_REAPURBNDELAY:
|
||||
snoop(&dev->dev, "%s: REAPURBDELAY\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: REAPURBDELAY\n", __func__);
|
||||
ret = proc_reapurbnonblock(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_DISCSIGNAL:
|
||||
snoop(&dev->dev, "%s: DISCSIGNAL\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__);
|
||||
ret = proc_disconnectsignal(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_CLAIMINTERFACE:
|
||||
snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __func__);
|
||||
ret = proc_claiminterface(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_RELEASEINTERFACE:
|
||||
snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __func__);
|
||||
ret = proc_releaseinterface(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_IOCTL:
|
||||
snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
|
||||
snoop(&dev->dev, "%s: IOCTL\n", __func__);
|
||||
ret = proc_ioctl_default(ps, p);
|
||||
break;
|
||||
}
|
||||
|
||||
+26
-26
@@ -157,7 +157,7 @@ static int usb_probe_device(struct device *dev)
|
||||
struct usb_device *udev;
|
||||
int error = -ENODEV;
|
||||
|
||||
dev_dbg(dev, "%s\n", __FUNCTION__);
|
||||
dev_dbg(dev, "%s\n", __func__);
|
||||
|
||||
if (!is_usb_device(dev)) /* Sanity check */
|
||||
return error;
|
||||
@@ -194,7 +194,7 @@ static int usb_probe_interface(struct device *dev)
|
||||
const struct usb_device_id *id;
|
||||
int error = -ENODEV;
|
||||
|
||||
dev_dbg(dev, "%s\n", __FUNCTION__);
|
||||
dev_dbg(dev, "%s\n", __func__);
|
||||
|
||||
if (is_usb_device(dev)) /* Sanity check */
|
||||
return error;
|
||||
@@ -211,7 +211,7 @@ static int usb_probe_interface(struct device *dev)
|
||||
if (!id)
|
||||
id = usb_match_dynamic_id(intf, driver);
|
||||
if (id) {
|
||||
dev_dbg(dev, "%s - got id\n", __FUNCTION__);
|
||||
dev_dbg(dev, "%s - got id\n", __func__);
|
||||
|
||||
error = usb_autoresume_device(udev);
|
||||
if (error)
|
||||
@@ -793,9 +793,7 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
|
||||
status = udriver->suspend(udev, msg);
|
||||
|
||||
done:
|
||||
dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
|
||||
if (status == 0)
|
||||
udev->dev.power.power_state.event = msg.event;
|
||||
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -823,11 +821,9 @@ static int usb_resume_device(struct usb_device *udev)
|
||||
status = udriver->resume(udev);
|
||||
|
||||
done:
|
||||
dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
|
||||
if (status == 0) {
|
||||
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
|
||||
if (status == 0)
|
||||
udev->autoresume_disabled = 0;
|
||||
udev->dev.power.power_state.event = PM_EVENT_ON;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -864,7 +860,7 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
|
||||
}
|
||||
|
||||
done:
|
||||
dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
|
||||
dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -914,7 +910,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
|
||||
}
|
||||
|
||||
done:
|
||||
dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
|
||||
dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
|
||||
if (status == 0)
|
||||
mark_active(intf);
|
||||
|
||||
@@ -936,7 +932,6 @@ static int autosuspend_check(struct usb_device *udev, int reschedule)
|
||||
* is disabled. Also fail if any interfaces require remote wakeup
|
||||
* but it isn't available.
|
||||
*/
|
||||
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
|
||||
if (udev->pm_usage_cnt > 0)
|
||||
return -EBUSY;
|
||||
if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled)
|
||||
@@ -1098,7 +1093,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
|
||||
}
|
||||
|
||||
done:
|
||||
dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
|
||||
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1180,8 +1175,7 @@ static int usb_resume_both(struct usb_device *udev)
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Needed for setting udev->dev.power.power_state.event,
|
||||
* for possible debugging message, and for reset_resume. */
|
||||
/* Needed for reset-resume */
|
||||
status = usb_resume_device(udev);
|
||||
}
|
||||
|
||||
@@ -1193,8 +1187,9 @@ static int usb_resume_both(struct usb_device *udev)
|
||||
}
|
||||
|
||||
done:
|
||||
dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
|
||||
udev->reset_resume = 0;
|
||||
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
|
||||
if (!status)
|
||||
udev->reset_resume = 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1262,7 +1257,7 @@ void usb_autosuspend_device(struct usb_device *udev)
|
||||
|
||||
status = usb_autopm_do_device(udev, -1);
|
||||
dev_vdbg(&udev->dev, "%s: cnt %d\n",
|
||||
__FUNCTION__, udev->pm_usage_cnt);
|
||||
__func__, udev->pm_usage_cnt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1282,7 +1277,7 @@ void usb_try_autosuspend_device(struct usb_device *udev)
|
||||
{
|
||||
usb_autopm_do_device(udev, 0);
|
||||
dev_vdbg(&udev->dev, "%s: cnt %d\n",
|
||||
__FUNCTION__, udev->pm_usage_cnt);
|
||||
__func__, udev->pm_usage_cnt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1310,7 +1305,7 @@ int usb_autoresume_device(struct usb_device *udev)
|
||||
|
||||
status = usb_autopm_do_device(udev, 1);
|
||||
dev_vdbg(&udev->dev, "%s: status %d cnt %d\n",
|
||||
__FUNCTION__, status, udev->pm_usage_cnt);
|
||||
__func__, status, udev->pm_usage_cnt);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1382,7 +1377,7 @@ void usb_autopm_put_interface(struct usb_interface *intf)
|
||||
|
||||
status = usb_autopm_do_interface(intf, -1);
|
||||
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
|
||||
__FUNCTION__, status, intf->pm_usage_cnt);
|
||||
__func__, status, intf->pm_usage_cnt);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
|
||||
|
||||
@@ -1426,7 +1421,7 @@ int usb_autopm_get_interface(struct usb_interface *intf)
|
||||
|
||||
status = usb_autopm_do_interface(intf, 1);
|
||||
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
|
||||
__FUNCTION__, status, intf->pm_usage_cnt);
|
||||
__func__, status, intf->pm_usage_cnt);
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
|
||||
@@ -1448,7 +1443,7 @@ int usb_autopm_set_interface(struct usb_interface *intf)
|
||||
|
||||
status = usb_autopm_do_interface(intf, 0);
|
||||
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
|
||||
__FUNCTION__, status, intf->pm_usage_cnt);
|
||||
__func__, status, intf->pm_usage_cnt);
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
|
||||
@@ -1523,9 +1518,14 @@ static int usb_suspend(struct device *dev, pm_message_t message)
|
||||
udev = to_usb_device(dev);
|
||||
|
||||
/* If udev is already suspended, we can skip this suspend and
|
||||
* we should also skip the upcoming system resume. */
|
||||
* we should also skip the upcoming system resume. High-speed
|
||||
* root hubs are an exception; they need to resume whenever the
|
||||
* system wakes up in order for USB-PERSIST port handover to work
|
||||
* properly.
|
||||
*/
|
||||
if (udev->state == USB_STATE_SUSPENDED) {
|
||||
udev->skip_sys_resume = 1;
|
||||
if (udev->parent || udev->speed != USB_SPEED_HIGH)
|
||||
udev->skip_sys_resume = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,6 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
if (pci_enable_device(dev) < 0)
|
||||
return -ENODEV;
|
||||
dev->current_state = PCI_D0;
|
||||
dev->dev.power.power_state = PMSG_ON;
|
||||
|
||||
if (!dev->irq) {
|
||||
dev_err(&dev->dev,
|
||||
@@ -216,9 +215,9 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
|
||||
hcd->state == HC_STATE_HALT))
|
||||
return -EBUSY;
|
||||
|
||||
if (hcd->driver->suspend) {
|
||||
retval = hcd->driver->suspend(hcd, message);
|
||||
suspend_report_result(hcd->driver->suspend, retval);
|
||||
if (hcd->driver->pci_suspend) {
|
||||
retval = hcd->driver->pci_suspend(hcd, message);
|
||||
suspend_report_result(hcd->driver->pci_suspend, retval);
|
||||
if (retval)
|
||||
goto done;
|
||||
}
|
||||
@@ -302,8 +301,6 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
|
||||
|
||||
done:
|
||||
if (retval == 0) {
|
||||
dev->dev.power.power_state = PMSG_SUSPEND;
|
||||
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
/* Disable ASIC clocks for USB */
|
||||
if (machine_is(powermac)) {
|
||||
@@ -406,12 +403,10 @@ int usb_hcd_pci_resume(struct pci_dev *dev)
|
||||
pci_set_master(dev);
|
||||
pci_restore_state(dev);
|
||||
|
||||
dev->dev.power.power_state = PMSG_ON;
|
||||
|
||||
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
|
||||
|
||||
if (hcd->driver->resume) {
|
||||
retval = hcd->driver->resume(hcd);
|
||||
if (hcd->driver->pci_resume) {
|
||||
retval = hcd->driver->pci_resume(hcd);
|
||||
if (retval) {
|
||||
dev_err(hcd->self.controller,
|
||||
"PCI post-resume error %d!\n", retval);
|
||||
|
||||
+12
-13
@@ -129,7 +129,7 @@ static const u8 usb2_rh_dev_descriptor [18] = {
|
||||
|
||||
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
|
||||
0x00, /* __u8 bDeviceSubClass; */
|
||||
0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/
|
||||
0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */
|
||||
0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
|
||||
|
||||
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
|
||||
@@ -291,7 +291,6 @@ static int ascii2utf (char *s, u8 *utf, int utfmax)
|
||||
* rh_string - provides manufacturer, product and serial strings for root hub
|
||||
* @id: the string ID number (1: serial number, 2: product, 3: vendor)
|
||||
* @hcd: the host controller for this root hub
|
||||
* @type: string describing our driver
|
||||
* @data: return packet in UTF-16 LE
|
||||
* @len: length of the return packet
|
||||
*
|
||||
@@ -355,9 +354,10 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
||||
__attribute__((aligned(4)));
|
||||
const u8 *bufp = tbuf;
|
||||
int len = 0;
|
||||
int patch_wakeup = 0;
|
||||
int status;
|
||||
int n;
|
||||
u8 patch_wakeup = 0;
|
||||
u8 patch_protocol = 0;
|
||||
|
||||
might_sleep();
|
||||
|
||||
@@ -434,6 +434,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
||||
else
|
||||
goto error;
|
||||
len = 18;
|
||||
if (hcd->has_tt)
|
||||
patch_protocol = 1;
|
||||
break;
|
||||
case USB_DT_CONFIG << 8:
|
||||
if (hcd->driver->flags & HCD_USB2) {
|
||||
@@ -528,6 +530,13 @@ error:
|
||||
bmAttributes))
|
||||
((struct usb_config_descriptor *)ubuf)->bmAttributes
|
||||
|= USB_CONFIG_ATT_WAKEUP;
|
||||
|
||||
/* report whether RH hardware has an integrated TT */
|
||||
if (patch_protocol &&
|
||||
len > offsetof(struct usb_device_descriptor,
|
||||
bDeviceProtocol))
|
||||
((struct usb_device_descriptor *) ubuf)->
|
||||
bDeviceProtocol = 1;
|
||||
}
|
||||
|
||||
/* any errors get returned through the urb completion */
|
||||
@@ -915,15 +924,6 @@ static int register_root_hub(struct usb_hcd *hcd)
|
||||
return retval;
|
||||
}
|
||||
|
||||
void usb_enable_root_hub_irq (struct usb_bus *bus)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
hcd = container_of (bus, struct usb_hcd, self);
|
||||
if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT)
|
||||
hcd->driver->hub_irq_enable (hcd);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@@ -1677,7 +1677,6 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
|
||||
* usb_hcd_irq - hook IRQs to HCD framework (bus glue)
|
||||
* @irq: the IRQ being raised
|
||||
* @__hcd: pointer to the HCD whose IRQ is being signaled
|
||||
* @r: saved hardware registers
|
||||
*
|
||||
* If the controller isn't HALTed, calls the driver's irq handler.
|
||||
* Checks whether the controller is now dead.
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
/*
|
||||
* USB Packet IDs (PIDs)
|
||||
*/
|
||||
#define USB_PID_UNDEF_0 0xf0
|
||||
#define USB_PID_EXT 0xf0 /* USB 2.0 LPM ECN */
|
||||
#define USB_PID_OUT 0xe1
|
||||
#define USB_PID_ACK 0xd2
|
||||
#define USB_PID_DATA0 0xc3
|
||||
@@ -99,6 +99,7 @@ struct usb_hcd {
|
||||
unsigned poll_pending:1; /* status has changed? */
|
||||
unsigned wireless:1; /* Wireless USB HCD */
|
||||
unsigned authorized_default:1;
|
||||
unsigned has_tt:1; /* Integrated TT in root hub */
|
||||
|
||||
int irq; /* irq allocated */
|
||||
void __iomem *regs; /* device memory/io */
|
||||
@@ -177,10 +178,10 @@ struct hc_driver {
|
||||
* a whole, not just the root hub; they're for PCI bus glue.
|
||||
*/
|
||||
/* called after suspending the hub, before entering D3 etc */
|
||||
int (*suspend) (struct usb_hcd *hcd, pm_message_t message);
|
||||
int (*pci_suspend) (struct usb_hcd *hcd, pm_message_t message);
|
||||
|
||||
/* called after entering D0 (etc), before resuming the hub */
|
||||
int (*resume) (struct usb_hcd *hcd);
|
||||
int (*pci_resume) (struct usb_hcd *hcd);
|
||||
|
||||
/* cleanly make HCD stop writing memory and doing I/O */
|
||||
void (*stop) (struct usb_hcd *hcd);
|
||||
@@ -209,8 +210,6 @@ struct hc_driver {
|
||||
int (*bus_suspend)(struct usb_hcd *);
|
||||
int (*bus_resume)(struct usb_hcd *);
|
||||
int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
|
||||
void (*hub_irq_enable)(struct usb_hcd *);
|
||||
/* Needed only if port-change IRQs are level-triggered */
|
||||
|
||||
/* force handover of high-speed port to full-speed companion */
|
||||
void (*relinquish_port)(struct usb_hcd *, int);
|
||||
|
||||
+256
-140
File diff suppressed because it is too large
Load Diff
@@ -41,9 +41,10 @@
|
||||
*/
|
||||
#define USB_PORT_FEAT_CONNECTION 0
|
||||
#define USB_PORT_FEAT_ENABLE 1
|
||||
#define USB_PORT_FEAT_SUSPEND 2
|
||||
#define USB_PORT_FEAT_SUSPEND 2 /* L2 suspend */
|
||||
#define USB_PORT_FEAT_OVER_CURRENT 3
|
||||
#define USB_PORT_FEAT_RESET 4
|
||||
#define USB_PORT_FEAT_L1 5 /* L1 suspend */
|
||||
#define USB_PORT_FEAT_POWER 8
|
||||
#define USB_PORT_FEAT_LOWSPEED 9
|
||||
#define USB_PORT_FEAT_HIGHSPEED 10
|
||||
@@ -54,6 +55,7 @@
|
||||
#define USB_PORT_FEAT_C_RESET 20
|
||||
#define USB_PORT_FEAT_TEST 21
|
||||
#define USB_PORT_FEAT_INDICATOR 22
|
||||
#define USB_PORT_FEAT_C_PORT_L1 23
|
||||
|
||||
/*
|
||||
* Hub Status and Hub Change results
|
||||
@@ -73,7 +75,8 @@ struct usb_port_status {
|
||||
#define USB_PORT_STAT_SUSPEND 0x0004
|
||||
#define USB_PORT_STAT_OVERCURRENT 0x0008
|
||||
#define USB_PORT_STAT_RESET 0x0010
|
||||
/* bits 5 to 7 are reserved */
|
||||
#define USB_PORT_STAT_L1 0x0020
|
||||
/* bits 6 to 7 are reserved */
|
||||
#define USB_PORT_STAT_POWER 0x0100
|
||||
#define USB_PORT_STAT_LOW_SPEED 0x0200
|
||||
#define USB_PORT_STAT_HIGH_SPEED 0x0400
|
||||
@@ -91,6 +94,7 @@ struct usb_port_status {
|
||||
#define USB_PORT_STAT_C_SUSPEND 0x0004
|
||||
#define USB_PORT_STAT_C_OVERCURRENT 0x0008
|
||||
#define USB_PORT_STAT_C_RESET 0x0010
|
||||
#define USB_PORT_STAT_C_L1 0x0020
|
||||
|
||||
/*
|
||||
* wHubCharacteristics (masks)
|
||||
@@ -191,5 +195,6 @@ struct usb_tt_clear {
|
||||
};
|
||||
|
||||
extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe);
|
||||
extern void usb_ep0_reinit(struct usb_device *);
|
||||
|
||||
#endif /* __LINUX_HUB_H */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user