Commit 117494a1 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (142 commits)
  USB: fix race in autosuspend reschedule
  atmel_usba_udc: Keep track of the device status
  USB: Nikon D40X unusual_devs entry
  USB: serial core should respect driver requirements
  USB: documentation for USB power management
  USB: skip autosuspended devices during system resume
  USB: mutual exclusion for EHCI init and port resets
  USB: allow usbstorage to have LUNS greater than 2Tb
  USB: Adding support for SHARP WS011SH to ipaq.c
  USB: add atmel_usba_udc driver
  USB: ohci SSB bus glue
  USB: ehci build fixes on au1xxx, ppc-soc
  USB: add runtime frame_no quirk for big-endian OHCI
  USB: funsoft: Fix termios
  USB: visor: termios bits
  USB: unusual_devs entry for Nikon DSC D2Xs
  USB: re-remove <linux/usb_sl811.h>
  USB: move <linux/usb_gadget.h> to <linux/usb/gadget.h>
  USB: Export URB statistics for powertop
  USB: serial gadget: Disable endpoints on unload
  ...
parents 4d5709a7 d1aa3e6a
Authorizing (or not) your USB devices to connect to the system
(C) 2007 Inaky Perez-Gonzalez <inaky@linux.intel.com> Intel Corporation
This feature allows you to control if a USB device can be used (or
not) in a system. This feature will allow you to implement a lock-down
of USB devices, fully controlled by user space.
As of now, when a USB device is connected it is configured and
it's interfaces inmediately made available to the users. With this
modification, only if root authorizes the device to be configured will
then it be possible to use it.
Usage:
Authorize a device to connect:
$ echo 1 > /sys/usb/devices/DEVICE/authorized
Deauthorize a device:
$ echo 0 > /sys/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
Remove the lock down:
$ echo 1 > /sys/bus/devices/usbX/authorized_default
By default, Wired USB devices are authorized by default to
connect. Wireless USB hosts deauthorize by default all new connected
devices (this is so because we need to do an authentication phase
before authorizing).
Example system lockdown (lame)
-----------------------
Imagine you want to implement a lockdown so only devices of type XYZ
can be connected (for example, it is a kiosk machine with a visible
USB port):
boot up
rc.local ->
for host in /sys/bus/devices/usb*
do
echo 0 > $host/authorized_default
done
Hookup an script to udev, for new USB devices
if device_is_my_type $DEV
then
echo 1 > $device_path/authorized
done
Now, device_is_my_type() is where the juice for a lockdown is. Just
checking if the class, type and protocol match something is the worse
security verification you can make (or the best, for someone willing
to break it). If you need something secure, use crypto and Certificate
Authentication or stuff like that. Something simple for an storage key
could be:
function device_is_my_type()
{
echo 1 > authorized # temporarily authorize it
# FIXME: make sure none can mount it
mount DEVICENODE /mntpoint
sum=$(md5sum /mntpoint/.signature)
if [ $sum = $(cat /etc/lockdown/keysum) ]
then
echo "We are good, connected"
umount /mntpoint
# Other stuff so others can use it
else
echo 0 > authorized
fi
}
Of course, this is lame, you'd want to do a real certificate
verification stuff with PKI, so you don't depend on a shared secret,
etc, but you get the idea. Anybody with access to a device gadget kit
can fake descriptors and device info. Don't trust that. You are
welcome.
This diff is collapsed.
......@@ -428,6 +428,17 @@ Options supported:
See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
information on this driver.
Winchiphead CH341 Driver
This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip
also implements an IEEE 1284 parallel port, I2C and SPI, but that is not
supported by the driver. The protocol was analyzed from the behaviour
of the Windows driver, no datasheet is available at present.
The manufacturer's website: http://www.winchiphead.com/.
For any questions or problems with this driver, please contact
frank@kingswood-consulting.co.uk.
Generic Serial driver
If your device is not one of the above listed devices, compatible with
......
......@@ -34,9 +34,12 @@ if usbmon is built into the kernel.
Verify that bus sockets are present.
# ls /sys/kernel/debug/usbmon
1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u
0s 0t 0u 1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u
#
Now you can choose to either use the sockets numbered '0' (to capture packets on
all buses), and skip to step #3, or find the bus used by your device with step #2.
2. Find which bus connects to the desired device
Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
......@@ -56,6 +59,10 @@ Bus=03 means it's bus 3.
# cat /sys/kernel/debug/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
This process will be reading until killed. Naturally, the output can be
redirected to a desirable location. This is preferred, because it is going
to be quite long.
......
......@@ -677,6 +677,13 @@ P: Haavard Skinnemoen
M: hskinnemoen@atmel.com
S: Supported
ATMEL USBA UDC DRIVER
P: Haavard Skinnemoen
M: hskinnemoen@atmel.com
L: kernel@avr32linux.org
W: http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver
S: Supported
ATMEL WIRELESS DRIVER
P: Simon Kelley
M: simon@thekelleys.org.uk
......
......@@ -40,7 +40,7 @@
#include <linux/pata_platform.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/usb_sl811.h>
#include <linux/usb/sl811.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
#include <asm/reboot.h>
......
......@@ -40,7 +40,7 @@
#include <linux/irq.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
#include <linux/usb_sl811.h>
#include <linux/usb/sl811.h>
#include <linux/spi/ad7877.h>
......
......@@ -40,7 +40,7 @@
#include <linux/pata_platform.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/usb_sl811.h>
#include <linux/usb/sl811.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
#include <asm/reboot.h>
......
......@@ -28,27 +28,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB_ADUTUX) += misc/
obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
obj-$(CONFIG_USB_AUERSWALD) += misc/
obj-$(CONFIG_USB_BERRY_CHARGE) += misc/
obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
obj-$(CONFIG_USB_CYTHERM) += misc/
obj-$(CONFIG_USB_EMI26) += misc/
obj-$(CONFIG_USB_EMI62) += misc/
obj-$(CONFIG_USB_FTDI_ELAN) += misc/
obj-$(CONFIG_USB_IDMOUSE) += misc/
obj-$(CONFIG_USB_LCD) += misc/
obj-$(CONFIG_USB_LD) += misc/
obj-$(CONFIG_USB_LED) += misc/
obj-$(CONFIG_USB_LEGOTOWER) += misc/
obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
obj-$(CONFIG_USB_RIO500) += misc/
obj-$(CONFIG_USB_SISUSBVGA) += misc/
obj-$(CONFIG_USB_TEST) += misc/
obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
obj-$(CONFIG_USB_USS720) += misc/
obj-$(CONFIG_USB_IOWARRIOR) += misc/
obj-$(CONFIG_USB) += misc/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
......@@ -482,7 +482,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
dbg("too big transfer requested");
if (printk_ratelimit())
usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n",
wbuflen, rbuflen);
ret = -ENOMEM;
goto fail;
}
......@@ -493,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
init_completion(&instance->rcv_done);
ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
if (ret < 0) {
dbg("submitting read urb for cm %#x failed", cm);
ret = ret;
if (printk_ratelimit())
usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n",
cm, ret);
goto fail;
}
......@@ -510,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
init_completion(&instance->snd_done);
ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
if (ret < 0) {
dbg("submitting write urb for cm %#x failed", cm);
ret = ret;
if (printk_ratelimit())
usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n",
cm, ret);
goto fail;
}
ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
if (ret < 0) {
dbg("sending cm %#x failed", cm);
ret = ret;
if (printk_ratelimit())
usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret);
goto fail;
}
ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
if (ret < 0) {
dbg("receiving cm %#x failed", cm);
ret = ret;
if (printk_ratelimit())
usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret);
goto fail;
}
if (actlen % CMD_PACKET_SIZE || !actlen) {
dbg("response is not a positive multiple of %d: %#x",
CMD_PACKET_SIZE, actlen);
if (printk_ratelimit())
usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n",
cm, actlen);
ret = -EIO;
goto fail;
}
......@@ -538,12 +543,16 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
/* check the return status and copy the data to the output buffer, if needed */
for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
if (rbuf[offb] != cm) {
dbg("wrong cm %#x in response", rbuf[offb]);
if (printk_ratelimit())
usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n",
rbuf[offb], cm);
ret = -EIO;
goto fail;
}
if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
dbg("response failed: %#x", rbuf[offb + 1]);
if (printk_ratelimit())
usb_err(instance->usbatm, "response to cm %#x failed: %#x\n",
cm, rbuf[offb + 1]);
ret = -EIO;
goto fail;
}
......@@ -582,14 +591,18 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
for (offb = 0; offb < len; ) {
int l = le32_to_cpu(buf[offb++]);
if (l > stride || l > (len - offb) / 2) {
dbg("wrong data length %#x in response", l);
if (printk_ratelimit())
usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
cm, l);
ret = -EIO;
goto cleanup;
}
while (l--) {
offd = le32_to_cpu(buf[offb++]);
if (offd >= size) {
dbg("wrong index %#x in response", offd);
if (printk_ratelimit())
usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n",
offd, cm);
ret = -EIO;
goto cleanup;
}
......
......@@ -251,7 +251,6 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
{
unsigned char *buffer;
struct usbatm_data *usbatm = instance->usbatm;
struct usb_interface *intf;
struct usb_device *usb_dev = usbatm->usb_dev;
int actual_length;
int ret = 0;
......@@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
goto out;
}
if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
if (!usb_ifnum_to_if(usb_dev, 2)) {
ret = -ENODEV;
usb_dbg(usbatm, "%s: interface not found!\n", __func__);
goto out_free;
......
This diff is collapsed.
......@@ -28,6 +28,7 @@
* v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
* v0.13 - alloc space for statusbuf (<status> not on stack);
* use usb_buffer_alloc() for read buf & write buf;
* none - Maintained in Linux kernel after v0.13
*/
/*
......@@ -69,7 +70,6 @@
#define USBLP_DEVICE_ID_SIZE 1024
/* ioctls: */
#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */
#define IOCNR_GET_DEVICE_ID 1
#define IOCNR_GET_PROTOCOLS 2
#define IOCNR_SET_PROTOCOL 3
......@@ -115,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
#define USBLP_MINORS 16
#define USBLP_MINOR_BASE 0
#define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */
#define USBLP_CTL_TIMEOUT 5000 /* 5 seconds */
#define USBLP_FIRST_PROTOCOL 1
#define USBLP_LAST_PROTOCOL 3
......@@ -159,10 +159,12 @@ struct usblp {
int wstatus; /* bytes written or error */
int rstatus; /* bytes ready or error */
unsigned int quirks; /* quirks flags */
unsigned int flags; /* mode flags */
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
unsigned char bidir; /* interface is bidirectional */
unsigned char sleeping; /* interface is suspended */
unsigned char no_paper; /* Paper Out happened */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
/* first 2 bytes are (big-endian) length */
};
......@@ -259,7 +261,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
retval = usb_control_msg(usblp->dev,
dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
request, !!dir, recip, value, index, len, retval);
return retval < 0 ? retval : 0;
......@@ -325,13 +327,11 @@ static void usblp_bulk_write(struct urb *urb)
usblp->wstatus = status;
else
usblp->wstatus = urb->actual_length;
usblp->no_paper = 0;
usblp->wcomplete = 1;
wake_up(&usblp->wwait);
spin_unlock(&usblp->lock);
/* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */
kfree(urb->transfer_buffer);
urb->transfer_buffer = NULL; /* Not refcounted, so to be safe... */
usb_free_urb(urb);
}
......@@ -346,16 +346,17 @@ static int usblp_check_status(struct usblp *usblp, int err)
unsigned char status, newerr = 0;
int error;
error = usblp_read_status (usblp, usblp->statusbuf);
if (error < 0) {
mutex_lock(&usblp->mut);
if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
mutex_unlock(&usblp->mut);
if (printk_ratelimit())
printk(KERN_ERR
"usblp%d: error %d reading printer status\n",
usblp->minor, error);
return 0;
}
status = *usblp->statusbuf;
mutex_unlock(&usblp->mut);
if (~status & LP_PERRORP)
newerr = 3;
......@@ -411,18 +412,10 @@ static int usblp_open(struct inode *inode, struct file *file)
goto out;
/*
* TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
* This is #if 0-ed because we *don't* want to fail an open
* just because the printer is off-line.
* We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
* - We do not want persistent state which close(2) does not clear
* - It is not used anyway, according to CUPS people
*/
#if 0
if ((retval = usblp_check_status(usblp, 0))) {
retval = retval > 1 ? -EIO : -ENOSPC;
goto out;
}
#else
retval = 0;
#endif
retval = usb_autopm_get_interface(intf);
if (retval < 0)
......@@ -463,6 +456,8 @@ static int usblp_release(struct inode *inode, struct file *file)
{
struct usblp *usblp = file->private_data;
usblp->flags &= ~LP_ABORT;
mutex_lock (&usblp_mutex);
usblp->used = 0;
if (usblp->present) {
......@@ -485,8 +480,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
poll_wait(file, &usblp->rwait, wait);
poll_wait(file, &usblp->wwait, wait);
spin_lock_irqsave(&usblp->lock, flags);
ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM)
| (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) |
((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0);
spin_unlock_irqrestore(&usblp->lock, flags);
return ret;
}
......@@ -675,6 +670,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
case LPABORT:
if (arg)
usblp->flags |= LP_ABORT;
else
usblp->flags &= ~LP_ABORT;
break;
default:
retval = -ENOTTY;
}
......@@ -684,10 +686,30 @@ done:
return retval;
}
static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
{
struct urb *urb;
char *writebuf;
if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL)
return NULL;
if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
kfree(writebuf);
return NULL;
}
usb_fill_bulk_urb(urb, usblp->dev,
usb_sndbulkpipe(usblp->dev,
usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
writebuf, transfer_length, usblp_bulk_write, usblp);
urb->transfer_flags |= URB_FREE_BUFFER;
return urb;
}
static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
char *writebuf;
struct urb *writeurb;
int rv;
int transfer_length;
......@@ -708,17 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
transfer_length = USBLP_BUF_SIZE;
rv = -ENOMEM;
if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
goto raise_buf;
if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL)
goto raise_urb;
usb_fill_bulk_urb(writeurb, usblp->dev,
usb_sndbulkpipe(usblp->dev,
usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
writebuf, transfer_length, usblp_bulk_write, usblp);
usb_anchor_urb(writeurb, &usblp->urbs);
if (copy_from_user(writebuf,
if (copy_from_user(writeurb->transfer_buffer,
buffer + writecount, transfer_length)) {
rv = -EFAULT;
goto raise_badaddr;
......@@ -730,6 +746,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
usblp->wstatus = 0;
spin_lock_irq(&usblp->lock);
usblp->no_paper = 0;
usblp->wcomplete = 1;
wake_up(&usblp->wwait);
spin_unlock_irq(&usblp->lock);
......@@ -747,12 +764,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
/* Presume that it's going to complete well. */
writecount += transfer_length;
}
if (rv == -ENOSPC) {
spin_lock_irq(&usblp->lock);
usblp->no_paper = 1; /* Mark for poll(2) */
spin_unlock_irq(&usblp->lock);
writecount += transfer_length;
}
/* Leave URB dangling, to be cleaned on close. */
goto collect_error;
}
if (usblp->wstatus < 0) {
usblp_check_status(usblp, 0);
rv = -EIO;
goto collect_error;
}
......@@ -771,8 +793,6 @@ raise_badaddr:
usb_unanchor_urb(writeurb);
usb_free_urb(writeurb);
raise_urb:
kfree(writebuf);
raise_buf:
raise_wait:
collect_error: /* Out of raise sequence */
mutex_unlock(&usblp->wmut);
......@@ -838,32 +858,36 @@ done:
* when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
* select(2) or poll(2) to wait for the buffer to drain before closing.
* Alternatively, set blocking mode with fcntl and issue a zero-size write.
*
* Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot
* to check the return code for timeout expiration, so it had no effect.
* Apparently, it was intended to check for error conditons, such as out
* of paper. It is going to return when we settle things with CUPS. XXX
*/
static int usblp_wwait(struct usblp *usblp, int nonblock)
{
DECLARE_WAITQUEUE(waita, current);
int rc;
int err = 0;
add_wait_queue(&usblp->wwait, &waita);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (mutex_lock_interruptible(&usblp->mut)) {
rc = -EINTR;
break;
}
set_current_state(TASK_INTERRUPTIBLE);
if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
mutex_unlock(&usblp->mut);
break;
}
rc = usblp_wtest(usblp, nonblock);
mutex_unlock(&usblp->mut);
if (rc == 0)
if (rc <= 0)
break;
schedule();
if (usblp->flags & LP_ABORT) {
if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
err = usblp_check_status(usblp, err);
if (err == 1) { /* Paper out */
rc = -ENOSPC;
break;
}
}
} else {
schedule();
}
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&usblp->wwait, &waita);
......
......@@ -507,18 +507,30 @@ void usb_destroy_configuration(struct usb_device *dev)
}
// hub-only!! ... and only in reset path, or usb_new_device()
// (used by real hubs and virtual root hubs)
/*
* Get the USB config descriptors, cache and parse'em
*
* hub-only!! ... and only in reset path, or usb_new_device()
* (used by real hubs and virtual root hubs)
*
* NOTE: if this is a WUSB device and is not authorized, we skip the
* whole thing. A non-authorized USB device has no
* configurations.
*/
int usb_get_configuration(struct usb_device *dev)
{
struct device *ddev = &dev->dev;
int ncfg = dev->descriptor.bNumConfigurations;
int result = -ENOMEM;
int result = 0;
unsigned int cfgno, length;
unsigned char *buffer;
unsigned char *bigbuffer;
struct usb_config_descriptor *desc;
cfgno = 0;
if (dev->authorized == 0) /* Not really an error */
goto out_not_authorized;
result = -ENOMEM;
if (ncfg > USB_MAXCONFIG) {
dev_warn(ddev, "too many configurations: %d, "
"using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
......@@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev)
goto err2;
desc = (struct usb_config_descriptor *)buffer;
for (cfgno = 0; cfgno < ncfg; cfgno++) {
result = 0;
for (; cfgno < ncfg; cfgno++) {
/* We grab just the first descriptor so we know how long
* the whole configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
buffer, USB_DT_CONFIG_SIZE);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
"descriptor/%s\n", cfgno, "start");
"descriptor/%s: %d\n", cfgno, "start", result);
dev_err(ddev, "chopping to %d config(s)\n", cfgno);
dev->descriptor.bNumConfigurations = cfgno;
break;
......@@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev)
err:
kfree(buffer);
out_not_authorized:
dev->descriptor.bNumConfigurations = cfgno;
err2:
if (result == -ENOMEM)
......
......@@ -71,6 +71,7 @@ struct async {
void __user *userbuffer;
void __user *userurb;
struct urb *urb;
int status;
u32 secid;
};
......@@ -289,10 +290,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
if (!usbfs_snoop)
return;
if (urb->pipe & USB_DIR_IN)
dev_info(&urb->dev->dev, "direction=IN\n");
else
dev_info(&urb->dev->dev, "direction=OUT\n");
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=%d\n",
urb->transfer_buffer_length);
......@@ -312,9 +311,10 @@ static void async_completed(struct urb *urb)
spin_lock(&ps->lock);
list_move_tail(&as->asynclist, &ps->async_completed);
spin_unlock(&ps->lock);
as->status = urb->status;
if (as->signr) {
sinfo.si_signo = as->signr;
sinfo.si_errno = as->urb->status;
sinfo.si_errno = as->status;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb;
kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
......@@ -910,6 +910,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
struct usb_ctrlrequest *dr = NULL;
unsigned int u, totlen, isofrmlen;
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))
......@@ -924,16 +925,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
if ((ret = checkintf(ps, ifnum)))
return ret;
}
if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0)
ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
else
ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
is_in = 1;
ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
} else {
is_in = 0;
ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
}
if (!ep)
return -ENOENT;
switch(uurb->type) {
case USBDEVFS_URB_TYPE_CONTROL:
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_CONTROL)
if (!usb_endpoint_xfer_control(&ep->desc))
return -EINVAL;
/* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
......@@ -952,23 +955,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
kfree(dr);
return ret;
}
uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
uurb->number_of_packets = 0;
uurb->buffer_length = le16_to_cpup(&dr->wLength);
uurb->buffer += 8;
if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) {
if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
is_in = 1;
uurb->endpoint |= USB_DIR_IN;
} else {
is_in = 0;
uurb->endpoint &= ~USB_DIR_IN;
}
if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
uurb->buffer, uurb->buffer_length)) {
kfree(dr);
return -EFAULT;
}
snoop(&ps->dev->dev, "control urb: bRequest=%02x "
"bRrequestType=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
dr->bRequest, dr->bRequestType, dr->wValue,
dr->wIndex, dr->wLength);
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:
switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
switch (usb_endpoint_type(&ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_ISOC:
return -EINVAL;
......@@ -977,7 +989,8 @@ 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;
if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
uurb->buffer, uurb->buffer_length))
return -EFAULT;
snoop(&ps->dev->dev, "bulk urb\n");
break;
......@@ -986,8 +999,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
/* arbitrary limit */
if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
return -EINVAL;
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_ISOC)
if (!usb_endpoint_xfer_isoc(&ep->desc))
return -EINVAL;
isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
......@@ -1014,12 +1026,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
case USBDEVFS_URB_TYPE_INTERRUPT:
uurb->number_of_packets = 0;
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_INT)
if (!usb_endpoint_xfer_int(&ep->desc))
return -EINVAL;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
uurb->buffer, uurb->buffer_length))
return -EFAULT;
snoop(&ps->dev->dev, "interrupt urb\n");
break;
......@@ -1039,8 +1051,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -ENOMEM;
}
as->urb->dev = ps->dev;
as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
as->urb->transfer_flags = uurb->flags;
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);
as->urb->transfer_buffer_length = uurb->buffer_length;
as->urb->setup_packet = (unsigned char*)dr;
as->urb->start_frame = uurb->start_frame;
......@@ -1070,13 +1085,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->uid = current->uid;
as->euid = current->euid;
security_task_getsecid(current, &as->secid);
if (!(uurb->endpoint & USB_DIR_IN)) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
if (!is_in) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
as->urb->transfer_buffer_length)) {
free_async(as);
return -EFAULT;
}
}
snoop(&as->urb->dev->dev, "submit urb\n");
snoop_urb(as->urb, as->userurb);
async_newpending(as);
if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
......@@ -1119,14 +1134,14 @@ static int processcompl(struct async *as, void __user * __user *arg)
if (as->userbuffer)
if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
return -EFAULT;
if (put_user(urb->status, &userurb->status))
if (put_user(as->status, &userurb->status))
return -EFAULT;
if (put_user(urb->actual_length, &userurb->actual_length))
return -EFAULT;
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
if (usb_pipeisoc(urb->pipe)) {
if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))
......@@ -1233,14 +1248,14 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
if (as->userbuffer)
if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
return -EFAULT;
if (put_user(urb->status, &userurb->status))
if (put_user(as->status, &userurb->status))
return -EFAULT;
if (put_user(urb->actual_length, &userurb->actual_length))
return -EFAULT;
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
if (usb_pipeisoc(urb->pipe)) {
if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))
......
......@@ -202,6 +202,11 @@ static int usb_probe_interface(struct device *dev)
intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf);
if (udev->authorized == 0) {
dev_err(&intf->dev, "Device is not authorized for usage\n");
return -ENODEV;
}
id = usb_match_id(intf, driver->id_table);
if (!id)
id = usb_match_dynamic_id(intf, driver);
......@@ -945,11 +950,11 @@ done:
#ifdef CONFIG_USB_SUSPEND
/* Internal routine to check whether we may autosuspend a device. */
static int autosuspend_check(struct usb_device *udev)
static int autosuspend_check(struct usb_device *udev, int reschedule)
{
int i;
struct usb_interface *intf;
unsigned long suspend_time;
unsigned long suspend_time, j;
/* For autosuspend, fail fast if anything is in use or autosuspend
* is disabled. Also fail if any interfaces require remote wakeup
......@@ -991,20 +996,20 @@ static int autosuspend_check(struct usb_device *udev)
}
/* If everything is okay but the device hasn't been idle for long
* enough, queue a delayed autosuspend request.
* enough, queue a delayed autosuspend request. If the device
* _has_ been idle for long enough and the reschedule flag is set,
* likewise queue a delayed (1 second) autosuspend request.
*/
if (time_after(suspend_time, jiffies)) {
j = jiffies;
if (time_before(j, suspend_time))
reschedule = 1;
else
suspend_time = j + HZ;
if (reschedule) {
if (!timer_pending(&udev->autosuspend.timer)) {
/* The value of jiffies may change between the
* time_after() comparison above and the subtraction
* below. That's okay; the system behaves sanely
* when a timer is registered for the present moment
* or for the past.
*/
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
round_jiffies_relative(suspend_time - jiffies));
}
round_jiffies_relative(suspend_time - j));
}
return -EAGAIN;
}
return 0;
......@@ -1012,7 +1017,7 @@ static int autosuspend_check(struct usb_device *udev)
#else
static inline int autosuspend_check(struct usb_device *udev)
static inline int autosuspend_check(struct usb_device *udev, int reschedule)
{
return 0;
}
......@@ -1069,7 +1074,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
if (udev->auto_pm) {
status = autosuspend_check(udev);
status = autosuspend_check(udev, 0);
if (status < 0)
goto done;
}
......@@ -1083,15 +1088,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
break;
}
}
if (status == 0) {
/* Non-root devices don't need to do anything for FREEZE
* or PRETHAW. */
if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
msg.event == PM_EVENT_PRETHAW))
goto done;
if (status == 0)
status = usb_suspend_device(udev, msg);
}
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
......@@ -1102,12 +1100,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
/* Try another autosuspend when the interfaces aren't busy */
if (udev->auto_pm)
autosuspend_check(udev);
autosuspend_check(udev, status == -EBUSY);
/* If the suspend succeeded, propagate it up the tree */
/* If the suspend succeeded then prevent any more URB submissions,
* flush any outstanding URBs, and propagate the suspend up the tree.
*/
} else {
cancel_delayed_work(&udev->autosuspend);
if (parent)
udev->can_submit = 0;
for (i = 0; i < 16; ++i) {
usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
}
/* If this is just a FREEZE or a PRETHAW, udev might
* not really be suspended. Only true suspends get
* propagated up the device tree.
*/
if (parent && udev->state == USB_STATE_SUSPENDED)
usb_autosuspend_device(parent);
}
......@@ -1156,6 +1166,7 @@ static int usb_resume_both(struct usb_device *udev)
status = -ENODEV;
goto done;
}
udev->can_submit = 1;
/* Propagate the resume up the tree, if necessary */
if (udev->state == USB_STATE_SUSPENDED) {
......@@ -1529,9 +1540,21 @@ int usb_external_resume_device(struct usb_device *udev)
static int usb_suspend(struct device *dev, pm_message_t message)
{
struct usb_device *udev;
if (!is_usb_device(dev)) /* Ignore PM for interfaces */
return 0;
return usb_external_suspend_device(to_usb_device(dev), 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. */
if (udev->state == USB_STATE_SUSPENDED) {
udev->skip_sys_resume = 1;
return 0;
}
udev->skip_sys_resume = 0;
return usb_external_suspend_device(udev, message);
}
static int usb_resume(struct device *dev)
......@@ -1542,13 +1565,14 @@ static int usb_resume(struct device *dev)
return 0;
udev = to_usb_device(dev);
/* If autoresume is disabled then we also want to prevent resume
* during system wakeup. However, a "persistent-device" reset-resume
* after power loss counts as a wakeup event. So allow a
* reset-resume to occur if remote wakeup is enabled. */
if (udev->autoresume_disabled) {
/* If udev->skip_sys_resume is set then udev was already suspended
* when the system suspend started, so we don't want to resume
* udev during this system wakeup. However a reset-resume counts
* as a wakeup event, so allow a reset-resume to occur if remote
* wakeup is enabled. */
if (udev->skip_sys_resume) {
if (!(udev->reset_resume && udev->do_remote_wakeup))
return -EPERM;
return -EHOSTUNREACH;
}
return usb_external_resume_device(udev);
}
......
......@@ -267,7 +267,6 @@ static void ep_device_release(struct device *dev)
{
struct ep_device *ep_dev = to_ep_device(dev);
dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
endpoint_free_minor(ep_dev);
kfree(ep_dev);
}
......
......@@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc)
&& desc->bInterfaceProtocol == 1;
}
static int choose_configuration(struct usb_device *udev)
int usb_choose_configuration(struct usb_device *udev)
{
int i;
int num_configs;
......@@ -161,17 +161,20 @@ 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.
*/
c = choose_configuration(udev);
if (c >= 0) {
err = usb_set_configuration(udev, c);
if (err) {
dev_err(&udev->dev, "can't set config #%d, error %d\n",
if (udev->authorized == 0)
dev_err(&udev->dev, "Device is not authorized for usage\n");
else {
c = usb_choose_configuration(udev);
if (c >= 0) {
err = usb_set_configuration(udev, c);
if (err) {
dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
/* This need not be fatal. The user can try to
* set other configurations. */
/* This need not be fatal. The user can try to
* set other configurations. */
}
}
}
/* USB device state == configured ... usable */
usb_notify_add_device(udev);
......@@ -203,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
*/
if (!udev->parent)
rc = hcd_bus_suspend(udev);
/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
rc = 0;
else
rc = usb_port_suspend(udev);
return rc;
}
......
This diff is collapsed.
......@@ -19,6 +19,8 @@
#ifdef __KERNEL__
#include <linux/rwsem.h>
/* This file contains declarations of usbcore internals that are mostly
* used or exposed by Host Controller Drivers.
*/
......@@ -51,6 +53,12 @@
*
* Since "struct usb_bus" is so thin, you can't share much code in it.
* This framework is a layer over that, and should be more sharable.
*
* @authorized_default: Specifies if new devices are authorized to
* connect by default or they require explicit
* user space authorization; this bit is settable
* through /sys/class/usb_host/X/authorized_default.
* For the rest is RO, so we don't lock to r/w it.
*/
/*-------------------------------------------------------------------------*/
......@@ -90,6 +98,7 @@ struct usb_hcd {
unsigned poll_rh:1; /* poll for rh status? */
unsigned poll_pending:1; /* status has changed? */
unsigned wireless:1; /* Wireless USB HCD */
unsigned authorized_default:1;
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
......@@ -182,11 +191,10 @@ struct hc_driver {
int (*get_frame_number) (struct usb_hcd *hcd);
/* manage i/o requests, device state */
int (*urb_enqueue) (struct usb_hcd *hcd,
struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags);
int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
int (*urb_enqueue)(struct usb_hcd *hcd,
struct urb *urb, gfp_t mem_flags);
int (*urb_dequeue)(struct usb_hcd *hcd,
struct urb *urb, int status);
/* hw synch, freeing endpoint resources that urb_dequeue can't */
void (*endpoint_disable)(struct usb_hcd *hcd,
......@@ -204,10 +212,18 @@ struct hc_driver {
/* Needed only if port-change IRQs are level-triggered */
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
int status);
extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
extern int usb_hcd_unlink_urb (struct urb *urb, int status);
extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
extern void usb_hcd_endpoint_disable (struct usb_device *udev,
extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
int status);
extern void usb_hcd_flush_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
extern void usb_hcd_disable_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
extern int usb_hcd_get_frame_number (struct usb_device *udev);
......@@ -402,7 +418,7 @@ static inline void usbfs_cleanup(void) { }
struct usb_mon_operations {
void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status);
/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
};
......@@ -421,10 +437,11 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
(*mon_ops->urb_submit_error)(bus, urb, error);
}
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
int status)
{
if (bus->monitored)
(*mon_ops->urb_complete)(bus, urb);
(*mon_ops->urb_complete)(bus, urb, status);
}
int usb_mon_register(struct usb_mon_operations *ops);
......@@ -435,7 +452,8 @@ void usb_mon_deregister(void);
static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
int error) {}
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
int status) {}
#endif /* CONFIG_USB_MON */
......@@ -454,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
: (in_interrupt () ? "in_interrupt" : "can sleep"))
#endif /* __KERNEL__ */
/* This rwsem is for use only by the hub driver and ehci-hcd.
* Nobody else should touch it.
*/
extern struct rw_semaphore ehci_cf_port_reset_rwsem;
#endif /* __KERNEL__ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -8,17 +8,22 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *
struct usb_device *udev);
extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
extern void usb_enable_endpoint(struct usb_device *dev,
struct usb_host_endpoint *ep);
extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
extern void usb_disable_interface (struct usb_device *dev,
struct usb_interface *intf);
extern void usb_release_interface_cache(struct kref *ref);
extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
extern int usb_deauthorize_device (struct usb_device *);
extern int usb_authorize_device (struct usb_device *);
extern void usb_detect_quirks(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size);
extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern int usb_choose_configuration(struct usb_device *udev);
extern void usb_kick_khubd(struct usb_device *dev);
extern int usb_match_device(struct usb_device *dev,
......
This diff is collapsed.
......@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
obj-$(CONFIG_USB_AT91) += at91_udc.o
obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
ohci->next_statechange = jiffies;
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
}
/*-------------------------------------------------------------------------*/
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment