diff options
author | Paul Mackerras <paulus@samba.org> | 2006-08-01 10:37:25 +1000 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-08-01 10:37:25 +1000 |
commit | 57cad8084e0837e0f2c97da789ec9b3f36809be9 (patch) | |
tree | e9c790afb4286f78cb08d9664f58baa7e876fe55 /drivers/usb | |
parent | cb18bd40030c879cd93fef02fd579f74dbab473d (diff) | |
parent | 49b1e3ea19b1c95c2f012b8331ffb3b169e4c042 (diff) |
Merge branch 'merge'
Diffstat (limited to 'drivers/usb')
75 files changed, 991 insertions, 735 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 7fdbc5dad5f..2ee742d40c4 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -23,6 +23,7 @@ config USB_ARCH_HAS_OHCI default y if ARCH_LH7A404 default y if ARCH_S3C2410 default y if PXA27x + default y if ARCH_EP93XX default y if ARCH_AT91RM9200 # PPC: default y if STB03xxx diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index c7123bf71c5..4710eb02ed6 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -48,7 +48,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB_AUERSWALD) += misc/ -obj-$(CONFIG_USB_CY7C63) += misc/ +obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/ obj-$(CONFIG_USB_CYTHERM) += misc/ obj-$(CONFIG_USB_EMI26) += misc/ obj-$(CONFIG_USB_EMI62) += misc/ diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 3670d77e912..ca90326f2f5 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -291,13 +291,13 @@ static void acm_read_bulk(struct urb *urb, struct pt_regs *regs) struct acm_ru *rcv = urb->context; struct acm *acm = rcv->instance; int status = urb->status; - dbg("Entering acm_read_bulk with status %d\n", urb->status); + dbg("Entering acm_read_bulk with status %d", urb->status); if (!ACM_READY(acm)) return; if (status) - dev_dbg(&acm->data->dev, "bulk rx status %d\n", status); + dev_dbg(&acm->data->dev, "bulk rx status %d", status); buf = rcv->buffer; buf->size = urb->actual_length; @@ -343,7 +343,7 @@ next_buffer: list_del(&buf->list); spin_unlock(&acm->read_lock); - dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d\n", buf, buf->size); + dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); tty_buffer_request_room(tty, buf->size); if (!acm->throttle) @@ -394,7 +394,7 @@ urbs: rcv->urb->transfer_dma = buf->dma; rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p\n", rcv->urb, rcv, buf); + dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf); /* This shouldn't kill the driver as unsuccessful URBs are returned to the free-urbs-pool and resubmited ASAP */ @@ -413,7 +413,7 @@ static void acm_write_bulk(struct urb *urb, struct pt_regs *regs) { struct acm *acm = (struct acm *)urb->context; - dbg("Entering acm_write_bulk with status %d\n", urb->status); + dbg("Entering acm_write_bulk with status %d", urb->status); acm_write_done(acm); acm_write_start(acm); @@ -424,7 +424,7 @@ static void acm_write_bulk(struct urb *urb, struct pt_regs *regs) static void acm_softint(void *private) { struct acm *acm = private; - dbg("Entering acm_softint.\n"); + dbg("Entering acm_softint."); if (!ACM_READY(acm)) return; @@ -440,7 +440,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) struct acm *acm; int rv = -EINVAL; int i; - dbg("Entering acm_tty_open.\n"); + dbg("Entering acm_tty_open."); mutex_lock(&open_mutex); @@ -541,7 +541,7 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c int wbn; struct acm_wb *wb; - dbg("Entering acm_tty_write to write %d bytes,\n", count); + dbg("Entering acm_tty_write to write %d bytes,", count); if (!ACM_READY(acm)) return -EINVAL; @@ -793,7 +793,7 @@ static int acm_probe (struct usb_interface *intf, if (!buflen) { if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { - dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n"); + dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint"); buflen = intf->cur_altsetting->endpoint->extralen; buffer = intf->cur_altsetting->endpoint->extra; } else { @@ -842,24 +842,24 @@ next_desc: if (!union_header) { if (call_interface_num > 0) { - dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n"); + dev_dbg(&intf->dev,"No union descriptor, using call management descriptor"); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); control_interface = intf; } else { - dev_dbg(&intf->dev,"No union descriptor, giving up\n"); + dev_dbg(&intf->dev,"No union descriptor, giving up"); return -ENODEV; } } else { control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); if (!control_interface || !data_interface) { - dev_dbg(&intf->dev,"no interfaces\n"); + dev_dbg(&intf->dev,"no interfaces"); return -ENODEV; } } if (data_interface_num != call_interface_num) - dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n"); + dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported."); skip_normal_probe: @@ -867,7 +867,7 @@ skip_normal_probe: if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) { if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) { struct usb_interface *t; - dev_dbg(&intf->dev,"Your device has switched interfaces.\n"); + dev_dbg(&intf->dev,"Your device has switched interfaces."); t = control_interface; control_interface = data_interface; @@ -878,7 +878,7 @@ skip_normal_probe: } if (usb_interface_claimed(data_interface)) { /* valid in this context */ - dev_dbg(&intf->dev,"The data interface isn't available\n"); + dev_dbg(&intf->dev,"The data interface isn't available"); return -EBUSY; } @@ -895,7 +895,7 @@ skip_normal_probe: if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) { /* descriptors are swapped */ struct usb_endpoint_descriptor *t; - dev_dbg(&intf->dev,"The data interface has switched endpoints\n"); + dev_dbg(&intf->dev,"The data interface has switched endpoints"); t = epread; epread = epwrite; @@ -910,7 +910,7 @@ skip_normal_probe: } if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) { - dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n"); + dev_dbg(&intf->dev, "out of memory (acm kzalloc)"); goto alloc_fail; } @@ -936,26 +936,26 @@ skip_normal_probe: buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); if (!buf) { - dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n"); + dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)"); goto alloc_fail2; } acm->ctrl_buffer = buf; if (acm_write_buffers_alloc(acm) < 0) { - dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n"); + dev_dbg(&intf->dev, "out of memory (write buffer alloc)"); goto alloc_fail4; } acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); if (!acm->ctrlurb) { - dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); + dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)"); goto alloc_fail5; } for (i = 0; i < num_rx_buf; i++) { struct acm_ru *rcv = &(acm->ru[i]); if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { - dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); + dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)"); goto alloc_fail7; } @@ -966,13 +966,13 @@ skip_normal_probe: struct acm_rb *buf = &(acm->rb[i]); if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) { - dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n"); + dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)"); goto alloc_fail7; } } acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); if (!acm->writeurb) { - dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n"); + dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)"); goto alloc_fail7; } @@ -1086,6 +1086,9 @@ static struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */ .driver_info = SINGLE_RX_URB, /* firmware bug */ }, + { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */ + .driver_info = SINGLE_RX_URB, /* firmware bug */ + }, /* control interfaces with various AT-command sets */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_ACM_PROTO_AT_V25TER) }, diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index a08787e253a..6e3b5358a76 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -31,9 +31,6 @@ config USB_DEVICEFS For the format of the various /proc/bus/usb/ files, please read <file:Documentation/usb/proc_usb_info.txt>. - Please note that this code is completely unrelated to devfs, the - "/dev file system support". - Most users want to say Y here. config USB_BANDWIDTH diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 875596e98e4..26c8cb5f3e6 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1790,7 +1790,10 @@ static int finish_device_resume(struct usb_device *udev) * and device drivers will know about any resume quirks. */ status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); - if (status < 2) + if (status >= 0) + status = (status == 2 ? 0 : -ENODEV); + + if (status) dev_dbg(&udev->dev, "gone after usb resume? status %d\n", status); @@ -1879,7 +1882,12 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) dev_dbg(hub->intfdev, "port %d status %04x.%04x after resume, %d\n", port1, portchange, devstatus, status); + if (status >= 0) + status = -ENODEV; } else { + if (portchange & USB_PORT_STAT_C_SUSPEND) + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_SUSPEND); /* TRSMRCY = 10 msec */ msleep(10); if (udev) diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index f48c3dbc367..3182c2224ba 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -695,7 +695,7 @@ static void usbfs_remove_device(struct usb_device *dev) wake_up_all(&ds->wait); list_del_init(&ds->list); if (ds->discsignr) { - sinfo.si_signo = SIGPIPE; + sinfo.si_signo = ds->discsignr; sinfo.si_errno = EPIPE; sinfo.si_code = SI_ASYNCIO; sinfo.si_addr = ds->disccontext; diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index f7c6d758e1b..53d584589c2 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -34,12 +34,12 @@ /* we must assign addresses for configurable endpoints (like net2280) */ -static __initdata unsigned epnum; +static __devinitdata unsigned epnum; // #define MANY_ENDPOINTS #ifdef MANY_ENDPOINTS /* more than 15 configurable endpoints */ -static __initdata unsigned in_epnum; +static __devinitdata unsigned in_epnum; #endif @@ -59,7 +59,7 @@ static __initdata unsigned in_epnum; * NOTE: each endpoint is unidirectional, as specified by its USB * descriptor; and isn't specific to a configuration or altsetting. */ -static int __init +static int __devinit ep_matches ( struct usb_gadget *gadget, struct usb_ep *ep, @@ -73,7 +73,7 @@ ep_matches ( /* endpoint already claimed? */ if (0 != ep->driver_data) return 0; - + /* only support ep0 for portable CONTROL traffic */ type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; if (USB_ENDPOINT_XFER_CONTROL == type) @@ -186,7 +186,7 @@ ep_matches ( return 1; } -static struct usb_ep * __init +static struct usb_ep * __devinit find_ep (struct usb_gadget *gadget, const char *name) { struct usb_ep *ep; @@ -228,7 +228,7 @@ find_ep (struct usb_gadget *gadget, const char *name) * * On failure, this returns a null endpoint descriptor. */ -struct usb_ep * __init usb_ep_autoconfig ( +struct usb_ep * __devinit usb_ep_autoconfig ( struct usb_gadget *gadget, struct usb_endpoint_descriptor *desc ) @@ -276,7 +276,7 @@ struct usb_ep * __init usb_ep_autoconfig ( return ep; } - /* Second, look at endpoints until an unclaimed one looks usable */ + /* Second, look at endpoints until an unclaimed one looks usable */ list_for_each_entry (ep, &gadget->ep_list, ep_list) { if (ep_matches (gadget, ep, desc)) return ep; @@ -295,7 +295,7 @@ struct usb_ep * __init usb_ep_autoconfig ( * state such as ep->driver_data and the record of assigned endpoints * used by usb_ep_autoconfig(). */ -void __init usb_ep_autoconfig_reset (struct usb_gadget *gadget) +void __devinit usb_ep_autoconfig_reset (struct usb_gadget *gadget) { struct usb_ep *ep; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 8320fcef042..4fe1bec1c25 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2131,7 +2131,7 @@ eth_req_free (struct usb_ep *ep, struct usb_request *req) } -static void __exit +static void /* __init_or_exit */ eth_unbind (struct usb_gadget *gadget) { struct eth_dev *dev = get_gadget_data (gadget); @@ -2158,7 +2158,7 @@ eth_unbind (struct usb_gadget *gadget) set_gadget_data (gadget, NULL); } -static u8 __init nibble (unsigned char c) +static u8 __devinit nibble (unsigned char c) { if (likely (isdigit (c))) return c - '0'; @@ -2168,7 +2168,7 @@ static u8 __init nibble (unsigned char c) return 0; } -static int __init get_ether_addr(const char *str, u8 *dev_addr) +static int __devinit get_ether_addr(const char *str, u8 *dev_addr) { if (str) { unsigned i; @@ -2189,7 +2189,7 @@ static int __init get_ether_addr(const char *str, u8 *dev_addr) return 1; } -static int __init +static int __devinit eth_bind (struct usb_gadget *gadget) { struct eth_dev *dev; diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index b1a9cf06f3e..8d7f1e84cd7 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -3691,7 +3691,7 @@ static void lun_release(struct device *dev) kref_put(&fsg->ref, fsg_release); } -static void __exit fsg_unbind(struct usb_gadget *gadget) +static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) { struct fsg_dev *fsg = get_gadget_data(gadget); int i; diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 354670d1230..408c3380d60 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -1398,7 +1398,7 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS]; #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ -int __init rndis_init (void) +int __devinit rndis_init (void) { u8 i; diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h index 2956608be75..4c3c7259f01 100644 --- a/drivers/usb/gadget/rndis.h +++ b/drivers/usb/gadget/rndis.h @@ -264,7 +264,7 @@ int rndis_signal_disconnect (int configNr); int rndis_state (int configNr); extern void rndis_set_host_mac (int configNr, const u8 *addr); -int __init rndis_init (void); +int __devinit rndis_init (void); void rndis_exit (void); #endif /* _LINUX_RNDIS_H */ diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 30d7664d449..e762aa19ab0 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -1473,7 +1473,7 @@ autoconf_fail: * Called on module unload. Frees the control request and device * structure. */ -static void __exit gs_unbind(struct usb_gadget *gadget) +static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget) { struct gs_dev *dev = get_gadget_data(gadget); diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 3a08a7ab4ce..b7018ee487e 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1121,7 +1121,7 @@ zero_autoresume (unsigned long _dev) /*-------------------------------------------------------------------------*/ -static void __exit +static void /* __init_or_exit */ zero_unbind (struct usb_gadget *gadget) { struct zero_dev *dev = get_gadget_data (gadget); diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index d66867aa527..26ed757d22a 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -41,8 +41,6 @@ #endif #define USBH_DISABLE (USB_MCFG_EBMEN | USB_MCFG_EMEMEN) -#endif /* Au1200 */ - extern int usb_disabled(void); /*-------------------------------------------------------------------------*/ @@ -107,9 +105,9 @@ int usb_ehci_au1xxx_probe(const struct hc_driver *driver, /* Au1200 AB USB does not support coherent memory */ if (!(read_c0_prid() & 0xff)) { - pr_info("%s: this is chip revision AB!\n", dev->dev.name); + pr_info("%s: this is chip revision AB!\n", dev->name); pr_info("%s: update your board or re-configure the kernel\n", - dev->dev.name); + dev->name); return -ENODEV; } #endif @@ -228,9 +226,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = { /*-------------------------------------------------------------------------*/ -static int ehci_hcd_au1xxx_drv_probe(struct device *dev) +static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev) { - struct platform_device *pdev = to_platform_device(dev); struct usb_hcd *hcd = NULL; int ret; @@ -243,10 +240,9 @@ static int ehci_hcd_au1xxx_drv_probe(struct device *dev) return ret; } -static int ehci_hcd_au1xxx_drv_remove(struct device *dev) +static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev) { - struct platform_device *pdev = to_platform_device(dev); - struct usb_hcd *hcd = dev_get_drvdata(dev); + struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_ehci_au1xxx_remove(hcd, pdev); return 0; @@ -269,12 +265,13 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev) } */ MODULE_ALIAS("au1xxx-ehci"); -/* FIXME use "struct platform_driver" */ -static struct device_driver ehci_hcd_au1xxx_driver = { - .name = "au1xxx-ehci", - .bus = &platform_bus_type, +static struct platform_driver ehci_hcd_au1xxx_driver = { .probe = ehci_hcd_au1xxx_drv_probe, .remove = ehci_hcd_au1xxx_drv_remove, /*.suspend = ehci_hcd_au1xxx_drv_suspend, */ /*.resume = ehci_hcd_au1xxx_drv_resume, */ + .driver = { + .name = "au1xxx-ehci", + .bus = &platform_bus_type + } }; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index cee6f538de0..85b0b4ad4c1 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -625,10 +625,11 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) writel (status | CMD_RUN, &ehci->regs->command); while (i--) { - status = readl (&ehci->regs->port_status [i]); - if (status & PORT_OWNER) + int pstatus = readl (&ehci->regs->port_status [i]); + + if (pstatus & PORT_OWNER) continue; - if (!(status & PORT_RESUME) + if (!(pstatus & PORT_RESUME) || ehci->reset_done [i] != 0) continue; diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 689261e4401..822914e2f43 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -101,13 +101,16 @@ static void au1xxx_start_ohc(struct platform_device *dev) #endif /* Au1200 */ +#ifndef CONFIG_SOC_AU1200 /* wait for reset complete (read register twice; see au1500 errata) */ while (au_readl(USB_HOST_CONFIG), !(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD)) +#endif udelay(1000); printk(KERN_DEBUG __FILE__ ": Clock to USB host has been enabled \n"); +#endif } static void au1xxx_stop_ohc(struct platform_device *dev) @@ -157,9 +160,9 @@ static int usb_ohci_au1xxx_probe(const struct hc_driver *driver, /* Au1200 AB USB does not support coherent memory */ if (!(read_c0_prid() & 0xff)) { pr_info("%s: this is chip revision AB !!\n", - dev->dev.name); + dev->name); pr_info("%s: update your board or re-configure the kernel\n", - dev->dev.name); + dev->name); return -ENODEV; } #endif diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c new file mode 100644 index 00000000000..6531c4d2652 --- /dev/null +++ b/drivers/usb/host/ohci-ep93xx.c @@ -0,0 +1,225 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> + * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> + * (C) Copyright 2002 Hewlett-Packard Company + * + * Bus Glue for ep93xx. + * + * Written by Christopher Hoover <ch@hpl.hp.com> + * Based on fragments of previous driver by Russell King et al. + * + * Modified for LH7A404 from ohci-sa1111.c + * by Durgesh Pattamatta <pattamattad@sharpsec.com> + * + * Modified for pxa27x from ohci-lh7a404.c + * by Nick Bane <nick@cecomputing.co.uk> 26-8-2004 + * + * Modified for ep93xx from ohci-pxa27x.c + * by Lennert Buytenhek <buytenh@wantstofly.org> 28-2-2006 + * Based on an earlier driver by Ray Lehtiniemi + * + * This file is licenced under the GPL. + */ + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/signal.h> +#include <linux/platform_device.h> + +#include <asm/mach-types.h> +#include <asm/hardware.h> + +static struct clk *usb_host_clock; + +static void ep93xx_start_hc(struct device *dev) +{ + clk_enable(usb_host_clock); +} + +static void ep93xx_stop_hc(struct device *dev) +{ + clk_disable(usb_host_clock); +} + +static int usb_hcd_ep93xx_probe(const struct hc_driver *driver, + struct platform_device *pdev) +{ + int retval; + struct usb_hcd *hcd; + + if (pdev->resource[1].flags != IORESOURCE_IRQ) { + pr_debug("resource[1] is not IORESOURCE_IRQ"); + return -ENOMEM; + } + + hcd = usb_create_hcd(driver, &pdev->dev, "ep93xx"); + if (hcd == NULL) + return -ENOMEM; + + hcd->rsrc_start = pdev->resource[0].start; + hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + usb_put_hcd(hcd); + retval = -EBUSY; + goto err1; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (hcd->regs == NULL) { + pr_debug("ioremap failed"); + retval = -ENOMEM; + goto err2; + } + + usb_host_clock = clk_get(&pdev->dev, "usb_host"); + ep93xx_start_hc(&pdev->dev); + + ohci_hcd_init(hcd_to_ohci(hcd)); + + retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT); + if (retval == 0) + return retval; + + ep93xx_stop_hc(&pdev->dev); + iounmap(hcd->regs); +err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err1: + usb_put_hcd(hcd); + + return retval; +} + +static void usb_hcd_ep93xx_remove(struct usb_hcd *hcd, + struct platform_device *pdev) +{ + usb_remove_hcd(hcd); + ep93xx_stop_hc(&pdev->dev); + clk_put(usb_host_clock); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); +} + +static int __devinit ohci_ep93xx_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + if ((ret = ohci_init(ohci)) < 0) + return ret; + + if ((ret = ohci_run(ohci)) < 0) { + err("can't start %s", hcd->self.bus_name); + ohci_stop(hcd); + return ret; + } + + return 0; +} + +static struct hc_driver ohci_ep93xx_hc_driver = { + .description = hcd_name, + .product_desc = "EP93xx OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + .start = ohci_ep93xx_start, + .stop = ohci_stop, + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + .get_frame_number = ohci_get_frame, + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +extern int usb_disabled(void); + +static int ohci_hcd_ep93xx_drv_probe(struct platform_device *pdev) +{ + int ret; + + ret = -ENODEV; + if (!usb_disabled()) + ret = usb_hcd_ep93xx_probe(&ohci_ep93xx_hc_driver, pdev); + + return ret; +} + +static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_hcd_ep93xx_remove(hcd, pdev); + + return 0; +} + +#ifdef CONFIG_PM +static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ochi_hcd *ohci = hcd_to_ohci(hcd); + + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + + ep93xx_stop_hc(&pdev->dev); + hcd->state = HC_STATE_SUSPENDED; + pdev->dev.power.power_state = PMSG_SUSPEND; + + return 0; +} + +static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int status; + + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + + ep93xx_start_hc(&pdev->dev); + pdev->dev.power.power_state = PMSG_ON; + usb_hcd_resume_root_hub(hcd); + + return 0; +} +#endif + + +static struct platform_driver ohci_hcd_ep93xx_driver = { + .probe = ohci_hcd_ep93xx_drv_probe, + .remove = ohci_hcd_ep93xx_drv_remove, +#ifdef CONFIG_PM + .suspend = ohci_hcd_ep93xx_drv_suspend, + .resume = ohci_hcd_ep93xx_drv_resume, +#endif + .driver = { + .name = "ep93xx-ohci", + }, +}; + +static int __init ohci_hcd_ep93xx_init(void) +{ + return platform_driver_register(&ohci_hcd_ep93xx_driver); +} + +static void __exit ohci_hcd_ep93xx_cleanup(void) +{ + platform_driver_unregister(&ohci_hcd_ep93xx_driver); +} + +module_init(ohci_hcd_ep93xx_init); +module_exit(ohci_hcd_ep93xx_cleanup); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 8fb842ed5f6..afef5ac35b4 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -901,6 +901,10 @@ MODULE_LICENSE ("GPL"); #include "ohci-pxa27x.c" #endif +#ifdef CONFIG_ARCH_EP93XX +#include "ohci-ep93xx.c" +#endif + #ifdef CONFIG_SOC_AU1X00 #include "ohci-au1xxx.c" #endif @@ -919,6 +923,7 @@ MODULE_LICENSE ("GPL"); || defined(CONFIG_ARCH_OMAP) \ || defined (CONFIG_ARCH_LH7A404) \ || defined (CONFIG_PXA27x) \ + || defined (CONFIG_ARCH_EP93XX) \ || defined (CONFIG_SOC_AU1X00) \ || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \ || defined (CONFIG_ARCH_AT91RM9200) \ diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 0bb972b5833..5b0a23fd798 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -581,14 +581,14 @@ static int ohci_hub_control ( break; case GetHubStatus: temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE); - *(__le32 *) buf = cpu_to_le32 (temp); + put_unaligned(cpu_to_le32 (temp), (__le32 *) buf); break; case GetPortStatus: if (!wIndex || wIndex > ports) goto error; wIndex--; temp = roothub_portstatus (ohci, wIndex); - *(__le32 *) buf = cpu_to_le32 (temp); + put_unaligned(cpu_to_le32 (temp), (__le32 *) buf); #ifndef OHCI_VERBOSE_DEBUG if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index dff60568b4a..20861650905 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -167,8 +167,6 @@ static int __devinit mmio_resource_enabled(struct pci_dev *pdev, int idx) static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) { void __iomem *base; - int wait_time; - u32 control; if (!mmio_resource_enabled(pdev, 0)) return; @@ -179,9 +177,10 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) /* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ #ifndef __hppa__ - control = readl(base + OHCI_CONTROL); +{ + u32 control = readl(base + OHCI_CONTROL); if (control & OHCI_CTRL_IR) { - wait_time = 500; /* arbitrary; 5 seconds */ + int wait_time = 500; /* arbitrary; 5 seconds */ writel(OHCI_INTR_OC, base + OHCI_INTRENABLE); writel(OHCI_OCR, base + OHCI_CMDSTATUS); while (wait_time > 0 && @@ -198,6 +197,7 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) /* reset controller, preserving RWC */ writel(control & OHCI_CTRL_RWC, base + OHCI_CONTROL); } +} #endif /* diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index b9fb9687f92..8ea9c915fbf 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1507,6 +1507,9 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104 #define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866 +#define USB_VENDOR_ID_WISEGROUP_LTD 0x6677 +#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802 + #define USB_VENDOR_ID_CODEMERCS 0x07c0 #define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500 #define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501 @@ -1670,6 +1673,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index daa486dde8c..88928a4be80 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -88,19 +88,19 @@ config USB_LED To compile this driver as a module, choose M here: the module will be called usbled. -config USB_CY7C63 +config USB_CYPRESS_CY7C63 tristate "Cypress CY7C63xxx USB driver support" depends on USB help Say Y here if you want to connect a Cypress CY7C63xxx - micro controller to your computer's USB port. This driver - supports the pre-programmed devices (incl. firmware) by - AK Modul-Bus Computer GmbH. + micro controller to your computer's USB port. Currently this + driver supports the pre-programmed devices (incl. firmware) + by AK Modul-Bus Computer GmbH. Please see: http://www.ak-modul-bus.de/stat/mikrocontroller.html To compile this driver as a module, choose M here: the - module will be called cy7c63. + module will be called cypress_cy7c63. config USB_CYTHERM tristate "Cypress USB thermometer driver support" diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index f25a9722729..2927260c581 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_USB_AUERSWALD) += auerswald.o -obj-$(CONFIG_USB_CY7C63) += cy7c63.o +obj-$(CONFIG_USB_CYPRESS_CY7C63)+= cypress_cy7c63.o obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o diff --git a/drivers/usb/misc/cy7c63.c b/drivers/usb/misc/cy7c63.c deleted file mode 100644 index 8a1c10b89b7..00000000000 --- a/drivers/usb/misc/cy7c63.c +++ /dev/null @@ -1,244 +0,0 @@ -/* -* cy7c63.c -* -* Copyright (c) 2006 Oliver Bock (bock@fh-wolfenbuettel.de) -* -* This driver is based on the Cypress Thermometer USB Driver by -* Marcus Maul and the 2.0 version of Greg Kroah-Hartman's -* USB Skeleton driver. -* -* Is is a generic driver for the Cypress CY7C63000 family. -* For the time being it enables you to toggle the single I/O ports -* of the device. -* -* Supported vendors: AK Modul-Bus Computer GmbH -* Supported devices: CY7C63001A-PC (to be continued...) -* Supported functions: Read/Write Ports (to be continued...) -* -* Chipsets families: CY7C63000, CY7C63001, CY7C63100, CY7C63101 -* -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation, version 2. -*/ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/usb.h> - -#define DRIVER_AUTHOR "Oliver Bock (bock@fh-wolfenbuettel.de)" -#define DRIVER_DESC "Cypress CY7C63xxx USB driver" - -#define CY7C63_VENDOR_ID 0xa2c -#define CY7C63_PRODUCT_ID 0x8 - -#define CY7C63_READ_PORT 0x4 -#define CY7C63_WRITE_PORT 0x5 -#define CY7C63_READ_RAM 0x2 -#define CY7C63_WRITE_RAM 0x3 -#define CY7C63_READ_ROM 0x1 - -#define CY7C63_READ_PORT_ID0 0 -#define CY7C63_WRITE_PORT_ID0 0 -#define CY7C63_READ_PORT_ID1 0x2 -#define CY7C63_WRITE_PORT_ID1 1 - -#define CY7C63_MAX_REQSIZE 8 - - -/* table of devices that work with this driver */ -static struct usb_device_id cy7c63_table [] = { - { USB_DEVICE(CY7C63_VENDOR_ID, CY7C63_PRODUCT_ID) }, - { } -}; -MODULE_DEVICE_TABLE(usb, cy7c63_table); - -/* structure to hold all of our device specific stuff */ -struct cy7c63 { - struct usb_device * udev; - char port0; - char port1; -}; - -/* used to send usb control messages to device */ -int vendor_command(struct cy7c63 *dev, unsigned char request, - unsigned char address, unsigned char data) { - - int retval = 0; - unsigned int pipe; - unsigned char *iobuf; - - /* allocate some memory for the i/o buffer*/ - iobuf = kzalloc(CY7C63_MAX_REQSIZE, GFP_KERNEL); - if (!iobuf) { - dev_err(&dev->udev->dev, "Out of memory!\n"); - retval = -ENOMEM; - goto error; - } - - dev_dbg(&dev->udev->dev, "Sending usb_control_msg (data: %d)\n", data); - - /* prepare usb control message and send it upstream */ - pipe = usb_rcvctrlpipe(dev->udev, 0); - retval = usb_control_msg(dev->udev, pipe, request, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, - address, data, iobuf, CY7C63_MAX_REQSIZE, - USB_CTRL_GET_TIMEOUT); - - /* store returned data (more READs to be added!) */ - switch (request) { - case CY7C63_READ_PORT: - if (address == CY7C63_READ_PORT_ID0) { - dev->port0 = iobuf[1]; - dev_dbg(&dev->udev->dev, - "READ_PORT0 returned: %d\n",dev->port0); - } - else if (address == CY7C63_READ_PORT_ID1) { - dev->port1 = iobuf[1]; - dev_dbg(&dev->udev->dev, - "READ_PORT1 returned: %d\n",dev->port1); - } - break; - } - - kfree(iobuf); -error: - return retval; -} - -#define get_set_port(num,read_id,write_id) \ -static ssize_t set_port##num(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) { \ - \ - int value; \ - int result = 0; \ - \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct cy7c63 *cyp = usb_get_intfdata(intf); \ - \ - dev_dbg(&cyp->udev->dev, "WRITE_PORT%d called\n", num); \ - \ - /* validate input data */ \ - if (sscanf(buf, "%d", &value) < 1) { \ - result = -EINVAL; \ - goto error; \ - } \ - if (value>255 || value<0) { \ - result = -EINVAL; \ - goto error; \ - } \ - \ - result = vendor_command(cyp, CY7C63_WRITE_PORT, write_id, \ - (unsigned char)value); \ - \ - dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n",result); \ -error: \ - return result < 0 ? result : count; \ -} \ - \ -static ssize_t get_port##num(struct device *dev, \ - struct device_attribute *attr, char *buf) { \ - \ - int result = 0; \ - \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct cy7c63 *cyp = usb_get_intfdata(intf); \ - \ - dev_dbg(&cyp->udev->dev, "READ_PORT%d called\n", num); \ - \ - result = vendor_command(cyp, CY7C63_READ_PORT, read_id, 0); \ - \ - dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result); \ - \ - return sprintf(buf, "%d", cyp->port##num); \ -} \ -static DEVICE_ATTR(port##num, S_IWUGO | S_IRUGO, get_port##num, set_port##num); - -get_set_port(0, CY7C63_READ_PORT_ID0, CY7C63_WRITE_PORT_ID0); -get_set_port(1, CY7C63_READ_PORT_ID1, CY7C63_WRITE_PORT_ID1); - -static int cy7c63_probe(struct usb_interface *interface, - const struct usb_device_id *id) { - - struct cy7c63 *dev = NULL; - int retval = -ENOMEM; - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&dev->udev->dev, "Out of memory!\n"); - goto error; - } - - dev->udev = usb_get_dev(interface_to_usbdev(interface)); - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - /* create device attribute files */ - device_create_file(&interface->dev, &dev_attr_port0); - device_create_file(&interface->dev, &dev_attr_port1); - - /* let the user know what node this device is now attached to */ - dev_info(&interface->dev, - "Cypress CY7C63xxx device now attached\n"); - - retval = 0; -error: - return retval; -} - -static void cy7c63_disconnect(struct usb_interface *interface) { - - struct cy7c63 *dev; - - dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - - /* remove device attribute files */ - device_remove_file(&interface->dev, &dev_attr_port0); - device_remove_file(&interface->dev, &dev_attr_port1); - - usb_put_dev(dev->udev); - - dev_info(&interface->dev, - "Cypress CY7C63xxx device now disconnected\n"); - - kfree(dev); -} - -static struct usb_driver cy7c63_driver = { - .name = "cy7c63", - .probe = cy7c63_probe, - .disconnect = cy7c63_disconnect, - .id_table = cy7c63_table, -}; - -static int __init cy7c63_init(void) { - - int result; - - /* register this driver with the USB subsystem */ - result = usb_register(&cy7c63_driver); - if (result) { - err("Function usb_register failed! Error number: %d\n", result); - } - - return result; -} - -static void __exit cy7c63_exit(void) { - - /* deregister this driver with the USB subsystem */ - usb_deregister(&cy7c63_driver); -} - -module_init(cy7c63_init); -module_exit(cy7c63_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); - -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c new file mode 100644 index 00000000000..e091d327bd9 --- /dev/null +++ b/drivers/usb/misc/cypress_cy7c63.c @@ -0,0 +1,279 @@ +/* +* cypress_cy7c63.c +* +* Copyright (c) 2006 Oliver Bock (o.bock@fh-wolfenbuettel.de) +* +* This driver is based on the Cypress USB Driver by Marcus Maul +* (cyport) and the 2.0 version of Greg Kroah-Hartman's +* USB Skeleton driver. +* +* This is a generic driver for the Cypress CY7C63xxx family. +* For the time being it enables you to read from and write to +* the single I/O ports of the device. +* +* Supported vendors: AK Modul-Bus Computer GmbH +* Supported devices: CY7C63001A-PC (to be continued...) +* Supported functions: Read/Write Ports (to be continued...) +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation, version 2. +*/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/usb.h> + +#define DRIVER_AUTHOR "Oliver Bock (o.bock@fh-wolfenbuettel.de)" +#define DRIVER_DESC "Cypress CY7C63xxx USB driver" + +#define CYPRESS_VENDOR_ID 0xa2c +#define CYPRESS_PRODUCT_ID 0x8 + +#define CYPRESS_READ_PORT 0x4 +#define CYPRESS_WRITE_PORT 0x5 + +#define CYPRESS_READ_RAM 0x2 +#define CYPRESS_WRITE_RAM 0x3 +#define CYPRESS_READ_ROM 0x1 + +#define CYPRESS_READ_PORT_ID0 0 +#define CYPRESS_WRITE_PORT_ID0 0 +#define CYPRESS_READ_PORT_ID1 0x2 +#define CYPRESS_WRITE_PORT_ID1 1 + +#define CYPRESS_MAX_REQSIZE 8 + + +/* table of devices that work with this driver */ +static struct usb_device_id cypress_table [] = { + { USB_DEVICE(CYPRESS_VENDOR_ID, CYPRESS_PRODUCT_ID) }, + { } +}; +MODULE_DEVICE_TABLE(usb, cypress_table); + +/* structure to hold all of our device specific stuff */ +struct cypress { + struct usb_device * udev; + unsigned char port[2]; +}; + +/* used to send usb control messages to device */ +static int vendor_command(struct cypress *dev, unsigned char request, + unsigned char address, unsigned char data) +{ + int retval = 0; + unsigned int pipe; + unsigned char *iobuf; + + /* allocate some memory for the i/o buffer*/ + iobuf = kzalloc(CYPRESS_MAX_REQSIZE, GFP_KERNEL); + if (!iobuf) { + dev_err(&dev->udev->dev, "Out of memory!\n"); + retval = -ENOMEM; + goto error; + } + + dev_dbg(&dev->udev->dev, "Sending usb_control_msg (data: %d)\n", data); + + /* prepare usb control message and send it upstream */ + pipe = usb_rcvctrlpipe(dev->udev, 0); + retval = usb_control_msg(dev->udev, pipe, request, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, + address, data, iobuf, CYPRESS_MAX_REQSIZE, + USB_CTRL_GET_TIMEOUT); + + /* store returned data (more READs to be added) */ + switch (request) { + case CYPRESS_READ_PORT: + if (address == CYPRESS_READ_PORT_ID0) { + dev->port[0] = iobuf[1]; + dev_dbg(&dev->udev->dev, + "READ_PORT0 returned: %d\n", + dev->port[0]); + } + else if (address == CYPRESS_READ_PORT_ID1) { + dev->port[1] = iobuf[1]; + dev_dbg(&dev->udev->dev, + "READ_PORT1 returned: %d\n", + dev->port[1]); + } + break; + } + + kfree(iobuf); +error: + return retval; +} + +/* write port value */ +static ssize_t write_port(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count, + int port_num, int write_id) +{ + int value = -1; + int result = 0; + + struct usb_interface *intf = to_usb_interface(dev); + struct cypress *cyp = usb_get_intfdata(intf); + + dev_dbg(&cyp->udev->dev, "WRITE_PORT%d called\n", port_num); + + /* validate input data */ + if (sscanf(buf, "%d", &value) < 1) { + result = -EINVAL; + goto error; + } + if (value < 0 || value > 255) { + result = -EINVAL; + goto error; + } + + result = vendor_command(cyp, CYPRESS_WRITE_PORT, write_id, + (unsigned char)value); + + dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result); +error: + return result < 0 ? result : count; +} + +/* attribute callback handler (write) */ +static ssize_t set_port0_handler(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return write_port(dev, attr, buf, count, 0, CYPRESS_WRITE_PORT_ID0); +} + +/* attribute callback handler (write) */ +static ssize_t set_port1_handler(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return write_port(dev, attr, buf, count, 1, CYPRESS_WRITE_PORT_ID1); +} + +/* read port value */ +static ssize_t read_port(struct device *dev, struct device_attribute *attr, + char *buf, int port_num, int read_id) +{ + int result = 0; + + struct usb_interface *intf = to_usb_interface(dev); + struct cypress *cyp = usb_get_intfdata(intf); + + dev_dbg(&cyp->udev->dev, "READ_PORT%d called\n", port_num); + + result = vendor_command(cyp, CYPRESS_READ_PORT, read_id, 0); + + dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result); + + return sprintf(buf, "%d", cyp->port[port_num]); +} + +/* attribute callback handler (read) */ +static ssize_t get_port0_handler(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return read_port(dev, attr, buf, 0, CYPRESS_READ_PORT_ID0); +} + +/* attribute callback handler (read) */ +static ssize_t get_port1_handler(struct device *dev, + struct device_attribute *attr, char *buf) +{ + 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(port1, S_IWUGO | S_IRUGO, + get_port1_handler, set_port1_handler); + + +static int cypress_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct cypress *dev = NULL; + int retval = -ENOMEM; + + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + dev_err(&dev->udev->dev, "Out of memory!\n"); + goto error; + } + + dev->udev = usb_get_dev(interface_to_usbdev(interface)); + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); + + /* create device attribute files */ + device_create_file(&interface->dev, &dev_attr_port0); + device_create_file(&interface->dev, &dev_attr_port1); + + /* let the user know that the device is now attached */ + dev_info(&interface->dev, + "Cypress CY7C63xxx device now attached\n"); + + retval = 0; +error: + return retval; +} + +static void cypress_disconnect(struct usb_interface *interface) +{ + struct cypress *dev; + + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + /* remove device attribute files */ + device_remove_file(&interface->dev, &dev_attr_port0); + device_remove_file(&interface->dev, &dev_attr_port1); + + usb_put_dev(dev->udev); + + dev_info(&interface->dev, + "Cypress CY7C63xxx device now disconnected\n"); + + kfree(dev); +} + +static struct usb_driver cypress_driver = { + .name = "cypress_cy7c63", + .probe = cypress_probe, + .disconnect = cypress_disconnect, + .id_table = cypress_table, +}; + +static int __init cypress_init(void) +{ + int result; + + /* register this driver with the USB subsystem */ + result = usb_register(&cypress_driver); + if (result) { + err("Function usb_register failed! Error number: %d\n", result); + } + + return result; +} + +static void __exit cypress_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&cypress_driver); +} + +module_init(cypress_init); +module_exit(cypress_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); + +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index c82c402285a..e095772dd8e 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -200,10 +200,8 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz /* create a urb, and a buffer for it, and copy the data to the urb */ urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - retval = -ENOMEM; - goto error; - } + if (!urb) + return -ENOMEM; buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); if (!buf) { diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index e02c1a30c4c..f961a770cee 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -64,7 +64,6 @@ struct mon_reader_text { }; static void mon_text_ctor(void *, kmem_cache_t *, unsigned long); -static void mon_text_dtor(void *, kmem_cache_t *, unsigned long); /* * mon_text_submit @@ -268,7 +267,7 @@ static int mon_text_open(struct inode *inode, struct file *file) (long)rp); rp->e_slab = kmem_cache_create(rp->slab_name, sizeof(struct mon_event_text), sizeof(long), 0, - mon_text_ctor, mon_text_dtor); + mon_text_ctor, NULL); if (rp->e_slab == NULL) { rc = -ENOMEM; goto err_slab; @@ -459,7 +458,3 @@ static void mon_text_ctor(void *mem, kmem_cache_t *slab, unsigned long sflags) memset(mem, 0xe5, sizeof(struct mon_event_text)); } -static void mon_text_dtor(void *mem, kmem_cache_t *slab, unsigned long sflags) -{ - ; -} diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index 718f8e2b552..e5e6e4f3ef8 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -128,11 +128,13 @@ #define VENDOR_ID_MELCO 0x0411 #define VENDOR_ID_MICRONET 0x3980 #define VENDOR_ID_LONGSHINE 0x07b8 +#define VENDOR_ID_ZYXEL 0x0586 #define PRODUCT_ID_RTL8150 0x8150 #define PRODUCT_ID_LUAKTX 0x0012 #define PRODUCT_ID_LCS8138TX 0x401a #define PRODUCT_ID_SP128AR 0x0003 +#define PRODUCT_ID_PRESTIGE 0x401a #undef EEPROM_WRITE @@ -142,6 +144,7 @@ static struct usb_device_id rtl8150_table[] = { {USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)}, {USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)}, {USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)}, + {USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)}, {} }; diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 8bd44fda5ea..ac33bd47cfc 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -456,6 +456,17 @@ config USB_SERIAL_SAFE_PADDED bool "USB Secure Encapsulated Driver - Padded" depends on USB_SERIAL_SAFE +config USB_SERIAL_SIERRAWIRELESS + tristate "USB Sierra Wireless Driver" + depends on USB_SERIAL + help + Say M here if you want to use a Sierra Wireless device (if + using an PC 5220 or AC580 please use the Airprime driver + instead). + + To compile this driver as a module, choose M here: the + module will be called sierra. + config USB_SERIAL_TI tristate "USB TI 3410/5052 Serial Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 5a0960fc9d3..35d4acc7f1d 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o obj-$(CONFIG_USB_SERIAL_OPTION) += option.o obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o +obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 94b9ba0ff87..62082532a8b 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -13,7 +13,7 @@ #include <linux/tty.h> #include <linux/module.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> static struct usb_device_id id_table [] = { { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ diff --git a/drivers/usb/serial/anydata.c b/drivers/usb/serial/anydata.c index 343f6f22822..01843ef8c11 100644 --- a/drivers/usb/serial/anydata.c +++ b/drivers/usb/serial/anydata.c @@ -13,7 +13,7 @@ #include <linux/tty.h> #include <linux/module.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> static struct usb_device_id id_table [] = { { USB_DEVICE(0x16d5, 0x6501) }, /* AirData CDMA device */ @@ -71,7 +71,7 @@ static int anydata_open(struct usb_serial_port *port, struct file *filp) port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, - usb_serial_generic_write_bulk_callback, port); + usb_serial_generic_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) dev_err(&port->dev, diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 8dec796222a..970d9ef0a7a 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -21,7 +21,7 @@ #include <linux/tty.h> #include <linux/module.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> static int debug; diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 3faa7aa0111..70ece9e01ce 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -74,7 +74,7 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> #include "belkin_sa.h" static int debug; diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index f2d993b70c1..6542f220468 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -13,7 +13,7 @@ #include <linux/tty.h> #include <linux/module.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> static int usb_serial_device_match (struct device *dev, struct device_driver *drv) { diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 3d456b32c31..3a9073dbfe6 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -17,11 +17,10 @@ #include <linux/tty.h> #include <linux/console.h> #include <linux/usb.h> +#include <linux/usb/serial.h> static int debug; -#include "usb-serial.h" - struct usbcons_info { int magic; int break_flag; diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index df0a4f98b4a..486c7411b9a 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -26,7 +26,7 @@ #include <linux/moduleparam.h> #include <linux/usb.h> #include <asm/uaccess.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> /* * Version Information diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 49b51ab0d4c..6286aba86fa 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -39,7 +39,7 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> #define CYBERJACK_LOCAL_BUF_SIZE 32 diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 4ff2dfb299b..ee70fddcab6 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -59,11 +59,11 @@ #include <linux/moduleparam.h> #include <linux/spinlock.h> #include <linux/usb.h> +#include <linux/usb/serial.h> #include <linux/serial.h> #include <linux/delay.h> #include <asm/uaccess.h> -#include "usb-serial.h" #include "cypress_m8.h" diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 6953d3ef573..9b225183fc7 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -246,7 +246,7 @@ #include <asm/uaccess.h> #include <linux/usb.h> #include <linux/wait.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> /* Defines */ diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 1e2b31eeb49..daafe405d86 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -62,7 +62,7 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> static int debug; diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c index debc3b0f966..5169c2d154a 100644 --- a/drivers/usb/serial/ezusb.c +++ b/drivers/usb/serial/ezusb.c @@ -15,7 +15,7 @@ #include <linux/tty.h> #include <linux/module.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ #define CPUCS_REG 0x7F92 diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 8a74b19f128..b458aedc5fb 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -257,7 +257,7 @@ #include <asm/uaccess.h> #include <linux/usb.h> #include <linux/serial.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> #include "ftdi_sio.h" /* @@ -313,6 +313,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, @@ -500,6 +501,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) }, + { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; @@ -548,11 +551,17 @@ struct ftdi_private { spinlock_t rx_lock; /* spinlock for receive state */ struct work_struct rx_work; int rx_processed; + unsigned long rx_bytes; __u16 interface; /* FT2232C port interface (0 for FT232/245) */ int force_baud; /* if non-zero, force the baud rate to this value */ int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ + + spinlock_t tx_lock; /* spinlock for transmit state */ + unsigned long tx_bytes; + unsigned long tx_outstanding_bytes; + unsigned long tx_outstanding_urbs; }; /* Used for TIOCMIWAIT */ @@ -626,6 +635,9 @@ static struct usb_serial_driver ftdi_sio_device = { #define HIGH 1 #define LOW 0 +/* number of outstanding urbs to prevent userspace DoS from happening */ +#define URB_UPPER_LIMIT 42 + /* * *************************************************************************** * Utlity functions @@ -1156,6 +1168,7 @@ static int ftdi_sio_attach (struct usb_serial *serial) } spin_lock_init(&priv->rx_lock); + spin_lock_init(&priv->tx_lock); init_waitqueue_head(&priv->delta_msr_wait); /* This will push the characters through immediately rather than queue a task to deliver them */ @@ -1270,6 +1283,13 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) dbg("%s", __FUNCTION__); + spin_lock_irqsave(&priv->tx_lock, flags); + priv->tx_bytes = 0; + spin_unlock_irqrestore(&priv->tx_lock, flags); + spin_lock_irqsave(&priv->rx_lock, flags); + priv->rx_bytes = 0; + spin_unlock_irqrestore(&priv->rx_lock, flags); + if (port->tty) port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; @@ -1372,6 +1392,7 @@ static int ftdi_write (struct usb_serial_port *port, int data_offset ; /* will be 1 for the SIO and 0 otherwise */ int status; int transfer_size; + unsigned long flags; dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count); @@ -1379,6 +1400,13 @@ static int ftdi_write (struct usb_serial_port *port, dbg("write request of 0 bytes"); return 0; } + spin_lock_irqsave(&priv->tx_lock, flags); + if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) { + spin_unlock_irqrestore(&priv->tx_lock, flags); + dbg("%s - write limit hit\n", __FUNCTION__); + return 0; + } + spin_unlock_irqrestore(&priv->tx_lock, flags); data_offset = priv->write_offset; dbg("data_offset set to %d",data_offset); @@ -1445,6 +1473,12 @@ static int ftdi_write (struct usb_serial_port *port, err("%s - failed submitting write urb, error %d", __FUNCTION__, status); count = status; kfree (buffer); + } else { + spin_lock_irqsave(&priv->tx_lock, flags); + ++priv->tx_outstanding_urbs; + priv->tx_outstanding_bytes += count; + priv->tx_bytes += count; + spin_unlock_irqrestore(&priv->tx_lock, flags); } /* we are done with this urb, so let the host driver @@ -1460,7 +1494,11 @@ static int ftdi_write (struct usb_serial_port *port, static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs) { + unsigned long flags; struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct ftdi_private *priv; + int data_offset; /* will be 1 for the SIO and 0 otherwise */ + unsigned long countback; /* free up the transfer buffer, as usb_free_urb() does not do this */ kfree (urb->transfer_buffer); @@ -1472,34 +1510,67 @@ static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs) return; } + priv = usb_get_serial_port_data(port); + if (!priv) { + dbg("%s - bad port private data pointer - exiting", __FUNCTION__); + return; + } + /* account for transferred data */ + countback = urb->actual_length; + data_offset = priv->write_offset; + if (data_offset > 0) { + /* Subtract the control bytes */ + countback -= (data_offset * ((countback + (PKTSZ - 1)) / PKTSZ)); + } + spin_lock_irqsave(&priv->tx_lock, flags); + --priv->tx_outstanding_urbs; + priv->tx_outstanding_bytes -= countback; + spin_unlock_irqrestore(&priv->tx_lock, flags); + usb_serial_port_softint(port); } /* ftdi_write_bulk_callback */ static int ftdi_write_room( struct usb_serial_port *port ) { + struct ftdi_private *priv = usb_get_serial_port_data(port); + int room; + unsigned long flags; + dbg("%s - port %d", __FUNCTION__, port->number); - /* - * We really can take anything the user throws at us - * but let's pick a nice big number to tell the tty - * layer that we have lots of free space - */ - return 2048; + spin_lock_irqsave(&priv->tx_lock, flags); + if (priv->tx_outstanding_urbs < URB_UPPER_LIMIT) { + /* + * We really can take anything the user throws at us + * but let's pick a nice big number to tell the tty + * layer that we have lots of free space + */ + room = 2048; + } else { + room = 0; + } + spin_unlock_irqrestore(&priv->tx_lock, flags); + return room; } /* ftdi_write_room */ static int ftdi_chars_in_buffer (struct usb_serial_port *port) { /* ftdi_chars_in_buffer */ + struct ftdi_private *priv = usb_get_serial_port_data(port); + int buffered; + unsigned long flags; + dbg("%s - port %d", __FUNCTION__, port->number); - /* - * We can't really account for how much data we - * have sent out, but hasn't made it through to the - * device, so just tell the tty layer that everything - * is flushed. - */ - return 0; + spin_lock_irqsave(&priv->tx_lock, flags); + buffered = (int)priv->tx_outstanding_bytes; + spin_unlock_irqrestore(&priv->tx_lock, flags); + if (buffered < 0) { + err("%s outstanding tx bytes is negative!", __FUNCTION__); + buffered = 0; + } + return buffered; } /* ftdi_chars_in_buffer */ @@ -1509,6 +1580,8 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct tty_struct *tty; struct ftdi_private *priv; + unsigned long countread; + unsigned long flags; if (urb->number_of_packets > 0) { err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__, @@ -1543,6 +1616,13 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) return; } + /* count data bytes, but not status bytes */ + countread = urb->actual_length; + countread -= 2 * ((countread + (PKTSZ - 1)) / PKTSZ); + spin_lock_irqsave(&priv->rx_lock, flags); + priv->rx_bytes += countread; + spin_unlock_irqrestore(&priv->rx_lock, flags); + ftdi_process_read(port); } /* ftdi_read_bulk_callback */ diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 6ab2ac845bd..04ef90fcb87 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -36,6 +36,9 @@ #define FTDI_ACTZWAVE_PID 0xF2D0 +/* www.starting-point-systems.com µChameleon device */ +#define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */ + /* www.irtrans.de device */ #define FTDI_IRTRANS_PID 0xFC60 /* Product Id */ @@ -442,6 +445,18 @@ */ #define FTDI_YEI_SERVOCENTER31_PID 0xE050 /* YEI ServoCenter3.1 USB */ +/* + * ThorLabs USB motor drivers + */ +#define FTDI_THORLABS_PID 0xfaf0 /* ThorLabs USB motor drivers */ + +/* + * Testo products (http://www.testo.com/) + * Submitted by Colin Leroy + */ +#define TESTO_VID 0x128D +#define TESTO_USB_INTERFACE_PID 0x0001 + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 803721b97e2..77b977206a8 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -13,7 +13,7 @@ #include <linux/tty.h> #include <linux/module.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> static struct usb_device_id id_table [] = { { USB_DEVICE(0x1404, 0xcddc) }, diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 1f5d1620baa..727852634be 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -35,6 +35,7 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> #include <linux/usb.h> +#include <linux/usb/serial.h> /* the mode to be set when the port ist opened */ static int initial_mode = 1; @@ -42,8 +43,6 @@ static int initial_mode = 1; /* debug flag */ static int debug = 0; -#include "usb-serial.h" - #define GARMIN_VENDOR_ID 0x091E /* diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 945b8bb38c9..17271355639 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -17,8 +17,8 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/usb.h> +#include <linux/usb/serial.h> #include <asm/uaccess.h> -#include "usb-serial.h" static int debug; @@ -285,6 +285,7 @@ void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *reg if (result) dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); } +EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs) { diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c index 7e06358b031..ebcac701b06 100644 --- a/drivers/usb/serial/hp4x.c +++ b/drivers/usb/serial/hp4x.c @@ -17,7 +17,7 @@ #include <linux/tty.h> #include <linux/module.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> /* * Version Information diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index bd2c05dac2a..c49976c3ad5 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -44,7 +44,7 @@ #include <linux/wait.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> #include "io_edgeport.h" #include "io_ionsp.h" /* info for the iosp messages */ #include "io_16654.h" /* 16654 UART defines */ diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 723a12ae87b..17c5b1d2311 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -39,8 +39,8 @@ #include <asm/uaccess.h> #include <asm/semaphore.h> #include <linux/usb.h> +#include <linux/usb/serial.h> -#include "usb-serial.h" #include "io_16654.h" #include "io_usbvend.h" #include "io_ti.h" diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index dbcfe172a5c..59c5d999009 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -55,7 +55,7 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> #include "ipaq.h" #define KP_RETRIES 100 @@ -70,6 +70,8 @@ static __u16 product, vendor; static int debug; +static int connect_retries = KP_RETRIES; +static int initial_wait; /* Function prototypes for an ipaq */ static int ipaq_open (struct usb_serial_port *port, struct file *filp); @@ -582,7 +584,7 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp) struct ipaq_private *priv; struct ipaq_packet *pkt; int i, result = 0; - int retries = KP_RETRIES; + int retries = connect_retries; dbg("%s - port %d", __FUNCTION__, port->number); @@ -646,16 +648,12 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp) port->read_urb->transfer_buffer_length = URBDATA_SIZE; port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE; + msleep(1000*initial_wait); /* Start reading from the device */ usb_fill_bulk_urb(port->read_urb, serial->dev, usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, ipaq_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) { - err("%s - failed submitting read urb, error %d", __FUNCTION__, result); - goto error; - } /* * Send out control message observed in win98 sniffs. Not sure what @@ -670,8 +668,14 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp) usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21, 0x1, 0, NULL, 0, 100); if (result == 0) { + result = usb_submit_urb(port->read_urb, GFP_KERNEL); + if (result) { + err("%s - failed submitting read urb, error %d", __FUNCTION__, result); + goto error; + } return 0; } + msleep(1000); } err("%s - failed doing control urb, error %d", __FUNCTION__, result); goto error; @@ -854,6 +858,7 @@ static void ipaq_write_bulk_callback(struct urb *urb, struct pt_regs *regs) if (urb->status) { dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); + return; } spin_lock_irqsave(&write_list_lock, flags); @@ -966,3 +971,9 @@ MODULE_PARM_DESC(vendor, "User specified USB idVendor"); module_param(product, ushort, 0); MODULE_PARM_DESC(product, "User specified USB idProduct"); + +module_param(connect_retries, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(connect_retries, "Maximum number of connect retries (one second each)"); + +module_param(initial_wait, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(initial_wait, "Time to wait before attempting a connection (in seconds)"); diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index a4a0bfeaab0..87306cb6f9f 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -46,8 +46,8 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/usb.h> +#include <linux/usb/serial.h> #include <asm/uaccess.h> -#include "usb-serial.h" /* * Version Information @@ -373,6 +373,8 @@ static void ipw_write_bulk_callback(struct urb *urb, struct pt_regs *regs) dbg("%s", __FUNCTION__); + port->write_urb_busy = 0; + if (urb->status) dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 2cf1fed3de4..1738b0b6a37 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -57,7 +57,7 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> /* * Version Information diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index d7c58f1bc96..015ad6cc1bb 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -107,7 +107,7 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> #include "keyspan.h" static int debug; diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 03ab3c0f3cc..49b8dc039d1 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -78,6 +78,7 @@ #include <linux/workqueue.h> #include <asm/uaccess.h> #include <linux/usb.h> +#include <linux/usb/serial.h> static int debug; @@ -107,8 +108,6 @@ struct ezusb_hex_record { #include "xircom_pgs_fw.h" #endif -#include "usb-serial.h" - /* * Version Information */ diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index b45ff3e7ab4..2a2f3e2da05 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -55,7 +55,7 @@ #include <linux/module.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> #include "kl5kusb105.h" static int debug; diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 45773337477..d50dce03495 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -46,8 +46,8 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> #include <linux/usb.h> +#include <linux/usb/serial.h> #include <linux/ioctl.h> -#include "usb-serial.h" #include "kobil_sct.h" static int debug; diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index ca05d3275f3..f4d4305c2c0 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -75,7 +75,7 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> #include "mct_u232.h" /* diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index 7f544081032..ac3f8b5d2c4 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -14,7 +14,7 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> static int debug; diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index cfb711a21a4..e49f40913c2 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -46,7 +46,7 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> static int debug; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 78ad4b3126a..f0530c1d7b7 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -35,6 +35,7 @@ 2006-06-01 v0.6.2 add backwards-compatibility stuff 2006-06-01 v0.6.3 add Novatel Wireless 2006-06-01 v0.7 Option => GSM + 2006-06-01 v0.7.1 add COBRA2 Work sponsored by: Sigos GmbH, Germany <info@sigos.de> @@ -53,7 +54,7 @@ device features. */ -#define DRIVER_VERSION "v0.7.0" +#define DRIVER_VERSION "v0.7.1" #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" #define DRIVER_DESC "USB Driver for GSM modems" @@ -64,7 +65,7 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> /* Function prototypes */ static int option_open(struct usb_serial_port *port, struct file *filp); @@ -102,6 +103,7 @@ static int option_send_setup(struct usb_serial_port *port); #define OPTION_PRODUCT_FUSION 0x6000 #define OPTION_PRODUCT_FUSION2 0x6300 #define OPTION_PRODUCT_COBRA 0x6500 +#define OPTION_PRODUCT_COBRA2 0x6600 #define HUAWEI_PRODUCT_E600 0x1001 #define AUDIOVOX_PRODUCT_AIRCARD 0x0112 #define SIERRAWIRELESS_PRODUCT_MC8755 0x6802 @@ -112,6 +114,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) }, @@ -124,6 +127,7 @@ static struct usb_device_id option_ids1[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index de93a2b909e..259db31b65c 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -27,7 +27,7 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> #include "pl2303.h" /* @@ -52,6 +52,7 @@ struct pl2303_buf { static struct usb_device_id id_table [] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, @@ -79,6 +80,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, { USB_DEVICE(OTI_VENDOR_ID, OTI_PRODUCT_ID) }, + { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 7f29e81d3e3..d9c1e6e0b4b 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -10,6 +10,7 @@ #define PL2303_VENDOR_ID 0x067b #define PL2303_PRODUCT_ID 0x2303 #define PL2303_PRODUCT_ID_RSAQ2 0x04bb +#define PL2303_PRODUCT_ID_DCU11 0x1234 #define PL2303_PRODUCT_ID_PHAROS 0xaaa0 #define PL2303_PRODUCT_ID_RSAQ3 0xaaa2 @@ -84,3 +85,7 @@ /* Ours Technology Inc DKU-5 clone, chipset: Prolific Technology Inc */ #define OTI_VENDOR_ID 0x0ea0 #define OTI_PRODUCT_ID 0x6858 + +/* DATAPILOT Universal-2 Phone Cable */ +#define DATAPILOT_U2_VENDOR_ID 0x0731 +#define DATAPILOT_U2_PRODUCT_ID 0x2003 diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 897d8447252..789771ecdb1 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -71,7 +71,7 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> #ifndef CONFIG_USB_SAFE_PADDED diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c new file mode 100644 index 00000000000..d29638daa98 --- /dev/null +++ b/drivers/usb/serial/sierra.c @@ -0,0 +1,75 @@ +/* + * Sierra Wireless CDMA Wireless Serial USB driver + * + * Current Copy modified by: Kevin Lloyd <linux@sierrawireless.com> + * Original Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> + +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ + { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ + { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ + { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ + { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ + { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ + /* Following devices are supported in the airprime.c driver */ + /* { USB_DEVICE(0x1199, 0x0112) }, */ /* Sierra Wireless AirCard 580 */ + /* { USB_DEVICE(0x0F3D, 0x0112) }, */ /* AirPrime/Sierra PC 5220 */ + { } +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_driver sierra_driver = { + .name = "sierra_wireless", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, +}; + +static struct usb_serial_driver sierra_device = { + .driver = { + .owner = THIS_MODULE, + .name = "Sierra_Wireless", + }, + .id_table = id_table, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, + .num_ports = 3, +}; + +static int __init sierra_init(void) +{ + int retval; + + retval = usb_serial_register(&sierra_device); + if (retval) + return retval; + retval = usb_register(&sierra_driver); + if (retval) + usb_serial_deregister(&sierra_device); + return retval; +} + +static void __exit sierra_exit(void) +{ + usb_deregister(&sierra_driver); + usb_serial_deregister(&sierra_device); +} + +module_init(sierra_init); +module_exit(sierra_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index a9afff31a92..ac9b8ee52d4 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -83,8 +83,8 @@ #include <asm/uaccess.h> #include <asm/semaphore.h> #include <linux/usb.h> +#include <linux/usb/serial.h> -#include "usb-serial.h" #include "ti_usb_3410_5052.h" #include "ti_fw_3410.h" /* firmware image for 3410 */ #include "ti_fw_5052.h" /* firmware image for 5052 */ diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index b59a0536ea5..12c1694d322 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -31,7 +31,7 @@ #include <linux/smp_lock.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> #include "pl2303.h" /* @@ -40,6 +40,8 @@ #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" #define DRIVER_DESC "USB Serial Driver core" +static void port_free(struct usb_serial_port *port); + /* Driver structure we register with the USB core */ static struct usb_driver usb_serial_driver = { .name = "usbserial", @@ -146,23 +148,10 @@ static void destroy_serial(struct kref *kref) port = serial->port[i]; if (!port) continue; - usb_kill_urb(port->read_urb); - usb_free_urb(port->read_urb); - usb_kill_urb(port->write_urb); - usb_free_urb(port->write_urb); - usb_kill_urb(port->interrupt_in_urb); - usb_free_urb(port->interrupt_in_urb); - usb_kill_urb(port->interrupt_out_urb); - usb_free_urb(port->interrupt_out_urb); - kfree(port->bulk_in_buffer); - kfree(port->bulk_out_buffer); - kfree(port->interrupt_in_buffer); - kfree(port->interrupt_out_buffer); + port_free(port); } } - flush_scheduled_work(); /* port->work */ - usb_put_dev(serial->dev); /* free up any memory that we allocated */ @@ -564,6 +553,11 @@ static void port_release(struct device *dev) struct usb_serial_port *port = to_usb_serial_port(dev); dbg ("%s - %s", __FUNCTION__, dev->bus_id); + port_free(port); +} + +static void port_free(struct usb_serial_port *port) +{ usb_kill_urb(port->read_urb); usb_free_urb(port->read_urb); usb_kill_urb(port->write_urb); @@ -576,6 +570,7 @@ static void port_release(struct device *dev) kfree(port->bulk_out_buffer); kfree(port->interrupt_in_buffer); kfree(port->interrupt_out_buffer); + flush_scheduled_work(); /* port->work */ kfree(port); } diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h deleted file mode 100644 index 0f2802a6019..00000000000 --- a/drivers/usb/serial/usb-serial.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - * USB Serial Converter driver - * - * Copyright (C) 1999 - 2005 - * Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. - * - */ - - -#ifndef __LINUX_USB_SERIAL_H -#define __LINUX_USB_SERIAL_H - -#include <linux/kref.h> -#include <linux/mutex.h> - -#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */ -#define SERIAL_TTY_MINORS 255 /* loads of devices :) */ - -#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */ - -/* parity check flag */ -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - -/** - * usb_serial_port: structure for the specific ports of a device. - * @serial: pointer back to the struct usb_serial owner of this port. - * @tty: pointer to the corresponding tty for this port. - * @lock: spinlock to grab when updating portions of this structure. - * @mutex: mutex used to synchronize serial_open() and serial_close() - * access for this port. - * @number: the number of the port (the minor number). - * @interrupt_in_buffer: pointer to the interrupt in buffer for this port. - * @interrupt_in_urb: pointer to the interrupt in struct urb for this port. - * @interrupt_in_endpointAddress: endpoint address for the interrupt in pipe - * for this port. - * @interrupt_out_buffer: pointer to the interrupt out buffer for this port. - * @interrupt_out_size: the size of the interrupt_out_buffer, in bytes. - * @interrupt_out_urb: pointer to the interrupt out struct urb for this port. - * @interrupt_out_endpointAddress: endpoint address for the interrupt out pipe - * for this port. - * @bulk_in_buffer: pointer to the bulk in buffer for this port. - * @read_urb: pointer to the bulk in struct urb for this port. - * @bulk_in_endpointAddress: endpoint address for the bulk in pipe for this - * port. - * @bulk_out_buffer: pointer to the bulk out buffer for this port. - * @bulk_out_size: the size of the bulk_out_buffer, in bytes. - * @write_urb: pointer to the bulk out struct urb for this port. - * @bulk_out_endpointAddress: endpoint address for the bulk out pipe for this - * port. - * @write_wait: a wait_queue_head_t used by the port. - * @work: work queue entry for the line discipline waking up. - * @open_count: number of times this port has been opened. - * - * This structure is used by the usb-serial core and drivers for the specific - * ports of a device. - */ -struct usb_serial_port { - struct usb_serial * serial; - struct tty_struct * tty; - spinlock_t lock; - struct mutex mutex; - unsigned char number; - - unsigned char * interrupt_in_buffer; - struct urb * interrupt_in_urb; - __u8 interrupt_in_endpointAddress; - - unsigned char * interrupt_out_buffer; - int interrupt_out_size; - struct urb * interrupt_out_urb; - __u8 interrupt_out_endpointAddress; - - unsigned char * bulk_in_buffer; - int bulk_in_size; - struct urb * read_urb; - __u8 bulk_in_endpointAddress; - - unsigned char * bulk_out_buffer; - int bulk_out_size; - struct urb * write_urb; - int write_urb_busy; - __u8 bulk_out_endpointAddress; - - wait_queue_head_t write_wait; - struct work_struct work; - int open_count; - struct device dev; -}; -#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev) - -/* get and set the port private data pointer helper functions */ -static inline void *usb_get_serial_port_data (struct usb_serial_port *port) -{ - return dev_get_drvdata(&port->dev); -} - -static inline void usb_set_serial_port_data (struct usb_serial_port *port, void *data) -{ - dev_set_drvdata(&port->dev, data); -} - -/** - * usb_serial - structure used by the usb-serial core for a device - * @dev: pointer to the struct usb_device for this device - * @type: pointer to the struct usb_serial_driver for this device - * @interface: pointer to the struct usb_interface for this device - * @minor: the starting minor number for this device - * @num_ports: the number of ports this device has - * @num_interrupt_in: number of interrupt in endpoints we have - * @num_interrupt_out: number of interrupt out endpoints we have - * @num_bulk_in: number of bulk in endpoints we have - * @num_bulk_out: number of bulk out endpoints we have - * @port: array of struct usb_serial_port structures for the different ports. - * @private: place to put any driver specific information that is needed. The - * usb-serial driver is required to manage this data, the usb-serial core - * will not touch this. Use usb_get_serial_data() and - * usb_set_serial_data() to access this. - */ -struct usb_serial { - struct usb_device * dev; - struct usb_serial_driver * type; - struct usb_interface * interface; - unsigned char minor; - unsigned char num_ports; - unsigned char num_port_pointers; - char num_interrupt_in; - char num_interrupt_out; - char num_bulk_in; - char num_bulk_out; - struct usb_serial_port * port[MAX_NUM_PORTS]; - struct kref kref; - void * private; -}; -#define to_usb_serial(d) container_of(d, struct usb_serial, kref) - -#define NUM_DONT_CARE (-1) - -/* get and set the serial private data pointer helper functions */ -static inline void *usb_get_serial_data (struct usb_serial *serial) -{ - return serial->private; -} - -static inline void usb_set_serial_data (struct usb_serial *serial, void *data) -{ - serial->private = data; -} - -/** - * usb_serial_driver - describes a usb serial driver - * @description: pointer to a string that describes this driver. This string used - * in the syslog messages when a device is inserted or removed. - * @id_table: pointer to a list of usb_device_id structures that define all - * of the devices this structure can support. - * @num_interrupt_in: the number of interrupt in endpoints this device will - * have. - * @num_interrupt_out: the number of interrupt out endpoints this device will - * have. - * @num_bulk_in: the number of bulk in endpoints this device will have. - * @num_bulk_out: the number of bulk out endpoints this device will have. - * @num_ports: the number of different ports this device will have. - * @calc_num_ports: pointer to a function to determine how many ports this - * device has dynamically. It will be called after the probe() - * callback is called, but before attach() - * @probe: pointer to the driver's probe function. - * This will be called when the device is inserted into the system, - * but before the device has been fully initialized by the usb_serial - * subsystem. Use this function to download any firmware to the device, - * or any other early initialization that might be needed. - * Return 0 to continue on with the initialization sequence. Anything - * else will abort it. - * @attach: pointer to the driver's attach function. - * This will be called when the struct usb_serial structure is fully set - * set up. Do any local initialization of the device, or any private - * memory structure allocation at this point in time. - * @shutdown: pointer to the driver's shutdown function. This will be - * called when the device is removed from the system. - * - * This structure is defines a USB Serial driver. It provides all of - * the information that the USB serial core code needs. If the function - * pointers are defined, then the USB serial core code will call them when - * the corresponding tty port functions are called. If they are not - * called, the generic serial function will be used instead. - * - * The driver.owner field should be set to the module owner of this driver. - * The driver.name field should be set to the name of this driver (remember - * it will show up in sysfs, so it needs to be short and to the point. - * Useing the module name is a good idea.) - */ -struct usb_serial_driver { - const char *description; - const struct usb_device_id *id_table; - char num_interrupt_in; - char num_interrupt_out; - char num_bulk_in; - char num_bulk_out; - char num_ports; - - struct list_head driver_list; - struct device_driver driver; - - int (*probe) (struct usb_serial *serial, const struct usb_device_id *id); - int (*attach) (struct usb_serial *serial); - int (*calc_num_ports) (struct usb_serial *serial); - - void (*shutdown) (struct usb_serial *serial); - - int (*port_probe) (struct usb_serial_port *port); - int (*port_remove) (struct usb_serial_port *port); - - /* serial function calls */ - int (*open) (struct usb_serial_port *port, struct file * filp); - void (*close) (struct usb_serial_port *port, struct file * filp); - int (*write) (struct usb_serial_port *port, const unsigned char *buf, int count); - int (*write_room) (struct usb_serial_port *port); - int (*ioctl) (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); - void (*set_termios) (struct usb_serial_port *port, struct termios * old); - void (*break_ctl) (struct usb_serial_port *port, int break_state); - int (*chars_in_buffer) (struct usb_serial_port *port); - void (*throttle) (struct usb_serial_port *port); - void (*unthrottle) (struct usb_serial_port *port); - int (*tiocmget) (struct usb_serial_port *port, struct file *file); - int (*tiocmset) (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); - - void (*read_int_callback)(struct urb *urb, struct pt_regs *regs); - void (*write_int_callback)(struct urb *urb, struct pt_regs *regs); - void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs); - void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs); -}; -#define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver) - -extern int usb_serial_register(struct usb_serial_driver *driver); -extern void usb_serial_deregister(struct usb_serial_driver *driver); -extern void usb_serial_port_softint(struct usb_serial_port *port); - -extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id); -extern void usb_serial_disconnect(struct usb_interface *iface); - -extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest); -extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit); - -/* USB Serial console functions */ -#ifdef CONFIG_USB_SERIAL_CONSOLE -extern void usb_serial_console_init (int debug, int minor); -extern void usb_serial_console_exit (void); -extern void usb_serial_console_disconnect(struct usb_serial *serial); -#else -static inline void usb_serial_console_init (int debug, int minor) { } -static inline void usb_serial_console_exit (void) { } -static inline void usb_serial_console_disconnect(struct usb_serial *serial) {} -#endif - -/* Functions needed by other parts of the usbserial core */ -extern struct usb_serial *usb_serial_get_by_index (unsigned int minor); -extern void usb_serial_put(struct usb_serial *serial); -extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp); -extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count); -extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp); -extern int usb_serial_generic_write_room (struct usb_serial_port *port); -extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port); -extern void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *regs); -extern void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs); -extern void usb_serial_generic_shutdown (struct usb_serial *serial); -extern int usb_serial_generic_register (int debug); -extern void usb_serial_generic_deregister (void); - -extern int usb_serial_bus_register (struct usb_serial_driver *device); -extern void usb_serial_bus_deregister (struct usb_serial_driver *device); - -extern struct usb_serial_driver usb_serial_generic_device; -extern struct bus_type usb_serial_bus_type; -extern struct tty_driver *usb_serial_tty_driver; - -static inline void usb_serial_debug_data(int debug, - struct device *dev, - const char *function, int size, - const unsigned char *data) -{ - int i; - - if (debug) { - dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ", function, size); - for (i = 0; i < size; ++i) - printk ("%.2x ", data[i]); - printk ("\n"); - } -} - -/* Use our own dbg macro */ -#undef dbg -#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg); } while (0) - - - -#endif /* ifdef __LINUX_USB_SERIAL_H */ - diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 95a2936e902..88949f7884c 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -25,7 +25,7 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> #include <linux/usb.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> #include "visor.h" /* @@ -302,7 +302,6 @@ static int visor_open (struct usb_serial_port *port, struct file *filp) spin_lock_irqsave(&priv->lock, flags); priv->bytes_in = 0; priv->bytes_out = 0; - priv->outstanding_urbs = 0; priv->throttled = 0; spin_unlock_irqrestore(&priv->lock, flags); @@ -435,13 +434,25 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf, static int visor_write_room (struct usb_serial_port *port) { + struct visor_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + dbg("%s - port %d", __FUNCTION__, port->number); /* * We really can take anything the user throws at us * but let's pick a nice big number to tell the tty - * layer that we have lots of free space + * layer that we have lots of free space, unless we don't. */ + + spin_lock_irqsave(&priv->lock, flags); + if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) { + spin_unlock_irqrestore(&priv->lock, flags); + dbg("%s - write limit hit\n", __FUNCTION__); + return 0; + } + spin_unlock_irqrestore(&priv->lock, flags); + return 2048; } @@ -758,15 +769,22 @@ static int visor_calc_num_ports (struct usb_serial *serial) static int generic_startup(struct usb_serial *serial) { + struct usb_serial_port **ports = serial->port; struct visor_private *priv; int i; for (i = 0; i < serial->num_ports; ++i) { priv = kzalloc (sizeof(*priv), GFP_KERNEL); - if (!priv) + if (!priv) { + while (i-- != 0) { + priv = usb_get_serial_port_data(ports[i]); + usb_set_serial_port_data(ports[i], NULL); + kfree(priv); + } return -ENOMEM; + } spin_lock_init(&priv->lock); - usb_set_serial_port_data(serial->port[i], priv); + usb_set_serial_port_data(ports[i], priv); } return 0; } @@ -876,7 +894,18 @@ static int clie_5_attach (struct usb_serial *serial) static void visor_shutdown (struct usb_serial *serial) { + struct visor_private *priv; + int i; + dbg("%s", __FUNCTION__); + + for (i = 0; i < serial->num_ports; i++) { + priv = usb_get_serial_port_data(serial->port[i]); + if (priv) { + usb_set_serial_port_data(serial->port[i], NULL); + kfree(priv); + } + } } static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 540438c3f38..6e6c7934be3 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -79,7 +79,7 @@ #include <linux/usb.h> #include <linux/serial_reg.h> #include <linux/serial.h> -#include "usb-serial.h" +#include <linux/usb/serial.h> #include "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */ #include "whiteheat.h" /* WhiteHEAT specific commands */ diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 5715291ba54..a4b7df9ff8c 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -112,13 +112,11 @@ static int slave_configure(struct scsi_device *sdev) if (sdev->scsi_level < SCSI_2) sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2; - /* According to the technical support people at Genesys Logic, - * devices using their chips have problems transferring more than - * 32 KB at a time. In practice people have found that 64 KB - * works okay and that's what Windows does. But we'll be - * conservative; people can always use the sysfs interface to - * increase max_sectors. */ - if (le16_to_cpu(us->pusb_dev->descriptor.idVendor) == USB_VENDOR_ID_GENESYS && + /* Many devices have trouble transfering more than 32KB at a time, + * while others have trouble with more than 64K. At this time we + * are limiting both to 32K (64 sectores). + */ + if ((us->flags & US_FL_MAX_SECTORS_64) && sdev->request_queue->max_sectors > 64) blk_queue_max_sectors(sdev->request_queue, 64); diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index eb7188b3565..d6acc92a4ae 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -180,7 +180,7 @@ static int usb_stor_msg_common(struct us_data *us, int timeout) if (timeleft <= 0) { US_DEBUGP("%s -- cancelling URB\n", timeleft == 0 ? "Timeout" : "Signal"); - usb_unlink_urb(us->current_urb); + usb_kill_urb(us->current_urb); } /* return the URB status */ diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index c7e84e653df..a5ca449f6e6 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -112,6 +112,19 @@ UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x0113, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), +/* Submitted by Ernestas Vaiciukevicius <ernisv@gmail.com> */ +UNUSUAL_DEV( 0x0419, 0x0100, 0x0100, 0x0100, + "Samsung Info. Systems America, Inc.", + "MP3 Player", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + +/* Reported by Orgad Shaneh <orgads@gmail.com> */ +UNUSUAL_DEV( 0x0419, 0xaace, 0x0100, 0x0100, + "Samsung", "MP3 Player", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + /* Reported by Christian Leber <christian@leber.de> */ UNUSUAL_DEV( 0x0419, 0xaaf5, 0x0100, 0x0100, "TrekStor", @@ -132,6 +145,14 @@ UNUSUAL_DEV( 0x0420, 0x0001, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Sumedha Swamy <sumedhaswamy@gmail.com> and + * Einar Th. Einarsson <einarthered@gmail.com> */ +UNUSUAL_DEV( 0x0421, 0x0444, 0x0100, 0x0100, + "Nokia", + "N91", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), + /* Reported by Jiri Slaby <jirislaby@gmail.com> and * Rene C. Castberg <Rene@Castberg.org> */ UNUSUAL_DEV( 0x0421, 0x0446, 0x0100, 0x0100, @@ -140,6 +161,13 @@ UNUSUAL_DEV( 0x0421, 0x0446, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), +/* Reported by Matthew Bloch <matthew@bytemark.co.uk> */ +UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100, + "Nokia", + "E61", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), + /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */ UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, "SMSC", @@ -473,10 +501,11 @@ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450, US_SC_SCSI, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN | US_FL_NOT_LOCKABLE | US_FL_NO_WP_DETECT ), -/* This entry is needed because the device reports Sub=ff */ -UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0600, +/* Submitted by Lars Jacob <jacob.lars@googlemail.com> + * This entry is needed because the device reports Sub=ff */ +UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0610, "Sony", - "DSC-T1/T5", + "DSC-T1/T5/H5", US_SC_8070, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN ), @@ -708,18 +737,22 @@ UNUSUAL_DEV( 0x05dc, 0xb002, 0x0000, 0x0113, * They were originally reported by Alexander Oltu * <alexander@all-2.com> and Peter Marks <peter.marks@turner.com> * respectively. + * + * US_FL_GO_SLOW and US_FL_MAX_SECTORS_64 added by Phil Dibowitz + * <phil@ipom.com> as these flags were made and hard-coded + * special-cases were pulled from scsiglue.c. */ UNUSUAL_DEV( 0x05e3, 0x0701, 0x0000, 0xffff, "Genesys Logic", "USB to IDE Optical", US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_GO_SLOW ), + US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ), UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff, "Genesys Logic", "USB to IDE Disk", US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_GO_SLOW ), + US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ), /* Reported by Hanno Boeck <hanno@gmx.de> * Taken from the Lycoris Kernel */ @@ -1196,6 +1229,14 @@ UNUSUAL_DEV( 0x0ea0, 0x6828, 0x0110, 0x0110, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Benjamin Schiller <sbenni@gmx.de> + * It is also sold by Easylite as DJ 20 */ +UNUSUAL_DEV( 0x0ed1, 0x7636, 0x0103, 0x0103, + "Typhoon", + "My DJ 1820", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE | US_FL_GO_SLOW | US_FL_MAX_SECTORS_64), + /* Reported by Michael Stattmann <michael@stattmann.com> */ UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000, "Sony Ericsson", @@ -1227,6 +1268,15 @@ UNUSUAL_DEV( 0x1370, 0x6828, 0x0110, 0x0110, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* patch submitted by Davide Perini <perini.davide@dpsoftware.org> + * and Renato Perini <rperini@email.it> + */ +UNUSUAL_DEV( 0x22b8, 0x3010, 0x0001, 0x0001, + "Motorola", + "RAZR V3x", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ), + /* Reported by Radovan Garabik <garabik@kassiopeia.juls.savba.sk> */ UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999, "MPIO", diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 1185acac4b2..5ee19be52f6 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -55,6 +55,7 @@ #include <linux/slab.h> #include <linux/kthread.h> #include <linux/mutex.h> +#include <linux/utsrelease.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -373,8 +374,12 @@ static int usb_stor_control_thread(void * __us) /* lock access to the state */ scsi_lock(host); + /* did the command already complete because of a disconnect? */ + if (!us->srb) + ; /* nothing to do */ + /* indicate that the command is done */ - if (us->srb->result != DID_ABORT << 16) { + else if (us->srb->result != DID_ABORT << 16) { US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result); us->srb->scsi_done(us->srb); @@ -524,7 +529,8 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id) if (msg >= 0 && !(us->flags & US_FL_NEED_OVERRIDE)) printk(KERN_NOTICE USB_STORAGE "This device " "(%04x,%04x,%04x S %02x P %02x)" - " has %s in unusual_devs.h\n" + " has %s in unusual_devs.h (kernel" + " %s)\n" " Please send a copy of this message to " "<linux-usb-devel@lists.sourceforge.net>\n", le16_to_cpu(ddesc->idVendor), @@ -532,7 +538,8 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id) le16_to_cpu(ddesc->bcdDevice), idesc->bInterfaceSubClass, idesc->bInterfaceProtocol, - msgs[msg]); + msgs[msg], + UTS_RELEASE); } } @@ -836,32 +843,34 @@ static void dissociate_dev(struct us_data *us) * the host */ static void quiesce_and_remove_host(struct us_data *us) { + struct Scsi_Host *host = us_to_host(us); + /* Prevent new USB transfers, stop the current command, and * interrupt a SCSI-scan or device-reset delay */ + scsi_lock(host); set_bit(US_FLIDX_DISCONNECTING, &us->flags); + scsi_unlock(host); usb_stor_stop_transport(us); wake_up(&us->delay_wait); /* It doesn't matter if the SCSI-scanning thread is still running. * The thread will exit when it sees the DISCONNECTING flag. */ - /* Wait for the current command to finish, then remove the host */ - mutex_lock(&us->dev_mutex); - mutex_unlock(&us->dev_mutex); - /* queuecommand won't accept any new commands and the control * thread won't execute a previously-queued command. If there * is such a command pending, complete it with an error. */ + mutex_lock(&us->dev_mutex); if (us->srb) { us->srb->result = DID_NO_CONNECT << 16; - scsi_lock(us_to_host(us)); + scsi_lock(host); us->srb->scsi_done(us->srb); us->srb = NULL; - scsi_unlock(us_to_host(us)); + scsi_unlock(host); } + mutex_unlock(&us->dev_mutex); /* Now we own no commands so it's safe to remove the SCSI host */ - scsi_remove_host(us_to_host(us)); + scsi_remove_host(host); } /* Second stage of disconnect processing: deallocate all resources */ diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index 5284abe1b5e..21f3ddbc908 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -176,8 +176,4 @@ extern void fill_inquiry_response(struct us_data *us, #define scsi_unlock(host) spin_unlock_irq(host->host_lock) #define scsi_lock(host) spin_lock_irq(host->host_lock) - -/* Vendor ID list for devices that require special handling */ -#define USB_VENDOR_ID_GENESYS 0x05e3 /* Genesys Logic */ - #endif |