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: (21 commits)
  USB: musb: fix srp sysfs entry deletion
  USB: musb: resume suspended root hub on disconnect
  USB: musb: use right poll limit for low speed devices
  USB: musb: be careful with 64K+ transfer lengths, host side
  USB: musb: fix data toggle saving with shared FIFO
  USB: musb: host endpoint_disable() oops fixes
  USB: musb: fix urb_dequeue() method
  USB: musb: fix musb_host_tx() for shared endpoint FIFO
  USB: musb: be careful with 64K+ transfer lengths (gadget side)
  usb: musb: make Davinci *work* in mainline
  USB: usb_get_string should check the descriptor type
  USB: gadget: fix build error in omap_apollon_2420_defconfig
  USB: g_file_storage: automatically disable stalls under Atmel
  USB: usb-storage: add IGNORE_RESIDUE flag for Genesys Logic adapters
  USB: Quirk for Hummingbird huc56s / Conexant ACM modem
  USB: serial: add support for second revision of Ericsson F3507G WWAN card
  USB: cdc-acm: add usb id for motomagx phones
  USB: option: add BenQ 3g modem information
  usb: gadget: obex: select correct ep descriptors
  USB: EHCI: slow down ITD reuse
  ...
This commit is contained in:
Linus Torvalds 2009-02-27 16:49:26 -08:00
commit 3c4f1158cd
19 changed files with 176 additions and 75 deletions

View File

@ -311,6 +311,9 @@ evm_u35_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
gpio_request(gpio + 7, "nCF_SEL"); gpio_request(gpio + 7, "nCF_SEL");
gpio_direction_output(gpio + 7, 1); gpio_direction_output(gpio + 7, 1);
/* irlml6401 sustains over 3A, switches 5V in under 8 msec */
setup_usb(500, 8);
return 0; return 0;
} }
@ -417,9 +420,6 @@ static __init void davinci_evm_init(void)
platform_add_devices(davinci_evm_devices, platform_add_devices(davinci_evm_devices,
ARRAY_SIZE(davinci_evm_devices)); ARRAY_SIZE(davinci_evm_devices));
evm_init_i2c(); evm_init_i2c();
/* irlml6401 sustains over 3A, switches 5V in under 8 msec */
setup_usb(500, 8);
} }
static __init void davinci_evm_irq_init(void) static __init void davinci_evm_irq_init(void)

View File

@ -230,6 +230,11 @@ static struct clk davinci_clks[] = {
.rate = &commonrate, .rate = &commonrate,
.lpsc = DAVINCI_LPSC_GPIO, .lpsc = DAVINCI_LPSC_GPIO,
}, },
{
.name = "usb",
.rate = &commonrate,
.lpsc = DAVINCI_LPSC_USB,
},
{ {
.name = "AEMIFCLK", .name = "AEMIFCLK",
.rate = &commonrate, .rate = &commonrate,

View File

@ -47,6 +47,7 @@ static struct musb_hdrc_platform_data usb_data = {
#elif defined(CONFIG_USB_MUSB_HOST) #elif defined(CONFIG_USB_MUSB_HOST)
.mode = MUSB_HOST, .mode = MUSB_HOST,
#endif #endif
.clock = "usb",
.config = &musb_config, .config = &musb_config,
}; };

View File

@ -1376,6 +1376,15 @@ static struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */ { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
}, },
{ USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
},
{ USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */
.driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on
data interface instead of
communications interface.
Maybe we should define a new
quirk for this. */
},
/* control interfaces with various AT-command sets */ /* control interfaces with various AT-command sets */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,

View File

