diff options
Diffstat (limited to 'drivers/usb/gadget')
26 files changed, 475 insertions, 226 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index ee411206c69..7460cd797f4 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -812,6 +812,16 @@ config USB_CDC_COMPOSITE Say "y" to link the driver statically, or "m" to build a dynamically linked module. +config USB_G_NOKIA + tristate "Nokia composite gadget" + depends on PHONET + help + The Nokia composite gadget provides support for acm, obex + and phonet in only one composite gadget driver. + + It's only really useful for N900 hardware. If you're building + a kernel for N900, say Y or M here. If unsure, say N. + config USB_G_MULTI tristate "Multifunction Composite Gadget (EXPERIMENTAL)" depends on BLOCK && NET diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 2e2c047262b..43b51da8d72 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -43,6 +43,7 @@ g_mass_storage-objs := mass_storage.o g_printer-objs := printer.o g_cdc-objs := cdc2.o g_multi-objs := multi.o +g_nokia-objs := nokia.o obj-$(CONFIG_USB_ZERO) += g_zero.o obj-$(CONFIG_USB_AUDIO) += g_audio.o @@ -55,4 +56,5 @@ obj-$(CONFIG_USB_G_PRINTER) += g_printer.o obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o obj-$(CONFIG_USB_G_MULTI) += g_multi.o +obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 043e04db2a0..12ac9cd32a0 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1656,9 +1656,7 @@ static int __init at91udc_probe(struct platform_device *pdev) if (!res) return -ENXIO; - if (!request_mem_region(res->start, - res->end - res->start + 1, - driver_name)) { + if (!request_mem_region(res->start, resource_size(res), driver_name)) { DBG("someone's using UDC memory\n"); return -EBUSY; } @@ -1699,7 +1697,7 @@ static int __init at91udc_probe(struct platform_device *pdev) udc->ep[3].maxpacket = 64; } - udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1); + udc->udp_baseaddr = ioremap(res->start, resource_size(res)); if (!udc->udp_baseaddr) { retval = -ENOMEM; goto fail0a; @@ -1781,7 +1779,7 @@ fail0a: if (cpu_is_at91rm9200()) gpio_free(udc->board.pullup_pin); fail0: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); DBG("%s probe failed, %d\n", driver_name, retval); return retval; } @@ -1813,7 +1811,7 @@ static int __exit at91udc_remove(struct platform_device *pdev) gpio_free(udc->board.pullup_pin); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); clk_put(udc->iclk); clk_put(udc->fclk); diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 4e970cf0e29..f79bdfe4bed 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -320,7 +320,7 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc) static int vbus_is_present(struct usba_udc *udc) { if (gpio_is_valid(udc->vbus_pin)) - return gpio_get_value(udc->vbus_pin); + return gpio_get_value(udc->vbus_pin) ^ udc->vbus_pin_inverted; /* No Vbus detection: Assume always present */ return 1; @@ -1763,7 +1763,7 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid) if (!udc->driver) goto out; - vbus = gpio_get_value(udc->vbus_pin); + vbus = vbus_is_present(udc); if (vbus != udc->vbus_prev) { if (vbus) { toggle_bias(1); @@ -1914,14 +1914,14 @@ static int __init usba_udc_probe(struct platform_device *pdev) udc->vbus_pin = -ENODEV; ret = -ENOMEM; - udc->regs = ioremap(regs->start, regs->end - regs->start + 1); + udc->regs = ioremap(regs->start, resource_size(regs)); if (!udc->regs) { dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n"); goto err_map_regs; } dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n", (unsigned long)regs->start, udc->regs); - udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1); + udc->fifo = ioremap(fifo->start, resource_size(fifo)); if (!udc->fifo) { dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n"); goto err_map_fifo; @@ -2000,6 +2000,7 @@ static int __init usba_udc_probe(struct platform_device *pdev) if (gpio_is_valid(pdata->vbus_pin)) { if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { udc->vbus_pin = pdata->vbus_pin; + udc->vbus_pin_inverted = pdata->vbus_pin_inverted; ret = request_irq(gpio_to_irq(udc->vbus_pin), usba_vbus_irq, 0, diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h index f7baea307f0..88a2e07a11a 100644 --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -323,6 +323,7 @@ struct usba_udc { struct platform_device *pdev; int irq; int vbus_pin; + int vbus_pin_inverted; struct clk *pclk; struct clk *hclk; diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index cd0914ec898..65a5f94cbc0 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -265,16 +265,24 @@ struct usb_ep * __init usb_ep_autoconfig ( return ep; } - } else if (gadget_is_sh (gadget) && USB_ENDPOINT_XFER_INT == type) { - /* single buffering is enough; maybe 8 byte fifo is too */ - ep = find_ep (gadget, "ep3in-bulk"); - if (ep && ep_matches (gadget, ep, desc)) - return ep; - - } else if (gadget_is_mq11xx (gadget) && USB_ENDPOINT_XFER_INT == type) { - ep = find_ep (gadget, "ep1-bulk"); +#ifdef CONFIG_BLACKFIN + } else if (gadget_is_musbhsfc(gadget) || gadget_is_musbhdrc(gadget)) { + if ((USB_ENDPOINT_XFER_BULK == type) || + (USB_ENDPOINT_XFER_ISOC == type)) { + if (USB_DIR_IN & desc->bEndpointAddress) + ep = find_ep (gadget, "ep5in"); + else + ep = find_ep (gadget, "ep6out"); + } else if (USB_ENDPOINT_XFER_INT == type) { + if (USB_DIR_IN & desc->bEndpointAddress) + ep = find_ep(gadget, "ep1in"); + else + ep = find_ep(gadget, "ep2out"); + } else + ep = NULL; if (ep && ep_matches (gadget, ep, desc)) return ep; +#endif } /* Second, look at endpoints until an unclaimed one looks usable */ diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 141372b6e7a..400f80372d9 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -259,7 +259,7 @@ static struct usb_configuration rndis_config_driver = { /*-------------------------------------------------------------------------*/ -#ifdef USB_ETH_EEM +#ifdef CONFIG_USB_ETH_EEM static int use_eem = 1; #else static int use_eem; diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index d10353d46b8..e49c7325dce 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -702,14 +702,6 @@ acm_unbind(struct usb_configuration *c, struct usb_function *f) /* Some controllers can't support CDC ACM ... */ static inline bool can_support_cdc(struct usb_configuration *c) { - /* SH3 doesn't support multiple interfaces */ - if (gadget_is_sh(c->cdev->gadget)) - return false; - - /* sa1100 doesn't have a third interrupt endpoint */ - if (gadget_is_sa1100(c->cdev->gadget)) - return false; - /* everything else is *probably* fine ... */ return true; } diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index ecf5bdd0ae0..2fff530efc1 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -497,12 +497,9 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) struct net_device *net; /* Enable zlps by default for ECM conformance; - * override for musb_hdrc (avoids txdma ovhead) - * and sa1100 (can't). + * override for musb_hdrc (avoids txdma ovhead). */ - ecm->port.is_zlp_ok = !( - gadget_is_sa1100(cdev->gadget) - || gadget_is_musbhdrc(cdev->gadget) + ecm->port.is_zlp_ok = !(gadget_is_musbhdrc(cdev->gadget) ); ecm->port.cdc_filter = DEFAULT_FILTER; DBG(cdev, "activate ecm\n"); diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index a37640eba43..5a3cdd08f1d 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -368,7 +368,7 @@ struct fsg_common { struct task_struct *thread_task; /* Callback function to call when thread exits. */ - void (*thread_exits)(struct fsg_common *common); + int (*thread_exits)(struct fsg_common *common); /* Gadget's private data. */ void *private_data; @@ -392,8 +392,12 @@ struct fsg_config { const char *lun_name_format; const char *thread_name; - /* Callback function to call when thread exits. */ - void (*thread_exits)(struct fsg_common *common); + /* Callback function to call when thread exits. If no + * callback is set or it returns value lower then zero MSF + * will force eject all LUNs it operates on (including those + * marked as non-removable or with prevent_medium_removal flag + * set). */ + int (*thread_exits)(struct fsg_common *common); /* Gadget's private data. */ void *private_data; @@ -614,7 +618,12 @@ static int fsg_setup(struct usb_function *f, return -EDOM; VDBG(fsg, "get max LUN\n"); *(u8 *) req->buf = fsg->common->nluns - 1; - return 1; + + /* Respond with data/status */ + req->length = min((u16)1, w_length); + fsg->common->ep0req_name = + ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out"; + return ep0_queue(fsg->common); } VDBG(fsg, @@ -1041,7 +1050,7 @@ static void invalidate_sub(struct fsg_lun *curlun) unsigned long rc; rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); - VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc); + VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc); } static int do_verify(struct fsg_common *common) @@ -2524,14 +2533,6 @@ static void handle_exception(struct fsg_common *common) case FSG_STATE_CONFIG_CHANGE: rc = do_set_config(common, new_config); - if (common->ep0_req_tag != exception_req_tag) - break; - if (rc != 0) { /* STALL on errors */ - DBG(common, "ep0 set halt\n"); - usb_ep_set_halt(common->ep0); - } else { /* Complete the status stage */ - ep0_queue(common); - } break; case FSG_STATE_EXIT: @@ -2615,8 +2616,20 @@ static int fsg_main_thread(void *common_) common->thread_task = NULL; spin_unlock_irq(&common->lock); - if (common->thread_exits) - common->thread_exits(common); + if (!common->thread_exits || common->thread_exits(common) < 0) { + struct fsg_lun *curlun = common->luns; + unsigned i = common->nluns; + + down_write(&common->filesem); + for (; i--; ++curlun) { + if (!fsg_lun_is_open(curlun)) + continue; + + fsg_lun_close(curlun); + curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; + } + up_write(&common->filesem); + } /* Let the unbind and cleanup routines know the thread has exited */ complete_and_exit(&common->thread_notifier, 0); @@ -2763,10 +2776,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, if (cfg->release != 0xffff) { i = cfg->release; } else { - /* The sa1100 controller is not supported */ - i = gadget_is_sa1100(gadget) - ? -1 - : usb_gadget_controller_number(gadget); + i = usb_gadget_controller_number(gadget); if (i >= 0) { i = 0x0300 + i; } else { @@ -2791,8 +2801,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, * disable stalls. */ common->can_stall = cfg->can_stall && - !(gadget_is_sh(common->gadget) || - gadget_is_at91(common->gadget)); + !(gadget_is_at91(common->gadget)); spin_lock_init(&common->lock); @@ -2852,7 +2861,6 @@ error_release: /* Call fsg_common_release() directly, ref might be not * initialised */ fsg_common_release(&common->ref); - complete(&common->thread_notifier); return ERR_PTR(rc); } diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 95dae4c1ea4..a30e60c7f12 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -769,10 +769,6 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f) /* Some controllers can't support RNDIS ... */ static inline bool can_support_rndis(struct usb_configuration *c) { - /* only two endpoints on sa1100 */ - if (gadget_is_sa1100(c->cdev->gadget)) - return false; - /* everything else is *presumably* fine */ return true; } diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 29dfb0277ff..b49d86e3e45 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1448,7 +1448,7 @@ static void invalidate_sub(struct fsg_lun *curlun) unsigned long rc; rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); - VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc); + VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc); } static int do_verify(struct fsg_dev *fsg) @@ -3208,15 +3208,11 @@ static int __init check_parameters(struct fsg_dev *fsg) * halt bulk endpoints correctly. If one of them is present, * disable stalls. */ - if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget)) + if (gadget_is_at91(fsg->gadget)) mod_data.can_stall = 0; if (mod_data.release == 0xffff) { // Parameter wasn't set - /* The sa1100 controller is not supported */ - if (gadget_is_sa1100(fsg->gadget)) - gcnum = -1; - else - gcnum = usb_gadget_controller_number(fsg->gadget); + gcnum = usb_gadget_controller_number(fsg->gadget); if (gcnum >= 0) mod_data.release = 0x0300 + gcnum; else { diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 7881f12413c..3537d51073b 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2749,7 +2749,7 @@ static int __devexit qe_udc_remove(struct of_device *ofdev) } /*-------------------------------------------------------------------------*/ -static struct of_device_id __devinitdata qe_udc_match[] = { +static const struct of_device_id qe_udc_match[] __devinitconst = { { .compatible = "fsl,mpc8323-qe-usb", .data = (void *)PORT_QE, diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index f2d270b202f..1edbc12fff1 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -45,46 +45,18 @@ #define gadget_is_goku(g) 0 #endif -/* SH3 UDC -- not yet ported 2.4 --> 2.6 */ -#ifdef CONFIG_USB_GADGET_SUPERH -#define gadget_is_sh(g) !strcmp("sh_udc", (g)->name) -#else -#define gadget_is_sh(g) 0 -#endif - -/* not yet stable on 2.6 (would help "original Zaurus") */ -#ifdef CONFIG_USB_GADGET_SA1100 -#define gadget_is_sa1100(g) !strcmp("sa1100_udc", (g)->name) -#else -#define gadget_is_sa1100(g) 0 -#endif - #ifdef CONFIG_USB_GADGET_LH7A40X #define gadget_is_lh7a40x(g) !strcmp("lh7a40x_udc", (g)->name) #else #define gadget_is_lh7a40x(g) 0 #endif -/* handhelds.org tree (?) */ -#ifdef CONFIG_USB_GADGET_MQ11XX -#define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name) -#else -#define gadget_is_mq11xx(g) 0 -#endif - #ifdef CONFIG_USB_GADGET_OMAP #define gadget_is_omap(g) !strcmp("omap_udc", (g)->name) #else #define gadget_is_omap(g) 0 #endif -/* not yet ported 2.4 --> 2.6 */ -#ifdef CONFIG_USB_GADGET_N9604 -#define gadget_is_n9604(g) !strcmp("n9604_udc", (g)->name) -#else -#define gadget_is_n9604(g) 0 -#endif - /* various unstable versions available */ #ifdef CONFIG_USB_GADGET_PXA27X #define gadget_is_pxa27x(g) !strcmp("pxa27x_udc", (g)->name) @@ -122,14 +94,6 @@ #define gadget_is_fsl_usb2(g) 0 #endif -/* Mentor high speed function controller */ -/* from Montavista kernel (?) */ -#ifdef CONFIG_USB_GADGET_MUSBHSFC -#define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name) -#else -#define gadget_is_musbhsfc(g) 0 -#endif - /* Mentor high speed "dual role" controller, in peripheral role */ #ifdef CONFIG_USB_GADGET_MUSB_HDRC #define gadget_is_musbhdrc(g) !strcmp("musb_hdrc", (g)->name) @@ -143,13 +107,6 @@ #define gadget_is_langwell(g) 0 #endif -/* from Montavista kernel (?) */ -#ifdef CONFIG_USB_GADGET_MPC8272 -#define gadget_is_mpc8272(g) !strcmp("mpc8272_udc", (g)->name) -#else -#define gadget_is_mpc8272(g) 0 -#endif - #ifdef CONFIG_USB_GADGET_M66592 #define gadget_is_m66592(g) !strcmp("m66592_udc", (g)->name) #else @@ -203,20 +160,12 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x02; else if (gadget_is_pxa(gadget)) return 0x03; - else if (gadget_is_sh(gadget)) - return 0x04; - else if (gadget_is_sa1100(gadget)) - return 0x05; else if (gadget_is_goku(gadget)) return 0x06; - else if (gadget_is_mq11xx(gadget)) - return 0x07; else if (gadget_is_omap(gadget)) return 0x08; else if (gadget_is_lh7a40x(gadget)) return 0x09; - else if (gadget_is_n9604(gadget)) - return 0x10; else if (gadget_is_pxa27x(gadget)) return 0x11; else if (gadget_is_s3c2410(gadget)) @@ -225,12 +174,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x13; else if (gadget_is_imx(gadget)) return 0x14; - else if (gadget_is_musbhsfc(gadget)) - return 0x15; else if (gadget_is_musbhdrc(gadget)) return 0x16; - else if (gadget_is_mpc8272(gadget)) - return 0x17; else if (gadget_is_atmel_usba(gadget)) return 0x18; else if (gadget_is_fsl_usb2(gadget)) @@ -265,10 +210,6 @@ static inline bool gadget_supports_altsettings(struct usb_gadget *gadget) if (gadget_is_pxa27x(gadget)) return false; - /* SH3 hardware just doesn't do altsettings */ - if (gadget_is_sh(gadget)) - return false; - /* Everything else is *presumably* fine ... */ return true; } diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 5f6a2e0a935..04f6224b7e0 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -618,11 +618,6 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags) } #endif - if (gadget_is_sa1100(gadget) && dev->config) { - /* tx fifo is full, but we can't clear it...*/ - ERROR(dev, "can't change configurations\n"); - return -ESPIPE; - } gmidi_reset_config(dev); switch (number) { diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 112bb40a427..e8edc640381 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1859,7 +1859,7 @@ done: /*-------------------------------------------------------------------------*/ -static struct pci_device_id pci_ids [] = { { +static const struct pci_device_id pci_ids[] = { { .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), .class_mask = ~0, .vendor = 0x102f, /* Toshiba */ diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index bf0f6520c6d..de8a8380350 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -194,7 +194,7 @@ enum ep_state { }; struct ep_data { - struct semaphore lock; + struct mutex lock; enum ep_state state; atomic_t count; struct dev_data *dev; @@ -298,10 +298,10 @@ get_ready_ep (unsigned f_flags, struct ep_data *epdata) int val; if (f_flags & O_NONBLOCK) { - if (down_trylock (&epdata->lock) != 0) + if (!mutex_trylock(&epdata->lock)) goto nonblock; if (epdata->state != STATE_EP_ENABLED) { - up (&epdata->lock); + mutex_unlock(&epdata->lock); nonblock: val = -EAGAIN; } else @@ -309,7 +309,8 @@ nonblock: return val; } - if ((val = down_interruptible (&epdata->lock)) < 0) + val = mutex_lock_interruptible(&epdata->lock); + if (val < 0) return val; switch (epdata->state) { @@ -323,7 +324,7 @@ nonblock: // FALLTHROUGH case STATE_EP_UNBOUND: /* clean disconnect */ val = -ENODEV; - up (&epdata->lock); + mutex_unlock(&epdata->lock); } return val; } @@ -393,7 +394,7 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) if (likely (data->ep != NULL)) usb_ep_set_halt (data->ep); spin_unlock_irq (&data->dev->lock); - up (&data->lock); + mutex_unlock(&data->lock); return -EBADMSG; } @@ -411,7 +412,7 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) value = -EFAULT; free1: - up (&data->lock); + mutex_unlock(&data->lock); kfree (kbuf); return value; } @@ -436,7 +437,7 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) if (likely (data->ep != NULL)) usb_ep_set_halt (data->ep); spin_unlock_irq (&data->dev->lock); - up (&data->lock); + mutex_unlock(&data->lock); return -EBADMSG; } @@ -455,7 +456,7 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) VDEBUG (data->dev, "%s write %zu IN, status %d\n", data->name, len, (int) value); free1: - up (&data->lock); + mutex_unlock(&data->lock); kfree (kbuf); return value; } @@ -466,7 +467,8 @@ ep_release (struct inode *inode, struct file *fd) struct ep_data *data = fd->private_data; int value; - if ((value = down_interruptible(&data->lock)) < 0) + value = mutex_lock_interruptible(&data->lock); + if (value < 0) return value; /* clean up if this can be reopened */ @@ -476,7 +478,7 @@ ep_release (struct inode *inode, struct file *fd) data->hs_desc.bDescriptorType = 0; usb_ep_disable(data->ep); } - up (&data->lock); + mutex_unlock(&data->lock); put_ep (data); return 0; } @@ -507,7 +509,7 @@ static long ep_ioctl(struct file *fd, unsigned code, unsigned long value) } else status = -ENODEV; spin_unlock_irq (&data->dev->lock); - up (&data->lock); + mutex_unlock(&data->lock); return status; } @@ -673,7 +675,7 @@ fail: value = -ENODEV; spin_unlock_irq(&epdata->dev->lock); - up(&epdata->lock); + mutex_unlock(&epdata->lock); if (unlikely(value)) { kfree(priv); @@ -765,7 +767,8 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) u32 tag; int value, length = len; - if ((value = down_interruptible (&data->lock)) < 0) + value = mutex_lock_interruptible(&data->lock); + if (value < 0) return value; if (data->state != STATE_EP_READY) { @@ -854,7 +857,7 @@ fail: data->desc.bDescriptorType = 0; data->hs_desc.bDescriptorType = 0; } - up (&data->lock); + mutex_unlock(&data->lock); return value; fail0: value = -EINVAL; @@ -870,7 +873,7 @@ ep_open (struct inode *inode, struct file *fd) struct ep_data *data = inode->i_private; int value = -EBUSY; - if (down_interruptible (&data->lock) != 0) + if (mutex_lock_interruptible(&data->lock) != 0) return -EINTR; spin_lock_irq (&data->dev->lock); if (data->dev->state == STATE_DEV_UNBOUND) @@ -885,7 +888,7 @@ ep_open (struct inode *inode, struct file *fd) DBG (data->dev, "%s state %d\n", data->name, data->state); spin_unlock_irq (&data->dev->lock); - up (&data->lock); + mutex_unlock(&data->lock); return value; } @@ -1631,7 +1634,7 @@ static int activate_ep_files (struct dev_data *dev) if (!data) goto enomem0; data->state = STATE_EP_DISABLED; - init_MUTEX (&data->lock); + mutex_init(&data->lock); init_waitqueue_head (&data->wait); strncpy (data->name, ep->name, sizeof (data->name) - 1); diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c index 19619fbf20a..705cc1f7632 100644 --- a/drivers/usb/gadget/mass_storage.c +++ b/drivers/usb/gadget/mass_storage.c @@ -135,6 +135,12 @@ FSG_MODULE_PARAMETERS(/* no prefix */, mod_data); static unsigned long msg_registered = 0; static void msg_cleanup(void); +static int msg_thread_exits(struct fsg_common *common) +{ + msg_cleanup(); + return 0; +} + static int __init msg_do_config(struct usb_configuration *c) { struct fsg_common *common; @@ -147,7 +153,7 @@ static int __init msg_do_config(struct usb_configuration *c) } fsg_config_from_params(&config, &mod_data); - config.thread_exits = (void(*)(struct fsg_common*))&msg_cleanup; + config.thread_exits = msg_thread_exits; common = fsg_common_init(0, c->cdev, &config); if (IS_ERR(common)) return PTR_ERR(common); diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c new file mode 100644 index 00000000000..7d6b66a8572 --- /dev/null +++ b/drivers/usb/gadget/nokia.c @@ -0,0 +1,259 @@ +/* + * nokia.c -- Nokia Composite Gadget Driver + * + * Copyright (C) 2008-2010 Nokia Corporation + * Contact: Felipe Balbi <felipe.balbi@nokia.com> + * + * This gadget driver borrows from serial.c which is: + * + * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) + * Copyright (C) 2008 by David Brownell + * Copyright (C) 2008 by Nokia Corporation + * + * This software is distributed under the terms of the GNU General + * Public License ("GPL") as published by the Free Software Foundation, + * version 2 of that License. + */ + +#include <linux/kernel.h> +#include <linux/utsname.h> +#include <linux/device.h> + +#include "u_serial.h" +#include "u_ether.h" +#include "u_phonet.h" +#include "gadget_chips.h" + +/* Defines */ + +#define NOKIA_VERSION_NUM 0x0211 +#define NOKIA_LONG_NAME "N900 (PC-Suite Mode)" + +/*-------------------------------------------------------------------------*/ + +/* + * Kbuild is not very cooperative with respect to linking separately + * compiled library objects into one module. So for now we won't use + * separate compilation ... ensuring init/exit sections work to shrink + * the runtime footprint, and giving us at least some parts of what + * a "gcc --combine ... part1.c part2.c part3.c ... " build would. + */ +#include "composite.c" +#include "usbstring.c" +#include "config.c" +#include "epautoconf.c" + +#include "u_serial.c" +#include "f_acm.c" +#include "f_ecm.c" +#include "f_obex.c" +#include "f_serial.c" +#include "f_phonet.c" +#include "u_ether.c" + +/*-------------------------------------------------------------------------*/ + +#define NOKIA_VENDOR_ID 0x0421 /* Nokia */ +#define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */ + +/* string IDs are assigned dynamically */ + +#define STRING_MANUFACTURER_IDX 0 +#define STRING_PRODUCT_IDX 1 +#define STRING_DESCRIPTION_IDX 2 + +static char manufacturer_nokia[] = "Nokia"; +static const char product_nokia[] = NOKIA_LONG_NAME; +static const char description_nokia[] = "PC-Suite Configuration"; + +static struct usb_string strings_dev[] = { + [STRING_MANUFACTURER_IDX].s = manufacturer_nokia, + [STRING_PRODUCT_IDX].s = NOKIA_LONG_NAME, + [STRING_DESCRIPTION_IDX].s = description_nokia, + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab_dev = { + .language = 0x0409, /* en-us */ + .strings = strings_dev, +}; + +static struct usb_gadget_strings *dev_strings[] = { + &stringtab_dev, + NULL, +}; + +static struct usb_device_descriptor device_desc = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_COMM, + .idVendor = __constant_cpu_to_le16(NOKIA_VENDOR_ID), + .idProduct = __constant_cpu_to_le16(NOKIA_PRODUCT_ID), + /* .iManufacturer = DYNAMIC */ + /* .iProduct = DYNAMIC */ + .bNumConfigurations = 1, +}; + +/*-------------------------------------------------------------------------*/ + +/* Module */ +MODULE_DESCRIPTION("Nokia composite gadget driver for N900"); +MODULE_AUTHOR("Felipe Balbi"); +MODULE_LICENSE("GPL"); + +/*-------------------------------------------------------------------------*/ + +static u8 hostaddr[ETH_ALEN]; + +static int __init nokia_bind_config(struct usb_configuration *c) +{ + int status = 0; + + status = phonet_bind_config(c); + if (status) + printk(KERN_DEBUG "could not bind phonet config\n"); + + status = obex_bind_config(c, 0); + if (status) + printk(KERN_DEBUG "could not bind obex config %d\n", 0); + + status = obex_bind_config(c, 1); + if (status) + printk(KERN_DEBUG "could not bind obex config %d\n", 0); + + status = acm_bind_config(c, 2); + if (status) + printk(KERN_DEBUG "could not bind acm config\n"); + + status = ecm_bind_config(c, hostaddr); + if (status) + printk(KERN_DEBUG "could not bind ecm config\n"); + + return status; +} + +static struct usb_configuration nokia_config_500ma_driver = { + .label = "Bus Powered", + .bind = nokia_bind_config, + .bConfigurationValue = 1, + /* .iConfiguration = DYNAMIC */ + .bmAttributes = USB_CONFIG_ATT_ONE, + .bMaxPower = 250, /* 500mA */ +}; + +static struct usb_configuration nokia_config_100ma_driver = { + .label = "Self Powered", + .bind = nokia_bind_config, + .bConfigurationValue = 2, + /* .iConfiguration = DYNAMIC */ + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 50, /* 100 mA */ +}; + +static int __init nokia_bind(struct usb_composite_dev *cdev) +{ + int gcnum; + struct usb_gadget *gadget = cdev->gadget; + int status; + + status = gphonet_setup(cdev->gadget); + if (status < 0) + goto err_phonet; + + status = gserial_setup(cdev->gadget, 3); + if (status < 0) + goto err_serial; + + status = gether_setup(cdev->gadget, hostaddr); + if (status < 0) + goto err_ether; + + status = usb_string_id(cdev); + if (status < 0) + goto err_usb; + strings_dev[STRING_MANUFACTURER_IDX].id = status; + + device_desc.iManufacturer = status; + + status = usb_string_id(cdev); + if (status < 0) + goto err_usb; + strings_dev[STRING_PRODUCT_IDX].id = status; + + device_desc.iProduct = status; + + /* config description */ + status = usb_string_id(cdev); + if (status < 0) + goto err_usb; + strings_dev[STRING_DESCRIPTION_IDX].id = status; + + nokia_config_500ma_driver.iConfiguration = status; + nokia_config_100ma_driver.iConfiguration = status; + + /* set up other descriptors */ + gcnum = usb_gadget_controller_number(gadget); + if (gcnum >= 0) + device_desc.bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM); + else { + /* this should only work with hw that supports altsettings + * and several endpoints, anything else, panic. + */ + pr_err("nokia_bind: controller '%s' not recognized\n", + gadget->name); + goto err_usb; + } + + /* finaly register the configuration */ + status = usb_add_config(cdev, &nokia_config_500ma_driver); + if (status < 0) + goto err_usb; + + status = usb_add_config(cdev, &nokia_config_100ma_driver); + if (status < 0) + goto err_usb; + + dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME); + + return 0; + +err_usb: + gether_cleanup(); +err_ether: + gserial_cleanup(); +err_serial: + gphonet_cleanup(); +err_phonet: + return status; +} + +static int __exit nokia_unbind(struct usb_composite_dev *cdev) +{ + gphonet_cleanup(); + gserial_cleanup(); + gether_cleanup(); + + return 0; +} + +static struct usb_composite_driver nokia_driver = { + .name = "g_nokia", + .dev = &device_desc, + .strings = dev_strings, + .bind = nokia_bind, + .unbind = __exit_p(nokia_unbind), +}; + +static int __init nokia_init(void) +{ + return usb_composite_register(&nokia_driver); +} +module_init(nokia_init); + +static void __exit nokia_cleanup(void) +{ + usb_composite_unregister(&nokia_driver); +} +module_exit(nokia_cleanup); + diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 2d867fd2241..6b8bf8c781c 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -949,12 +949,6 @@ printer_set_config(struct printer_dev *dev, unsigned number) int result = 0; struct usb_gadget *gadget = dev->gadget; - if (gadget_is_sa1100(gadget) && dev->config) { - /* tx fifo is full, but we can't clear it...*/ - INFO(dev, "can't change configurations\n"); - return -ESPIPE; - } - switch (number) { case DEV_CONFIG_VALUE: result = 0; @@ -1033,12 +1027,6 @@ set_interface(struct printer_dev *dev, unsigned number) { int result = 0; - if (gadget_is_sa1100(dev->gadget) && dev->interface < 0) { - /* tx fifo is full, but we can't clear it...*/ - INFO(dev, "can't change interfaces\n"); - return -ESPIPE; - } - /* Free the current interface */ switch (dev->interface) { case PRINTER_INTERFACE: @@ -1392,12 +1380,6 @@ printer_bind(struct usb_gadget *gadget) goto fail; } - if (gadget_is_sa1100(gadget)) { - /* hardware can't write zero length packets. */ - ERROR(dev, "SA1100 controller is unsupport by this driver\n"); - goto fail; - } - gcnum = usb_gadget_controller_number(gadget); if (gcnum >= 0) { device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index adda1208a1e..05b892c3d68 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -742,13 +742,17 @@ static void ep_del_request(struct pxa_ep *ep, struct pxa27x_request *req) * @ep: pxa physical endpoint * @req: pxa request * @status: usb request status sent to gadget API + * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held * - * Context: ep->lock held + * Context: ep->lock held if flags not NULL, else ep->lock released * * Retire a pxa27x usb request. Endpoint must be locked. */ -static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status) +static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status, + unsigned long *pflags) { + unsigned long flags; + ep_del_request(ep, req); if (likely(req->req.status == -EINPROGRESS)) req->req.status = status; @@ -760,38 +764,48 @@ static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status) &req->req, status, req->req.actual, req->req.length); + if (pflags) + spin_unlock_irqrestore(&ep->lock, *pflags); + local_irq_save(flags); req->req.complete(&req->udc_usb_ep->usb_ep, &req->req); + local_irq_restore(flags); + if (pflags) + spin_lock_irqsave(&ep->lock, *pflags); } /** * ep_end_out_req - Ends endpoint OUT request * @ep: physical endpoint * @req: pxa request + * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held * - * Context: ep->lock held + * Context: ep->lock held or released (see req_done()) * * Ends endpoint OUT request (completes usb request). */ -static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req) +static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req, + unsigned long *pflags) { inc_ep_stats_reqs(ep, !USB_DIR_IN); - req_done(ep, req, 0); + req_done(ep, req, 0, pflags); } /** * ep0_end_out_req - Ends control endpoint OUT request (ends data stage) * @ep: physical endpoint * @req: pxa request + * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held * - * Context: ep->lock held + * Context: ep->lock held or released (see req_done()) * * Ends control endpoint OUT request (completes usb request), and puts * control endpoint into idle state */ -static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req) +static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req, + unsigned long *pflags) { set_ep0state(ep->dev, OUT_STATUS_STAGE); - ep_end_out_req(ep, req); + ep_end_out_req(ep, req, pflags); ep0_idle(ep->dev); } @@ -799,31 +813,35 @@ static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req) * ep_end_in_req - Ends endpoint IN request * @ep: physical endpoint * @req: pxa request + * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held * - * Context: ep->lock held + * Context: ep->lock held or released (see req_done()) * * Ends endpoint IN request (completes usb request). */ -static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req) +static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req, + unsigned long *pflags) { inc_ep_stats_reqs(ep, USB_DIR_IN); - req_done(ep, req, 0); + req_done(ep, req, 0, pflags); } /** * ep0_end_in_req - Ends control endpoint IN request (ends data stage) * @ep: physical endpoint * @req: pxa request + * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held * - * Context: ep->lock held + * Context: ep->lock held or released (see req_done()) * * Ends control endpoint IN request (completes usb request), and puts * control endpoint into status state */ -static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req) +static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req, + unsigned long *pflags) { set_ep0state(ep->dev, IN_STATUS_STAGE); - ep_end_in_req(ep, req); + ep_end_in_req(ep, req, pflags); } /** @@ -831,19 +849,22 @@ static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req) * @ep: pxa endpoint * @status: usb request status * - * Context: ep->lock held + * Context: ep->lock released * * Dequeues all requests on an endpoint. As a side effect, interrupts will be * disabled on that endpoint (because no more requests). */ static void nuke(struct pxa_ep *ep, int status) { - struct pxa27x_request *req; + struct pxa27x_request *req; + unsigned long flags; + spin_lock_irqsave(&ep->lock, flags); while (!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct pxa27x_request, queue); - req_done(ep, req, status); + req_done(ep, req, status, &flags); } + spin_unlock_irqrestore(&ep->lock, flags); } /** @@ -1123,6 +1144,7 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int rc = 0; int is_first_req; unsigned length; + int recursion_detected; req = container_of(_req, struct pxa27x_request, req); udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); @@ -1152,6 +1174,7 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req, return -EMSGSIZE; spin_lock_irqsave(&ep->lock, flags); + recursion_detected = ep->in_handle_ep; is_first_req = list_empty(&ep->queue); ep_dbg(ep, "queue req %p(first=%s), len %d buf %p\n", @@ -1161,12 +1184,12 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req, if (!ep->enabled) { _req->status = -ESHUTDOWN; rc = -ESHUTDOWN; - goto out; + goto out_locked; } if (req->in_use) { ep_err(ep, "refusing to queue req %p (already queued)\n", req); - goto out; + goto out_locked; } length = _req->length; @@ -1174,12 +1197,13 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req, _req->actual = 0; ep_add_request(ep, req); + spin_unlock_irqrestore(&ep->lock, flags); if (is_ep0(ep)) { switch (dev->ep0state) { case WAIT_ACK_SET_CONF_INTERF: if (length == 0) { - ep_end_in_req(ep, req); + ep_end_in_req(ep, req, NULL); } else { ep_err(ep, "got a request of %d bytes while" "in state WAIT_ACK_SET_CONF_INTERF\n", @@ -1192,12 +1216,12 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req, case IN_DATA_STAGE: if (!ep_is_full(ep)) if (write_ep0_fifo(ep, req)) - ep0_end_in_req(ep, req); + ep0_end_in_req(ep, req, NULL); break; case OUT_DATA_STAGE: if ((length == 0) || !epout_has_pkt(ep)) if (read_ep0_fifo(ep, req)) - ep0_end_out_req(ep, req); + ep0_end_out_req(ep, req, NULL); break; default: ep_err(ep, "odd state %s to send me a request\n", @@ -1207,12 +1231,15 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req, break; } } else { - handle_ep(ep); + if (!recursion_detected) + handle_ep(ep); } out: - spin_unlock_irqrestore(&ep->lock, flags); return rc; +out_locked: + spin_unlock_irqrestore(&ep->lock, flags); + goto out; } /** @@ -1242,13 +1269,14 @@ static int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) /* make sure it's actually queued on this endpoint */ list_for_each_entry(req, &ep->queue, queue) { if (&req->req == _req) { - req_done(ep, req, -ECONNRESET); rc = 0; break; } } spin_unlock_irqrestore(&ep->lock, flags); + if (!rc) + req_done(ep, req, -ECONNRESET, NULL); return rc; } @@ -1445,7 +1473,6 @@ static int pxa_ep_disable(struct usb_ep *_ep) { struct pxa_ep *ep; struct udc_usb_ep *udc_usb_ep; - unsigned long flags; if (!_ep) return -EINVAL; @@ -1455,10 +1482,8 @@ static int pxa_ep_disable(struct usb_ep *_ep) if (!ep || is_ep0(ep) || !list_empty(&ep->queue)) return -EINVAL; - spin_lock_irqsave(&ep->lock, flags); ep->enabled = 0; nuke(ep, -ESHUTDOWN); - spin_unlock_irqrestore(&ep->lock, flags); pxa_ep_fifo_flush(_ep); udc_usb_ep->pxa_ep = NULL; @@ -1907,8 +1932,10 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc, } u; int i; int have_extrabytes = 0; + unsigned long flags; nuke(ep, -EPROTO); + spin_lock_irqsave(&ep->lock, flags); /* * In the PXA320 manual, in the section about Back-to-Back setup @@ -1947,10 +1974,13 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc, /* Tell UDC to enter Data Stage */ ep_write_UDCCSR(ep, UDCCSR0_SA | UDCCSR0_OPC); + spin_unlock_irqrestore(&ep->lock, flags); i = udc->driver->setup(&udc->gadget, &u.r); + spin_lock_irqsave(&ep->lock, flags); if (i < 0) goto stall; out: + spin_unlock_irqrestore(&ep->lock, flags); return; stall: ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n", @@ -2055,13 +2085,13 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq) if (req && !ep_is_full(ep)) completed = write_ep0_fifo(ep, req); if (completed) - ep0_end_in_req(ep, req); + ep0_end_in_req(ep, req, NULL); break; case OUT_DATA_STAGE: /* SET_DESCRIPTOR */ if (epout_has_pkt(ep) && req) completed = read_ep0_fifo(ep, req); if (completed) - ep0_end_out_req(ep, req); + ep0_end_out_req(ep, req, NULL); break; case STALL: ep_write_UDCCSR(ep, UDCCSR0_FST); @@ -2091,7 +2121,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq) * Tries to transfer all pending request data into the endpoint and/or * transfer all pending data in the endpoint into usb requests. * - * Is always called when in_interrupt() or with ep->lock held. + * Is always called when in_interrupt() and with ep->lock released. */ static void handle_ep(struct pxa_ep *ep) { @@ -2100,10 +2130,17 @@ static void handle_ep(struct pxa_ep *ep) u32 udccsr; int is_in = ep->dir_in; int loop = 0; + unsigned long flags; + + spin_lock_irqsave(&ep->lock, flags); + if (ep->in_handle_ep) + goto recursion_detected; + ep->in_handle_ep = 1; do { completed = 0; udccsr = udc_ep_readl(ep, UDCCSR); + if (likely(!list_empty(&ep->queue))) req = list_entry(ep->queue.next, struct pxa27x_request, queue); @@ -2122,15 +2159,22 @@ static void handle_ep(struct pxa_ep *ep) if (unlikely(is_in)) { if (likely(!ep_is_full(ep))) completed = write_fifo(ep, req); - if (completed) - ep_end_in_req(ep, req); } else { if (likely(epout_has_pkt(ep))) completed = read_fifo(ep, req); - if (completed) - ep_end_out_req(ep, req); + } + + if (completed) { + if (is_in) + ep_end_in_req(ep, req, &flags); + else + ep_end_out_req(ep, req, &flags); } } while (completed); + + ep->in_handle_ep = 0; +recursion_detected: + spin_unlock_irqrestore(&ep->lock, flags); } /** @@ -2218,9 +2262,13 @@ static void irq_handle_data(int irq, struct pxa_udc *udc) continue; udc_writel(udc, UDCISR0, UDCISR_INT(i, UDCISR_INT_MASK)); - ep = &udc->pxa_ep[i]; - ep->stats.irqs++; - handle_ep(ep); + + WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep)); + if (i < ARRAY_SIZE(udc->pxa_ep)) { + ep = &udc->pxa_ep[i]; + ep->stats.irqs++; + handle_ep(ep); + } } for (i = 16; udcisr1 != 0 && i < 24; udcisr1 >>= 2, i++) { @@ -2228,9 +2276,12 @@ static void irq_handle_data(int irq, struct pxa_udc *udc) if (!(udcisr1 & UDCISR_INT_MASK)) continue; - ep = &udc->pxa_ep[i]; - ep->stats.irqs++; - handle_ep(ep); + WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep)); + if (i < ARRAY_SIZE(udc->pxa_ep)) { + ep = &udc->pxa_ep[i]; + ep->stats.irqs++; + handle_ep(ep); + } } } @@ -2439,7 +2490,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev) } retval = -ENOMEM; - udc->regs = ioremap(regs->start, regs->end - regs->start + 1); + udc->regs = ioremap(regs->start, resource_size(regs)); if (!udc->regs) { dev_err(&pdev->dev, "Unable to map UDC I/O memory\n"); goto err_map; diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h index e25225e2658..ff61e4866e8 100644 --- a/drivers/usb/gadget/pxa27x_udc.h +++ b/drivers/usb/gadget/pxa27x_udc.h @@ -318,6 +318,11 @@ struct udc_usb_ep { * @queue: requests queue * @lock: lock to pxa_ep data (queues and stats) * @enabled: true when endpoint enabled (not stopped by gadget layer) + * @in_handle_ep: number of recursions of handle_ep() function + * Prevents deadlocks or infinite recursions of types : + * irq->handle_ep()->req_done()->req.complete()->pxa_ep_queue()->handle_ep() + * or + * pxa_ep_queue()->handle_ep()->req_done()->req.complete()->pxa_ep_queue() * @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX) * @name: endpoint name (for trace/debug purpose) * @dir_in: 1 if IN endpoint, 0 if OUT endpoint @@ -346,6 +351,7 @@ struct pxa_ep { spinlock_t lock; /* Protects this structure */ /* (queues, stats) */ unsigned enabled:1; + unsigned in_handle_ep:1; unsigned idx:5; char *name; diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 5fc80a10415..7e5bf593d38 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -317,7 +317,8 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) * * Allocate a new USB request structure appropriate for the specified endpoint */ -struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, gfp_t flags) +static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, + gfp_t flags) { struct s3c_hsotg_req *req; @@ -373,7 +374,7 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, req->dma = DMA_ADDR_INVALID; hs_req->mapped = 0; } else { - dma_sync_single(hsotg->dev, req->dma, req->length, dir); + dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir); } } @@ -755,7 +756,7 @@ static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg, hs_req->mapped = 1; req->dma = dma; } else { - dma_sync_single(hsotg->dev, req->dma, req->length, dir); + dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir); hs_req->mapped = 0; } @@ -1460,7 +1461,7 @@ static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg) * as the actual data should be sent to the memory directly and we turn * on the completion interrupts to get notifications of transfer completion. */ -void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) +static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) { u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP); u32 epnum, status, size; @@ -3094,7 +3095,7 @@ static void s3c_hsotg_gate(struct platform_device *pdev, bool on) local_irq_restore(flags); } -struct s3c_hsotg_plat s3c_hsotg_default_pdata; +static struct s3c_hsotg_plat s3c_hsotg_default_pdata; static int __devinit s3c_hsotg_probe(struct platform_device *pdev) { diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 2fc02bd9584..84ca195c2d1 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -746,6 +746,10 @@ static const struct net_device_ops eth_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; +static struct device_type gadget_type = { + .name = "gadget", +}; + /** * gether_setup - initialize one ethernet-over-usb link * @g: gadget to associated with these links @@ -808,6 +812,7 @@ int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) dev->gadget = g; SET_NETDEV_DEV(net, &g->dev); + SET_NETDEV_DEVTYPE(net, &gadget_type); status = register_netdev(net); if (status < 0) { diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h index fd55f450bc0..3c8c0c9f9d7 100644 --- a/drivers/usb/gadget/u_ether.h +++ b/drivers/usb/gadget/u_ether.h @@ -93,13 +93,6 @@ static inline bool can_support_ecm(struct usb_gadget *gadget) if (!gadget_supports_altsettings(gadget)) return false; - /* SA1100 can do ECM, *without* status endpoint ... but we'll - * only use it in non-ECM mode for backwards compatibility - * (and since we currently require a status endpoint) - */ - if (gadget_is_sa1100(gadget)) - return false; - /* Everything else is *presumably* fine ... but this is a bit * chancy, so be **CERTAIN** there are no hardware issues with * your controller. Add it above if it can't handle CDC. diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 2d772401b7a..fac81ee193d 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -297,12 +297,10 @@ static int __init zero_bind(struct usb_composite_dev *cdev) */ if (loopdefault) { loopback_add(cdev, autoresume != 0); - if (!gadget_is_sh(gadget)) - sourcesink_add(cdev, autoresume != 0); + sourcesink_add(cdev, autoresume != 0); } else { sourcesink_add(cdev, autoresume != 0); - if (!gadget_is_sh(gadget)) - loopback_add(cdev, autoresume != 0); + loopback_add(cdev, autoresume != 0); } gcnum = usb_gadget_controller_number(gadget); |