aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/class/cdc-acm.c18
-rw-r--r--drivers/usb/core/hub.c2
-rw-r--r--drivers/usb/gadget/amd5536udc.c49
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/ehci-pci.c4
-rw-r--r--drivers/usb/host/ehci-q.c16
-rw-r--r--drivers/usb/host/ehci-sched.c12
-rw-r--r--drivers/usb/host/ehci.h2
-rw-r--r--drivers/usb/host/ohci-hcd.c5
-rw-r--r--drivers/usb/host/ohci-pci.c20
-rw-r--r--drivers/usb/host/ohci-q.c18
-rw-r--r--drivers/usb/host/ohci.h9
-rw-r--r--drivers/usb/host/xhci-mem.c10
-rw-r--r--drivers/usb/host/xhci-ring.c7
-rw-r--r--drivers/usb/mon/mon_bin.c11
-rw-r--r--drivers/usb/musb/cppi_dma.c10
-rw-r--r--drivers/usb/musb/musb_core.c4
-rw-r--r--drivers/usb/musb/musb_gadget.c79
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c3
-rw-r--r--drivers/usb/musb/musb_host.c5
-rw-r--r--drivers/usb/serial/cp210x.c21
-rw-r--r--drivers/usb/serial/ftdi_sio.c3
-rw-r--r--drivers/usb/serial/option.c7
23 files changed, 217 insertions, 100 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index e3861b21e77..e4eca7810bc 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -609,9 +609,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
acm->throttle = 0;
- tasklet_schedule(&acm->urb_task);
set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
rv = tty_port_block_til_ready(&acm->port, tty, filp);
+ tasklet_schedule(&acm->urb_task);
done:
mutex_unlock(&acm->mutex);
err_out:
@@ -686,15 +686,21 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
/* Perform the closing process and see if we need to do the hardware
shutdown */
- if (!acm || tty_port_close_start(&acm->port, tty, filp) == 0)
+ if (!acm)
+ return;
+ if (tty_port_close_start(&acm->port, tty, filp) == 0) {
+ mutex_lock(&open_mutex);
+ if (!acm->dev) {
+ tty_port_tty_set(&acm->port, NULL);
+ acm_tty_unregister(acm);
+ tty->driver_data = NULL;
+ }
+ mutex_unlock(&open_mutex);
return;
+ }
acm_port_down(acm, 0);
tty_port_close_end(&acm->port, tty);
- mutex_lock(&open_mutex);
tty_port_tty_set(&acm->port, NULL);
- if (!acm->dev)
- acm_tty_unregister(acm);
- mutex_unlock(&open_mutex);
}
static int acm_tty_write(struct tty_struct *tty,
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5ce839137ad..0f857e64505 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -444,7 +444,7 @@ resubmit:
static inline int
hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt)
{
- return usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
+ return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo,
tt, NULL, 0, 1000);
}
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index d5b65962dd3..731150d4b1d 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -1213,7 +1213,12 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
tmp &= AMD_UNMASK_BIT(ep->num);
writel(tmp, &dev->regs->ep_irqmsk);
}
- }
+ } else if (ep->in) {
+ /* enable ep irq */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp &= AMD_UNMASK_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+ }
} else if (ep->dma) {
@@ -2005,18 +2010,17 @@ __acquires(dev->lock)
{
int tmp;
- /* empty queues and init hardware */
- udc_basic_init(dev);
- for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
- empty_req_queue(&dev->ep[tmp]);
- }
-
if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
- /* init */
+
+ /* empty queues and init hardware */
+ udc_basic_init(dev);
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
+ empty_req_queue(&dev->ep[tmp]);
+
udc_setup_endpoints(dev);
}
@@ -2472,6 +2476,13 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
}
}
+ } else if (!use_dma && ep->in) {
+ /* disable interrupt */
+ tmp = readl(
+ &dev->regs->ep_irqmsk);
+ tmp |= AMD_BIT(ep->num);
+ writel(tmp,
+ &dev->regs->ep_irqmsk);
}
}
/* clear status bits */
@@ -3279,6 +3290,17 @@ static int udc_pci_probe(
goto finished;
}
+ spin_lock_init(&dev->lock);
+ /* udc csr registers base */
+ dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+ /* dev registers base */
+ dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+ /* ep registers base */
+ dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+ /* fifo's base */
+ dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+ dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+
if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
kfree(dev);
@@ -3331,7 +3353,6 @@ static int udc_probe(struct udc *dev)
udc_pollstall_timer.data = 0;
/* device struct setup */
- spin_lock_init(&dev->lock);
dev->gadget.ops = &udc_ops;
dev_set_name(&dev->gadget.dev, "gadget");
@@ -3340,16 +3361,6 @@ static int udc_probe(struct udc *dev)
dev->gadget.name = name;
dev->gadget.is_dualspeed = 1;
- /* udc csr registers base */
- dev->csr = dev->virt_addr + UDC_CSR_ADDR;
- /* dev registers base */
- dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
- /* ep registers base */
- dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
- /* fifo's base */
- dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
- dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
-
/* init registers, interrupts, ... */
startup_registers(dev);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 9835e071394..f5f5601701c 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -28,6 +28,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
+#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/usb.h>
@@ -676,6 +677,7 @@ static int ehci_run (struct usb_hcd *hcd)
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
msleep(5);
up_write(&ehci_cf_port_reset_rwsem);
+ ehci->last_periodic_enable = ktime_get_real();
temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info (ehci,
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 378861b9d79..ead5f4f2aa5 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -111,6 +111,10 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
switch (pdev->vendor) {
case PCI_VENDOR_ID_INTEL:
ehci->need_io_watchdog = 0;
+ if (pdev->device == 0x27cc) {
+ ehci->broken_periodic = 1;
+ ehci_info(ehci, "using broken periodic workaround\n");
+ }
break;
case PCI_VENDOR_ID_TDI:
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 00ad9ce392e..139a2cc3f64 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -487,8 +487,20 @@ halt:
* we must clear the TT buffer (11.17.5).
*/
if (unlikely(last_status != -EINPROGRESS &&
- last_status != -EREMOTEIO))
- ehci_clear_tt_buffer(ehci, qh, urb, token);
+ last_status != -EREMOTEIO)) {
+ /* The TT's in some hubs malfunction when they
+ * receive this request following a STALL (they
+ * stop sending isochronous packets). Since a
+ * STALL can't leave the TT buffer in a busy
+ * state (if you believe Figures 11-48 - 11-51
+ * in the USB 2.0 spec), we won't clear the TT
+ * buffer in this case. Strictly speaking this
+ * is a violation of the spec.
+ */
+ if (last_status != -EPIPE)
+ ehci_clear_tt_buffer(ehci, qh, urb,
+ token);
+ }
}
/* if we're removing something not at the queue head,
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index b25cdea93a1..a5535b5e3fe 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -475,6 +475,8 @@ static int enable_periodic (struct ehci_hcd *ehci)
/* make sure ehci_work scans these */
ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
% (ehci->periodic_size << 3);
+ if (unlikely(ehci->broken_periodic))
+ ehci->last_periodic_enable = ktime_get_real();
return 0;
}
@@ -486,6 +488,16 @@ static int disable_periodic (struct ehci_hcd *ehci)
if (--ehci->periodic_sched)
return 0;
+ if (unlikely(ehci->broken_periodic)) {
+ /* delay experimentally determined */
+ ktime_t safe = ktime_add_us(ehci->last_periodic_enable, 1000);
+ ktime_t now = ktime_get_real();
+ s64 delay = ktime_us_delta(safe, now);
+
+ if (unlikely(delay > 0))
+ udelay(delay);
+ }
+
/* did setting PSE not take effect yet?
* takes effect only at frame boundaries...
*/
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 064e76821ff..2d85e21ff28 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -118,6 +118,7 @@ struct ehci_hcd { /* one per controller */
unsigned stamp;
unsigned random_frame;
unsigned long next_statechange;
+ ktime_t last_periodic_enable;
u32 command;
/* SILICON QUIRKS */
@@ -127,6 +128,7 @@ struct ehci_hcd { /* one per controller */
unsigned big_endian_desc:1;
unsigned has_amcc_usb23:1;
unsigned need_io_watchdog:1;
+ unsigned broken_periodic:1;
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 78bb7710f36..24eb7478191 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -87,6 +87,7 @@ static int ohci_restart (struct ohci_hcd *ohci);
#ifdef CONFIG_PCI
static void quirk_amd_pll(int state);
static void amd_iso_dev_put(void);
+static void sb800_prefetch(struct ohci_hcd *ohci, int on);
#else
static inline void quirk_amd_pll(int state)
{
@@ -96,6 +97,10 @@ static inline void amd_iso_dev_put(void)
{
return;
}
+static inline void sb800_prefetch(struct ohci_hcd *ohci, int on)
+{
+ return;
+}
#endif
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index d2ba04dd785..b8a1148f248 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -177,6 +177,13 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd)
return 0;
pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
+
+ /* SB800 needs pre-fetch fix */
+ if ((rev >= 0x40) && (rev <= 0x4f)) {
+ ohci->flags |= OHCI_QUIRK_AMD_PREFETCH;
+ ohci_dbg(ohci, "enabled AMD prefetch quirk\n");
+ }
+
if ((rev > 0x3b) || (rev < 0x30)) {
pci_dev_put(amd_smbus_dev);
amd_smbus_dev = NULL;
@@ -262,6 +269,19 @@ static void amd_iso_dev_put(void)
}
+static void sb800_prefetch(struct ohci_hcd *ohci, int on)
+{
+ struct pci_dev *pdev;
+ u16 misc;
+
+ pdev = to_pci_dev(ohci_to_hcd(ohci)->self.controller);
+ pci_read_config_word(pdev, 0x50, &misc);
+ if (on == 0)
+ pci_write_config_word(pdev, 0x50, misc & 0xfcff);
+ else
+ pci_write_config_word(pdev, 0x50, misc | 0x0300);
+}
+
/* List of quirks for OHCI */
static const struct pci_device_id ohci_pci_quirks[] = {
{
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 16fecb8ecc3..35288bcae0d 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -49,9 +49,12 @@ __acquires(ohci->lock)
switch (usb_pipetype (urb->pipe)) {
case PIPE_ISOCHRONOUS:
ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--;
- if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0
- && quirk_amdiso(ohci))
- quirk_amd_pll(1);
+ if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
+ if (quirk_amdiso(ohci))
+ quirk_amd_pll(1);
+ if (quirk_amdprefetch(ohci))
+ sb800_prefetch(ohci, 0);
+ }
break;
case PIPE_INTERRUPT:
ohci_to_hcd(ohci)->self.bandwidth_int_reqs--;
@@ -680,9 +683,12 @@ static void td_submit_urb (
data + urb->iso_frame_desc [cnt].offset,
urb->iso_frame_desc [cnt].length, urb, cnt);
}
- if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0
- && quirk_amdiso(ohci))
- quirk_amd_pll(0);
+ if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
+ if (quirk_amdiso(ohci))
+ quirk_amd_pll(0);
+ if (quirk_amdprefetch(ohci))
+ sb800_prefetch(ohci, 1);
+ }
periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0
&& ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0;
break;
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 222011f6172..5bf15fed0d9 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -402,6 +402,7 @@ struct ohci_hcd {
#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */
#define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */
#define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/
+#define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */
// there are also chip quirks/bugs in init logic
struct work_struct nec_work; /* Worker for NEC quirk */
@@ -433,6 +434,10 @@ static inline int quirk_amdiso(struct ohci_hcd *ohci)
{
return ohci->flags & OHCI_QUIRK_AMD_ISO;
}
+static inline int quirk_amdprefetch(struct ohci_hcd *ohci)
+{
+ return ohci->flags & OHCI_QUIRK_AMD_PREFETCH;
+}
#else
static inline int quirk_nec(struct ohci_hcd *ohci)
{
@@ -446,6 +451,10 @@ static inline int quirk_amdiso(struct ohci_hcd *ohci)
{
return 0;
}
+static inline int quirk_amdprefetch(struct ohci_hcd *ohci)
+{
+ return 0;
+}
#endif
/* convert between an hcd pointer and the corresponding ohci_hcd */
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 1db4fea8c17..b8fd270a8b0 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -802,9 +802,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
int i;
/* Free the Event Ring Segment Table and the actual Event Ring */
- xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
- xhci_write_64(xhci, 0, &xhci->ir_set->erst_base);
- xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue);
+ if (xhci->ir_set) {
+ xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
+ xhci_write_64(xhci, 0, &xhci->ir_set->erst_base);
+ xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue);
+ }
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
if (xhci->erst.entries)
pci_free_consistent(pdev, size,
@@ -841,9 +843,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->dcbaa, xhci->dcbaa->dma);
xhci->dcbaa = NULL;
+ scratchpad_free(xhci);
xhci->page_size = 0;
xhci->page_shift = 0;
- scratchpad_free(xhci);
}
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 173c39c7648..821b7b4709d 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -864,9 +864,11 @@ static struct xhci_segment *trb_in_td(
cur_seg = start_seg;
do {
+ if (start_dma == 0)
+ return 0;
/* We may get an event for a Link TRB in the middle of a TD */
end_seg_dma = xhci_trb_virt_to_dma(cur_seg,
- &start_seg->trbs[TRBS_PER_SEGMENT - 1]);
+ &cur_seg->trbs[TRBS_PER_SEGMENT - 1]);
/* If the end TRB isn't in this segment, this is set to 0 */
end_trb_dma = xhci_trb_virt_to_dma(cur_seg, end_trb);
@@ -893,8 +895,9 @@ static struct xhci_segment *trb_in_td(
}
cur_seg = cur_seg->next;
start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]);
- } while (1);
+ } while (cur_seg != start_seg);
+ return 0;
}
/*
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index 9ed3e741bee..10f3205798e 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -348,12 +348,12 @@ static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp,
/*
* Return a few (kilo-)bytes to the head of the buffer.
- * This is used if a DMA fetch fails.
+ * This is used if a data fetch fails.
*/
static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size)
{
- size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ /* size &= ~(PKT_ALIGN-1); -- we're called with aligned size */
rp->b_cnt -= size;
if (rp->b_in < size)
rp->b_in += rp->b_size;
@@ -433,6 +433,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
unsigned int urb_length;
unsigned int offset;
unsigned int length;
+ unsigned int delta;
unsigned int ndesc, lendesc;
unsigned char dir;
struct mon_bin_hdr *ep;
@@ -537,8 +538,10 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
if (length != 0) {
ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */
- ep->len_cap = 0;
- mon_buff_area_shrink(rp, length);
+ delta = (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ ep->len_cap -= length;
+ delta -= (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ mon_buff_area_shrink(rp, delta);
}
} else {
ep->flag_data = data_tag;
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index c3577bbbae6..ef2332a9941 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -1442,11 +1442,6 @@ static int cppi_channel_abort(struct dma_channel *channel)
musb_writew(regs, MUSB_TXCSR, value);
musb_writew(regs, MUSB_TXCSR, value);
- /* re-enable interrupt */
- if (enabled)
- musb_writel(tibase, DAVINCI_TXCPPI_INTENAB_REG,
- (1 << cppi_ch->index));
-
/* While we scrub the TX state RAM, ensure that we clean
* up any interrupt that's currently asserted:
* 1. Write to completion Ptr value 0x1(bit 0 set)
@@ -1459,6 +1454,11 @@ static int cppi_channel_abort(struct dma_channel *channel)
cppi_reset_tx(tx_ram, 1);
musb_writel(&tx_ram->tx_complete, 0, 0);
+ /* re-enable interrupt */
+ if (enabled)
+ musb_writel(tibase, DAVINCI_TXCPPI_INTENAB_REG,
+ (1 << cppi_ch->index));
+
cppi_dump_tx(5, cppi_ch, " (done teardown)");
/* REVISIT tx side _should_ clean up the same way
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 3a61ddb62bd..547e0e39072 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1450,7 +1450,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
#endif
if (hw_ep->max_packet_sz_tx) {
- printk(KERN_DEBUG
+ DBG(1,
"%s: hw_ep %d%s, %smax %d\n",
musb_driver_name, i,
hw_ep->is_shared_fifo ? "shared" : "tx",
@@ -1459,7 +1459,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
hw_ep->max_packet_sz_tx);
}
if (hw_ep->max_packet_sz_rx && !hw_ep->is_shared_fifo) {
- printk(KERN_DEBUG
+ DBG(1,
"%s: hw_ep %d%s, %smax %d\n",
musb_driver_name, i,
"rx",
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 8b3c4e2ed7b..74073f9a43f 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -4,6 +4,7 @@
* Copyright 2005 Mentor Graphics Corporation
* Copyright (C) 2005-2006 by Texas Instruments
* Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2009 MontaVista Software, Inc. <source@mvista.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -436,14 +437,6 @@ void musb_g_tx(struct musb *musb, u8 epnum)
csr |= MUSB_TXCSR_P_WZC_BITS;
csr &= ~MUSB_TXCSR_P_SENTSTALL;
musb_writew(epio, MUSB_TXCSR, csr);
- if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
- dma->status = MUSB_DMA_STATUS_CORE_ABORT;
- musb->dma_controller->channel_abort(dma);
- }
-
- if (request)
- musb_g_giveback(musb_ep, request, -EPIPE);
-
break;
}
@@ -582,15 +575,25 @@ void musb_g_tx(struct musb *musb, u8 epnum)
*/
static void rxstate(struct musb *musb, struct musb_request *req)
{
- u16 csr = 0;
const u8 epnum = req->epnum;
struct usb_request *request = &req->request;
struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out;
void __iomem *epio = musb->endpoints[epnum].regs;
unsigned fifo_count = 0;
u16 len = musb_ep->packet_sz;
+ u16 csr = musb_readw(epio, MUSB_RXCSR);
- csr = musb_readw(epio, MUSB_RXCSR);
+ /* We shouldn't get here while DMA is active, but we do... */
+ if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
+ DBG(4, "DMA pending...\n");
+ return;
+ }
+
+ if (csr & MUSB_RXCSR_P_SENDSTALL) {
+ DBG(5, "%s stalling, RXCSR %04x\n",
+ musb_ep->end_point.name, csr);
+ return;
+ }
if (is_cppi_enabled() && musb_ep->dma) {
struct dma_controller *c = musb->dma_controller;
@@ -761,19 +764,10 @@ void musb_g_rx(struct musb *musb, u8 epnum)
csr, dma ? " (dma)" : "", request);
if (csr & MUSB_RXCSR_P_SENTSTALL) {
- if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
- dma->status = MUSB_DMA_STATUS_CORE_ABORT;
- (void) musb->dma_controller->channel_abort(dma);
- request->actual += musb_ep->dma->actual_len;
- }
-
csr |= MUSB_RXCSR_P_WZC_BITS;
csr &= ~MUSB_RXCSR_P_SENTSTALL;
musb_writew(epio, MUSB_RXCSR, csr);
-
- if (request)
- musb_g_giveback(musb_ep, request, -EPIPE);
- goto done;
+ return;
}
if (csr & MUSB_RXCSR_P_OVERRUN) {
@@ -795,7 +789,7 @@ void musb_g_rx(struct musb *musb, u8 epnum)
DBG((csr & MUSB_RXCSR_DMAENAB) ? 4 : 1,
"%s busy, csr %04x\n",
musb_ep->end_point.name, csr);
- goto done;
+ return;
}
if (dma && (csr & MUSB_RXCSR_DMAENAB)) {
@@ -826,22 +820,15 @@ void musb_g_rx(struct musb *musb, u8 epnum)
if ((request->actual < request->length)
&& (musb_ep->dma->actual_len
== musb_ep->packet_sz))
- goto done;
+ return;
#endif
musb_g_giveback(musb_ep, request, 0);
request = next_request(musb_ep);
if (!request)
- goto done;
-
- /* don't start more i/o till the stall clears */
- musb_ep_select(mbase, epnum);
- csr = musb_readw(epio, MUSB_RXCSR);
- if (csr & MUSB_RXCSR_P_SENDSTALL)
- goto done;
+ return;
}
-
/* analyze request if the ep is hot */
if (request)
rxstate(musb, to_musb_request(request));
@@ -849,8 +836,6 @@ void musb_g_rx(struct musb *musb, u8 epnum)
DBG(3, "packet waiting for %s%s request\n",
musb_ep->desc ? "" : "inactive ",
musb_ep->end_point.name);
-
-done:
return;
}
@@ -1244,7 +1229,7 @@ int musb_gadget_set_halt(struct usb_ep *ep, int value)
void __iomem *mbase;
unsigned long flags;
u16 csr;
- struct musb_request *request = NULL;
+ struct musb_request *request;
int status = 0;
if (!ep)
@@ -1260,24 +1245,29 @@ int musb_gadget_set_halt(struct usb_ep *ep, int value)
musb_ep_select(mbase, epnum);
- /* cannot portably stall with non-empty FIFO */
request = to_musb_request(next_request(musb_ep));
- if (value && musb_ep->is_in) {
- csr = musb_readw(epio, MUSB_TXCSR);
- if (csr & MUSB_TXCSR_FIFONOTEMPTY) {
- DBG(3, "%s fifo busy, cannot halt\n", ep->name);
- spin_unlock_irqrestore(&musb->lock, flags);
- return -EAGAIN;
+ if (value) {
+ if (request) {
+ DBG(3, "request in progress, cannot halt %s\n",
+ ep->name);
+ status = -EAGAIN;
+ goto done;
+ }
+ /* Cannot portably stall with non-empty FIFO */
+ if (musb_ep->is_in) {
+ csr = musb_readw(epio, MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_FIFONOTEMPTY) {
+ DBG(3, "FIFO busy, cannot halt %s\n", ep->name);
+ status = -EAGAIN;
+ goto done;
+ }
}
-
}
/* set/clear the stall and toggle bits */
DBG(2, "%s: %s stall\n", ep->name, value ? "set" : "clear");
if (musb_ep->is_in) {
csr = musb_readw(epio, MUSB_TXCSR);
- if (csr & MUSB_TXCSR_FIFONOTEMPTY)
- csr |= MUSB_TXCSR_FLUSHFIFO;
csr |= MUSB_TXCSR_P_WZC_BITS
| MUSB_TXCSR_CLRDATATOG;
if (value)
@@ -1300,14 +1290,13 @@ int musb_gadget_set_halt(struct usb_ep *ep, int value)
musb_writew(epio, MUSB_RXCSR, csr);
}
-done:
-
/* maybe start the first request in the queue */
if (!musb_ep->busy && !value && request) {
DBG(3, "restarting the request\n");
musb_ep_restart(musb, request);
}
+done:
spin_unlock_irqrestore(&musb->lock, flags);
return status;
}
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 7a6778675ad..522efb31b56 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -511,7 +511,8 @@ static void ep0_txstate(struct musb *musb)
/* update the flags */
if (fifo_count < MUSB_MAX_END0_PACKET
- || request->actual == request->length) {
+ || (request->actual == request->length
+ && !request->zero)) {
musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT;
csr |= MUSB_CSR0_P_DATAEND;
} else
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index cf94511485f..e3ab40a966e 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -1301,8 +1301,11 @@ void musb_host_tx(struct musb *musb, u8 epnum)
return;
} else if (usb_pipeisoc(pipe) && dma) {
if (musb_tx_dma_program(musb->dma_controller, hw_ep, qh, urb,
- offset, length))
+ offset, length)) {
+ if (is_cppi_enabled() || tusb_dma_omap())
+ musb_h_tx_dma_start(hw_ep);
return;
+ }
} else if (tx_csr & MUSB_TXCSR_DMAENAB) {
DBG(1, "not complete, but DMA enabled?\n");
return;
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 698252a4dc5..bd254ec97d1 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -50,6 +50,8 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *,
static void cp210x_break_ctl(struct tty_struct *, int);
static int cp210x_startup(struct usb_serial *);
static void cp210x_disconnect(struct usb_serial *);
+static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
+static int cp210x_carrier_raised(struct usb_serial_port *p);
static int debug;
@@ -143,6 +145,8 @@ static struct usb_serial_driver cp210x_device = {
.tiocmset = cp210x_tiocmset,
.attach = cp210x_startup,
.disconnect = cp210x_disconnect,
+ .dtr_rts = cp210x_dtr_rts,
+ .carrier_raised = cp210x_carrier_raised
};
/* Config request types */
@@ -746,6 +750,14 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *file,
return cp210x_set_config(port, CP210X_SET_MHS, &control, 2);
}
+static void cp210x_dtr_rts(struct usb_serial_port *p, int on)
+{
+ if (on)
+ cp210x_tiocmset_port(p, NULL, TIOCM_DTR|TIOCM_RTS, 0);
+ else
+ cp210x_tiocmset_port(p, NULL, 0, TIOCM_DTR|TIOCM_RTS);
+}
+
static int cp210x_tiocmget (struct tty_struct *tty, struct file *file)
{
struct usb_serial_port *port = tty->driver_data;
@@ -768,6 +780,15 @@ static int cp210x_tiocmget (struct tty_struct *tty, struct file *file)
return result;
}
+static int cp210x_carrier_raised(struct usb_serial_port *p)
+{
+ unsigned int control;
+ cp210x_get_config(p, CP210X_GET_MDMSTS, &control, 1);
+ if (control & CONTROL_DCD)
+ return 1;
+ return 0;
+}
+
static void cp210x_break_ctl (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 9c60d6d4908..ebcc6d0e2e9 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1937,7 +1937,7 @@ static void ftdi_write_bulk_callback(struct urb *urb)
return;
}
/* account for transferred data */
- countback = urb->actual_length;
+ countback = urb->transfer_buffer_length;
data_offset = priv->write_offset;
if (data_offset > 0) {
/* Subtract the control bytes */
@@ -1950,7 +1950,6 @@ static void ftdi_write_bulk_callback(struct urb *urb)
if (status) {
dbg("nonzero write bulk status received: %d", status);
- return;
}
usb_serial_port_softint(port);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index cd44c68954d..0577e4b6111 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -308,6 +308,7 @@ static int option_resume(struct usb_serial *serial);
#define DLINK_VENDOR_ID 0x1186
#define DLINK_PRODUCT_DWM_652 0x3e04
+#define DLINK_PRODUCT_DWM_652_U5 0xce16
#define QISDA_VENDOR_ID 0x1da5
#define QISDA_PRODUCT_H21_4512 0x4512
@@ -335,6 +336,10 @@ static int option_resume(struct usb_serial *serial);
#define AIRPLUS_VENDOR_ID 0x1011
#define AIRPLUS_PRODUCT_MCD650 0x3198
+/* 4G Systems products */
+#define FOUR_G_SYSTEMS_VENDOR_ID 0x1c9e
+#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603
+
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -586,6 +591,7 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
{ USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
+ { USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5) }, /* Yes, ALINK_VENDOR_ID */
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) },
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) },
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) },
@@ -597,6 +603,7 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) },
{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
{ USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
+ { USB_DEVICE(FOUR_G_SYSTEMS_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);