@ -653,7 +653,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type,
if (result <= 0 && result != -ETIMEDOUT) if (result <= 0 && result != -ETIMEDOUT)
continue; continue;
if (result > 1 && ((u8 *)buf)[1] != type) { if (result > 1 && ((u8 *)buf)[1] != type) {
result = -EPROTO; result = -ENODATA;
continue; continue;
} }
break; break;
@ -696,8 +696,13 @@ static int usb_get_string(struct usb_device *dev, unsigned short langid,
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(USB_DT_STRING << 8) + index, langid, buf, size, (USB_DT_STRING << 8) + index, langid, buf, size,
USB_CTRL_GET_TIMEOUT); USB_CTRL_GET_TIMEOUT);
if (!(result == 0 || result == -EPIPE)) if (result == 0 || result == -EPIPE)
break; continue;
if (result > 1 && ((u8 *) buf)[1] != USB_DT_STRING) {
result = -ENODATA;
continue;
}
break;
} }
return result; return result;
} }

View File

@ -191,6 +191,7 @@ config USB_GADGET_OMAP
boolean "OMAP USB Device Controller" boolean "OMAP USB Device Controller"
depends on ARCH_OMAP depends on ARCH_OMAP
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
select USB_OTG_UTILS if ARCH_OMAP
help help
Many Texas Instruments OMAP processors have flexible full Many Texas Instruments OMAP processors have flexible full
speed USB device controllers, with support for up to 30 speed USB device controllers, with support for up to 30

View File

@ -366,9 +366,9 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
f->hs_descriptors = usb_copy_descriptors(hs_function); f->hs_descriptors = usb_copy_descriptors(hs_function);
obex->hs.obex_in = usb_find_endpoint(hs_function, obex->hs.obex_in = usb_find_endpoint(hs_function,
f->descriptors, &obex_hs_ep_in_desc); f->hs_descriptors, &obex_hs_ep_in_desc);
obex->hs.obex_out = usb_find_endpoint(hs_function, obex->hs.obex_out = usb_find_endpoint(hs_function,
f->descriptors, &obex_hs_ep_out_desc); f->hs_descriptors, &obex_hs_ep_out_desc);
} }
/* Avoid letting this gadget enumerate until the userspace /* Avoid letting this gadget enumerate until the userspace

View File

@ -3879,7 +3879,11 @@ static int __init check_parameters(struct fsg_dev *fsg)
mod_data.protocol_type = USB_SC_SCSI; mod_data.protocol_type = USB_SC_SCSI;
mod_data.protocol_name = "Transparent SCSI"; mod_data.protocol_name = "Transparent SCSI";
if (gadget_is_sh(fsg->gadget)) /* Some peripheral controllers are known not to be able to
* halt bulk endpoints correctly. If one of them is present,
* disable stalls.
*/
if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget))
mod_data.can_stall = 0; mod_data.can_stall = 0;
if (mod_data.release == 0xffff) { // Parameter wasn't set if (mod_data.release == 0xffff) { // Parameter wasn't set

View File

@ -404,7 +404,10 @@ static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num,
} }
if (zlt) if (zlt)
tmp |= EP_QUEUE_HEAD_ZLT_SEL; tmp |= EP_QUEUE_HEAD_ZLT_SEL;
p_QH->max_pkt_length = cpu_to_le32(tmp); p_QH->max_pkt_length = cpu_to_le32(tmp);
p_QH->next_dtd_ptr = 1;
p_QH->size_ioc_int_sts = 0;
return; return;
} }

View File

