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
This commit is contained in:
commit
2d5bc23b32
9 changed files with 78 additions and 22 deletions
|
@ -609,9 +609,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
||||||
|
|
||||||
acm->throttle = 0;
|
acm->throttle = 0;
|
||||||
|
|
||||||
tasklet_schedule(&acm->urb_task);
|
|
||||||
set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
|
set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
|
||||||
rv = tty_port_block_til_ready(&acm->port, tty, filp);
|
rv = tty_port_block_til_ready(&acm->port, tty, filp);
|
||||||
|
tasklet_schedule(&acm->urb_task);
|
||||||
done:
|
done:
|
||||||
mutex_unlock(&acm->mutex);
|
mutex_unlock(&acm->mutex);
|
||||||
err_out:
|
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
|
/* Perform the closing process and see if we need to do the hardware
|
||||||
shutdown */
|
shutdown */
|
||||||
if (!acm || tty_port_close_start(&acm->port, tty, filp) == 0)
|
if (!acm)
|
||||||
return;
|
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);
|
acm_port_down(acm, 0);
|
||||||
tty_port_close_end(&acm->port, tty);
|
tty_port_close_end(&acm->port, tty);
|
||||||
mutex_lock(&open_mutex);
|
|
||||||
tty_port_tty_set(&acm->port, NULL);
|
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,
|
static int acm_tty_write(struct tty_struct *tty,
|
||||||
|
|
|
@ -87,6 +87,7 @@ static int ohci_restart (struct ohci_hcd *ohci);
|
||||||
#ifdef CONFIG_PCI
|
#ifdef CONFIG_PCI
|
||||||
static void quirk_amd_pll(int state);
|
static void quirk_amd_pll(int state);
|
||||||
static void amd_iso_dev_put(void);
|
static void amd_iso_dev_put(void);
|
||||||
|
static void sb800_prefetch(struct ohci_hcd *ohci, int on);
|
||||||
#else
|
#else
|
||||||
static inline void quirk_amd_pll(int state)
|
static inline void quirk_amd_pll(int state)
|
||||||
{
|
{
|
||||||
|
@ -96,6 +97,10 @@ static inline void amd_iso_dev_put(void)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
static inline void sb800_prefetch(struct ohci_hcd *ohci, int on)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -177,6 +177,13 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
|
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)) {
|
if ((rev > 0x3b) || (rev < 0x30)) {
|
||||||
pci_dev_put(amd_smbus_dev);
|
pci_dev_put(amd_smbus_dev);
|
||||||
amd_smbus_dev = NULL;
|
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 */
|
/* List of quirks for OHCI */
|
||||||
static const struct pci_device_id ohci_pci_quirks[] = {
|
static const struct pci_device_id ohci_pci_quirks[] = {
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,9 +49,12 @@ __acquires(ohci->lock)
|
||||||
switch (usb_pipetype (urb->pipe)) {
|
switch (usb_pipetype (urb->pipe)) {
|
||||||
case PIPE_ISOCHRONOUS:
|
case PIPE_ISOCHRONOUS:
|
||||||
ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--;
|
ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--;
|
||||||
if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0
|
if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
|
||||||
&& quirk_amdiso(ohci))
|
if (quirk_amdiso(ohci))
|
||||||
quirk_amd_pll(1);
|
quirk_amd_pll(1);
|
||||||
|
if (quirk_amdprefetch(ohci))
|
||||||
|
sb800_prefetch(ohci, 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PIPE_INTERRUPT:
|
case PIPE_INTERRUPT:
|
||||||
ohci_to_hcd(ohci)->self.bandwidth_int_reqs--;
|
ohci_to_hcd(ohci)->self.bandwidth_int_reqs--;
|
||||||
|
@ -680,9 +683,12 @@ static void td_submit_urb (
|
||||||
data + urb->iso_frame_desc [cnt].offset,
|
data + urb->iso_frame_desc [cnt].offset,
|
||||||
urb->iso_frame_desc [cnt].length, urb, cnt);
|
urb->iso_frame_desc [cnt].length, urb, cnt);
|
||||||
}
|
}
|
||||||
if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0
|
if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
|
||||||
&& quirk_amdiso(ohci))
|
if (quirk_amdiso(ohci))
|
||||||
quirk_amd_pll(0);
|
quirk_amd_pll(0);
|
||||||
|
if (quirk_amdprefetch(ohci))
|
||||||
|
sb800_prefetch(ohci, 1);
|
||||||
|
}
|
||||||
periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0
|
periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0
|
||||||
&& ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0;
|
&& ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -402,6 +402,7 @@ struct ohci_hcd {
|
||||||
#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */
|
#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_HUB_POWER 0x100 /* distrust firmware power/oc setup */
|
||||||
#define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/
|
#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
|
// there are also chip quirks/bugs in init logic
|
||||||
|
|
||||||
struct work_struct nec_work; /* Worker for NEC quirk */
|
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;
|
return ohci->flags & OHCI_QUIRK_AMD_ISO;
|
||||||
}
|
}
|
||||||
|
static inline int quirk_amdprefetch(struct ohci_hcd *ohci)
|
||||||
|
{
|
||||||
|
return ohci->flags & OHCI_QUIRK_AMD_PREFETCH;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
static inline int quirk_nec(struct ohci_hcd *ohci)
|
static inline int quirk_nec(struct ohci_hcd *ohci)
|
||||||
{
|
{
|
||||||
|
@ -446,6 +451,10 @@ static inline int quirk_amdiso(struct ohci_hcd *ohci)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
static inline int quirk_amdprefetch(struct ohci_hcd *ohci)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* convert between an hcd pointer and the corresponding ohci_hcd */
|
/* convert between an hcd pointer and the corresponding ohci_hcd */
|
||||||
|
|
|
@ -802,9 +802,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Free the Event Ring Segment Table and the actual Event Ring */
|
/* Free the Event Ring Segment Table and the actual Event Ring */
|
||||||
xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
|
if (xhci->ir_set) {
|
||||||
xhci_write_64(xhci, 0, &xhci->ir_set->erst_base);
|
xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
|
||||||
xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue);
|
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);
|
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
|
||||||
if (xhci->erst.entries)
|
if (xhci->erst.entries)
|
||||||
pci_free_consistent(pdev, size,
|
pci_free_consistent(pdev, size,
|
||||||
|
@ -841,9 +843,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||||
xhci->dcbaa, xhci->dcbaa->dma);
|
xhci->dcbaa, xhci->dcbaa->dma);
|
||||||
xhci->dcbaa = NULL;
|
xhci->dcbaa = NULL;
|
||||||
|
|
||||||
|
scratchpad_free(xhci);
|
||||||
xhci->page_size = 0;
|
xhci->page_size = 0;
|
||||||
xhci->page_shift = 0;
|
xhci->page_shift = 0;
|
||||||
scratchpad_free(xhci);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||||
|
|
|
@ -864,9 +864,11 @@ static struct xhci_segment *trb_in_td(
|
||||||
cur_seg = start_seg;
|
cur_seg = start_seg;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
if (start_dma == 0)
|
||||||
|
return 0;
|
||||||
/* We may get an event for a Link TRB in the middle of a TD */
|
/* 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,
|
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 */
|
/* 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);
|
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;
|
cur_seg = cur_seg->next;
|
||||||
start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]);
|
start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]);
|
||||||
} while (1);
|
} while (cur_seg != start_seg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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.
|
* 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)
|
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;
|
rp->b_cnt -= size;
|
||||||
if (rp->b_in < size)
|
if (rp->b_in < size)
|
||||||
rp->b_in += rp->b_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 urb_length;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
|
unsigned int delta;
|
||||||
unsigned int ndesc, lendesc;
|
unsigned int ndesc, lendesc;
|
||||||
unsigned char dir;
|
unsigned char dir;
|
||||||
struct mon_bin_hdr *ep;
|
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) {
|
if (length != 0) {
|
||||||
ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
|
ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
|
||||||
if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */
|
if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */
|
||||||
ep->len_cap = 0;
|
delta = (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
|
||||||
mon_buff_area_shrink(rp, length);
|
ep->len_cap -= length;
|
||||||
|
delta -= (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
|
||||||
|
mon_buff_area_shrink(rp, delta);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ep->flag_data = data_tag;
|
ep->flag_data = data_tag;
|
||||||
|
|
|
@ -308,6 +308,7 @@ static int option_resume(struct usb_serial *serial);
|
||||||
|
|
||||||
#define DLINK_VENDOR_ID 0x1186
|
#define DLINK_VENDOR_ID 0x1186
|
||||||
#define DLINK_PRODUCT_DWM_652 0x3e04
|
#define DLINK_PRODUCT_DWM_652 0x3e04
|
||||||
|
#define DLINK_PRODUCT_DWM_652_U5 0xce16
|
||||||
|
|
||||||
#define QISDA_VENDOR_ID 0x1da5
|
#define QISDA_VENDOR_ID 0x1da5
|
||||||
#define QISDA_PRODUCT_H21_4512 0x4512
|
#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_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
|
||||||
{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
|
{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
|
||||||
{ USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
|
{ 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_4512) },
|
||||||
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) },
|
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) },
|
||||||
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) },
|
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) },
|
||||||
|
|
Loading…
Reference in a new issue