summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/atm/ueagle-atm.c7
-rw-r--r--drivers/usb/atm/usbatm.c15
-rw-r--r--drivers/usb/core/Kconfig12
-rw-r--r--drivers/usb/core/devices.c1
-rw-r--r--drivers/usb/core/devio.c8
-rw-r--r--drivers/usb/core/file.c1
-rw-r--r--drivers/usb/core/hcd.c2
-rw-r--r--drivers/usb/core/inode.c1
-rw-r--r--drivers/usb/gadget/Kconfig2
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c2
-rw-r--r--drivers/usb/gadget/composite.c18
-rw-r--r--drivers/usb/gadget/f_fs.c1
-rw-r--r--drivers/usb/gadget/f_hid.c1
-rw-r--r--drivers/usb/gadget/goku_udc.h3
-rw-r--r--drivers/usb/gadget/u_ether.c1
-rw-r--r--drivers/usb/gadget/u_serial.c54
-rw-r--r--drivers/usb/host/Kconfig2
-rw-r--r--drivers/usb/host/ehci-dbg.c2
-rw-r--r--drivers/usb/host/ehci-hcd.c10
-rw-r--r--drivers/usb/host/ehci-mem.c26
-rw-r--r--drivers/usb/host/ehci-mxc.c14
-rw-r--r--drivers/usb/host/ehci-pci.c25
-rw-r--r--drivers/usb/host/ehci-sched.c21
-rw-r--r--drivers/usb/host/ehci.h2
-rw-r--r--drivers/usb/host/isp1362-hcd.c3
-rw-r--r--drivers/usb/host/ohci-jz4740.c2
-rw-r--r--drivers/usb/host/uhci-debug.c1
-rw-r--r--drivers/usb/host/xhci-hub.c7
-rw-r--r--drivers/usb/host/xhci-mem.c173
-rw-r--r--drivers/usb/host/xhci-ring.c1
-rw-r--r--drivers/usb/host/xhci.c91
-rw-r--r--drivers/usb/host/xhci.h31
-rw-r--r--drivers/usb/image/microtek.c6
-rw-r--r--drivers/usb/misc/cypress_cy7c63.c6
-rw-r--r--drivers/usb/misc/iowarrior.c1
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c1
-rw-r--r--drivers/usb/misc/trancevibrator.c2
-rw-r--r--drivers/usb/misc/usbled.c2
-rw-r--r--drivers/usb/misc/usbsevseg.c10
-rw-r--r--drivers/usb/misc/uss720.c4
-rw-r--r--drivers/usb/misc/yurex.c1
-rw-r--r--drivers/usb/mon/mon_bin.c1
-rw-r--r--drivers/usb/mon/mon_stat.c1
-rw-r--r--drivers/usb/musb/blackfin.c80
-rw-r--r--drivers/usb/musb/musb_core.c44
-rw-r--r--drivers/usb/musb/musb_core.h2
-rw-r--r--drivers/usb/musb/musb_gadget.c165
-rw-r--r--drivers/usb/musb/musb_regs.h3
-rw-r--r--drivers/usb/musb/musbhsdma.c14
-rw-r--r--drivers/usb/otg/langwell_otg.c9
-rw-r--r--drivers/usb/serial/ftdi_sio.c5
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h16
-rw-r--r--drivers/usb/serial/option.c2
-rw-r--r--drivers/usb/serial/usb-serial.c4
-rw-r--r--drivers/usb/storage/scsiglue.c4
-rw-r--r--drivers/usb/storage/sierra_ms.c2
-rw-r--r--drivers/usb/storage/uas.c9
-rw-r--r--drivers/usb/storage/unusual_devs.h7
58 files changed, 715 insertions, 226 deletions
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index ea071a5..44447f5 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -2301,7 +2301,7 @@ out:
return ret;
}
-static DEVICE_ATTR(stat_status, S_IWUGO | S_IRUGO, read_status, reboot);
+static DEVICE_ATTR(stat_status, S_IWUSR | S_IRUGO, read_status, reboot);
static ssize_t read_human_status(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -2364,8 +2364,7 @@ out:
return ret;
}
-static DEVICE_ATTR(stat_human_status, S_IWUGO | S_IRUGO,
- read_human_status, NULL);
+static DEVICE_ATTR(stat_human_status, S_IRUGO, read_human_status, NULL);
static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -2397,7 +2396,7 @@ out:
return ret;
}
-static DEVICE_ATTR(stat_delin, S_IWUGO | S_IRUGO, read_delin, NULL);
+static DEVICE_ATTR(stat_delin, S_IRUGO, read_delin, NULL);
#define UEA_ATTR(name, reset) \
\
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 05bf5a2..989e16e 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -951,7 +951,9 @@ static int usbatm_atm_init(struct usbatm_data *instance)
* condition: callbacks we register can be executed at once, before we have
* initialized the struct atm_dev. To protect against this, all callbacks
* abort if atm_dev->dev_data is NULL. */
- atm_dev = atm_dev_register(instance->driver_name, &usbatm_atm_devops, -1, NULL);
+ atm_dev = atm_dev_register(instance->driver_name,
+ &instance->usb_intf->dev, &usbatm_atm_devops,
+ -1, NULL);
if (!atm_dev) {
usb_err(instance, "%s: failed to register ATM device!\n", __func__);
return -1;
@@ -966,14 +968,6 @@ static int usbatm_atm_init(struct usbatm_data *instance)
/* temp init ATM device, set to 128kbit */
atm_dev->link_rate = 128 * 1000 / 424;
- ret = sysfs_create_link(&atm_dev->class_dev.kobj,
- &instance->usb_intf->dev.kobj, "device");
- if (ret) {
- atm_err(instance, "%s: sysfs_create_link failed: %d\n",
- __func__, ret);
- goto fail_sysfs;
- }
-
if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) {
atm_err(instance, "%s: atm_start failed: %d!\n", __func__, ret);
goto fail;
@@ -992,8 +986,6 @@ static int usbatm_atm_init(struct usbatm_data *instance)
return 0;
fail:
- sysfs_remove_link(&atm_dev->class_dev.kobj, "device");
- fail_sysfs:
instance->atm_dev = NULL;
atm_dev_deregister(atm_dev); /* usbatm_atm_dev_close will eventually be called */
return ret;
@@ -1329,7 +1321,6 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
/* ATM finalize */
if (instance->atm_dev) {
- sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device");
atm_dev_deregister(instance->atm_dev);
instance->atm_dev = NULL;
}
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 9eed5b5..bcc2477 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -107,11 +107,19 @@ config USB_SUSPEND
If you are unsure about this, say N here.
config USB_OTG
- bool
+ bool "OTG support"
depends on USB && EXPERIMENTAL
depends on USB_SUSPEND
default n
-
+ help
+ The most notable feature of USB OTG is support for a
+ "Dual-Role" device, which can act as either a device
+ or a host. The initial role is decided by the type of
+ plug inserted and can be changed later when two dual
+ role devices talk to each other.
+
+ Select this only if your board has Mini-AB/Micro-AB
+ connector.
config USB_OTG_WHITELIST
bool "Rely on OTG Targeted Peripherals List"
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index ddb4dc9..a3d2e23 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -54,7 +54,6 @@
#include <linux/gfp.h>
#include <linux/poll.h>
#include <linux/usb.h>
-#include <linux/smp_lock.h>
#include <linux/usbdevice_fs.h>
#include <linux/usb/hcd.h>
#include <linux/mutex.h>
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index f1aaff6..a7131ad 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -37,7 +37,6 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/signal.h>
#include <linux/poll.h>
#include <linux/module.h>
@@ -965,10 +964,11 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
static int proc_connectinfo(struct dev_state *ps, void __user *arg)
{
- struct usbdevfs_connectinfo ci;
+ struct usbdevfs_connectinfo ci = {
+ .devnum = ps->dev->devnum,
+ .slow = ps->dev->speed == USB_SPEED_LOW
+ };
- ci.devnum = ps->dev->devnum;
- ci.slow = ps->dev->speed == USB_SPEED_LOW;
if (copy_to_user(arg, &ci, sizeof(ci)))
return -EFAULT;
return 0;
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 9fe34fb..cf6a542 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -19,7 +19,6 @@
#include <linux/errno.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/usb.h>
#include "usb.h"
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 61800f7..ced846a 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1330,6 +1330,8 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
*/
if (usb_endpoint_xfer_control(&urb->ep->desc)) {
+ if (hcd->self.uses_pio_for_control)
+ return ret;
if (hcd->self.uses_dma) {
urb->setup_dma = dma_map_single(
hcd->self.controller,
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 9819a4c..b690aa3 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -39,7 +39,6 @@
#include <linux/parser.h>
#include <linux/notifier.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <linux/usb/hcd.h>
#include <asm/byteorder.h>
#include "usb.h"
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index b739ca8..607d0db 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -158,7 +158,7 @@ config USB_GADGET_FSL_USB2
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on FSL_SOC || ARCH_MXC
select USB_GADGET_DUALSPEED
- select USB_FSL_MPH_DR_OF
+ select USB_FSL_MPH_DR_OF if OF
help
Some of Freescale PowerPC processors have a High Speed
Dual-Role(DR) USB controller, which supports device mode.
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index b5e20e8..717ff65 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -2017,7 +2017,7 @@ static int __init usba_udc_probe(struct platform_device *pdev)
}
} else {
/* gpio_request fail so use -EINVAL for gpio_is_valid */
- ubc->vbus_pin = -EINVAL;
+ udc->vbus_pin = -EINVAL;
}
}
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 7b5cc16..8572dad 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1047,9 +1047,9 @@ composite_unbind(struct usb_gadget *gadget)
kfree(cdev->req->buf);
usb_ep_free_request(gadget->ep0, cdev->req);
}
+ device_remove_file(&gadget->dev, &dev_attr_suspended);
kfree(cdev);
set_gadget_data(gadget, NULL);
- device_remove_file(&gadget->dev, &dev_attr_suspended);
composite = NULL;
}
@@ -1107,14 +1107,6 @@ static int composite_bind(struct usb_gadget *gadget)
*/
usb_ep_autoconfig_reset(cdev->gadget);
- /* standardized runtime overrides for device ID data */
- if (idVendor)
- cdev->desc.idVendor = cpu_to_le16(idVendor);
- if (idProduct)
- cdev->desc.idProduct = cpu_to_le16(idProduct);
- if (bcdDevice)
- cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
-
/* composite gadget needs to assign strings for whole device (like
* serial number), register function drivers, potentially update
* power state and consumption, etc
@@ -1126,6 +1118,14 @@ static int composite_bind(struct usb_gadget *gadget)
cdev->desc = *composite->dev;
cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+ /* standardized runtime overrides for device ID data */
+ if (idVendor)
+ cdev->desc.idVendor = cpu_to_le16(idVendor);
+ if (idProduct)
+ cdev->desc.idProduct = cpu_to_le16(idProduct);
+ if (bcdDevice)
+ cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
+
/* stirng overrides */
if (iManufacturer || !cdev->desc.iManufacturer) {
if (!iManufacturer && !composite->iManufacturer &&
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index 4a830df..484c5ba 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -30,7 +30,6 @@
#include <linux/blkdev.h>
#include <linux/pagemap.h>
#include <asm/unaligned.h>
-#include <linux/smp_lock.h>
#include <linux/usb/composite.h>
#include <linux/usb/functionfs.h>
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index 4f891ed..598e7e2 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -25,7 +25,6 @@
#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/usb/g_hid.h>
diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h
index 566cb23..e7e0c69 100644
--- a/drivers/usb/gadget/goku_udc.h
+++ b/drivers/usb/gadget/goku_udc.h
@@ -251,7 +251,8 @@ struct goku_udc {
got_region:1,
req_config:1,
configured:1,
- enabled:1;
+ enabled:1,
+ registered:1;
/* pci state used to access those endpoints */
struct pci_dev *pdev;
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index cb23355..fbe86ca 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -811,7 +811,6 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
INFO(dev, "MAC %pM\n", net->dev_addr);
INFO(dev, "HOST MAC %pM\n", dev->host_mac);
- netif_stop_queue(net);
the_dev = dev;
}
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 01e5354..40f7716 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -105,11 +105,15 @@ struct gs_port {
wait_queue_head_t close_wait; /* wait for last close */
struct list_head read_pool;
+ int read_started;
+ int read_allocated;
struct list_head read_queue;
unsigned n_read;
struct tasklet_struct push;
struct list_head write_pool;
+ int write_started;
+ int write_allocated;
struct gs_buf port_write_buf;
wait_queue_head_t drain_wait; /* wait while writes drain */
@@ -363,6 +367,9 @@ __acquires(&port->port_lock)
struct usb_request *req;
int len;
+ if (port->write_started >= QUEUE_SIZE)
+ break;
+
req = list_entry(pool->next, struct usb_request, list);
len = gs_send_packet(port, req->buf, in->maxpacket);
if (len == 0) {
@@ -397,6 +404,8 @@ __acquires(&port->port_lock)
break;
}
+ port->write_started++;
+
/* abort immediately after disconnect */
if (!port->port_usb)
break;
@@ -418,7 +427,6 @@ __acquires(&port->port_lock)
{
struct list_head *pool = &port->read_pool;
struct usb_ep *out = port->port_usb->out;
- unsigned started = 0;
while (!list_empty(pool)) {
struct usb_request *req;
@@ -430,6 +438,9 @@ __acquires(&port->port_lock)
if (!tty)
break;
+ if (port->read_started >= QUEUE_SIZE)
+ break;
+
req = list_entry(pool->next, struct usb_request, list);
list_del(&req->list);
req->length = out->maxpacket;
@@ -447,13 +458,13 @@ __acquires(&port->port_lock)
list_add(&req->list, pool);
break;
}
- started++;
+ port->read_started++;
/* abort immediately after disconnect */
if (!port->port_usb)
break;
}
- return started;
+ return port->read_started;
}
/*
@@ -535,6 +546,7 @@ static void gs_rx_push(unsigned long _port)
}
recycle:
list_move(&req->list, &port->read_pool);
+ port->read_started--;
}
/* Push from tty to ldisc; without low_latency set this is handled by
@@ -587,6 +599,7 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
spin_lock(&port->port_lock);
list_add(&req->list, &port->write_pool);
+ port->write_started--;
switch (req->status) {
default:
@@ -608,7 +621,8 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
spin_unlock(&port->port_lock);
}
-static void gs_free_requests(struct usb_ep *ep, struct list_head *head)
+static void gs_free_requests(struct usb_ep *ep, struct list_head *head,
+ int *allocated)
{
struct usb_request *req;
@@ -616,25 +630,31 @@ static void gs_free_requests(struct usb_ep *ep, struct list_head *head)
req = list_entry(head->next, struct usb_request, list);
list_del(&req->list);
gs_free_req(ep, req);
+ if (allocated)
+ (*allocated)--;
}
}
static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head,
- void (*fn)(struct usb_ep *, struct usb_request *))
+ void (*fn)(struct usb_ep *, struct usb_request *),
+ int *allocated)
{
int i;
struct usb_request *req;
+ int n = allocated ? QUEUE_SIZE - *allocated : QUEUE_SIZE;
/* Pre-allocate up to QUEUE_SIZE transfers, but if we can't
* do quite that many this time, don't fail ... we just won't
* be as speedy as we might otherwise be.
*/
- for (i = 0; i < QUEUE_SIZE; i++) {
+ for (i = 0; i < n; i++) {
req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC);
if (!req)
return list_empty(head) ? -ENOMEM : 0;
req->complete = fn;
list_add_tail(&req->list, head);
+ if (allocated)
+ (*allocated)++;
}
return 0;
}
@@ -661,14 +681,15 @@ static int gs_start_io(struct gs_port *port)
* configurations may use different endpoints with a given port;
* and high speed vs full speed changes packet sizes too.
*/
- status = gs_alloc_requests(ep, head, gs_read_complete);
+ status = gs_alloc_requests(ep, head, gs_read_complete,
+ &port->read_allocated);
if (status)
return status;
status = gs_alloc_requests(port->port_usb->in, &port->write_pool,
- gs_write_complete);
+ gs_write_complete, &port->write_allocated);
if (status) {
- gs_free_requests(ep, head);
+ gs_free_requests(ep, head, &port->read_allocated);
return status;
}
@@ -680,8 +701,9 @@ static int gs_start_io(struct gs_port *port)
if (started) {
tty_wakeup(port->port_tty);
} else {
- gs_free_requests(ep, head);
- gs_free_requests(port->port_usb->in, &port->write_pool);
+ gs_free_requests(ep, head, &port->read_allocated);
+ gs_free_requests(port->port_usb->in, &port->write_pool,
+ &port->write_allocated);
status = -EIO;
}
@@ -1315,8 +1337,12 @@ void gserial_disconnect(struct gserial *gser)
spin_lock_irqsave(&port->port_lock, flags);
if (port->open_count == 0 && !port->openclose)
gs_buf_free(&port->port_write_buf);
- gs_free_requests(gser->out, &port->read_pool);
- gs_free_requests(gser->out, &port->read_queue);
- gs_free_requests(gser->in, &port->write_pool);
+ gs_free_requests(gser->out, &port->read_pool, NULL);
+ gs_free_requests(gser->out, &port->read_queue, NULL);
+ gs_free_requests(gser->in, &port->write_pool, NULL);
+
+ port->read_allocated = port->read_started =
+ port->write_allocated = port->write_started = 0;
+
spin_unlock_irqrestore(&port->port_lock, flags);
}
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 2391c39..6f4f8e6 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -122,7 +122,7 @@ config USB_EHCI_FSL
bool "Support for Freescale on-chip EHCI USB controller"
depends on USB_EHCI_HCD && FSL_SOC
select USB_EHCI_ROOT_HUB_TT
- select USB_FSL_MPH_DR_OF
+ select USB_FSL_MPH_DR_OF if OF
---help---
Variation of ARC USB block used in some Freescale chips.
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 86afdc7..6e25996 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -1067,7 +1067,7 @@ static inline void create_debug_files (struct ehci_hcd *ehci)
&debug_registers_fops))
goto file_error;
- if (!debugfs_create_file("lpm", S_IRUGO|S_IWUGO, ehci->debug_dir, bus,
+ if (!debugfs_create_file("lpm", S_IRUGO|S_IWUSR, ehci->debug_dir, bus,
&debug_lpm_fops))
goto file_error;
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 502a7e6..e906280 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1063,10 +1063,11 @@ rescan:
tmp && tmp != qh;
tmp = tmp->qh_next.qh)
continue;
- /* periodic qh self-unlinks on empty */
- if (!tmp)
- goto nogood;
- unlink_async (ehci, qh);
+ /* periodic qh self-unlinks on empty, and a COMPLETING qh
+ * may already be unlinked.
+ */
+ if (tmp)
+ unlink_async(ehci, qh);
/* FALL THROUGH */
case QH_STATE_UNLINK: /* wait for hw to finish? */
case QH_STATE_UNLINK_WAIT:
@@ -1083,7 +1084,6 @@ idle_timeout:
}
/* else FALL THROUGH */
default:
-nogood:
/* caller was supposed to have unlinked any requests;
* that's not our job. just leak this memory.
*/
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index d36e4e7..12f70c3 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -141,6 +141,10 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci)
qh_put (ehci->async);
ehci->async = NULL;
+ if (ehci->dummy)
+ qh_put(ehci->dummy);
+ ehci->dummy = NULL;
+
/* DMA consistent memory and pools */
if (ehci->qtd_pool)
dma_pool_destroy (ehci->qtd_pool);
@@ -227,8 +231,26 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
if (ehci->periodic == NULL) {
goto fail;
}
- for (i = 0; i < ehci->periodic_size; i++)
- ehci->periodic [i] = EHCI_LIST_END(ehci);
+
+ if (ehci->use_dummy_qh) {
+ struct ehci_qh_hw *hw;
+ ehci->dummy = ehci_qh_alloc(ehci, flags);
+ if (!ehci->dummy)
+ goto fail;
+
+ hw = ehci->dummy->hw;
+ hw->hw_next = EHCI_LIST_END(ehci);
+ hw->hw_qtd_next = EHCI_LIST_END(ehci);
+ hw->hw_alt_next = EHCI_LIST_END(ehci);
+ hw->hw_token &= ~QTD_STS_ACTIVE;
+ ehci->dummy->hw = hw;
+
+ for (i = 0; i < ehci->periodic_size; i++)
+ ehci->periodic[i] = ehci->dummy->qh_dma;
+ } else {
+ for (i = 0; i < ehci->periodic_size; i++)
+ ehci->periodic[i] = EHCI_LIST_END(ehci);
+ }
/* software shadow of hardware table */
ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index ac9c4d7..bce8505 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -36,6 +36,8 @@ struct ehci_mxc_priv {
static int ehci_mxc_setup(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct device *dev = hcd->self.controller;
+ struct mxc_usbh_platform_data *pdata = dev_get_platdata(dev);
int retval;
/* EHCI registers start at offset 0x100 */
@@ -63,6 +65,12 @@ static int ehci_mxc_setup(struct usb_hcd *hcd)
ehci_reset(ehci);
+ /* set up the PORTSCx register */
+ ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
+
+ /* is this really needed? */
+ msleep(10);
+
ehci_port_power(ehci, 0);
return 0;
}
@@ -114,7 +122,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
struct usb_hcd *hcd;
struct resource *res;
- int irq, ret, temp;
+ int irq, ret;
struct ehci_mxc_priv *priv;
struct device *dev = &pdev->dev;
@@ -188,10 +196,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
clk_enable(priv->ahbclk);
}
- /* set up the PORTSCx register */
- ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
- mdelay(10);
-
/* setup specific usb hw */
ret = mxc_initialize_usb_hw(pdev->id, pdata->flags);
if (ret < 0)
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index a1e8d27..655f3c9 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -103,6 +103,19 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
if (retval)
return retval;
+ if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x7808) ||
+ (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x4396)) {
+ /* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
+ * read/write memory space which does not belong to it when
+ * there is NULL pointer with T-bit set to 1 in the frame list
+ * table. To avoid the issue, the frame list link pointer
+ * should always contain a valid pointer to a inactive qh.
+ */
+ ehci->use_dummy_qh = 1;
+ ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI "
+ "dummy qh workaround\n");
+ }
+
/* data structure init */
retval = ehci_init(hcd);
if (retval)
@@ -148,6 +161,18 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
if (pdev->revision < 0xa4)
ehci->no_selective_suspend = 1;
break;
+
+ /* MCP89 chips on the MacBookAir3,1 give EPROTO when
+ * fetching device descriptors unless LPM is disabled.
+ * There are also intermittent problems enumerating
+ * devices with PPCD enabled.
+ */
+ case 0x0d9d:
+ ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89");
+ ehci->has_lpm = 0;
+ ehci->has_ppcd = 0;
+ ehci->command &= ~CMD_PPCEE;
+ break;
}
break;
case PCI_VENDOR_ID_VIA:
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index a92526d..d9f78eb 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -98,7 +98,14 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
*/
*prev_p = *periodic_next_shadow(ehci, &here,
Q_NEXT_TYPE(ehci, *hw_p));
- *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p));
+
+ if (!ehci->use_dummy_qh ||
+ *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p))
+ != EHCI_LIST_END(ehci))
+ *hw_p = *shadow_next_periodic(ehci, &here,
+ Q_NEXT_TYPE(ehci, *hw_p));
+ else
+ *hw_p = ehci->dummy->qh_dma;
}
/* how many of the uframe's 125 usecs are allocated? */
@@ -2335,7 +2342,11 @@ restart:
* pointer for much longer, if at all.
*/
*q_p = q.itd->itd_next;
- *hw_p = q.itd->hw_next;
+ if (!ehci->use_dummy_qh ||
+ q.itd->hw_next != EHCI_LIST_END(ehci))
+ *hw_p = q.itd->hw_next;
+ else
+ *hw_p = ehci->dummy->qh_dma;
type = Q_NEXT_TYPE(ehci, q.itd->hw_next);
wmb();
modified = itd_complete (ehci, q.itd);
@@ -2368,7 +2379,11 @@ restart:
* URB completion.
*/
*q_p = q.sitd->sitd_next;
- *hw_p = q.sitd->hw_next;
+ if (!ehci->use_dummy_qh ||
+ q.sitd->hw_next != EHCI_LIST_END(ehci))
+ *hw_p = q.sitd->hw_next;
+ else
+ *hw_p = ehci->dummy->qh_dma;
type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
wmb();
modified = sitd_complete (ehci, q.sitd);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index bde823f..ba8eab3 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -73,6 +73,7 @@ struct ehci_hcd { /* one per controller */
/* async schedule support */
struct ehci_qh *async;
+ struct ehci_qh *dummy; /* For AMD quirk use */
struct ehci_qh *reclaim;
unsigned scanning : 1;
@@ -131,6 +132,7 @@ struct ehci_hcd { /* one per controller */
unsigned need_io_watchdog:1;
unsigned broken_periodic:1;
unsigned fs_i_thresh:1; /* Intel iso scheduling */
+ unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index 8196fa1..43a39eb 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -70,7 +70,6 @@
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/list.h>
@@ -2684,7 +2683,7 @@ static int __devexit isp1362_remove(struct platform_device *pdev)
return 0;
}
-static int __init isp1362_probe(struct platform_device *pdev)
+static int __devinit isp1362_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct isp1362_hcd *isp1362_hcd;
diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c
index 10e1872f..931d588 100644
--- a/drivers/usb/host/ohci-jz4740.c
+++ b/drivers/usb/host/ohci-jz4740.c
@@ -273,4 +273,4 @@ static struct platform_driver ohci_hcd_jz4740_driver = {
},
};
-MODULE_ALIAS("platfrom:jz4740-ohci");
+MODULE_ALIAS("platform:jz4740-ohci");
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 6e7fb5f..ee60cd3 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -12,7 +12,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>
-#include <linux/smp_lock.h>
#include <asm/io.h>
#include "uhci-hcd.h"
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index fef5a1f..5d963e3 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -229,6 +229,13 @@ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex,
u32 __iomem *addr, u32 port_status)
{
+ /* Don't allow the USB core to disable SuperSpeed ports. */
+ if (xhci->port_array[wIndex] == 0x03) {
+ xhci_dbg(xhci, "Ignoring request to disable "
+ "SuperSpeed port.\n");
+ return;
+ }
+
/* Write 1 to disable the port */
xhci_writel(xhci, port_status | PORT_PE, addr);
port_status = xhci_readl(xhci, addr);
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 2027706..1d0f45f 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1045,7 +1045,7 @@ static inline u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
if (udev->speed == USB_SPEED_SUPER)
return ep->ss_ep_comp.wBytesPerInterval;
- max_packet = ep->desc.wMaxPacketSize & 0x3ff;
+ max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize);
max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11;
/* A 0 in max burst means 1 transfer per ESIT */
return max_packet * (max_burst + 1);
@@ -1135,7 +1135,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
/* Fall through */
case USB_SPEED_FULL:
case USB_SPEED_LOW:
- max_packet = ep->desc.wMaxPacketSize & 0x3ff;
+ max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize);
ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
break;
default:
@@ -1443,6 +1443,13 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->dcbaa = NULL;
scratchpad_free(xhci);
+
+ xhci->num_usb2_ports = 0;
+ xhci->num_usb3_ports = 0;
+ kfree(xhci->usb2_ports);
+ kfree(xhci->usb3_ports);
+ kfree(xhci->port_array);
+
xhci->page_size = 0;
xhci->page_shift = 0;
xhci->bus_suspended = 0;
@@ -1627,6 +1634,166 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
&xhci->ir_set->erst_dequeue);
}
+static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
+ u32 __iomem *addr, u8 major_revision)
+{
+ u32 temp, port_offset, port_count;
+ int i;
+
+ if (major_revision > 0x03) {
+ xhci_warn(xhci, "Ignoring unknown port speed, "
+ "Ext Cap %p, revision = 0x%x\n",
+ addr, major_revision);
+ /* Ignoring port protocol we can't understand. FIXME */
+ return;
+ }
+
+ /* Port offset and count in the third dword, see section 7.2 */
+ temp = xhci_readl(xhci, addr + 2);
+ port_offset = XHCI_EXT_PORT_OFF(temp);
+ port_count = XHCI_EXT_PORT_COUNT(temp);
+ xhci_dbg(xhci, "Ext Cap %p, port offset = %u, "
+ "count = %u, revision = 0x%x\n",
+ addr, port_offset, port_count, major_revision);
+ /* Port count includes the current port offset */
+ if (port_offset == 0 || (port_offset + port_count - 1) > num_ports)
+ /* WTF? "Valid values are ‘1’ to MaxPorts" */
+ return;
+ port_offset--;
+ for (i = port_offset; i < (port_offset + port_count); i++) {
+ /* Duplicate entry. Ignore the port if the revisions differ. */
+ if (xhci->port_array[i] != 0) {
+ xhci_warn(xhci, "Duplicate port entry, Ext Cap %p,"
+ " port %u\n", addr, i);
+ xhci_warn(xhci, "Port was marked as USB %u, "
+ "duplicated as USB %u\n",
+ xhci->port_array[i], major_revision);
+ /* Only adjust the roothub port counts if we haven't
+ * found a similar duplicate.
+ */
+ if (xhci->port_array[i] != major_revision &&
+ xhci->port_array[i] != (u8) -1) {
+ if (xhci->port_array[i] == 0x03)
+ xhci->num_usb3_ports--;
+ else
+ xhci->num_usb2_ports--;
+ xhci->port_array[i] = (u8) -1;
+ }
+ /* FIXME: Should we disable the port? */
+ continue;
+ }
+ xhci->port_array[i] = major_revision;
+ if (major_revision == 0x03)
+ xhci->num_usb3_ports++;
+ else
+ xhci->num_usb2_ports++;
+ }
+ /* FIXME: Should we disable ports not in the Extended Capabilities? */
+}
+
+/*
+ * Scan the Extended Capabilities for the "Supported Protocol Capabilities" that
+ * specify what speeds each port is supposed to be. We can't count on the port
+ * speed bits in the PORTSC register being correct until a device is connected,
+ * but we need to set up the two fake roothubs with the correct number of USB
+ * 3.0 and USB 2.0 ports at host controller initialization time.
+ */
+static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
+{
+ u32 __iomem *addr;
+ u32 offset;
+ unsigned int num_ports;
+ int i, port_index;
+
+ addr = &xhci->cap_regs->hcc_params;
+ offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr));
+ if (offset == 0) {
+ xhci_err(xhci, "No Extended Capability registers, "
+ "unable to set up roothub.\n");
+ return -ENODEV;
+ }
+
+ num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
+ xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags);
+ if (!xhci->port_array)
+ return -ENOMEM;
+
+ /*
+ * For whatever reason, the first capability offset is from the
+ * capability register base, not from the HCCPARAMS register.
+ * See section 5.3.6 for offset calculation.
+ */
+ addr = &xhci->cap_regs->hc_capbase + offset;
+ while (1) {
+ u32 cap_id;
+
+ cap_id = xhci_readl(xhci, addr);
+ if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL)
+ xhci_add_in_port(xhci, num_ports, addr,
+ (u8) XHCI_EXT_PORT_MAJOR(cap_id));
+ offset = XHCI_EXT_CAPS_NEXT(cap_id);
+ if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports)
+ == num_ports)
+ break;
+ /*
+ * Once you're into the Extended Capabilities, the offset is
+ * always relative to the register holding the offset.
+ */
+ addr += offset;
+ }
+
+ if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) {
+ xhci_warn(xhci, "No ports on the roothubs?\n");
+ return -ENODEV;
+ }
+ xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n",
+ xhci->num_usb2_ports, xhci->num_usb3_ports);
+ /*
+ * Note we could have all USB 3.0 ports, or all USB 2.0 ports.
+ * Not sure how the USB core will handle a hub with no ports...
+ */
+ if (xhci->num_usb2_ports) {
+ xhci->usb2_ports = kmalloc(sizeof(*xhci->usb2_ports)*
+ xhci->num_usb2_ports, flags);
+ if (!xhci->usb2_ports)
+ return -ENOMEM;
+
+ port_index = 0;
+ for (i = 0; i < num_ports; i++) {
+ if (xhci->port_array[i] == 0x03 ||
+ xhci->port_array[i] == 0 ||
+ xhci->port_array[i] == -1)
+ continue;
+
+ xhci->usb2_ports[port_index] =
+ &xhci->op_regs->port_status_base +
+ NUM_PORT_REGS*i;
+ xhci_dbg(xhci, "USB 2.0 port at index %u, "
+ "addr = %p\n", i,
+ xhci->usb2_ports[port_index]);
+ port_index++;
+ }
+ }
+ if (xhci->num_usb3_ports) {
+ xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)*
+ xhci->num_usb3_ports, flags);
+ if (!xhci->usb3_ports)
+ return -ENOMEM;
+
+ port_index = 0;
+ for (i = 0; i < num_ports; i++)
+ if (xhci->port_array[i] == 0x03) {
+ xhci->usb3_ports[port_index] =
+ &xhci->op_regs->port_status_base +
+ NUM_PORT_REGS*i;
+ xhci_dbg(xhci, "USB 3.0 port at index %u, "
+ "addr = %p\n", i,
+ xhci->usb3_ports[port_index]);
+ port_index++;
+ }
+ }
+ return 0;
+}
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
{
@@ -1809,6 +1976,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
if (scratchpad_alloc(xhci, flags))
goto fail;
+ if (xhci_setup_port_arrays(xhci, flags))
+ goto fail;
return 0;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 9f3115e..df558f6 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2104,7 +2104,6 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
if (!(status & STS_EINT)) {
spin_unlock(&xhci->lock);
- xhci_warn(xhci, "Spurious interrupt.\n");
return IRQ_NONE;
}
xhci_dbg(xhci, "op reg status = %08x\n", status);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 5d7d4e9..45e4a31 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -577,6 +577,65 @@ static void xhci_restore_registers(struct xhci_hcd *xhci)
xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
}
+static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
+{
+ u64 val_64;
+
+ /* step 2: initialize command ring buffer */
+ val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+ val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
+ (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
+ xhci->cmd_ring->dequeue) &
+ (u64) ~CMD_RING_RSVD_BITS) |
+ xhci->cmd_ring->cycle_state;
+ xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
+ (long unsigned long) val_64);
+ xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
+}
+
+/*
+ * The whole command ring must be cleared to zero when we suspend the host.
+ *
+ * The host doesn't save the command ring pointer in the suspend well, so we
+ * need to re-program it on resume. Unfortunately, the pointer must be 64-byte
+ * aligned, because of the reserved bits in the command ring dequeue pointer
+ * register. Therefore, we can't just set the dequeue pointer back in the
+ * middle of the ring (TRBs are 16-byte aligned).
+ */
+static void xhci_clear_command_ring(struct xhci_hcd *xhci)
+{
+ struct xhci_ring *ring;
+ struct xhci_segment *seg;
+
+ ring = xhci->cmd_ring;
+ seg = ring->deq_seg;
+ do {
+ memset(seg->trbs, 0, SEGMENT_SIZE);
+ seg = seg->next;
+ } while (seg != ring->deq_seg);
+
+ /* Reset the software enqueue and dequeue pointers */
+ ring->deq_seg = ring->first_seg;
+ ring->dequeue = ring->first_seg->trbs;
+ ring->enq_seg = ring->deq_seg;
+ ring->enqueue = ring->dequeue;
+
+ /*
+ * Ring is now zeroed, so the HW should look for change of ownership
+ * when the cycle bit is set to 1.
+ */
+ ring->cycle_state = 1;
+
+ /*
+ * Reset the hardware dequeue pointer.
+ * Yes, this will need to be re-written after resume, but we're paranoid
+ * and want to make sure the hardware doesn't access bogus memory
+ * because, say, the BIOS or an SMI started the host without changing
+ * the command ring pointers.
+ */
+ xhci_set_cmd_ring_deq(xhci);
+}
+
/*
* Stop HC (not bus-specific)
*
@@ -604,6 +663,7 @@ int xhci_suspend(struct xhci_hcd *xhci)
spin_unlock_irq(&xhci->lock);
return -ETIMEDOUT;
}
+ xhci_clear_command_ring(xhci);
/* step 3: save registers */
xhci_save_registers(xhci);
@@ -635,7 +695,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
u32 command, temp = 0;
struct usb_hcd *hcd = xhci_to_hcd(xhci);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
- u64 val_64;
int old_state, retval;
old_state = hcd->state;
@@ -648,15 +707,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
/* step 1: restore register */
xhci_restore_registers(xhci);
/* step 2: initialize command ring buffer */
- val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
- val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
- (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
- xhci->cmd_ring->dequeue) &
- (u64) ~CMD_RING_RSVD_BITS) |
- xhci->cmd_ring->cycle_state;
- xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
- (long unsigned long) val_64);
- xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
+ xhci_set_cmd_ring_deq(xhci);
/* step 3: restore state and start state*/
/* step 3: set CRS flag */
command = xhci_readl(xhci, &xhci->op_regs->command);
@@ -714,6 +765,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
return retval;
}
+ spin_unlock_irq(&xhci->lock);
/* Re-setup MSI-X */
if (hcd->irq)
free_irq(hcd->irq, hcd);
@@ -736,6 +788,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
hcd->irq = pdev->irq;
}
+ spin_lock_irq(&xhci->lock);
/* step 4: set Run/Stop bit */
command = xhci_readl(xhci, &xhci->op_regs->command);
command |= CMD_RUN;
@@ -1496,6 +1549,15 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
cmd_completion = command->completion;
cmd_status = &command->status;
command->command_trb = xhci->cmd_ring->enqueue;
+
+ /* Enqueue pointer can be left pointing to the link TRB,
+ * we must handle that
+ */
+ if ((command->command_trb->link.control & TRB_TYPE_BITMASK)
+ == TRB_TYPE(TRB_LINK))
+ command->command_trb =
+ xhci->cmd_ring->enq_seg->next->trbs;
+
list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
} else {
in_ctx = virt_dev->in_ctx;
@@ -2219,6 +2281,15 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
/* Attempt to submit the Reset Device command to the command ring */
spin_lock_irqsave(&xhci->lock, flags);
reset_device_cmd->command_trb = xhci->cmd_ring->enqueue;
+
+ /* Enqueue pointer can be left pointing to the link TRB,
+ * we must handle that
+ */
+ if ((reset_device_cmd->command_trb->link.control & TRB_TYPE_BITMASK)
+ == TRB_TYPE(TRB_LINK))
+ reset_device_cmd->command_trb =
+ xhci->cmd_ring->enq_seg->next->trbs;
+
list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list);
ret = xhci_queue_reset_device(xhci, slot_id);
if (ret) {
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 93d3bf4..170c367 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -454,6 +454,24 @@ struct xhci_doorbell_array {
/**
+ * struct xhci_protocol_caps
+ * @revision: major revision, minor revision, capability ID,
+ * and next capability pointer.
+ * @name_string: Four ASCII characters to say which spec this xHC
+ * follows, typically "USB ".
+ * @port_info: Port offset, count, and protocol-defined information.
+ */
+struct xhci_protocol_caps {
+ u32 revision;
+ u32 name_string;
+ u32 port_info;
+};
+
+#define XHCI_EXT_PORT_MAJOR(x) (((x) >> 24) & 0xff)
+#define XHCI_EXT_PORT_OFF(x) ((x) & 0xff)
+#define XHCI_EXT_PORT_COUNT(x) (((x) >> 8) & 0xff)
+
+/**
* struct xhci_container_ctx
* @type: Type of context. Used to calculated offsets to contained contexts.
* @size: Size of the context data
@@ -621,6 +639,11 @@ struct xhci_ep_ctx {
#define MAX_PACKET_MASK (0xffff << 16)
#define MAX_PACKET_DECODED(p) (((p) >> 16) & 0xffff)
+/* Get max packet size from ep desc. Bit 10..0 specify the max packet size.
+ * USB2.0 spec 9.6.6.
+ */
+#define GET_MAX_PACKET(p) ((p) & 0x7ff)
+
/* tx_info bitmasks */
#define AVG_TRB_LENGTH_FOR_EP(p) ((p) & 0xffff)
#define MAX_ESIT_PAYLOAD_FOR_EP(p) (((p) & 0xffff) << 16)
@@ -1235,6 +1258,14 @@ struct xhci_hcd {
u32 suspended_ports[8]; /* which ports are
suspended */
unsigned long resume_done[MAX_HC_PORTS];
+ /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
+ u8 *port_array;
+ /* Array of pointers to USB 3.0 PORTSC registers */
+ u32 __iomem **usb3_ports;
+ unsigned int num_usb3_ports;
+ /* Array of pointers to USB 2.0 PORTSC registers */
+ u32 __iomem **usb2_ports;
+ unsigned int num_usb2_ports;
};
/* For testing purposes */
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 5a47805..c90c89d 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -364,7 +364,7 @@ static int mts_scsi_host_reset(struct scsi_cmnd *srb)
}
static int
-mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback);
+mts_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *srb);
static void mts_transfer_cleanup( struct urb *transfer );
static void mts_do_sg(struct urb * transfer);
@@ -573,7 +573,7 @@ mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc)
static int
-mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback)
+mts_scsi_queuecommand_lck(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback)
{
struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
int err = 0;
@@ -626,6 +626,8 @@ out:
return err;
}
+static DEF_SCSI_QCMD(mts_scsi_queuecommand)
+
static struct scsi_host_template mts_scsi_host_template = {
.module = THIS_MODULE,
.name = "microtekX6",
diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c
index 2f43c57..9251773 100644
--- a/drivers/usb/misc/cypress_cy7c63.c
+++ b/drivers/usb/misc/cypress_cy7c63.c
@@ -196,11 +196,9 @@ static ssize_t get_port1_handler(struct device *dev,
return read_port(dev, attr, buf, 1, CYPRESS_READ_PORT_ID1);
}
-static DEVICE_ATTR(port0, S_IWUGO | S_IRUGO,
- get_port0_handler, set_port0_handler);
+static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR, get_port0_handler, set_port0_handler);
-static DEVICE_ATTR(port1, S_IWUGO | S_IRUGO,
- get_port1_handler, set_port1_handler);
+static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR, get_port1_handler, set_port1_handler);
static int cypress_probe(struct usb_interface *interface,
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 7a10e48..e573e4704 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -553,6 +553,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
/* needed for power consumption */
struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc;
+ memset(&info, 0, sizeof(info));
/* directly from the descriptor */
info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
info.product = dev->product_id;
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 70d00e9..dd573ab 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -3008,6 +3008,7 @@ sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
#else
x.sisusb_conactive = 0;
#endif
+ memset(x.sisusb_reserved, 0, sizeof(x.sisusb_reserved));
if (copy_to_user((void __user *)arg, &x, sizeof(x)))
retval = -EFAULT;
diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c
index d77aba4..f63776a 100644
--- a/drivers/usb/misc/trancevibrator.c
+++ b/drivers/usb/misc/trancevibrator.c
@@ -86,7 +86,7 @@ static ssize_t set_speed(struct device *dev, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(speed, S_IWUGO | S_IRUGO, show_speed, set_speed);
+static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR, show_speed, set_speed);
static int tv_probe(struct usb_interface *interface,
const struct usb_device_id *id)
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
index 63da2c3..c96f51d 100644
--- a/drivers/usb/misc/usbled.c
+++ b/drivers/usb/misc/usbled.c
@@ -94,7 +94,7 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co
change_color(led); \
return count; \
} \
-static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
+static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, show_##value, set_##value);
show_set(blue);
show_set(red);
show_set(green);
diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c
index de8ef94..417b8f2 100644
--- a/drivers/usb/misc/usbsevseg.c
+++ b/drivers/usb/misc/usbsevseg.c
@@ -192,7 +192,7 @@ static ssize_t set_attr_##name(struct device *dev, \
\
return count; \
} \
-static DEVICE_ATTR(name, S_IWUGO | S_IRUGO, show_attr_##name, set_attr_##name);
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_attr_##name, set_attr_##name);
static ssize_t show_attr_text(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -223,7 +223,7 @@ static ssize_t set_attr_text(struct device *dev,
return count;
}
-static DEVICE_ATTR(text, S_IWUGO | S_IRUGO, show_attr_text, set_attr_text);
+static DEVICE_ATTR(text, S_IRUGO | S_IWUSR, show_attr_text, set_attr_text);
static ssize_t show_attr_decimals(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -272,8 +272,7 @@ static ssize_t set_attr_decimals(struct device *dev,
return count;
}
-static DEVICE_ATTR(decimals, S_IWUGO | S_IRUGO,
- show_attr_decimals, set_attr_decimals);
+static DEVICE_ATTR(decimals, S_IRUGO | S_IWUSR, show_attr_decimals, set_attr_decimals);
static ssize_t show_attr_textmode(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -319,8 +318,7 @@ static ssize_t set_attr_textmode(struct device *dev,
return -EINVAL;
}
-static DEVICE_ATTR(textmode, S_IWUGO | S_IRUGO,
- show_attr_textmode, set_attr_textmode);
+static DEVICE_ATTR(textmode, S_IRUGO | S_IWUSR, show_attr_textmode, set_attr_textmode);
MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered);
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 796e2f6..4ff2158 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -3,7 +3,7 @@
/*
* uss720.c -- USS720 USB Parport Cable.
*
- * Copyright (C) 1999, 2005
+ * Copyright (C) 1999, 2005, 2010
* Thomas Sailer (t.sailer@alumni.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
@@ -776,6 +776,8 @@ static const struct usb_device_id uss720_table[] = {
{ USB_DEVICE(0x0557, 0x2001) },
{ USB_DEVICE(0x0729, 0x1284) },
{ USB_DEVICE(0x1293, 0x0002) },
+ { USB_DEVICE(0x1293, 0x0002) },
+ { USB_DEVICE(0x050d, 0x0002) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index 719c618..ac5bfd6 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -536,6 +536,7 @@ static const struct file_operations yurex_fops = {
.open = yurex_open,
.release = yurex_release,
.fasync = yurex_fasync,
+ .llseek = default_llseek,
};
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index 44cb37b..c436e1e 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -15,7 +15,6 @@
#include <linux/poll.h>
#include <linux/compat.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c
index 8ec94f1..e5ce42b 100644
--- a/drivers/usb/mon/mon_stat.c
+++ b/drivers/usb/mon/mon_stat.c
@@ -11,7 +11,6 @@
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include "usb_mon.h"
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 611a9d2..fcb5206 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -171,8 +171,9 @@ static irqreturn_t blackfin_interrupt(int irq, void *__hci)
}
/* Start sampling ID pin, when plug is removed from MUSB */
- if (is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE
- || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+ if ((is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE
+ || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) ||
+ (musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) {
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
musb->a_wait_bcon = TIMER_DELAY;
}
@@ -323,30 +324,8 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
return -EIO;
}
-int __init musb_platform_init(struct musb *musb, void *board_data)
+static void musb_platform_reg_init(struct musb *musb)
{
-
- /*
- * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
- * and OTG HOST modes, while rev 1.1 and greater require PE7 to
- * be low for DEVICE mode and high for HOST mode. We set it high
- * here because we are in host mode
- */
-
- if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
- printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d \n",
- musb->config->gpio_vrsel);
- return -ENODEV;
- }
- gpio_direction_output(musb->config->gpio_vrsel, 0);
-
- usb_nop_xceiv_register();
- musb->xceiv = otg_get_transceiver();
- if (!musb->xceiv) {
- gpio_free(musb->config->gpio_vrsel);
- return -ENODEV;
- }
-
if (ANOMALY_05000346) {
bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
SSYNC();
@@ -358,7 +337,8 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
}
/* Configure PLL oscillator register */
- bfin_write_USB_PLLOSC_CTRL(0x30a8);
+ bfin_write_USB_PLLOSC_CTRL(0x3080 |
+ ((480/musb->config->clkin) << 1));
SSYNC();
bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1);
@@ -380,6 +360,33 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA |
EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA);
SSYNC();
+}
+
+int __init musb_platform_init(struct musb *musb, void *board_data)
+{
+
+ /*
+ * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
+ * and OTG HOST modes, while rev 1.1 and greater require PE7 to
+ * be low for DEVICE mode and high for HOST mode. We set it high
+ * here because we are in host mode
+ */
+
+ if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
+ printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d\n",
+ musb->config->gpio_vrsel);
+ return -ENODEV;
+ }
+ gpio_direction_output(musb->config->gpio_vrsel, 0);
+
+ usb_nop_xceiv_register();
+ musb->xceiv = otg_get_transceiver();
+ if (!musb->xceiv) {
+ gpio_free(musb->config->gpio_vrsel);
+ return -ENODEV;
+ }
+
+ musb_platform_reg_init(musb);
if (is_host_enabled(musb)) {
musb->board_set_vbus = bfin_set_vbus;
@@ -394,6 +401,27 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
return 0;
}
+#ifdef CONFIG_PM
+void musb_platform_save_context(struct musb *musb,
+ struct musb_context_registers *musb_context)
+{
+ if (is_host_active(musb))
+ /*
+ * During hibernate gpio_vrsel will change from high to low
+ * low which will generate wakeup event resume the system
+ * immediately. Set it to 0 before hibernate to avoid this
+ * wakeup event.
+ */
+ gpio_set_value(musb->config->gpio_vrsel, 0);
+}
+
+void musb_platform_restore_context(struct musb *musb,
+ struct musb_context_registers *musb_context)
+{
+ musb_platform_reg_init(musb);
+}
+#endif
+
int musb_platform_exit(struct musb *musb)
{
gpio_free(musb->config->gpio_vrsel);
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index c9f9024..99beebc 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -552,7 +552,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
if (int_usb & MUSB_INTR_SESSREQ) {
void __iomem *mbase = musb->mregs;
- if (devctl & MUSB_DEVCTL_BDEVICE) {
+ if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS
+ && (devctl & MUSB_DEVCTL_BDEVICE)) {
DBG(3, "SessReq while on B state\n");
return IRQ_HANDLED;
}
@@ -1052,6 +1053,11 @@ static void musb_shutdown(struct platform_device *pdev)
clk_put(musb->clock);
spin_unlock_irqrestore(&musb->lock, flags);
+ if (!is_otg_enabled(musb) && is_host_enabled(musb))
+ usb_remove_hcd(musb_to_hcd(musb));
+ musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
+ musb_platform_exit(musb);
+
/* FIXME power down */
}
@@ -2110,12 +2116,15 @@ bad_config:
* Otherwise, wait till the gadget driver hooks up.
*/
if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
+ struct usb_hcd *hcd = musb_to_hcd(musb);
+
MUSB_HST_MODE(musb);
musb->xceiv->default_a = 1;
musb->xceiv->state = OTG_STATE_A_IDLE;
status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
+ hcd->self.uses_pio_for_control = 1;
DBG(1, "%s mode, status %d, devctl %02x %c\n",
"HOST", status,
musb_readb(musb->mregs, MUSB_DEVCTL),
@@ -2244,13 +2253,6 @@ static int __exit musb_remove(struct platform_device *pdev)
*/
musb_exit_debugfs(musb);
musb_shutdown(pdev);
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
- if (musb->board_mode == MUSB_HOST)
- usb_remove_hcd(musb_to_hcd(musb));
-#endif
- musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
- musb_platform_exit(musb);
- musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
musb_free(musb);
iounmap(ctrl_base);
@@ -2411,9 +2413,6 @@ static int musb_suspend(struct device *dev)
unsigned long flags;
struct musb *musb = dev_to_musb(&pdev->dev);
- if (!musb->clock)
- return 0;
-
spin_lock_irqsave(&musb->lock, flags);
if (is_peripheral_active(musb)) {
@@ -2428,10 +2427,12 @@ static int musb_suspend(struct device *dev)
musb_save_context(musb);
- if (musb->set_clock)
- musb->set_clock(musb->clock, 0);
- else
- clk_disable(musb->clock);
+ if (musb->clock) {
+ if (musb->set_clock)
+ musb->set_clock(musb->clock, 0);
+ else
+ clk_disable(musb->clock);
+ }
spin_unlock_irqrestore(&musb->lock, flags);
return 0;
}
@@ -2441,13 +2442,12 @@ static int musb_resume_noirq(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct musb *musb = dev_to_musb(&pdev->dev);
- if (!musb->clock)
- return 0;
-
- if (musb->set_clock)
- musb->set_clock(musb->clock, 1);
- else
- clk_enable(musb->clock);
+ if (musb->clock) {
+ if (musb->set_clock)
+ musb->set_clock(musb->clock, 1);
+ else
+ clk_enable(musb->clock);
+ }
musb_restore_context(musb);
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 69797e5..febaabc 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -487,7 +487,7 @@ struct musb_context_registers {
};
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
- defined(CONFIG_ARCH_OMAP4)
+ defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_BLACKFIN)
extern void musb_platform_save_context(struct musb *musb,
struct musb_context_registers *musb_context);
extern void musb_platform_restore_context(struct musb *musb,
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 1cbeaa1..d5b9cfc 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -92,6 +92,59 @@
/* ----------------------------------------------------------------------- */
+/* Maps the buffer to dma */
+
+static inline void map_dma_buffer(struct musb_request *request,
+ struct musb *musb)
+{
+ if (request->request.dma == DMA_ADDR_INVALID) {
+ request->request.dma = dma_map_single(
+ musb->controller,
+ request->request.buf,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->mapped = 1;
+ } else {
+ dma_sync_single_for_device(musb->controller,
+ request->request.dma,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->mapped = 0;
+ }
+}
+
+/* Unmap the buffer from dma and maps it back to cpu */
+static inline void unmap_dma_buffer(struct musb_request *request,
+ struct musb *musb)
+{
+ if (request->request.dma == DMA_ADDR_INVALID) {
+ DBG(20, "not unmapping a never mapped buffer\n");
+ return;
+ }
+ if (request->mapped) {
+ dma_unmap_single(musb->controller,
+ request->request.dma,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ request->request.dma = DMA_ADDR_INVALID;
+ request->mapped = 0;
+ } else {
+ dma_sync_single_for_cpu(musb->controller,
+ request->request.dma,
+ request->request.length,
+ request->tx
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+
+ }
+}
+
/*
* Immediately complete a request.
*
@@ -119,24 +172,8 @@ __acquires(ep->musb->lock)
ep->busy = 1;
spin_unlock(&musb->lock);
- if (is_dma_capable()) {
- if (req->mapped) {
- dma_unmap_single(musb->controller,
- req->request.dma,
- req->request.length,
- req->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->request.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- } else if (req->request.dma != DMA_ADDR_INVALID)
- dma_sync_single_for_cpu(musb->controller,
- req->request.dma,
- req->request.length,
- req->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- }
+ if (is_dma_capable() && ep->dma)
+ unmap_dma_buffer(req, musb);
if (request->status == 0)
DBG(5, "%s done request %p, %d/%d\n",
ep->end_point.name, request,
@@ -395,6 +432,13 @@ static void txstate(struct musb *musb, struct musb_request *req)
#endif
if (!use_dma) {
+ /*
+ * Unmap the dma buffer back to cpu if dma channel
+ * programming fails
+ */
+ if (is_dma_capable() && musb_ep->dma)
+ unmap_dma_buffer(req, musb);
+
musb_write_fifo(musb_ep->hw_ep, fifo_count,
(u8 *) (request->buf + request->actual));
request->actual += fifo_count;
@@ -644,10 +688,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
*/
csr |= MUSB_RXCSR_DMAENAB;
- if (!musb_ep->hb_mult &&
- musb_ep->hw_ep->rx_double_buffered)
- csr |= MUSB_RXCSR_AUTOCLEAR;
#ifdef USE_MODE1
+ csr |= MUSB_RXCSR_AUTOCLEAR;
/* csr |= MUSB_RXCSR_DMAMODE; */
/* this special sequence (enabling and then
@@ -656,6 +698,10 @@ static void rxstate(struct musb *musb, struct musb_request *req)
*/
musb_writew(epio, MUSB_RXCSR,
csr | MUSB_RXCSR_DMAMODE);
+#else
+ if (!musb_ep->hb_mult &&
+ musb_ep->hw_ep->rx_double_buffered)
+ csr |= MUSB_RXCSR_AUTOCLEAR;
#endif
musb_writew(epio, MUSB_RXCSR, csr);
@@ -711,6 +757,21 @@ static void rxstate(struct musb *musb, struct musb_request *req)
return;
}
#endif
+ /*
+ * Unmap the dma buffer back to cpu if dma channel
+ * programming fails. This buffer is mapped if the
+ * channel allocation is successful
+ */
+ if (is_dma_capable() && musb_ep->dma) {
+ unmap_dma_buffer(req, musb);
+
+ /*
+ * Clear DMAENAB and AUTOCLEAR for the
+ * PIO mode transfer
+ */
+ csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR);
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *)
(request->buf + request->actual));
@@ -807,7 +868,7 @@ void musb_g_rx(struct musb *musb, u8 epnum)
#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
/* Autoclear doesn't clear RxPktRdy for short packets */
- if ((dma->desired_mode == 0)
+ if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered)
|| (dma->actual_len
& (musb_ep->packet_sz - 1))) {
/* ack the read! */
@@ -818,8 +879,16 @@ void musb_g_rx(struct musb *musb, u8 epnum)
/* incomplete, and not short? wait for next IN packet */
if ((request->actual < request->length)
&& (musb_ep->dma->actual_len
- == musb_ep->packet_sz))
+ == musb_ep->packet_sz)) {
+ /* In double buffer case, continue to unload fifo if
+ * there is Rx packet in FIFO.
+ **/
+ csr = musb_readw(epio, MUSB_RXCSR);
+ if ((csr & MUSB_RXCSR_RXPKTRDY) &&
+ hw_ep->rx_double_buffered)
+ goto exit;
return;
+ }
#endif
musb_g_giveback(musb_ep, request, 0);
@@ -827,7 +896,9 @@ void musb_g_rx(struct musb *musb, u8 epnum)
if (!request)
return;
}
-
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
+exit:
+#endif
/* Analyze request */
rxstate(musb, to_musb_request(request));
}
@@ -916,13 +987,9 @@ static int musb_gadget_enable(struct usb_ep *ep,
* likewise high bandwidth periodic tx
*/
/* Set TXMAXP with the FIFO size of the endpoint
- * to disable double buffering mode. Currently, It seems that double
- * buffering has problem if musb RTL revision number < 2.0.
+ * to disable double buffering mode.
*/
- if (musb->hwvers < MUSB_HWVERS_2000)
- musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
- else
- musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+ musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
if (musb_readw(regs, MUSB_TXCSR)
@@ -958,10 +1025,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
/* Set RXMAXP with the FIFO size of the endpoint
* to disable double buffering mode.
*/
- if (musb->hwvers < MUSB_HWVERS_2000)
- musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_rx);
- else
- musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+ musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
/* force shared fifo to OUT-only mode */
if (hw_ep->is_shared_fifo) {
@@ -1147,28 +1211,9 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
request->epnum = musb_ep->current_epnum;
request->tx = musb_ep->is_in;
- if (is_dma_capable() && musb_ep->dma) {
- if (request->request.dma == DMA_ADDR_INVALID) {
- request->request.dma = dma_map_single(
- musb->controller,
- request->request.buf,
- request->request.length,
- request->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- request->mapped = 1;
- } else {
- dma_sync_single_for_device(musb->controller,
- request->request.dma,
- request->request.length,
- request->tx
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- request->mapped = 0;
- }
- } else if (!req->buf) {
- return -ENODATA;
- } else
+ if (is_dma_capable() && musb_ep->dma)
+ map_dma_buffer(request, musb);
+ else
request->mapped = 0;
spin_lock_irqsave(&musb->lock, lockflags);
@@ -1695,8 +1740,10 @@ int __init musb_gadget_setup(struct musb *musb)
musb_platform_try_idle(musb, 0);
status = device_register(&musb->g.dev);
- if (status != 0)
+ if (status != 0) {
+ put_device(&musb->g.dev);
the_gadget = NULL;
+ }
return status;
}
@@ -1786,6 +1833,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
spin_unlock_irqrestore(&musb->lock, flags);
if (is_otg_enabled(musb)) {
+ struct usb_hcd *hcd = musb_to_hcd(musb);
+
DBG(3, "OTG startup...\n");
/* REVISIT: funcall to other code, which also
@@ -1800,6 +1849,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
musb->gadget_driver = NULL;
musb->g.dev.driver = NULL;
spin_unlock_irqrestore(&musb->lock, flags);
+ } else {
+ hcd->self.uses_pio_for_control = 1;
}
}
}
diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h
index 2442675..5a727c5 100644
--- a/drivers/usb/musb/musb_regs.h
+++ b/drivers/usb/musb/musb_regs.h
@@ -633,8 +633,9 @@ static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
return 0;
}
-static inline void musb_read_txhubport(void __iomem *mbase, u8 epnum)
+static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum)
{
+ return 0;
}
#endif /* CONFIG_BLACKFIN */
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 6f771af..563114d 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -158,6 +158,8 @@ static int dma_channel_program(struct dma_channel *channel,
dma_addr_t dma_addr, u32 len)
{
struct musb_dma_channel *musb_channel = channel->private_data;
+ struct musb_dma_controller *controller = musb_channel->controller;
+ struct musb *musb = controller->private_data;
DBG(2, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
musb_channel->epnum,
@@ -167,6 +169,18 @@ static int dma_channel_program(struct dma_channel *channel,
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
channel->status == MUSB_DMA_STATUS_BUSY);
+ /*
+ * The DMA engine in RTL1.8 and above cannot handle
+ * DMA addresses that are not aligned to a 4 byte boundary.
+ * It ends up masking the last two bits of the address
+ * programmed in DMA_ADDR.
+ *
+ * Fail such DMA transfers, so that the backup PIO mode
+ * can carry out the transfer
+ */
+ if ((musb->hwvers >= MUSB_HWVERS_1800) && (dma_addr % 4))
+ return false;
+
channel->actual_len = 0;
musb_channel->start_addr = dma_addr;
musb_channel->len = len;
diff --git a/drivers/usb/otg/langwell_otg.c b/drivers/usb/otg/langwell_otg.c
index bdc3ea6..9fea482 100644
--- a/drivers/usb/otg/langwell_otg.c
+++ b/drivers/usb/otg/langwell_otg.c
@@ -1896,7 +1896,7 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr,
}
return count;
}
-static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUGO, get_a_bus_req, set_a_bus_req);
+static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, set_a_bus_req);
static ssize_t
get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1942,8 +1942,7 @@ set_a_bus_drop(struct device *dev, struct device_attribute *attr,
}
return count;
}
-static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUGO,
- get_a_bus_drop, set_a_bus_drop);
+static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, get_a_bus_drop, set_a_bus_drop);
static ssize_t
get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1988,7 +1987,7 @@ set_b_bus_req(struct device *dev, struct device_attribute *attr,
}
return count;
}
-static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUGO, get_b_bus_req, set_b_bus_req);
+static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR, get_b_bus_req, set_b_bus_req);
static ssize_t
set_a_clr_err(struct device *dev, struct device_attribute *attr,
@@ -2012,7 +2011,7 @@ set_a_clr_err(struct device *dev, struct device_attribute *attr,
}
return count;
}
-static DEVICE_ATTR(a_clr_err, S_IWUGO, NULL, set_a_clr_err);
+static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err);
static struct attribute *inputs_attrs[] = {
&dev_attr_a_bus_req.attr,
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 89a9a58..2dec500 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -201,6 +201,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) },
+ { USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) },
@@ -696,6 +697,7 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
@@ -794,6 +796,9 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
+ { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 7dfe02f1..bf08672 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -114,6 +114,9 @@
/* Lenz LI-USB Computer Interface. */
#define FTDI_LENZ_LIUSB_PID 0xD780
+/* Vardaan Enterprises Serial Interface VEUSB422R3 */
+#define FTDI_VARDAAN_PID 0xF070
+
/*
* Xsens Technologies BV products (http://www.xsens.com).
*/
@@ -721,6 +724,7 @@
*/
#define RTSYSTEMS_VID 0x2100 /* Vendor ID */
#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */
+#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */
/*
* Bayer Ascensia Contour blood glucose meter USB-converter cable.
@@ -1077,6 +1081,11 @@
#define MJSG_HD_RADIO_PID 0x937C
/*
+ * D.O.Tec products (http://www.directout.eu)
+ */
+#define FTDI_DOTEC_PID 0x9868
+
+/*
* Xverve Signalyzer tools (http://www.signalyzer.com/)
*/
#define XVERVE_SIGNALYZER_ST_PID 0xBCA0
@@ -1100,3 +1109,10 @@
#define FTDI_SCIENCESCOPE_LOGBOOKML_PID 0xFF18
#define FTDI_SCIENCESCOPE_LS_LOGBOOK_PID 0xFF1C
#define FTDI_SCIENCESCOPE_HS_LOGBOOK_PID 0xFF1D
+
+/*
+ * Milkymist One JTAG/Serial
+ */
+#define QIHARDWARE_VID 0x20B7
+#define MILKYMISTONE_JTAGSERIAL_PID 0x0713
+
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 2297fb1..ef2977d 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -518,7 +518,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) },
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index e64da74..6954de5 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -21,7 +21,6 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
@@ -52,6 +51,7 @@ static struct usb_driver usb_serial_driver = {
.suspend = usb_serial_suspend,
.resume = usb_serial_resume,
.no_dynamic_id = 1,
+ .supports_autosuspend = 1,
};
/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
@@ -1344,6 +1344,8 @@ int usb_serial_register(struct usb_serial_driver *driver)
return -ENODEV;
fixup_generic(driver);
+ if (driver->usb_driver)
+ driver->usb_driver->supports_autosuspend = 1;
if (!driver->description)
driver->description = driver->driver.name;
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index a688b1e..689ee1f 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -285,7 +285,7 @@ static int slave_configure(struct scsi_device *sdev)
/* queue a command */
/* This is always called with scsi_lock(host) held */
-static int queuecommand(struct scsi_cmnd *srb,
+static int queuecommand_lck(struct scsi_cmnd *srb,
void (*done)(struct scsi_cmnd *))
{
struct us_data *us = host_to_us(srb->device->host);
@@ -315,6 +315,8 @@ static int queuecommand(struct scsi_cmnd *srb,
return 0;
}
+static DEF_SCSI_QCMD(queuecommand)
+
/***********************************************************************
* Error handling functions
***********************************************************************/
diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c
index 57fc2f5..ceba512 100644
--- a/drivers/usb/storage/sierra_ms.c
+++ b/drivers/usb/storage/sierra_ms.c
@@ -121,7 +121,7 @@ static ssize_t show_truinst(struct device *dev, struct device_attribute *attr,
}
return result;
}
-static DEVICE_ATTR(truinst, S_IWUGO | S_IRUGO, show_truinst, NULL);
+static DEVICE_ATTR(truinst, S_IRUGO, show_truinst, NULL);
int sierra_ms_init(struct us_data *us)
{
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 2054b1e..339fac3 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -331,10 +331,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
iu->iu_id = IU_ID_COMMAND;
iu->tag = cpu_to_be16(stream_id);
- if (sdev->ordered_tags && (cmnd->request->cmd_flags & REQ_HARDBARRIER))
- iu->prio_attr = UAS_ORDERED_TAG;
- else
- iu->prio_attr = UAS_SIMPLE_TAG;
+ iu->prio_attr = UAS_SIMPLE_TAG;
iu->len = len;
int_to_scsilun(sdev->lun, &iu->lun);
memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);
@@ -433,7 +430,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
return 0;
}
-static int uas_queuecommand(struct scsi_cmnd *cmnd,
+static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
void (*done)(struct scsi_cmnd *))
{
struct scsi_device *sdev = cmnd->device;
@@ -491,6 +488,8 @@ static int uas_queuecommand(struct scsi_cmnd *cmnd,
return 0;
}
+static DEF_SCSI_QCMD(uas_queuecommand)
+
static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
{
struct scsi_device *sdev = cmnd->device;
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 6ccdd3d..fcc1e32 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -481,6 +481,13 @@ UNUSUAL_DEV( 0x04e8, 0x507c, 0x0220, 0x0220,
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_MAX_SECTORS_64),
+/* Reported by Vitaly Kuznetsov <vitty@altlinux.ru> */
+UNUSUAL_DEV( 0x04e8, 0x5122, 0x0000, 0x9999,
+ "Samsung",
+ "YP-CP3",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 | US_FL_BULK_IGNORE_TAG),
+
/* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
* Device uses standards-violating 32-byte Bulk Command Block Wrappers and
* reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011.
OpenPOWER on IntegriCloud