@ -485,6 +485,7 @@ static int ehci_init(struct usb_hcd *hcd)
* periodic_size can shrink by USBCMD update if hcc_params allows. * periodic_size can shrink by USBCMD update if hcc_params allows.
*/ */
ehci->periodic_size = DEFAULT_I_TDPS; ehci->periodic_size = DEFAULT_I_TDPS;
INIT_LIST_HEAD(&ehci->cached_itd_list);
if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0) if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0)
return retval; return retval;
@ -497,6 +498,7 @@ static int ehci_init(struct usb_hcd *hcd)
ehci->reclaim = NULL; ehci->reclaim = NULL;
ehci->next_uframe = -1; ehci->next_uframe = -1;
ehci->clock_frame = -1;
/* /*
* dedicate a qh for the async ring head, since we couldn't unlink * dedicate a qh for the async ring head, since we couldn't unlink

View File

@ -128,6 +128,7 @@ static inline void qh_put (struct ehci_qh *qh)
static void ehci_mem_cleanup (struct ehci_hcd *ehci) static void ehci_mem_cleanup (struct ehci_hcd *ehci)
{ {
free_cached_itd_list(ehci);
if (ehci->async) if (ehci->async)
qh_put (ehci->async); qh_put (ehci->async);
ehci->async = NULL; ehci->async = NULL;

View File

@ -1004,7 +1004,8 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0; is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0;
stream->bEndpointAddress &= 0x0f; stream->bEndpointAddress &= 0x0f;
stream->ep->hcpriv = NULL; if (stream->ep)
stream->ep->hcpriv = NULL;
if (stream->rescheduled) { if (stream->rescheduled) {
ehci_info (ehci, "ep%d%s-iso rescheduled " ehci_info (ehci, "ep%d%s-iso rescheduled "
@ -1653,14 +1654,28 @@ itd_complete (
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
} }
iso_stream_put (ehci, stream); iso_stream_put (ehci, stream);
/* OK to recycle this ITD now that its completion callback ran. */
done: done:
usb_put_urb(urb); usb_put_urb(urb);
itd->urb = NULL; itd->urb = NULL;
itd->stream = NULL; if (ehci->clock_frame != itd->frame || itd->index[7] != -1) {
list_move(&itd->itd_list, &stream->free_list); /* OK to recycle this ITD now. */
iso_stream_put(ehci, stream); itd->stream = NULL;
list_move(&itd->itd_list, &stream->free_list);
iso_stream_put(ehci, stream);
} else {
/* HW might remember this ITD, so we can't recycle it yet.
* Move it to a safe place until a new frame starts.
*/
list_move(&itd->itd_list, &ehci->cached_itd_list);
if (stream->refcount == 2) {
/* If iso_stream_put() were called here, stream
* would be freed. Instead, just prevent reuse.
*/
stream->ep->hcpriv = NULL;
stream->ep = NULL;
}
}
return retval; return retval;
} }
@ -2101,6 +2116,20 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static void free_cached_itd_list(struct ehci_hcd *ehci)
{
struct ehci_itd *itd, *n;
list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
struct ehci_iso_stream *stream = itd->stream;
itd->stream = NULL;
list_move(&itd->itd_list, &stream->free_list);
iso_stream_put(ehci, stream);
}
}
/*-------------------------------------------------------------------------*/
static void static void
scan_periodic (struct ehci_hcd *ehci) scan_periodic (struct ehci_hcd *ehci)
{ {
@ -2115,10 +2144,17 @@ scan_periodic (struct ehci_hcd *ehci)
* Touches as few pages as possible: cache-friendly. * Touches as few pages as possible: cache-friendly.
*/ */
now_uframe = ehci->next_uframe; now_uframe = ehci->next_uframe;
if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
clock = ehci_readl(ehci, &ehci->regs->frame_index); clock = ehci_readl(ehci, &ehci->regs->frame_index);
else clock_frame = (clock >> 3) % ehci->periodic_size;
} else {
clock = now_uframe + mod - 1; clock = now_uframe + mod - 1;
clock_frame = -1;
}
if (ehci->clock_frame != clock_frame) {
free_cached_itd_list(ehci);
ehci->clock_frame = clock_frame;
}
clock %= mod; clock %= mod;
clock_frame = clock >> 3; clock_frame = clock >> 3;
@ -2277,6 +2313,10 @@ scan_periodic (struct ehci_hcd *ehci)
/* rescan the rest of this frame, then ... */ /* rescan the rest of this frame, then ... */
clock = now; clock = now;
clock_frame = clock >> 3; clock_frame = clock >> 3;
if (ehci->clock_frame != clock_frame) {
free_cached_itd_list(ehci);
ehci->clock_frame = clock_frame;
}
} else { } else {
now_uframe++; now_uframe++;
now_uframe %= mod; now_uframe %= mod;

View File

@ -87,6 +87,10 @@ struct ehci_hcd { /* one per controller */
int next_uframe; /* scan periodic, start here */ int next_uframe; /* scan periodic, start here */
unsigned periodic_sched; /* periodic activity count */ unsigned periodic_sched; /* periodic activity count */
/* list of itds completed while clock_frame was still active */
struct list_head cached_itd_list;
unsigned clock_frame;
/* per root hub port */ /* per root hub port */
unsigned long reset_done [EHCI_MAX_ROOT_PORTS]; unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
@ -220,6 +224,8 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
} }
} }
static void free_cached_itd_list(struct ehci_hcd *ehci);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#include <linux/usb/ehci_def.h> #include <linux/usb/ehci_def.h>

