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: (142 commits) USB: Fix sysfs paths in documentation USB: skeleton: fix coding style issues. USB: O_NONBLOCK in read path of skeleton USB: make usb-skeleton honor O_NONBLOCK in write path USB: skel_read really sucks royally USB: Add hub descriptor update hook for xHCI USB: xhci: Support USB hubs. USB: xhci: Set multi-TT field for LS/FS devices under hubs. USB: xhci: Set route string for all devices. USB: xhci: Fix command wait list handling. USB: xhci: Change how xHCI commands are handled. USB: xhci: Refactor input device context setup. USB: xhci: Endpoint representation refactoring. USB: gadget: ether needs to select CRC32 USB: fix USBTMC get_capabilities success handling USB: fix missing error check in probing USB: usbfs: add USBDEVFS_URB_BULK_CONTINUATION flag USB: support for autosuspend in sierra while online USB: ehci-dbgp,ehci: Allow dbpg to work with suspend/resume USB: ehci-dbgp,documentation: Documentation updates for ehci-dbgp ...
This commit is contained in:
@@ -671,7 +671,7 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||
earlyprintk= [X86,SH,BLACKFIN]
|
||||
earlyprintk=vga
|
||||
earlyprintk=serial[,ttySn[,baudrate]]
|
||||
earlyprintk=dbgp
|
||||
earlyprintk=dbgp[debugController#]
|
||||
|
||||
Append ",keep" to not disable it when the real console
|
||||
takes over.
|
||||
|
||||
@@ -16,20 +16,20 @@ Usage:
|
||||
|
||||
Authorize a device to connect:
|
||||
|
||||
$ echo 1 > /sys/usb/devices/DEVICE/authorized
|
||||
$ echo 1 > /sys/bus/usb/devices/DEVICE/authorized
|
||||
|
||||
Deauthorize a device:
|
||||
|
||||
$ echo 0 > /sys/usb/devices/DEVICE/authorized
|
||||
$ echo 0 > /sys/bus/usb/devices/DEVICE/authorized
|
||||
|
||||
Set new devices connected to hostX to be deauthorized by default (ie:
|
||||
lock down):
|
||||
|
||||
$ echo 0 > /sys/bus/devices/usbX/authorized_default
|
||||
$ echo 0 > /sys/bus/usb/devices/usbX/authorized_default
|
||||
|
||||
Remove the lock down:
|
||||
|
||||
$ echo 1 > /sys/bus/devices/usbX/authorized_default
|
||||
$ echo 1 > /sys/bus/usb/devices/usbX/authorized_default
|
||||
|
||||
By default, Wired USB devices are authorized by default to
|
||||
connect. Wireless USB hosts deauthorize by default all new connected
|
||||
@@ -47,7 +47,7 @@ USB port):
|
||||
boot up
|
||||
rc.local ->
|
||||
|
||||
for host in /sys/bus/devices/usb*
|
||||
for host in /sys/bus/usb/devices/usb*
|
||||
do
|
||||
echo 0 > $host/authorized_default
|
||||
done
|
||||
|
||||
@@ -33,7 +33,7 @@ if usbmon is built into the kernel.
|
||||
|
||||
Verify that bus sockets are present.
|
||||
|
||||
# ls /sys/kernel/debug/usbmon
|
||||
# ls /sys/kernel/debug/usb/usbmon
|
||||
0s 0u 1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u
|
||||
#
|
||||
|
||||
@@ -58,11 +58,11 @@ Bus=03 means it's bus 3.
|
||||
|
||||
3. Start 'cat'
|
||||
|
||||
# cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out
|
||||
# cat /sys/kernel/debug/usb/usbmon/3u > /tmp/1.mon.out
|
||||
|
||||
to listen on a single bus, otherwise, to listen on all buses, type:
|
||||
|
||||
# cat /sys/kernel/debug/usbmon/0u > /tmp/1.mon.out
|
||||
# cat /sys/kernel/debug/usb/usbmon/0u > /tmp/1.mon.out
|
||||
|
||||
This process will be reading until killed. Naturally, the output can be
|
||||
redirected to a desirable location. This is preferred, because it is going
|
||||
@@ -305,7 +305,7 @@ Before the call, hdr, data, and alloc should be filled. Upon return, the area
|
||||
pointed by hdr contains the next event structure, and the data buffer contains
|
||||
the data, if any. The event is removed from the kernel buffer.
|
||||
|
||||
The MON_IOCX_GET copies 48 bytes, MON_IOCX_GETX copies 64 bytes.
|
||||
The MON_IOCX_GET copies 48 bytes to hdr area, MON_IOCX_GETX copies 64 bytes.
|
||||
|
||||
MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ and two USB cables, connected like this:
|
||||
|
||||
[host/target] <-------> [USB debug key] <-------> [client/console]
|
||||
|
||||
1. There are three specific hardware requirements:
|
||||
1. There are a number of specific hardware requirements:
|
||||
|
||||
a.) Host/target system needs to have USB debug port capability.
|
||||
|
||||
@@ -42,7 +42,35 @@ and two USB cables, connected like this:
|
||||
This is a small blue plastic connector with two USB connections,
|
||||
it draws power from its USB connections.
|
||||
|
||||
c.) Thirdly, you need a second client/console system with a regular USB port.
|
||||
c.) You need a second client/console system with a high speed USB 2.0
|
||||
port.
|
||||
|
||||
d.) The Netchip device must be plugged directly into the physical
|
||||
debug port on the "host/target" system. You cannot use a USB hub in
|
||||
between the physical debug port and the "host/target" system.
|
||||
|
||||
The EHCI debug controller is bound to a specific physical USB
|
||||
port and the Netchip device will only work as an early printk
|
||||
device in this port. The EHCI host controllers are electrically
|
||||
wired such that the EHCI debug controller is hooked up to the
|
||||
first physical and there is no way to change this via software.
|
||||
You can find the physical port through experimentation by trying
|
||||
each physical port on the system and rebooting. Or you can try
|
||||
and use lsusb or look at the kernel info messages emitted by the
|
||||
usb stack when you plug a usb device into various ports on the
|
||||
"host/target" system.
|
||||
|
||||
Some hardware vendors do not expose the usb debug port with a
|
||||
physical connector and if you find such a device send a complaint
|
||||
to the hardware vendor, because there is no reason not to wire
|
||||
this port into one of the physically accessible ports.
|
||||
|
||||
e.) It is also important to note, that many versions of the Netchip
|
||||
device require the "client/console" system to be plugged into the
|
||||
right and side of the device (with the product logo facing up and
|
||||
readable left to right). The reason being is that the 5 volt
|
||||
power supply is taken from only one side of the device and it
|
||||
must be the side that does not get rebooted.
|
||||
|
||||
2. Software requirements:
|
||||
|
||||
@@ -56,6 +84,13 @@ and two USB cables, connected like this:
|
||||
(If you are using Grub, append it to the 'kernel' line in
|
||||
/etc/grub.conf)
|
||||
|
||||
On systems with more than one EHCI debug controller you must
|
||||
specify the correct EHCI debug controller number. The ordering
|
||||
comes from the PCI bus enumeration of the EHCI controllers. The
|
||||
default with no number argument is "0" the first EHCI debug
|
||||
controller. To use the second EHCI debug controller, you would
|
||||
use the command line: "earlyprintk=dbgp1"
|
||||
|
||||
NOTE: normally earlyprintk console gets turned off once the
|
||||
regular console is alive - use "earlyprintk=dbgp,keep" to keep
|
||||
this channel open beyond early bootup. This can be useful for
|
||||
|
||||
+2
-2
@@ -2107,12 +2107,12 @@ S: Supported
|
||||
F: arch/powerpc/sysdev/qe_lib/
|
||||
F: arch/powerpc/include/asm/*qe.h
|
||||
|
||||
FREESCALE HIGHSPEED USB DEVICE DRIVER
|
||||
FREESCALE USB PERIPHERIAL DRIVERS
|
||||
M: Li Yang <leoli@freescale.com>
|
||||
L: linux-usb@vger.kernel.org
|
||||
L: linuxppc-dev@ozlabs.org
|
||||
S: Maintained
|
||||
F: drivers/usb/gadget/fsl_usb2_udc.c
|
||||
F: drivers/usb/gadget/fsl*
|
||||
|
||||
FREESCALE QUICC ENGINE UCC ETHERNET DRIVER
|
||||
M: Li Yang <leoli@freescale.com>
|
||||
|
||||
+32
-746
File diff suppressed because it is too large
Load Diff
@@ -300,20 +300,23 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
crc = get_unaligned_le32(skb2->data
|
||||
+ len - ETH_FCS_LEN);
|
||||
skb_trim(skb2, len - ETH_FCS_LEN);
|
||||
|
||||
/*
|
||||
* The bmCRC helps to denote when the CRC field in
|
||||
* the Ethernet frame contains a calculated CRC:
|
||||
* bmCRC = 1 : CRC is calculated
|
||||
* bmCRC = 0 : CRC = 0xDEADBEEF
|
||||
*/
|
||||
if (header & BIT(14))
|
||||
crc2 = ~crc32_le(~0, skb2->data, skb2->len);
|
||||
else
|
||||
if (header & BIT(14)) {
|
||||
crc = get_unaligned_le32(skb2->data
|
||||
+ len - ETH_FCS_LEN);
|
||||
crc2 = ~crc32_le(~0, skb2->data, skb2->len
|
||||
- ETH_FCS_LEN);
|
||||
} else {
|
||||
crc = get_unaligned_be32(skb2->data
|
||||
+ len - ETH_FCS_LEN);
|
||||
crc2 = 0xdeadbeef;
|
||||
}
|
||||
skb_trim(skb2, len - ETH_FCS_LEN);
|
||||
|
||||
if (is_last)
|
||||
return crc == crc2;
|
||||
|
||||
@@ -39,6 +39,7 @@ config USB_ARCH_HAS_OHCI
|
||||
default y if ARCH_AT91
|
||||
default y if ARCH_PNX4008 && I2C
|
||||
default y if MFD_TC6393XB
|
||||
default y if ARCH_W90X900
|
||||
# PPC:
|
||||
default y if STB03xxx
|
||||
default y if PPC_MPC52xx
|
||||
@@ -58,6 +59,8 @@ config USB_ARCH_HAS_EHCI
|
||||
default y if PPC_83xx
|
||||
default y if SOC_AU1200
|
||||
default y if ARCH_IXP4XX
|
||||
default y if ARCH_W90X900
|
||||
default y if ARCH_AT91SAM9G45
|
||||
default PCI
|
||||
|
||||
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
|
||||
|
||||
@@ -16,6 +16,7 @@ obj-$(CONFIG_USB_UHCI_HCD) += host/
|
||||
obj-$(CONFIG_USB_FHCI_HCD) += host/
|
||||
obj-$(CONFIG_USB_XHCI_HCD) += host/
|
||||
obj-$(CONFIG_USB_SL811_HCD) += host/
|
||||
obj-$(CONFIG_USB_ISP1362_HCD) += host/
|
||||
obj-$(CONFIG_USB_U132_HCD) += host/
|
||||
obj-$(CONFIG_USB_R8A66597_HCD) += host/
|
||||
obj-$(CONFIG_USB_HWA_HCD) += host/
|
||||
@@ -39,6 +40,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
|
||||
obj-$(CONFIG_USB_SERIAL) += serial/
|
||||
|
||||
obj-$(CONFIG_USB) += misc/
|
||||
obj-y += early/
|
||||
|
||||
obj-$(CONFIG_USB_ATM) += atm/
|
||||
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/tty_driver.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/module.h>
|
||||
@@ -609,6 +610,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
acm->throttle = 0;
|
||||
|
||||
tasklet_schedule(&acm->urb_task);
|
||||
set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
|
||||
rv = tty_port_block_til_ready(&acm->port, tty, filp);
|
||||
done:
|
||||
mutex_unlock(&acm->mutex);
|
||||
|
||||
@@ -313,8 +313,13 @@ static ssize_t wdm_write
|
||||
r = usb_autopm_get_interface(desc->intf);
|
||||
if (r < 0)
|
||||
goto outnp;
|
||||
r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
|
||||
&desc->flags));
|
||||
|
||||
if (!file->f_flags && O_NONBLOCK)
|
||||
r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
|
||||
&desc->flags));
|
||||
else
|
||||
if (test_bit(WDM_IN_USE, &desc->flags))
|
||||
r = -EAGAIN;
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
@@ -377,7 +382,7 @@ outnl:
|
||||
static ssize_t wdm_read
|
||||
(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
int rv, cntr;
|
||||
int rv, cntr = 0;
|
||||
int i = 0;
|
||||
struct wdm_device *desc = file->private_data;
|
||||
|
||||
@@ -389,10 +394,23 @@ static ssize_t wdm_read
|
||||
if (desc->length == 0) {
|
||||
desc->read = 0;
|
||||
retry:
|
||||
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
|
||||
rv = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
i++;
|
||||
rv = wait_event_interruptible(desc->wait,
|
||||
test_bit(WDM_READ, &desc->flags));
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (!test_bit(WDM_READ, &desc->flags)) {
|
||||
rv = cntr ? cntr : -EAGAIN;
|
||||
goto err;
|
||||
}
|
||||
rv = 0;
|
||||
} else {
|
||||
rv = wait_event_interruptible(desc->wait,
|
||||
test_bit(WDM_READ, &desc->flags));
|
||||
}
|
||||
|
||||
/* may have happened while we slept */
|
||||
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
|
||||
rv = -ENODEV;
|
||||
goto err;
|
||||
@@ -448,7 +466,7 @@ retry:
|
||||
|
||||
err:
|
||||
mutex_unlock(&desc->rlock);
|
||||
if (rv < 0)
|
||||
if (rv < 0 && rv != -EAGAIN)
|
||||
dev_err(&desc->intf->dev, "wdm_read: exit error\n");
|
||||
return rv;
|
||||
}
|
||||
|
||||
+69
-15
@@ -57,7 +57,9 @@ MODULE_DEVICE_TABLE(usb, usbtmc_devices);
|
||||
|
||||
/*
|
||||
* This structure is the capabilities for the device
|
||||
* See section 4.2.1.8 of the USBTMC specification for details.
|
||||
* See section 4.2.1.8 of the USBTMC specification,
|
||||
* and section 4.2.2 of the USBTMC usb488 subclass
|
||||
* specification for details.
|
||||
*/
|
||||
struct usbtmc_dev_capabilities {
|
||||
__u8 interface_capabilities;
|
||||
@@ -86,6 +88,8 @@ struct usbtmc_device_data {
|
||||
bool TermCharEnabled;
|
||||
bool auto_abort;
|
||||
|
||||
bool zombie; /* fd of disconnected device */
|
||||
|
||||
struct usbtmc_dev_capabilities capabilities;
|
||||
struct kref kref;
|
||||
struct mutex io_mutex; /* only one i/o function running at a time */
|
||||
@@ -367,13 +371,13 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
|
||||
{
|
||||
struct usbtmc_device_data *data;
|
||||
struct device *dev;
|
||||
unsigned long int n_characters;
|
||||
u32 n_characters;
|
||||
u8 *buffer;
|
||||
int actual;
|
||||
int done;
|
||||
int remaining;
|
||||
size_t done;
|
||||
size_t remaining;
|
||||
int retval;
|
||||
int this_part;
|
||||
size_t this_part;
|
||||
|
||||
/* Get pointer to private data structure */
|
||||
data = filp->private_data;
|
||||
@@ -384,6 +388,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&data->io_mutex);
|
||||
if (data->zombie) {
|
||||
retval = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
remaining = count;
|
||||
done = 0;
|
||||
@@ -401,10 +409,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
|
||||
buffer[1] = data->bTag;
|
||||
buffer[2] = ~(data->bTag);
|
||||
buffer[3] = 0; /* Reserved */
|
||||
buffer[4] = (this_part - 12 - 3) & 255;
|
||||
buffer[5] = ((this_part - 12 - 3) >> 8) & 255;
|
||||
buffer[6] = ((this_part - 12 - 3) >> 16) & 255;
|
||||
buffer[7] = ((this_part - 12 - 3) >> 24) & 255;
|
||||
buffer[4] = (this_part) & 255;
|
||||
buffer[5] = ((this_part) >> 8) & 255;
|
||||
buffer[6] = ((this_part) >> 16) & 255;
|
||||
buffer[7] = ((this_part) >> 24) & 255;
|
||||
buffer[8] = data->TermCharEnabled * 2;
|
||||
/* Use term character? */
|
||||
buffer[9] = data->TermChar;
|
||||
@@ -455,6 +463,22 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
|
||||
(buffer[6] << 16) +
|
||||
(buffer[7] << 24);
|
||||
|
||||
/* Ensure the instrument doesn't lie about it */
|
||||
if(n_characters > actual - 12) {
|
||||
dev_err(dev, "Device lies about message size: %u > %d\n", n_characters, actual - 12);
|
||||
n_characters = actual - 12;
|
||||
}
|
||||
|
||||
/* Ensure the instrument doesn't send more back than requested */
|
||||
if(n_characters > this_part) {
|
||||
dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part);
|
||||
n_characters = this_part;
|
||||
}
|
||||
|
||||
/* Bound amount of data received by amount of data requested */
|
||||
if (n_characters > this_part)
|
||||
n_characters = this_part;
|
||||
|
||||
/* Copy buffer to user space */
|
||||
if (copy_to_user(buf + done, &buffer[12], n_characters)) {
|
||||
/* There must have been an addressing problem */
|
||||
@@ -463,8 +487,11 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
|
||||
}
|
||||
|
||||
done += n_characters;
|
||||
if (n_characters < USBTMC_SIZE_IOBUFFER)
|
||||
/* Terminate if end-of-message bit recieved from device */
|
||||
if ((buffer[8] & 0x01) && (actual >= n_characters + 12))
|
||||
remaining = 0;
|
||||
else
|
||||
remaining -= n_characters;
|
||||
}
|
||||
|
||||
/* Update file position value */
|
||||
@@ -496,6 +523,10 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&data->io_mutex);
|
||||
if (data->zombie) {
|
||||
retval = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
remaining = count;
|
||||
done = 0;
|
||||
@@ -767,20 +798,21 @@ static int get_capabilities(struct usbtmc_device_data *data)
|
||||
}
|
||||
|
||||
dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
|
||||
dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]);
|
||||
dev_dbg(dev, "Device capabilities are %x\n", buffer[5]);
|
||||
dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]);
|
||||
dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]);
|
||||
if (buffer[0] != USBTMC_STATUS_SUCCESS) {
|
||||
dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
|
||||
rv = -EPERM;
|
||||
goto err_out;
|
||||
}
|
||||
dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]);
|
||||
dev_dbg(dev, "Device capabilities are %x\n", buffer[5]);
|
||||
dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]);
|
||||
dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]);
|
||||
|
||||
data->capabilities.interface_capabilities = buffer[4];
|
||||
data->capabilities.device_capabilities = buffer[5];
|
||||
data->capabilities.usb488_interface_capabilities = buffer[14];
|
||||
data->capabilities.usb488_device_capabilities = buffer[15];
|
||||
rv = 0;
|
||||
|
||||
err_out:
|
||||
kfree(buffer);
|
||||
@@ -925,6 +957,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
|
||||
data = file->private_data;
|
||||
mutex_lock(&data->io_mutex);
|
||||
if (data->zombie) {
|
||||
retval = -ENODEV;
|
||||
goto skip_io_on_zombie;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case USBTMC_IOCTL_CLEAR_OUT_HALT:
|
||||
@@ -952,6 +988,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
break;
|
||||
}
|
||||
|
||||
skip_io_on_zombie:
|
||||
mutex_unlock(&data->io_mutex);
|
||||
return retval;
|
||||
}
|
||||
@@ -995,6 +1032,7 @@ static int usbtmc_probe(struct usb_interface *intf,
|
||||
usb_set_intfdata(intf, data);
|
||||
kref_init(&data->kref);
|
||||
mutex_init(&data->io_mutex);
|
||||
data->zombie = 0;
|
||||
|
||||
/* Initialize USBTMC bTag and other fields */
|
||||
data->bTag = 1;
|
||||
@@ -1065,14 +1103,30 @@ static void usbtmc_disconnect(struct usb_interface *intf)
|
||||
usb_deregister_dev(intf, &usbtmc_class);
|
||||
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
|
||||
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
|
||||
mutex_lock(&data->io_mutex);
|
||||
data->zombie = 1;
|
||||
mutex_unlock(&data->io_mutex);
|
||||
kref_put(&data->kref, usbtmc_delete);
|
||||
}
|
||||
|
||||
static int usbtmc_suspend (struct usb_interface *intf, pm_message_t message)
|
||||
{
|
||||
/* this driver does not have pending URBs */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbtmc_resume (struct usb_interface *intf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_driver usbtmc_driver = {
|
||||
.name = "usbtmc",
|
||||
.id_table = usbtmc_devices,
|
||||
.probe = usbtmc_probe,
|
||||
.disconnect = usbtmc_disconnect
|
||||
.disconnect = usbtmc_disconnect,
|
||||
.suspend = usbtmc_suspend,
|
||||
.resume = usbtmc_resume,
|
||||
};
|
||||
|
||||
static int __init usbtmc_init(void)
|
||||
|
||||
@@ -105,7 +105,7 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
|
||||
ep->ss_ep_comp->extralen = i;
|
||||
buffer += i;
|
||||
size -= i;
|
||||
retval = buffer - buffer_start + i;
|
||||
retval = buffer - buffer_start;
|
||||
if (num_skipped > 0)
|
||||
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
|
||||
num_skipped, plural(num_skipped),
|
||||
|
||||
+176
-71
@@ -52,6 +52,7 @@
|
||||
|
||||
#include "hcd.h" /* for usbcore internals */
|
||||
#include "usb.h"
|
||||
#include "hub.h"
|
||||
|
||||
#define USB_MAXBUS 64
|
||||
#define USB_DEVICE_MAX USB_MAXBUS * 128
|
||||
@@ -73,6 +74,7 @@ struct dev_state {
|
||||
void __user *disccontext;
|
||||
unsigned long ifclaimed;
|
||||
u32 secid;
|
||||
u32 disabled_bulk_eps;
|
||||
};
|
||||
|
||||
struct async {
|
||||
@@ -87,6 +89,8 @@ struct async {
|
||||
struct urb *urb;
|
||||
int status;
|
||||
u32 secid;
|
||||
u8 bulk_addr;
|
||||
u8 bulk_status;
|
||||
};
|
||||
|
||||
static int usbfs_snoop;
|
||||
@@ -99,11 +103,15 @@ MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
|
||||
dev_info(dev , format , ## arg); \
|
||||
} while (0)
|
||||
|
||||
enum snoop_when {
|
||||
SUBMIT, COMPLETE
|
||||
};
|
||||
|
||||
#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)
|
||||
|
||||
|
||||
#define MAX_USBFS_BUFFER_SIZE 16384
|
||||
|
||||
|
||||
static int connected(struct dev_state *ps)
|
||||
{
|
||||
return (!list_empty(&ps->list) &&
|
||||
@@ -300,24 +308,79 @@ static struct async *async_getpending(struct dev_state *ps,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void snoop_urb(struct urb *urb, void __user *userurb)
|
||||
static void snoop_urb(struct usb_device *udev,
|
||||
void __user *userurb, int pipe, unsigned length,
|
||||
int timeout_or_status, enum snoop_when when)
|
||||
{
|
||||
unsigned j;
|
||||
unsigned char *data = urb->transfer_buffer;
|
||||
static const char *types[] = {"isoc", "int", "ctrl", "bulk"};
|
||||
static const char *dirs[] = {"out", "in"};
|
||||
int ep;
|
||||
const char *t, *d;
|
||||
|
||||
if (!usbfs_snoop)
|
||||
return;
|
||||
|
||||
dev_info(&urb->dev->dev, "direction=%s\n",
|
||||
usb_urb_dir_in(urb) ? "IN" : "OUT");
|
||||
dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
|
||||
dev_info(&urb->dev->dev, "transfer_buffer_length=%u\n",
|
||||
urb->transfer_buffer_length);
|
||||
dev_info(&urb->dev->dev, "actual_length=%u\n", urb->actual_length);
|
||||
dev_info(&urb->dev->dev, "data: ");
|
||||
for (j = 0; j < urb->transfer_buffer_length; ++j)
|
||||
printk("%02x ", data[j]);
|
||||
printk("\n");
|
||||
ep = usb_pipeendpoint(pipe);
|
||||
t = types[usb_pipetype(pipe)];
|
||||
d = dirs[!!usb_pipein(pipe)];
|
||||
|
||||
if (userurb) { /* Async */
|
||||
if (when == SUBMIT)
|
||||
dev_info(&udev->dev, "userurb %p, ep%d %s-%s, "
|
||||
"length %u\n",
|
||||
userurb, ep, t, d, length);
|
||||
else
|
||||
dev_info(&udev->dev, "userurb %p, ep%d %s-%s, "
|
||||
"actual_length %u status %d\n",
|
||||
userurb, ep, t, d, length,
|
||||
timeout_or_status);
|
||||
} else {
|
||||
if (when == SUBMIT)
|
||||
dev_info(&udev->dev, "ep%d %s-%s, length %u, "
|
||||
"timeout %d\n",
|
||||
ep, t, d, length, timeout_or_status);
|
||||
else
|
||||
dev_info(&udev->dev, "ep%d %s-%s, actual_length %u, "
|
||||
"status %d\n",
|
||||
ep, t, d, length, timeout_or_status);
|
||||
}
|
||||
}
|
||||
|
||||
#define AS_CONTINUATION 1
|
||||
#define AS_UNLINK 2
|
||||
|
||||
static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr)
|
||||
__releases(ps->lock)
|
||||
__acquires(ps->lock)
|
||||
{
|
||||
struct async *as;
|
||||
|
||||
/* Mark all the pending URBs that match bulk_addr, up to but not
|
||||
* including the first one without AS_CONTINUATION. If such an
|
||||
* URB is encountered then a new transfer has already started so
|
||||
* the endpoint doesn't need to be disabled; otherwise it does.
|
||||
*/
|
||||
list_for_each_entry(as, &ps->async_pending, asynclist) {
|
||||
if (as->bulk_addr == bulk_addr) {
|
||||
if (as->bulk_status != AS_CONTINUATION)
|
||||
goto rescan;
|
||||
as->bulk_status = AS_UNLINK;
|
||||
as->bulk_addr = 0;
|
||||
}
|
||||
}
|
||||
ps->disabled_bulk_eps |= (1 << bulk_addr);
|
||||
|
||||
/* Now carefully unlink all the marked pending URBs */
|
||||
rescan:
|
||||
list_for_each_entry(as, &ps->async_pending, asynclist) {
|
||||
if (as->bulk_status == AS_UNLINK) {
|
||||
as->bulk_status = 0; /* Only once */
|
||||
spin_unlock(&ps->lock); /* Allow completions */
|
||||
usb_unlink_urb(as->urb);
|
||||
spin_lock(&ps->lock);
|
||||
goto rescan;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void async_completed(struct urb *urb)
|
||||
@@ -346,7 +409,11 @@ static void async_completed(struct urb *urb)
|
||||
secid = as->secid;
|
||||
}
|
||||
snoop(&urb->dev->dev, "urb complete\n");
|
||||
snoop_urb(urb, as->userurb);
|
||||
snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
|
||||
as->status, COMPLETE);
|
||||
if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
|
||||
as->status != -ENOENT)
|
||||
cancel_bulk_urbs(ps, as->bulk_addr);
|
||||
spin_unlock(&ps->lock);
|
||||
|
||||
if (signr)
|
||||
@@ -655,6 +722,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
|
||||
struct async *as;
|
||||
|
||||
usb_lock_device(dev);
|
||||
usb_hub_release_all_ports(dev, ps);
|
||||
|
||||
/* Protect against simultaneous open */
|
||||
mutex_lock(&usbfs_mutex);
|
||||
@@ -688,7 +756,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)
|
||||
unsigned int tmo;
|
||||
unsigned char *tbuf;
|
||||
unsigned wLength;
|
||||
int i, j, ret;
|
||||
int i, pipe, ret;
|
||||
|
||||
if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
|
||||
return -EFAULT;
|
||||
@@ -708,24 +776,17 @@ static int proc_control(struct dev_state *ps, void __user *arg)
|
||||
free_page((unsigned long)tbuf);
|
||||
return -EINVAL;
|
||||
}
|
||||
snoop(&dev->dev, "control read: bRequest=%02x "
|
||||
"bRrequestType=%02x wValue=%04x "
|
||||
"wIndex=%04x wLength=%04x\n",
|
||||
ctrl.bRequest, ctrl.bRequestType, ctrl.wValue,
|
||||
ctrl.wIndex, ctrl.wLength);
|
||||
pipe = usb_rcvctrlpipe(dev, 0);
|
||||
snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
|
||||
|
||||
usb_unlock_device(dev);
|
||||
i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest,
|
||||
i = usb_control_msg(dev, pipe, ctrl.bRequest,
|
||||
ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
|
||||
tbuf, ctrl.wLength, tmo);
|
||||
usb_lock_device(dev);
|
||||
snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
|
||||
|
||||
if ((i > 0) && ctrl.wLength) {
|
||||
if (usbfs_snoop) {
|
||||
dev_info(&dev->dev, "control read: data ");
|
||||
for (j = 0; j < i; ++j)
|
||||
printk("%02x ", (u8)(tbuf)[j]);
|
||||
printk("\n");
|
||||
}
|
||||
if (copy_to_user(ctrl.data, tbuf, i)) {
|
||||
free_page((unsigned long)tbuf);
|
||||
return -EFAULT;
|
||||
@@ -738,22 +799,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
snoop(&dev->dev, "control write: bRequest=%02x "
|
||||
"bRrequestType=%02x wValue=%04x "
|
||||
"wIndex=%04x wLength=%04x\n",
|
||||
ctrl.bRequest, ctrl.bRequestType, ctrl.wValue,
|
||||
ctrl.wIndex, ctrl.wLength);
|
||||
if (usbfs_snoop) {
|
||||
dev_info(&dev->dev, "control write: data: ");
|
||||
for (j = 0; j < ctrl.wLength; ++j)
|
||||
printk("%02x ", (unsigned char)(tbuf)[j]);
|
||||
printk("\n");
|
||||
}
|
||||
pipe = usb_sndctrlpipe(dev, 0);
|
||||
snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
|
||||
|
||||
usb_unlock_device(dev);
|
||||
i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
|
||||
ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
|
||||
tbuf, ctrl.wLength, tmo);
|
||||
usb_lock_device(dev);
|
||||
snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
|
||||
}
|
||||
free_page((unsigned long)tbuf);
|
||||
if (i < 0 && i != -EPIPE) {
|
||||
@@ -772,7 +826,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
|
||||
unsigned int tmo, len1, pipe;
|
||||
int len2;
|
||||
unsigned char *tbuf;
|
||||
int i, j, ret;
|
||||
int i, ret;
|
||||
|
||||
if (copy_from_user(&bulk, arg, sizeof(bulk)))
|
||||
return -EFAULT;
|
||||
@@ -799,18 +853,14 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
|
||||
kfree(tbuf);
|
||||
return -EINVAL;
|
||||
}
|
||||
snoop(&dev->dev, "bulk read: len=0x%02x timeout=%04d\n",
|
||||
bulk.len, bulk.timeout);
|
||||
snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
|
||||
|
||||
usb_unlock_device(dev);
|
||||
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
|
||||
usb_lock_device(dev);
|
||||
snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
|
||||
|
||||
if (!i && len2) {
|
||||
if (usbfs_snoop) {
|
||||
dev_info(&dev->dev, "bulk read: data ");
|
||||
for (j = 0; j < len2; ++j)
|
||||
printk("%02x ", (u8)(tbuf)[j]);
|
||||
printk("\n");
|
||||
}
|
||||
if (copy_to_user(bulk.data, tbuf, len2)) {
|
||||
kfree(tbuf);
|
||||
return -EFAULT;
|
||||
@@ -823,17 +873,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
snoop(&dev->dev, "bulk write: len=0x%02x timeout=%04d\n",
|
||||
bulk.len, bulk.timeout);
|
||||
if (usbfs_snoop) {
|
||||
dev_info(&dev->dev, "bulk write: data: ");
|
||||
for (j = 0; j < len1; ++j)
|
||||
printk("%02x ", (unsigned char)(tbuf)[j]);
|
||||
printk("\n");
|
||||
}
|
||||
snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
|
||||
|
||||
usb_unlock_device(dev);
|
||||
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
|
||||
usb_lock_device(dev);
|
||||
snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
|
||||
}
|
||||
kfree(tbuf);
|
||||
if (i < 0)
|
||||
@@ -991,6 +1036,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
|
||||
|
||||
if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP |
|
||||
USBDEVFS_URB_SHORT_NOT_OK |
|
||||
USBDEVFS_URB_BULK_CONTINUATION |
|
||||
USBDEVFS_URB_NO_FSBR |
|
||||
USBDEVFS_URB_ZERO_PACKET |
|
||||
USBDEVFS_URB_NO_INTERRUPT))
|
||||
@@ -1051,13 +1097,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
|
||||
is_in = 0;
|
||||
uurb->endpoint &= ~USB_DIR_IN;
|
||||
}
|
||||
snoop(&ps->dev->dev, "control urb: bRequest=%02x "
|
||||
"bRrequestType=%02x wValue=%04x "
|
||||
"wIndex=%04x wLength=%04x\n",
|
||||
dr->bRequest, dr->bRequestType,
|
||||
__le16_to_cpup(&dr->wValue),
|
||||
__le16_to_cpup(&dr->wIndex),
|
||||
__le16_to_cpup(&dr->wLength));
|
||||
break;
|
||||
|
||||
case USBDEVFS_URB_TYPE_BULK:
|
||||
@@ -1070,7 +1109,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
|
||||
uurb->number_of_packets = 0;
|
||||
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
|
||||
return -EINVAL;
|
||||
snoop(&ps->dev->dev, "bulk urb\n");
|
||||
break;
|
||||
|
||||
case USBDEVFS_URB_TYPE_ISO:
|
||||
@@ -1097,12 +1135,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
|
||||
}
|
||||
totlen += isopkt[u].length;
|
||||
}
|
||||
if (totlen > 32768) {
|
||||
/* 3072 * 64 microframes */
|
||||
if (totlen > 196608) {
|
||||
kfree(isopkt);
|
||||
return -EINVAL;
|
||||
}
|
||||
uurb->buffer_length = totlen;
|
||||
snoop(&ps->dev->dev, "iso urb\n");
|
||||
break;
|
||||
|
||||
case USBDEVFS_URB_TYPE_INTERRUPT:
|
||||
@@ -1111,7 +1149,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
|
||||
return -EINVAL;
|
||||
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
|
||||
return -EINVAL;
|
||||
snoop(&ps->dev->dev, "interrupt urb\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1198,11 +1235,46 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
snoop_urb(as->urb, as->userurb);
|
||||
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
|
||||
as->urb->transfer_buffer_length, 0, SUBMIT);
|
||||
async_newpending(as);
|
||||
if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
|
||||
|
||||
if (usb_endpoint_xfer_bulk(&ep->desc)) {
|
||||
spin_lock_irq(&ps->lock);
|
||||
|
||||
/* Not exactly the endpoint address; the direction bit is
|
||||
* shifted to the 0x10 position so that the value will be
|
||||
* between 0 and 31.
|
||||
*/
|
||||
as->bulk_addr = usb_endpoint_num(&ep->desc) |
|
||||
((ep->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK)
|
||||
>> 3);
|
||||
|
||||
/* If this bulk URB is the start of a new transfer, re-enable
|
||||
* the endpoint. Otherwise mark it as a continuation URB.
|
||||
*/
|
||||
if (uurb->flags & USBDEVFS_URB_BULK_CONTINUATION)
|
||||
as->bulk_status = AS_CONTINUATION;
|
||||
else
|
||||
ps->disabled_bulk_eps &= ~(1 << as->bulk_addr);
|
||||
|
||||
/* Don't accept continuation URBs if the endpoint is
|
||||
* disabled because of an earlier error.
|
||||
*/
|
||||
if (ps->disabled_bulk_eps & (1 << as->bulk_addr))
|
||||
ret = -EREMOTEIO;
|
||||
else
|
||||
ret = usb_submit_urb(as->urb, GFP_ATOMIC);
|
||||
spin_unlock_irq(&ps->lock);
|
||||
} else {
|
||||
ret = usb_submit_urb(as->urb, GFP_KERNEL);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
dev_printk(KERN_DEBUG, &ps->dev->dev,
|
||||
"usbfs: usb_submit_urb returned %d\n", ret);
|
||||
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
|
||||
0, ret, COMPLETE);
|
||||
async_removepending(as);
|
||||
free_async(as);
|
||||
return ret;
|
||||
@@ -1548,6 +1620,29 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int proc_claim_port(struct dev_state *ps, void __user *arg)
|
||||
{
|
||||
unsigned portnum;
|
||||
int rc;
|
||||
|
||||
if (get_user(portnum, (unsigned __user *) arg))
|
||||
return -EFAULT;
|
||||
rc = usb_hub_claim_port(ps->dev, portnum, ps);
|
||||
if (rc == 0)
|
||||
snoop(&ps->dev->dev, "port %d claimed by process %d: %s\n",
|
||||
portnum, task_pid_nr(current), current->comm);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int proc_release_port(struct dev_state *ps, void __user *arg)
|
||||
{
|
||||
unsigned portnum;
|
||||
|
||||
if (get_user(portnum, (unsigned __user *) arg))
|
||||
return -EFAULT;
|
||||
return usb_hub_release_port(ps->dev, portnum, ps);
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: All requests here that have interface numbers as parameters
|
||||
* are assuming that somehow the configuration has been prevented from
|
||||
@@ -1645,7 +1740,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
|
||||
break;
|
||||
|
||||
case USBDEVFS_REAPURBNDELAY32:
|
||||
snoop(&dev->dev, "%s: REAPURBDELAY32\n", __func__);
|
||||
snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
|
||||
ret = proc_reapurbnonblock_compat(ps, p);
|
||||
break;
|
||||
|
||||
@@ -1666,7 +1761,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
|
||||
break;
|
||||
|
||||
case USBDEVFS_REAPURBNDELAY:
|
||||
snoop(&dev->dev, "%s: REAPURBDELAY\n", __func__);
|
||||
snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
|
||||
ret = proc_reapurbnonblock(ps, p);
|
||||
break;
|
||||
|
||||
@@ -1689,6 +1784,16 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
|
||||
snoop(&dev->dev, "%s: IOCTL\n", __func__);
|
||||
ret = proc_ioctl_default(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_CLAIM_PORT:
|
||||
snoop(&dev->dev, "%s: CLAIM_PORT\n", __func__);
|
||||
ret = proc_claim_port(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_RELEASE_PORT:
|
||||
snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__);
|
||||
ret = proc_release_port(ps, p);
|
||||
break;
|
||||
}
|
||||
usb_unlock_device(dev);
|
||||
if (ret >= 0)
|
||||
|
||||
+47
-28
@@ -207,6 +207,9 @@ static int usb_probe_interface(struct device *dev)
|
||||
|
||||
intf->needs_binding = 0;
|
||||
|
||||
if (usb_device_is_owned(udev))
|
||||
return -ENODEV;
|
||||
|
||||
if (udev->authorized == 0) {
|
||||
dev_err(&intf->dev, "Device is not authorized for usage\n");
|
||||
return -ENODEV;
|
||||
@@ -232,28 +235,35 @@ static int usb_probe_interface(struct device *dev)
|
||||
/* The interface should always appear to be in use
|
||||
* unless the driver suports autosuspend.
|
||||
*/
|
||||
intf->pm_usage_cnt = !(driver->supports_autosuspend);
|
||||
atomic_set(&intf->pm_usage_cnt, !driver->supports_autosuspend);
|
||||
|
||||
/* Carry out a deferred switch to altsetting 0 */
|
||||
if (intf->needs_altsetting0) {
|
||||
usb_set_interface(udev, intf->altsetting[0].
|
||||
error = usb_set_interface(udev, intf->altsetting[0].
|
||||
desc.bInterfaceNumber, 0);
|
||||
if (error < 0)
|
||||
goto err;
|
||||
|
||||
intf->needs_altsetting0 = 0;
|
||||
}
|
||||
|
||||
error = driver->probe(intf, id);
|
||||
if (error) {
|
||||
mark_quiesced(intf);
|
||||
intf->needs_remote_wakeup = 0;
|
||||
intf->condition = USB_INTERFACE_UNBOUND;
|
||||
usb_cancel_queued_reset(intf);
|
||||
} else
|
||||
intf->condition = USB_INTERFACE_BOUND;
|
||||
if (error)
|
||||
goto err;
|
||||
|
||||
intf->condition = USB_INTERFACE_BOUND;
|
||||
usb_autosuspend_device(udev);
|
||||
}
|
||||
|
||||
return error;
|
||||
|
||||
err:
|
||||
mark_quiesced(intf);
|
||||
intf->needs_remote_wakeup = 0;
|
||||
intf->condition = USB_INTERFACE_UNBOUND;
|
||||
usb_cancel_queued_reset(intf);
|
||||
usb_autosuspend_device(udev);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* called from driver core with dev locked */
|
||||
@@ -262,7 +272,7 @@ static int usb_unbind_interface(struct device *dev)
|
||||
struct usb_driver *driver = to_usb_driver(dev->driver);
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_device *udev;
|
||||
int error;
|
||||
int error, r;
|
||||
|
||||
intf->condition = USB_INTERFACE_UNBINDING;
|
||||
|
||||
@@ -290,11 +300,14 @@ static int usb_unbind_interface(struct device *dev)
|
||||
* Just re-enable it without affecting the endpoint toggles.
|
||||
*/
|
||||
usb_enable_interface(udev, intf, false);
|
||||
} else if (!error && intf->dev.power.status == DPM_ON)
|
||||
usb_set_interface(udev, intf->altsetting[0].
|
||||
} else if (!error && intf->dev.power.status == DPM_ON) {
|
||||
r = usb_set_interface(udev, intf->altsetting[0].
|
||||
desc.bInterfaceNumber, 0);
|
||||
else
|
||||
if (r < 0)
|
||||
intf->needs_altsetting0 = 1;
|
||||
} else {
|
||||
intf->needs_altsetting0 = 1;
|
||||
}
|
||||
usb_set_intfdata(intf, NULL);
|
||||
|
||||
intf->condition = USB_INTERFACE_UNBOUND;
|
||||
@@ -344,7 +357,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
|
||||
usb_pm_lock(udev);
|
||||
iface->condition = USB_INTERFACE_BOUND;
|
||||
mark_active(iface);
|
||||
iface->pm_usage_cnt = !(driver->supports_autosuspend);
|
||||
atomic_set(&iface->pm_usage_cnt, !driver->supports_autosuspend);
|
||||
usb_pm_unlock(udev);
|
||||
|
||||
/* if interface was already added, bind now; else let
|
||||
@@ -1065,7 +1078,7 @@ static int autosuspend_check(struct usb_device *udev, int reschedule)
|
||||
intf = udev->actconfig->interface[i];
|
||||
if (!is_active(intf))
|
||||
continue;
|
||||
if (intf->pm_usage_cnt > 0)
|
||||
if (atomic_read(&intf->pm_usage_cnt) > 0)
|
||||
return -EBUSY;
|
||||
if (intf->needs_remote_wakeup &&
|
||||
!udev->do_remote_wakeup) {
|
||||
@@ -1461,17 +1474,19 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
|
||||
status = -ENODEV;
|
||||
else {
|
||||
udev->auto_pm = 1;
|
||||
intf->pm_usage_cnt += inc_usage_cnt;
|
||||
atomic_add(inc_usage_cnt, &intf->pm_usage_cnt);
|
||||
udev->last_busy = jiffies;
|
||||
if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) {
|
||||
if (inc_usage_cnt >= 0 &&
|
||||
atomic_read(&intf->pm_usage_cnt) > 0) {
|
||||
if (udev->state == USB_STATE_SUSPENDED)
|
||||
status = usb_resume_both(udev,
|
||||
PMSG_AUTO_RESUME);
|
||||
if (status != 0)
|
||||
intf->pm_usage_cnt -= inc_usage_cnt;
|
||||
atomic_sub(inc_usage_cnt, &intf->pm_usage_cnt);
|
||||
else
|
||||
udev->last_busy = jiffies;
|
||||
} else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) {
|
||||
} else if (inc_usage_cnt <= 0 &&
|
||||
atomic_read(&intf->pm_usage_cnt) <= 0) {
|
||||
status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
|
||||
}
|
||||
}
|
||||
@@ -1516,7 +1531,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",
|
||||
__func__, status, intf->pm_usage_cnt);
|
||||
__func__, status, atomic_read(&intf->pm_usage_cnt));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
|
||||
|
||||
@@ -1544,10 +1559,10 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
|
||||
status = -ENODEV;
|
||||
} else {
|
||||
udev->last_busy = jiffies;
|
||||
--intf->pm_usage_cnt;
|
||||
atomic_dec(&intf->pm_usage_cnt);
|
||||
if (udev->autosuspend_disabled || udev->autosuspend_delay < 0)
|
||||
status = -EPERM;
|
||||
else if (intf->pm_usage_cnt <= 0 &&
|
||||
else if (atomic_read(&intf->pm_usage_cnt) <= 0 &&
|
||||
!timer_pending(&udev->autosuspend.timer)) {
|
||||
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
|
||||
round_jiffies_up_relative(
|
||||
@@ -1555,7 +1570,7 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
|
||||
}
|
||||
}
|
||||
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
|
||||
__func__, status, intf->pm_usage_cnt);
|
||||
__func__, status, atomic_read(&intf->pm_usage_cnt));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
|
||||
|
||||
@@ -1599,7 +1614,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",
|
||||
__func__, status, intf->pm_usage_cnt);
|
||||
__func__, status, atomic_read(&intf->pm_usage_cnt));
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
|
||||
@@ -1627,10 +1642,14 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
|
||||
status = -ENODEV;
|
||||
else if (udev->autoresume_disabled)
|
||||
status = -EPERM;
|
||||
else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED)
|
||||
queue_work(ksuspend_usb_wq, &udev->autoresume);
|
||||
else {
|
||||
atomic_inc(&intf->pm_usage_cnt);
|
||||
if (atomic_read(&intf->pm_usage_cnt) > 0 &&
|
||||
udev->state == USB_STATE_SUSPENDED)
|
||||
queue_work(ksuspend_usb_wq, &udev->autoresume);
|
||||
}
|
||||
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
|
||||
__func__, status, intf->pm_usage_cnt);
|
||||
__func__, status, atomic_read(&intf->pm_usage_cnt));
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
|
||||
@@ -1652,7 +1671,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",
|
||||
__func__, status, intf->pm_usage_cnt);
|
||||
__func__, status, atomic_read(&intf->pm_usage_cnt));
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
|
||||
|
||||
@@ -158,7 +158,9 @@ static int generic_probe(struct usb_device *udev)
|
||||
/* Choose and set the configuration. This registers the interfaces
|
||||
* with the driver core and lets interface drivers bind to them.
|
||||
*/
|
||||
if (udev->authorized == 0)
|
||||
if (usb_device_is_owned(udev))
|
||||
; /* Don't configure if the device is owned */
|
||||
else if (udev->authorized == 0)
|
||||
dev_err(&udev->dev, "Device is not authorized for usage\n");
|
||||
else {
|
||||
c = usb_choose_configuration(udev);
|
||||
|
||||
+64
-47
@@ -337,72 +337,89 @@ static const u8 ss_rh_config_descriptor[] = {
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* helper routine for returning string descriptors in UTF-16LE
|
||||
* input can actually be ISO-8859-1; ASCII is its 7-bit subset
|
||||
/**
|
||||
* ascii2desc() - Helper routine for producing UTF-16LE string descriptors
|
||||
* @s: Null-terminated ASCII (actually ISO-8859-1) string
|
||||
* @buf: Buffer for USB string descriptor (header + UTF-16LE)
|
||||
* @len: Length (in bytes; may be odd) of descriptor buffer.
|
||||
*
|
||||
* The return value is the number of bytes filled in: 2 + 2*strlen(s) or
|
||||
* buflen, whichever is less.
|
||||
*
|
||||
* USB String descriptors can contain at most 126 characters; input
|
||||
* strings longer than that are truncated.
|
||||
*/
|
||||
static unsigned ascii2utf(char *s, u8 *utf, int utfmax)
|
||||
static unsigned
|
||||
ascii2desc(char const *s, u8 *buf, unsigned len)
|
||||
{
|
||||
unsigned retval;
|
||||
unsigned n, t = 2 + 2*strlen(s);
|
||||
|
||||
for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
|
||||
*utf++ = *s++;
|
||||
*utf++ = 0;
|
||||
if (t > 254)
|
||||
t = 254; /* Longest possible UTF string descriptor */
|
||||
if (len > t)
|
||||
len = t;
|
||||
|
||||
t += USB_DT_STRING << 8; /* Now t is first 16 bits to store */
|
||||
|
||||
n = len;
|
||||
while (n--) {
|
||||
*buf++ = t;
|
||||
if (!n--)
|
||||
break;
|
||||
*buf++ = t >> 8;
|
||||
t = (unsigned char)*s++;
|
||||
}
|
||||
if (utfmax > 0) {
|
||||
*utf = *s;
|
||||
++retval;
|
||||
}
|
||||
return retval;
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* rh_string - provides manufacturer, product and serial strings for root hub
|
||||
* @id: the string ID number (1: serial number, 2: product, 3: vendor)
|
||||
/**
|
||||
* rh_string() - provides string descriptors for root hub
|
||||
* @id: the string ID number (0: langids, 1: serial #, 2: product, 3: vendor)
|
||||
* @hcd: the host controller for this root hub
|
||||
* @data: return packet in UTF-16 LE
|
||||
* @len: length of the return packet
|
||||
* @data: buffer for output packet
|
||||
* @len: length of the provided buffer
|
||||
*
|
||||
* Produces either a manufacturer, product or serial number string for the
|
||||
* virtual root hub device.
|
||||
* Returns the number of bytes filled in: the length of the descriptor or
|
||||
* of the provided buffer, whichever is less.
|
||||
*/
|
||||
static unsigned rh_string(int id, struct usb_hcd *hcd, u8 *data, unsigned len)
|
||||
static unsigned
|
||||
rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len)
|
||||
{
|
||||
char buf [100];
|
||||
char buf[100];
|
||||
char const *s;
|
||||
static char const langids[4] = {4, USB_DT_STRING, 0x09, 0x04};
|
||||
|
||||
// language ids
|
||||
if (id == 0) {
|
||||
buf[0] = 4; buf[1] = 3; /* 4 bytes string data */
|
||||
buf[2] = 0x09; buf[3] = 0x04; /* MSFT-speak for "en-us" */
|
||||
len = min_t(unsigned, len, 4);
|
||||
memcpy (data, buf, len);
|
||||
switch (id) {
|
||||
case 0:
|
||||
/* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */
|
||||
/* See http://www.usb.org/developers/docs/USB_LANGIDs.pdf */
|
||||
if (len > 4)
|
||||
len = 4;
|
||||
memcpy(data, langids, len);
|
||||
return len;
|
||||
|
||||
// serial number
|
||||
} else if (id == 1) {
|
||||
strlcpy (buf, hcd->self.bus_name, sizeof buf);
|
||||
|
||||
// product description
|
||||
} else if (id == 2) {
|
||||
strlcpy (buf, hcd->product_desc, sizeof buf);
|
||||
|
||||
// id 3 == vendor description
|
||||
} else if (id == 3) {
|
||||
case 1:
|
||||
/* Serial number */
|
||||
s = hcd->self.bus_name;
|
||||
break;
|
||||
case 2:
|
||||
/* Product name */
|
||||
s = hcd->product_desc;
|
||||
break;
|
||||
case 3:
|
||||
/* Manufacturer */
|
||||
snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname,
|
||||
init_utsname()->release, hcd->driver->description);
|
||||
s = buf;
|
||||
break;
|
||||
default:
|
||||
/* Can't happen; caller guarantees it */
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (len) { /* All cases fall through */
|
||||
default:
|
||||
len = 2 + ascii2utf (buf, data + 2, len - 2);
|
||||
case 2:
|
||||
data [1] = 3; /* type == string */
|
||||
case 1:
|
||||
data [0] = 2 * (strlen (buf) + 1);
|
||||
case 0:
|
||||
; /* Compiler wants a statement here */
|
||||
}
|
||||
return len;
|
||||
return ascii2desc(s, data, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -267,6 +267,11 @@ struct hc_driver {
|
||||
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
|
||||
/* Returns the hardware-chosen device address */
|
||||
int (*address_device)(struct usb_hcd *, struct usb_device *udev);
|
||||
/* Notifies the HCD after a hub descriptor is fetched.
|
||||
* Will block.
|
||||
*/
|
||||
int (*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags);
|
||||
};
|
||||
|
||||
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
|
||||
|
||||
+108
-18
@@ -78,6 +78,7 @@ struct usb_hub {
|
||||
u8 indicator[USB_MAXCHILDREN];
|
||||
struct delayed_work leds;
|
||||
struct delayed_work init_work;
|
||||
void **port_owners;
|
||||
};
|
||||
|
||||
|
||||
@@ -162,8 +163,10 @@ static inline char *portspeed(int portstatus)
|
||||
}
|
||||
|
||||
/* Note that hdev or one of its children must be locked! */
|
||||
static inline struct usb_hub *hdev_to_hub(struct usb_device *hdev)
|
||||
static struct usb_hub *hdev_to_hub(struct usb_device *hdev)
|
||||
{
|
||||
if (!hdev || !hdev->actconfig)
|
||||
return NULL;
|
||||
return usb_get_intfdata(hdev->actconfig->interface[0]);
|
||||
}
|
||||
|
||||
@@ -372,7 +375,7 @@ static void kick_khubd(struct usb_hub *hub)
|
||||
unsigned long flags;
|
||||
|
||||
/* Suppress autosuspend until khubd runs */
|
||||
to_usb_interface(hub->intfdev)->pm_usage_cnt = 1;
|
||||
atomic_set(&to_usb_interface(hub->intfdev)->pm_usage_cnt, 1);
|
||||
|
||||
spin_lock_irqsave(&hub_event_lock, flags);
|
||||
if (!hub->disconnected && list_empty(&hub->event_list)) {
|
||||
@@ -384,8 +387,10 @@ static void kick_khubd(struct usb_hub *hub)
|
||||
|
||||
void usb_kick_khubd(struct usb_device *hdev)
|
||||
{
|
||||
/* FIXME: What if hdev isn't bound to the hub driver? */
|
||||
kick_khubd(hdev_to_hub(hdev));
|
||||
struct usb_hub *hub = hdev_to_hub(hdev);
|
||||
|
||||
if (hub)
|
||||
kick_khubd(hub);
|
||||
}
|
||||
|
||||
|
||||
@@ -677,7 +682,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
||||
msecs_to_jiffies(delay));
|
||||
|
||||
/* Suppress autosuspend until init is done */
|
||||
to_usb_interface(hub->intfdev)->pm_usage_cnt = 1;
|
||||
atomic_set(&to_usb_interface(hub->intfdev)->
|
||||
pm_usage_cnt, 1);
|
||||
return; /* Continues at init2: below */
|
||||
} else {
|
||||
hub_power_on(hub, true);
|
||||
@@ -854,25 +860,24 @@ static int hub_post_reset(struct usb_interface *intf)
|
||||
static int hub_configure(struct usb_hub *hub,
|
||||
struct usb_endpoint_descriptor *endpoint)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
struct device *hub_dev = hub->intfdev;
|
||||
u16 hubstatus, hubchange;
|
||||
u16 wHubCharacteristics;
|
||||
unsigned int pipe;
|
||||
int maxp, ret;
|
||||
char *message;
|
||||
char *message = "out of memory";
|
||||
|
||||
hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,
|
||||
&hub->buffer_dma);
|
||||
if (!hub->buffer) {
|
||||
message = "can't allocate hub irq buffer";
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
|
||||
if (!hub->status) {
|
||||
message = "can't kmalloc hub status buffer";
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
@@ -880,7 +885,6 @@ static int hub_configure(struct usb_hub *hub,
|
||||
|
||||
hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
|
||||
if (!hub->descriptor) {
|
||||
message = "can't kmalloc hub descriptor";
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
@@ -904,6 +908,12 @@ static int hub_configure(struct usb_hub *hub,
|
||||
dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
|
||||
(hdev->maxchild == 1) ? "" : "s");
|
||||
|
||||
hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
|
||||
if (!hub->port_owners) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
|
||||
|
||||
if (wHubCharacteristics & HUB_CHAR_COMPOUND) {
|
||||
@@ -1052,6 +1062,19 @@ static int hub_configure(struct usb_hub *hub,
|
||||
dev_dbg(hub_dev, "%umA bus power budget for each child\n",
|
||||
hub->mA_per_port);
|
||||
|
||||
/* Update the HCD's internal representation of this hub before khubd
|
||||
* starts getting port status changes for devices under the hub.
|
||||
*/
|
||||
hcd = bus_to_hcd(hdev->bus);
|
||||
if (hcd->driver->update_hub_device) {
|
||||
ret = hcd->driver->update_hub_device(hcd, hdev,
|
||||
&hub->tt, GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
message = "can't update HCD hub info";
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = hub_hub_status(hub, &hubstatus, &hubchange);
|
||||
if (ret < 0) {
|
||||
message = "can't get hub status";
|
||||
@@ -1082,7 +1105,6 @@ static int hub_configure(struct usb_hub *hub,
|
||||
|
||||
hub->urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!hub->urb) {
|
||||
message = "couldn't allocate interrupt urb";
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
@@ -1131,11 +1153,13 @@ static void hub_disconnect(struct usb_interface *intf)
|
||||
hub_quiesce(hub, HUB_DISCONNECT);
|
||||
|
||||
usb_set_intfdata (intf, NULL);
|
||||
hub->hdev->maxchild = 0;
|
||||
|
||||
if (hub->hdev->speed == USB_SPEED_HIGH)
|
||||
highspeed_hubs--;
|
||||
|
||||
usb_free_urb(hub->urb);
|
||||
kfree(hub->port_owners);
|
||||
kfree(hub->descriptor);
|
||||
kfree(hub->status);
|
||||
usb_buffer_free(hub->hdev, sizeof(*hub->buffer), hub->buffer,
|
||||
@@ -1250,6 +1274,79 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow user programs to claim ports on a hub. When a device is attached
|
||||
* to one of these "claimed" ports, the program will "own" the device.
|
||||
*/
|
||||
static int find_port_owner(struct usb_device *hdev, unsigned port1,
|
||||
void ***ppowner)
|
||||
{
|
||||
if (hdev->state == USB_STATE_NOTATTACHED)
|
||||
return -ENODEV;
|
||||
if (port1 == 0 || port1 > hdev->maxchild)
|
||||
return -EINVAL;
|
||||
|
||||
/* This assumes that devices not managed by the hub driver
|
||||
* will always have maxchild equal to 0.
|
||||
*/
|
||||
*ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In the following three functions, the caller must hold hdev's lock */
|
||||
int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, void *owner)
|
||||
{
|
||||
int rc;
|
||||
void **powner;
|
||||
|
||||
rc = find_port_owner(hdev, port1, &powner);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (*powner)
|
||||
return -EBUSY;
|
||||
*powner = owner;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner)
|
||||
{
|
||||
int rc;
|
||||
void **powner;
|
||||
|
||||
rc = find_port_owner(hdev, port1, &powner);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (*powner != owner)
|
||||
return -ENOENT;
|
||||
*powner = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
void usb_hub_release_all_ports(struct usb_device *hdev, void *owner)
|
||||
{
|
||||
int n;
|
||||
void **powner;
|
||||
|
||||
n = find_port_owner(hdev, 1, &powner);
|
||||
if (n == 0) {
|
||||
for (; n < hdev->maxchild; (++n, ++powner)) {
|
||||
if (*powner == owner)
|
||||
*powner = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The caller must hold udev's lock */
|
||||
bool usb_device_is_owned(struct usb_device *udev)
|
||||
{
|
||||
struct usb_hub *hub;
|
||||
|
||||
if (udev->state == USB_STATE_NOTATTACHED || !udev->parent)
|
||||
return false;
|
||||
hub = hdev_to_hub(udev->parent);
|
||||
return !!hub->port_owners[udev->portnum - 1];
|
||||
}
|
||||
|
||||
|
||||
static void recursively_mark_NOTATTACHED(struct usb_device *udev)
|
||||
{
|
||||
@@ -2849,14 +2946,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
/* For a suspended device, treat this as a
|
||||
* remote wakeup event.
|
||||
*/
|
||||
if (udev->do_remote_wakeup)
|
||||
status = remote_wakeup(udev);
|
||||
|
||||
/* Otherwise leave it be; devices can't tell the
|
||||
* difference between suspended and disabled.
|
||||
*/
|
||||
else
|
||||
status = 0;
|
||||
status = remote_wakeup(udev);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
+10
-22
@@ -459,35 +459,23 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
|
||||
io->urbs[i]->context = io;
|
||||
|
||||
/*
|
||||
* Some systems need to revert to PIO when DMA is
|
||||
* temporarily unavailable. For their sakes, both
|
||||
* transfer_buffer and transfer_dma are set when
|
||||
* possible. However this can only work on systems
|
||||
* without:
|
||||
* Some systems need to revert to PIO when DMA is temporarily
|
||||
* unavailable. For their sakes, both transfer_buffer and
|
||||
* transfer_dma are set when possible.
|
||||
*
|
||||
* - HIGHMEM, since DMA buffers located in high memory
|
||||
* are not directly addressable by the CPU for PIO;
|
||||
*
|
||||
* - IOMMU, since dma_map_sg() is allowed to use an
|
||||
* IOMMU to make virtually discontiguous buffers be
|
||||
* "dma-contiguous" so that PIO and DMA need diferent
|
||||
* numbers of URBs.
|
||||
*
|
||||
* So when HIGHMEM or IOMMU are in use, transfer_buffer
|
||||
* is NULL to prevent stale pointers and to help spot
|
||||
* bugs.
|
||||
* Note that if IOMMU coalescing occurred, we cannot
|
||||
* trust sg_page anymore, so check if S/G list shrunk.
|
||||
*/
|
||||
if (io->nents == io->entries && !PageHighMem(sg_page(sg)))
|
||||
io->urbs[i]->transfer_buffer = sg_virt(sg);
|
||||
else
|
||||
io->urbs[i]->transfer_buffer = NULL;
|
||||
|
||||
if (dma) {
|
||||
io->urbs[i]->transfer_dma = sg_dma_address(sg);
|
||||
len = sg_dma_len(sg);
|
||||
#if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU)
|
||||
io->urbs[i]->transfer_buffer = NULL;
|
||||
#else
|
||||
io->urbs[i]->transfer_buffer = sg_virt(sg);
|
||||
#endif
|
||||
} else {
|
||||
/* hc may use _only_ transfer_buffer */
|
||||
io->urbs[i]->transfer_buffer = sg_virt(sg);
|
||||
len = sg->length;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user