diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-11-18 07:37:51 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-11-18 07:37:51 -0800 |
commit | 2d5bc23b32e0ec6fe9c1cdd9f371063881dc1ffc (patch) | |
tree | 3203cf45058a8ce7ebc3c712fd872e0c85fd5ccc /drivers | |
parent | 78db1caa8ae4e549ffc0bbf0f9b52c113e9a4da0 (diff) | |
parent | ff854ce0b17161a86b5ae444c6cb0aa221720fab (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6:
USB: option.c: add support for D-Link DWM-162-U5
USB: usbmon: fix bug in mon_buff_area_shrink
USB: xhci: Fix scratchpad deallocation.
USB: xhci: Fix TRB physical to virtual address translation.
USB: xhci: Fix bug memory free after failed initialization.
USB: cdc_acm: Fix memory leak after hangup
USB: cdc_acm: Fix race condition when opening tty
USB: ohci: quirk AMD prefetch for USB 1.1 ISO transfer
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 18 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/ohci-pci.c | 20 | ||||
-rw-r--r-- | drivers/usb/host/ohci-q.c | 18 | ||||
-rw-r--r-- | drivers/usb/host/ohci.h | 9 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 10 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 7 | ||||
-rw-r--r-- | drivers/usb/mon/mon_bin.c | 11 | ||||
-rw-r--r-- | drivers/usb/serial/option.c | 2 |
9 files changed, 78 insertions, 22 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index e3861b21e776..e4eca7810bcf 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/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 78bb7710f36d..24eb74781919 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 d2ba04dd785e..b8a1148f248e 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 16fecb8ecc39..35288bcae0db 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 222011f6172c..5bf15fed0d9f 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 1db4fea8c170..b8fd270a8b0d 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 173c39c76489..821b7b4709de 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 9ed3e741bee1..10f3205798e8 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/serial/option.c b/drivers/usb/serial/option.c index cd44c68954df..319aaf9725b3 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 @@ -586,6 +587,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) }, |