diff options
author | Dmitry Torokhov <dtor@insightbb.com> | 2006-09-19 01:56:44 -0400 |
---|---|---|
committer | Dmitry Torokhov <dtor@insightbb.com> | 2006-09-19 01:56:44 -0400 |
commit | 0612ec48762bf8712db1925b2e67246d2237ebab (patch) | |
tree | 01b0d69c9c9915015c0f23ad4263646dd5413e99 /drivers/usb/gadget | |
parent | 4263cf0fac28122c8381b6f4f9441a43cd93c81f (diff) | |
parent | 47a5c6fa0e204a2b63309c648bb2fde36836c826 (diff) | |
download | kernel_samsung_espresso10-0612ec48762bf8712db1925b2e67246d2237ebab.zip kernel_samsung_espresso10-0612ec48762bf8712db1925b2e67246d2237ebab.tar.gz kernel_samsung_espresso10-0612ec48762bf8712db1925b2e67246d2237ebab.tar.bz2 |
Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/Kconfig | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/at91_udc.c | 176 | ||||
-rw-r--r-- | drivers/usb/gadget/at91_udc.h | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/dummy_hcd.c | 6 | ||||
-rw-r--r-- | drivers/usb/gadget/epautoconf.c | 16 | ||||
-rw-r--r-- | drivers/usb/gadget/ether.c | 53 | ||||
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/rndis.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/rndis.h | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/serial.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/zero.c | 2 |
11 files changed, 166 insertions, 98 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 363b2ad..1a32d96 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -207,7 +207,7 @@ config USB_AT91 config USB_GADGET_DUMMY_HCD boolean "Dummy HCD (DEVELOPMENT)" - depends on USB && EXPERIMENTAL + depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL select USB_GADGET_DUALSPEED help This host controller driver emulates USB, looping all data transfer diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 1c459ff..cfebca0 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -57,19 +57,23 @@ /* * This controller is simple and PIO-only. It's used in many AT91-series - * ARMv4T controllers, including the at91rm9200 (arm920T, with MMU), - * at91sam9261 (arm926ejs, with MMU), and several no-mmu versions. + * full speed USB controllers, including the at91rm9200 (arm920T, with MMU), + * at91sam926x (arm926ejs, with MMU), and several no-mmu versions. * * This driver expects the board has been wired with two GPIOs suppporting * a VBUS sensing IRQ, and a D+ pullup. (They may be omitted, but the - * testing hasn't covered such cases.) The pullup is most important; it + * testing hasn't covered such cases.) + * + * The pullup is most important (so it's integrated on sam926x parts). It * provides software control over whether the host enumerates the device. + * * The VBUS sensing helps during enumeration, and allows both USB clocks * (and the transceiver) to stay gated off until they're necessary, saving - * power. During USB suspend, the 48 MHz clock is gated off. + * power. During USB suspend, the 48 MHz clock is gated off in hardware; + * it may also be gated off by software during some Linux sleep states. */ -#define DRIVER_VERSION "8 March 2005" +#define DRIVER_VERSION "3 May 2006" static const char driver_name [] = "at91_udc"; static const char ep0name[] = "ep0"; @@ -316,9 +320,15 @@ static void done(struct at91_ep *ep, struct at91_request *req, int status) * * There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE * that shouldn't normally be changed. + * + * NOTE at91sam9260 docs mention synch between UDPCK and MCK clock domains, + * implying a need to wait for one write to complete (test relevant bits) + * before starting the next write. This shouldn't be an issue given how + * infrequently we write, except maybe for write-then-read idioms. */ #define SET_FX (AT91_UDP_TXPKTRDY) -#define CLR_FX (RX_DATA_READY | AT91_UDP_RXSETUP | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP) +#define CLR_FX (RX_DATA_READY | AT91_UDP_RXSETUP \ + | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP) /* pull OUT packet data from the endpoint's fifo */ static int read_fifo (struct at91_ep *ep, struct at91_request *req) @@ -472,7 +482,8 @@ static void nuke(struct at91_ep *ep, int status) /*-------------------------------------------------------------------------*/ -static int at91_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +static int at91_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) { struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); struct at91_udc *dev = ep->udc; @@ -582,11 +593,12 @@ static int at91_ep_disable (struct usb_ep * _ep) * interesting for request or buffer allocation. */ -static struct usb_request *at91_ep_alloc_request (struct usb_ep *_ep, unsigned int gfp_flags) +static struct usb_request * +at91_ep_alloc_request(struct usb_ep *_ep, unsigned int gfp_flags) { struct at91_request *req; - req = kcalloc(1, sizeof (struct at91_request), SLAB_KERNEL); + req = kcalloc(1, sizeof (struct at91_request), gfp_flags); if (!req) return NULL; @@ -862,6 +874,7 @@ static void stop_activity(struct at91_udc *udc) if (udc->gadget.speed == USB_SPEED_UNKNOWN) driver = NULL; udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->suspended = 0; for (i = 0; i < NUM_ENDPOINTS; i++) { struct at91_ep *ep = &udc->ep[i]; @@ -889,8 +902,8 @@ static void clk_off(struct at91_udc *udc) return; udc->clocked = 0; udc->gadget.speed = USB_SPEED_UNKNOWN; - clk_disable(udc->iclk); clk_disable(udc->fclk); + clk_disable(udc->iclk); } /* @@ -911,9 +924,6 @@ static void pullup(struct at91_udc *udc, int is_on) at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); at91_set_gpio_value(udc->board.pullup_pin, 0); clk_off(udc); - - // REVISIT: with transceiver disabled, will D- float - // so that a host would falsely detect a device? } } @@ -1290,7 +1300,8 @@ static void handle_ep0(struct at91_udc *udc) if (udc->wait_for_addr_ack) { u32 tmp; - at91_udp_write(AT91_UDP_FADDR, AT91_UDP_FEN | udc->addr); + at91_udp_write(AT91_UDP_FADDR, + AT91_UDP_FEN | udc->addr); tmp = at91_udp_read(AT91_UDP_GLB_STAT); tmp &= ~AT91_UDP_FADDEN; if (udc->addr) @@ -1361,9 +1372,10 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r) u32 rescans = 5; while (rescans--) { - u32 status = at91_udp_read(AT91_UDP_ISR); + u32 status; - status &= at91_udp_read(AT91_UDP_IMR); + status = at91_udp_read(AT91_UDP_ISR) + & at91_udp_read(AT91_UDP_IMR); if (!status) break; @@ -1379,18 +1391,17 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r) stop_activity(udc); /* enable ep0 */ - at91_udp_write(AT91_UDP_CSR(0), AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL); + at91_udp_write(AT91_UDP_CSR(0), + AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL); udc->gadget.speed = USB_SPEED_FULL; udc->suspended = 0; at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0)); /* * NOTE: this driver keeps clocks off unless the - * USB host is present. That saves power, and also - * eliminates IRQs (reset, resume, suspend) that can - * otherwise flood from the controller. If your - * board doesn't support VBUS detection, suspend and - * resume irq logic may need more attention... + * USB host is present. That saves power, but for + * boards that don't support VBUS detection, both + * clocks need to be active most of the time. */ /* host initiated suspend (3+ms bus idle) */ @@ -1452,13 +1463,19 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r) /*-------------------------------------------------------------------------*/ +static void nop_release(struct device *dev) +{ + /* nothing to free */ +} + static struct at91_udc controller = { .gadget = { - .ops = &at91_udc_ops, - .ep0 = &controller.ep[0].ep, - .name = driver_name, - .dev = { - .bus_id = "gadget" + .ops = &at91_udc_ops, + .ep0 = &controller.ep[0].ep, + .name = driver_name, + .dev = { + .bus_id = "gadget", + .release = nop_release, } }, .ep[0] = { @@ -1468,7 +1485,8 @@ static struct at91_udc controller = { }, .udc = &controller, .maxpacket = 8, - .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(0)), + .creg = (void __iomem *)(AT91_VA_BASE_UDP + + AT91_UDP_CSR(0)), .int_mask = 1 << 0, }, .ep[1] = { @@ -1479,7 +1497,8 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 64, - .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(1)), + .creg = (void __iomem *)(AT91_VA_BASE_UDP + + AT91_UDP_CSR(1)), .int_mask = 1 << 1, }, .ep[2] = { @@ -1490,7 +1509,8 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 64, - .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(2)), + .creg = (void __iomem *)(AT91_VA_BASE_UDP + + AT91_UDP_CSR(2)), .int_mask = 1 << 2, }, .ep[3] = { @@ -1501,7 +1521,8 @@ static struct at91_udc controller = { }, .udc = &controller, .maxpacket = 8, - .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(3)), + .creg = (void __iomem *)(AT91_VA_BASE_UDP + + AT91_UDP_CSR(3)), .int_mask = 1 << 3, }, .ep[4] = { @@ -1512,7 +1533,8 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 256, - .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(4)), + .creg = (void __iomem *)(AT91_VA_BASE_UDP + + AT91_UDP_CSR(4)), .int_mask = 1 << 4, }, .ep[5] = { @@ -1523,10 +1545,11 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 256, - .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(5)), + .creg = (void __iomem *)(AT91_VA_BASE_UDP + + AT91_UDP_CSR(5)), .int_mask = 1 << 5, }, - /* ep6 and ep7 are also reserved */ + /* ep6 and ep7 are also reserved (custom silicon might use them) */ }; static irqreturn_t at91_vbus_irq(int irq, void *_udc, struct pt_regs *r) @@ -1593,6 +1616,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) local_irq_disable(); udc->enabled = 0; + at91_udp_write(AT91_UDP_IDR, ~0); pullup(udc, 0); local_irq_enable(); @@ -1624,6 +1648,16 @@ static int __devinit at91udc_probe(struct platform_device *pdev) return -ENODEV; } + if (pdev->num_resources != 2) { + DBG("invalid num_resources"); + return -ENODEV; + } + if ((pdev->resource[0].flags != IORESOURCE_MEM) + || (pdev->resource[1].flags != IORESOURCE_IRQ)) { + DBG("invalid resource type"); + return -ENODEV; + } + if (!request_mem_region(AT91_BASE_UDP, SZ_16K, driver_name)) { DBG("someone's using UDC memory\n"); return -EBUSY; @@ -1649,19 +1683,26 @@ static int __devinit at91udc_probe(struct platform_device *pdev) if (retval < 0) goto fail0; - /* disable everything until there's a gadget driver and vbus */ - pullup(udc, 0); + /* don't do anything until we have both gadget driver and VBUS */ + clk_enable(udc->iclk); + at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); + at91_udp_write(AT91_UDP_IDR, 0xffffffff); + clk_disable(udc->iclk); /* request UDC and maybe VBUS irqs */ - if (request_irq(AT91_ID_UDP, at91_udc_irq, IRQF_DISABLED, driver_name, udc)) { - DBG("request irq %d failed\n", AT91_ID_UDP); + udc->udp_irq = platform_get_irq(pdev, 0); + if (request_irq(udc->udp_irq, at91_udc_irq, + IRQF_DISABLED, driver_name, udc)) { + DBG("request irq %d failed\n", udc->udp_irq); retval = -EBUSY; goto fail1; } if (udc->board.vbus_pin > 0) { - if (request_irq(udc->board.vbus_pin, at91_vbus_irq, IRQF_DISABLED, driver_name, udc)) { - DBG("request vbus irq %d failed\n", udc->board.vbus_pin); - free_irq(AT91_ID_UDP, udc); + if (request_irq(udc->board.vbus_pin, at91_vbus_irq, + IRQF_DISABLED, driver_name, udc)) { + DBG("request vbus irq %d failed\n", + udc->board.vbus_pin); + free_irq(udc->udp_irq, udc); retval = -EBUSY; goto fail1; } @@ -1670,6 +1711,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev) udc->vbus = 1; } dev_set_drvdata(dev, udc); + device_init_wakeup(dev, 1); create_debug_file(udc); INFO("%s version %s\n", driver_name, DRIVER_VERSION); @@ -1678,14 +1720,14 @@ static int __devinit at91udc_probe(struct platform_device *pdev) fail1: device_unregister(&udc->gadget.dev); fail0: - release_mem_region(AT91_VA_BASE_UDP, SZ_16K); + release_mem_region(AT91_BASE_UDP, SZ_16K); DBG("%s probe failed, %d\n", driver_name, retval); return retval; } -static int __devexit at91udc_remove(struct platform_device *dev) +static int __devexit at91udc_remove(struct platform_device *pdev) { - struct at91_udc *udc = platform_get_drvdata(dev); + struct at91_udc *udc = platform_get_drvdata(pdev); DBG("remove\n"); @@ -1694,10 +1736,11 @@ static int __devexit at91udc_remove(struct platform_device *dev) if (udc->driver != 0) usb_gadget_unregister_driver(udc->driver); + device_init_wakeup(&pdev->dev, 0); remove_debug_file(udc); if (udc->board.vbus_pin > 0) free_irq(udc->board.vbus_pin, udc); - free_irq(AT91_ID_UDP, udc); + free_irq(udc->udp_irq, udc); device_unregister(&udc->gadget.dev); release_mem_region(AT91_BASE_UDP, SZ_16K); @@ -1708,31 +1751,36 @@ static int __devexit at91udc_remove(struct platform_device *dev) } #ifdef CONFIG_PM -static int at91udc_suspend(struct platform_device *dev, pm_message_t mesg) +static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) { - struct at91_udc *udc = platform_get_drvdata(dev); + struct at91_udc *udc = platform_get_drvdata(pdev); + int wake = udc->driver && device_may_wakeup(&pdev->dev); - /* - * The "safe" suspend transitions are opportunistic ... e.g. when - * the USB link is suspended (48MHz clock autogated off), or when - * it's disconnected (programmatically gated off, elsewhere). - * Then we can suspend, and the chip can enter slow clock mode. - * - * The problem case is some component (user mode?) suspending this - * device while it's active, with the 48 MHz clock in use. There - * are two basic approaches: (a) veto suspend levels involving slow - * clock mode, (b) disconnect, so 48 MHz will no longer be in use - * and we can enter slow clock mode. This uses (b) for now, since - * it's simplest until AT91 PM exists and supports the other option. + /* Unless we can act normally to the host (letting it wake us up + * whenever it has work for us) force disconnect. Wakeup requires + * PLLB for USB events (signaling for reset, wakeup, or incoming + * tokens) and VBUS irqs (on systems which support them). */ - if (udc->vbus && !udc->suspended) + if ((!udc->suspended && udc->addr) + || !wake + || at91_suspend_entering_slow_clock()) { pullup(udc, 0); + disable_irq_wake(udc->udp_irq); + } else + enable_irq_wake(udc->udp_irq); + + if (udc->board.vbus_pin > 0) { + if (wake) + enable_irq_wake(udc->board.vbus_pin); + else + disable_irq_wake(udc->board.vbus_pin); + } return 0; } -static int at91udc_resume(struct platform_device *dev) +static int at91udc_resume(struct platform_device *pdev) { - struct at91_udc *udc = platform_get_drvdata(dev); + struct at91_udc *udc = platform_get_drvdata(pdev); /* maybe reconnect to host; if so, clocks on */ pullup(udc, 1); @@ -1748,7 +1796,7 @@ static struct platform_driver at91_udc = { .remove = __devexit_p(at91udc_remove), .shutdown = at91udc_shutdown, .suspend = at91udc_suspend, - .resume = at91udc_resume, + .resume = at91udc_resume, .driver = { .name = (char *) driver_name, .owner = THIS_MODULE, @@ -1767,6 +1815,6 @@ static void __devexit udc_exit_module(void) } module_exit(udc_exit_module); -MODULE_DESCRIPTION("AT91RM9200 udc driver"); +MODULE_DESCRIPTION("AT91 udc driver"); MODULE_AUTHOR("Thomas Rathbone, David Brownell"); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index 5a4799c..882af42 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -141,6 +141,7 @@ struct at91_udc { struct clk *iclk, *fclk; struct platform_device *pdev; struct proc_dir_entry *pde; + int udp_irq; }; static inline struct at91_udc *to_udc(struct usb_gadget *g) diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 4be4719..7d1c22c 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -609,7 +609,8 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) if (!dum->driver) return -ESHUTDOWN; - spin_lock_irqsave (&dum->lock, flags); + local_irq_save (flags); + spin_lock (&dum->lock); list_for_each_entry (req, &ep->queue, queue) { if (&req->req == _req) { list_del_init (&req->queue); @@ -618,7 +619,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) break; } } - spin_unlock_irqrestore (&dum->lock, flags); + spin_unlock (&dum->lock); if (retval == 0) { dev_dbg (udc_dev(dum), @@ -626,6 +627,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) req, _ep->name, _req->length, _req->buf); _req->complete (_ep, _req); } + local_irq_restore (flags); return retval; } diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index f7c6d75..53d5845 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 8320fce..30299c6 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -117,6 +117,8 @@ struct eth_dev { struct usb_ep *in_ep, *out_ep, *status_ep; const struct usb_endpoint_descriptor *in, *out, *status; + + spinlock_t req_lock; struct list_head tx_reqs, rx_reqs; struct net_device *net; @@ -1066,21 +1068,31 @@ static void eth_reset_config (struct eth_dev *dev) */ if (dev->in) { usb_ep_disable (dev->in_ep); + spin_lock(&dev->req_lock); while (likely (!list_empty (&dev->tx_reqs))) { req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del (&req->list); + + spin_unlock(&dev->req_lock); usb_ep_free_request (dev->in_ep, req); + spin_lock(&dev->req_lock); } + spin_unlock(&dev->req_lock); } if (dev->out) { usb_ep_disable (dev->out_ep); + spin_lock(&dev->req_lock); while (likely (!list_empty (&dev->rx_reqs))) { req = container_of (dev->rx_reqs.next, struct usb_request, list); list_del (&req->list); + + spin_unlock(&dev->req_lock); usb_ep_free_request (dev->out_ep, req); + spin_lock(&dev->req_lock); } + spin_unlock(&dev->req_lock); } if (dev->status) { @@ -1659,9 +1671,9 @@ enomem: if (retval) { DEBUG (dev, "rx submit --> %d\n", retval); dev_kfree_skb_any (skb); - spin_lock (&dev->lock); + spin_lock(&dev->req_lock); list_add (&req->list, &dev->rx_reqs); - spin_unlock (&dev->lock); + spin_unlock(&dev->req_lock); } return retval; } @@ -1730,8 +1742,9 @@ quiesce: dev_kfree_skb_any (skb); if (!netif_running (dev->net)) { clean: - /* nobody reading rx_reqs, so no dev->lock */ + spin_lock(&dev->req_lock); list_add (&req->list, &dev->rx_reqs); + spin_unlock(&dev->req_lock); req = NULL; } if (req) @@ -1782,15 +1795,18 @@ static int alloc_requests (struct eth_dev *dev, unsigned n, gfp_t gfp_flags) { int status; + spin_lock(&dev->req_lock); status = prealloc (&dev->tx_reqs, dev->in_ep, n, gfp_flags); if (status < 0) goto fail; status = prealloc (&dev->rx_reqs, dev->out_ep, n, gfp_flags); if (status < 0) goto fail; - return 0; + goto done; fail: DEBUG (dev, "can't alloc requests\n"); +done: + spin_unlock(&dev->req_lock); return status; } @@ -1800,21 +1816,21 @@ static void rx_fill (struct eth_dev *dev, gfp_t gfp_flags) unsigned long flags; /* fill unused rxq slots with some skb */ - spin_lock_irqsave (&dev->lock, flags); + spin_lock_irqsave(&dev->req_lock, flags); while (!list_empty (&dev->rx_reqs)) { req = container_of (dev->rx_reqs.next, struct usb_request, list); list_del_init (&req->list); - spin_unlock_irqrestore (&dev->lock, flags); + spin_unlock_irqrestore(&dev->req_lock, flags); if (rx_submit (dev, req, gfp_flags) < 0) { defer_kevent (dev, WORK_RX_MEMORY); return; } - spin_lock_irqsave (&dev->lock, flags); + spin_lock_irqsave(&dev->req_lock, flags); } - spin_unlock_irqrestore (&dev->lock, flags); + spin_unlock_irqrestore(&dev->req_lock, flags); } static void eth_work (void *_dev) @@ -1848,9 +1864,9 @@ static void tx_complete (struct usb_ep *ep, struct usb_request *req) } dev->stats.tx_packets++; - spin_lock (&dev->lock); + spin_lock(&dev->req_lock); list_add (&req->list, &dev->tx_reqs); - spin_unlock (&dev->lock); + spin_unlock(&dev->req_lock); dev_kfree_skb_any (skb); atomic_dec (&dev->tx_qlen); @@ -1896,12 +1912,12 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) /* ignores USB_CDC_PACKET_TYPE_DIRECTED */ } - spin_lock_irqsave (&dev->lock, flags); + spin_lock_irqsave(&dev->req_lock, flags); req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del (&req->list); if (list_empty (&dev->tx_reqs)) netif_stop_queue (net); - spin_unlock_irqrestore (&dev->lock, flags); + spin_unlock_irqrestore(&dev->req_lock, flags); /* no buffer copies needed, unless the network stack did it * or the hardware can't use skb buffers. @@ -1955,11 +1971,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) drop: dev->stats.tx_dropped++; dev_kfree_skb_any (skb); - spin_lock_irqsave (&dev->lock, flags); + spin_lock_irqsave(&dev->req_lock, flags); if (list_empty (&dev->tx_reqs)) netif_start_queue (net); list_add (&req->list, &dev->tx_reqs); - spin_unlock_irqrestore (&dev->lock, flags); + spin_unlock_irqrestore(&dev->req_lock, flags); } return 0; } @@ -2131,7 +2147,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 +2174,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 +2184,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 +2205,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; @@ -2378,6 +2394,7 @@ autoconf_fail: return status; dev = netdev_priv(net); spin_lock_init (&dev->lock); + spin_lock_init (&dev->req_lock); INIT_WORK (&dev->work, eth_work, dev); INIT_LIST_HEAD (&dev->tx_reqs); INIT_LIST_HEAD (&dev->rx_reqs); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index b1a9cf0..8d7f1e8 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 354670d..408c338 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 2956608..4c3c725 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 30d7664..e762aa1 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 3a08a7a..b7018ee 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); |