View File

@ -377,18 +377,8 @@ int __init musb_platform_init(struct musb *musb)
u32 revision; u32 revision;
musb->mregs += DAVINCI_BASE_OFFSET; musb->mregs += DAVINCI_BASE_OFFSET;
#if 0
/* REVISIT there's something odd about clocking, this
* didn't appear do the job ...
*/
musb->clock = clk_get(pDevice, "usb");
if (IS_ERR(musb->clock))
return PTR_ERR(musb->clock);
status = clk_enable(musb->clock); clk_enable(musb->clock);
if (status < 0)
return -ENODEV;
#endif
/* returns zero if e.g. not clocked */ /* returns zero if e.g. not clocked */
revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG); revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
@ -453,5 +443,8 @@ int musb_platform_exit(struct musb *musb)
} }
phy_off(); phy_off();
clk_disable(musb->clock);
return 0; return 0;
} }

View File

@ -115,7 +115,7 @@
unsigned musb_debug; unsigned musb_debug;
module_param(musb_debug, uint, S_IRUGO | S_IWUSR); module_param_named(debug, musb_debug, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug message level. Default = 0"); MODULE_PARM_DESC(debug, "Debug message level. Default = 0");
#define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia" #define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia"
@ -767,6 +767,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
#ifdef CONFIG_USB_MUSB_HDRC_HCD #ifdef CONFIG_USB_MUSB_HDRC_HCD
case OTG_STATE_A_HOST: case OTG_STATE_A_HOST:
case OTG_STATE_A_SUSPEND: case OTG_STATE_A_SUSPEND:
usb_hcd_resume_root_hub(musb_to_hcd(musb));
musb_root_disconnect(musb); musb_root_disconnect(musb);
if (musb->a_wait_bcon != 0) if (musb->a_wait_bcon != 0)
musb_platform_try_idle(musb, jiffies musb_platform_try_idle(musb, jiffies
@ -1815,7 +1816,7 @@ static void musb_free(struct musb *musb)
#ifdef CONFIG_SYSFS #ifdef CONFIG_SYSFS
device_remove_file(musb->controller, &dev_attr_mode); device_remove_file(musb->controller, &dev_attr_mode);
device_remove_file(musb->controller, &dev_attr_vbus); device_remove_file(musb->controller, &dev_attr_vbus);
#ifdef CONFIG_USB_MUSB_OTG #ifdef CONFIG_USB_GADGET_MUSB_HDRC
device_remove_file(musb->controller, &dev_attr_srp); device_remove_file(musb->controller, &dev_attr_srp);
#endif #endif
#endif #endif
@ -2063,7 +2064,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
#ifdef CONFIG_SYSFS #ifdef CONFIG_SYSFS
device_remove_file(musb->controller, &dev_attr_mode); device_remove_file(musb->controller, &dev_attr_mode);
device_remove_file(musb->controller, &dev_attr_vbus); device_remove_file(musb->controller, &dev_attr_vbus);
#ifdef CONFIG_USB_MUSB_OTG #ifdef CONFIG_USB_GADGET_MUSB_HDRC
device_remove_file(musb->controller, &dev_attr_srp); device_remove_file(musb->controller, &dev_attr_srp);
#endif #endif
#endif #endif
@ -2243,10 +2244,10 @@ static int __init musb_init(void)
return platform_driver_probe(&musb_driver, musb_probe); return platform_driver_probe(&musb_driver, musb_probe);
} }
/* make us init after usbcore and before usb /* make us init after usbcore and i2c (transceivers, regulators, etc)
* gadget and host-side drivers start to register * and before usb gadget and host-side drivers start to register
*/ */
subsys_initcall(musb_init); fs_initcall(musb_init);
static void __exit musb_cleanup(void) static void __exit musb_cleanup(void)
{ {

View File

@ -575,7 +575,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
struct usb_request *request = &req->request; struct usb_request *request = &req->request;
struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out; struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out;
void __iomem *epio = musb->endpoints[epnum].regs; void __iomem *epio = musb->endpoints[epnum].regs;
u16 fifo_count = 0; unsigned fifo_count = 0;
u16 len = musb_ep->packet_sz; u16 len = musb_ep->packet_sz;
csr = musb_readw(epio, MUSB_RXCSR); csr = musb_readw(epio, MUSB_RXCSR);
@ -687,7 +687,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
len, fifo_count, len, fifo_count,
musb_ep->packet_sz); musb_ep->packet_sz);
fifo_count = min(len, fifo_count); fifo_count = min_t(unsigned, len, fifo_count);
#ifdef CONFIG_USB_TUSB_OMAP_DMA #ifdef CONFIG_USB_TUSB_OMAP_DMA
if (tusb_dma_omap() && musb_ep->dma) { if (tusb_dma_omap() && musb_ep->dma) {

View File

@ -335,16 +335,11 @@ musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb)
static struct musb_qh * static struct musb_qh *
musb_giveback(struct musb_qh *qh, struct urb *urb, int status) musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
{ {
int is_in;
struct musb_hw_ep *ep = qh->hw_ep; struct musb_hw_ep *ep = qh->hw_ep;
struct musb *musb = ep->musb; struct musb *musb = ep->musb;
int is_in = usb_pipein(urb->pipe);
int ready = qh->is_ready; int ready = qh->is_ready;
if (ep->is_shared_fifo)
is_in = 1;
else
is_in = usb_pipein(urb->pipe);
/* save toggle eagerly, for paranoia */ /* save toggle eagerly, for paranoia */
switch (qh->type) { switch (qh->type) {
case USB_ENDPOINT_XFER_BULK: case USB_ENDPOINT_XFER_BULK:
@ -432,7 +427,7 @@ musb_advance_schedule(struct musb *musb, struct urb *urb,
else else
qh = musb_giveback(qh, urb, urb->status); qh = musb_giveback(qh, urb, urb->status);
if (qh && qh->is_ready && !list_empty(&qh->hep->urb_list)) { if (qh != NULL && qh->is_ready) {
DBG(4, "... next ep%d %cX urb %p\n", DBG(4, "... next ep%d %cX urb %p\n",
hw_ep->epnum, is_in ? 'R' : 'T', hw_ep->epnum, is_in ? 'R' : 'T',
next_urb(qh)); next_urb(qh));
@ -942,8 +937,8 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
switch (musb->ep0_stage) { switch (musb->ep0_stage) {
case MUSB_EP0_IN: case MUSB_EP0_IN:
fifo_dest = urb->transfer_buffer + urb->actual_length; fifo_dest = urb->transfer_buffer + urb->actual_length;
fifo_count = min(len, ((u16) (urb->transfer_buffer_length fifo_count = min_t(size_t, len, urb->transfer_buffer_length -
- urb->actual_length))); urb->actual_length);
if (fifo_count < len) if (fifo_count < len)
urb->status = -EOVERFLOW; urb->status = -EOVERFLOW;
@ -976,10 +971,9 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
} }
/* FALLTHROUGH */ /* FALLTHROUGH */
case MUSB_EP0_OUT: case MUSB_EP0_OUT:
fifo_count = min(qh->maxpacket, ((u16) fifo_count = min_t(size_t, qh->maxpacket,
(urb->transfer_buffer_length urb->transfer_buffer_length -
- urb->actual_length))); urb->actual_length);
if (fifo_count) { if (fifo_count) {
fifo_dest = (u8 *) (urb->transfer_buffer fifo_dest = (u8 *) (urb->transfer_buffer
+ urb->actual_length); + urb->actual_length);
@ -1161,7 +1155,8 @@ void musb_host_tx(struct musb *musb, u8 epnum)
struct urb *urb; struct urb *urb;
struct musb_hw_ep *hw_ep = musb->endpoints + epnum; struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
void __iomem *epio = hw_ep->regs; void __iomem *epio = hw_ep->regs;
struct musb_qh *qh = hw_ep->out_qh; struct musb_qh *qh = hw_ep->is_shared_fifo ? hw_ep->in_qh
: hw_ep->out_qh;
u32 status = 0; u32 status = 0;
void __iomem *mbase = musb->mregs; void __iomem *mbase = musb->mregs;
struct dma_channel *dma; struct dma_channel *dma;
@ -1308,7 +1303,8 @@ void musb_host_tx(struct musb *musb, u8 epnum)
* packets before updating TXCSR ... other docs disagree ... * packets before updating TXCSR ... other docs disagree ...
*/ */
/* PIO: start next packet in this URB */ /* PIO: start next packet in this URB */
wLength = min(qh->maxpacket, (u16) wLength); if (wLength > qh->maxpacket)
wLength = qh->maxpacket;
musb_write_fifo(hw_ep, wLength, buf); musb_write_fifo(hw_ep, wLength, buf);
qh->segsize = wLength; qh->segsize = wLength;
@ -1867,19 +1863,21 @@ static int musb_urb_enqueue(
} }
qh->type_reg = type_reg; qh->type_reg = type_reg;
/* precompute rxinterval/txinterval register */ /* Precompute RXINTERVAL/TXINTERVAL register */
interval = min((u8)16, epd->bInterval); /* log encoding */
switch (qh->type) { switch (qh->type) {
case USB_ENDPOINT_XFER_INT: case USB_ENDPOINT_XFER_INT:
/* fullspeed uses linear encoding */ /*
if (USB_SPEED_FULL == urb->dev->speed) { * Full/low speeds use the linear encoding,
interval = epd->bInterval; * high speed uses the logarithmic encoding.
if (!interval) */
interval = 1; if (urb->dev->speed <= USB_SPEED_FULL) {
interval = max_t(u8, epd->bInterval, 1);
break;
} }
/* FALLTHROUGH */ /* FALLTHROUGH */
case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_ISOC:
/* iso always uses log encoding */ /* ISO always uses logarithmic encoding */
interval = min_t(u8, epd->bInterval, 16);
break; break;
default: default:
/* REVISIT we actually want to use NAK limits, hinting to the /* REVISIT we actually want to use NAK limits, hinting to the
@ -2037,9 +2035,9 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
goto done; goto done;
/* Any URB not actively programmed into endpoint hardware can be /* Any URB not actively programmed into endpoint hardware can be
* immediately given back. Such an URB must be at the head of its * immediately given back; that's any URB not at the head of an
* endpoint queue, unless someday we get real DMA queues. And even * endpoint queue, unless someday we get real DMA queues. And even
* then, it might not be known to the hardware... * if it's at the head, it might not be known to the hardware...
* *
* Otherwise abort current transfer, pending dma, etc.; urb->status * Otherwise abort current transfer, pending dma, etc.; urb->status
* has already been updated. This is a synchronous abort; it'd be * has already been updated. This is a synchronous abort; it'd be
@ -2078,6 +2076,15 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
qh->is_ready = 0; qh->is_ready = 0;
__musb_giveback(musb, urb, 0); __musb_giveback(musb, urb, 0);
qh->is_ready = ready; qh->is_ready = ready;
/* If nothing else (usually musb_giveback) is using it
* and its URB list has emptied, recycle this qh.
*/
if (ready && list_empty(&qh->hep->urb_list)) {
qh->hep->hcpriv = NULL;
list_del(&qh->ring);
kfree(qh);
}
} else } else
ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN); ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
done: done:
@ -2093,15 +2100,16 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
unsigned long flags; unsigned long flags;
struct musb *musb = hcd_to_musb(hcd); struct musb *musb = hcd_to_musb(hcd);
u8 is_in = epnum & USB_DIR_IN; u8 is_in = epnum & USB_DIR_IN;
struct musb_qh *qh = hep->hcpriv; struct musb_qh *qh;
struct urb *urb, *tmp; struct urb *urb;
struct list_head *sched; struct list_head *sched;
if (!qh)
return;
spin_lock_irqsave(&musb->lock, flags); spin_lock_irqsave(&musb->lock, flags);
qh = hep->hcpriv;
if (qh == NULL)
goto exit;
switch (qh->type) { switch (qh->type) {
case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_CONTROL:
sched = &musb->control; sched = &musb->control;
@ -2135,13 +2143,28 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
/* cleanup */ /* cleanup */
musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN); musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
} else
urb = NULL;
/* then just nuke all the others */ /* Then nuke all the others ... and advance the
list_for_each_entry_safe_from(urb, tmp, &hep->urb_list, urb_list) * queue on hw_ep (e.g. bulk ring) when we're done.
musb_giveback(qh, urb, -ESHUTDOWN); */
while (!list_empty(&hep->urb_list)) {
urb = next_urb(qh);
urb->status = -ESHUTDOWN;
musb_advance_schedule(musb, urb, qh->hw_ep, is_in);
}
} else {
/* Just empty the queue; the hardware is busy with
* other transfers, and since !qh->is_ready nothing
* will activate any of these as it advances.
*/
while (!list_empty(&hep->urb_list))
__musb_giveback(musb, next_urb(qh), -ESHUTDOWN);
hep->hcpriv = NULL;
list_del(&qh->ring);
kfree(qh);
}
exit:
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
} }

View File

@ -294,7 +294,11 @@ static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *po
/* Ericsson products */ /* Ericsson products */
#define ERICSSON_VENDOR_ID 0x0bdb #define ERICSSON_VENDOR_ID 0x0bdb
#define ERICSSON_PRODUCT_F3507G 0x1900 #define ERICSSON_PRODUCT_F3507G_1 0x1900
#define ERICSSON_PRODUCT_F3507G_2 0x1902
#define BENQ_VENDOR_ID 0x04a5
#define BENQ_PRODUCT_H10 0x4068
static struct usb_device_id option_ids[] = { static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
@ -509,7 +513,10 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626) }, { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626) },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) }, { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) }, { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) },
{ USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G) }, { USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G_1) },
{ USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G_2) },
{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
{ USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
MODULE_DEVICE_TABLE(usb, option_ids); MODULE_DEVICE_TABLE(usb, option_ids);

View File

@ -907,13 +907,13 @@ UNUSUAL_DEV( 0x05e3, 0x0701, 0x0000, 0xffff,
"Genesys Logic", "Genesys Logic",
"USB to IDE Optical", "USB to IDE Optical",
US_SC_DEVICE, US_PR_DEVICE, NULL, US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ), US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ),
UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff, UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff,
"Genesys Logic", "Genesys Logic",
"USB to IDE Disk", "USB to IDE Disk",
US_SC_DEVICE, US_PR_DEVICE, NULL, US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ), US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ),
/* Reported by Ben Efros <ben@pc-doctor.com> */ /* Reported by Ben Efros <ben@pc-doctor.com> */
UNUSUAL_DEV( 0x05e3, 0x0723, 0x9451, 0x9451, UNUSUAL_DEV( 0x05e3, 0x0723, 0x9451, 0x9451,