diff options
Diffstat (limited to 'drivers/usb/gadget')
25 files changed, 4708 insertions, 1004 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index f771a7cae9e..45e01e28945 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -42,6 +42,20 @@ config USB_GADGET For more information, see <http://www.linux-usb.org/gadget> and the kernel DocBook documentation for this API. +config USB_GADGET_DEBUG + boolean "Debugging messages" + depends on USB_GADGET && DEBUG_KERNEL && EXPERIMENTAL + help + Many controller and gadget drivers will print some debugging + messages if you use this option to ask for those messages. + + Avoid enabling these messages, even if you're actively + debugging such a driver. Many drivers will emit so many + messages that the driver timings are affected, which will + either create new failure modes or remove the one you're + trying to track down. Never enable these messages for a + production build. + config USB_GADGET_DEBUG_FILES boolean "Debugging information files" depends on USB_GADGET && PROC_FS @@ -208,6 +222,27 @@ config USB_OTG Select this only if your OMAP board has a Mini-AB connector. +config USB_GADGET_S3C2410 + boolean "S3C2410 USB Device Controller" + depends on ARCH_S3C2410 + help + Samsung's S3C2410 is an ARM-4 processor with an integrated + full speed USB 1.1 device controller. It has 4 configurable + endpoints, as well as endpoint zero (for control transfers). + + This driver has been tested on the S3C2410, S3C2412, and + S3C2440 processors. + +config USB_S3C2410 + tristate + depends on USB_GADGET_S3C2410 + default USB_GADGET + select USB_GADGET_SELECTED + +config USB_S3C2410_DEBUG + boolean "S3C2410 udc debug messages" + depends on USB_GADGET_S3C2410 + config USB_GADGET_AT91 boolean "AT91 USB Device Port" depends on ARCH_AT91 && !ARCH_AT91SAM9RL @@ -226,6 +261,24 @@ config USB_AT91 depends on USB_GADGET_AT91 default USB_GADGET +config USB_GADGET_M66592 + boolean "M66592 driver" + select USB_GADGET_DUALSPEED + help + M66592 is a USB 2.0 peripheral controller. + + It has seven configurable endpoints, and endpoint zero. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "m66592_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_M66592 + tristate + depends on USB_GADGET_M66592 + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_DUMMY_HCD boolean "Dummy HCD (DEVELOPMENT)" depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 5db19396631..8ae76f73863 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -1,14 +1,20 @@ # # USB peripheral controller drivers # +ifeq ($(CONFIG_USB_GADGET_DEBUG),y) + EXTRA_CFLAGS += -DDEBUG +endif + obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_NET2280) += net2280.o obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o +obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o obj-$(CONFIG_USB_AT91) += at91_udc.o obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o +obj-$(CONFIG_USB_M66592) += m66592-udc.o # # USB gadget drivers diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index ba163f35bf2..63d7d656869 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -601,25 +601,6 @@ static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) kfree(req); } -static void *at91_ep_alloc_buffer( - struct usb_ep *_ep, - unsigned bytes, - dma_addr_t *dma, - gfp_t gfp_flags) -{ - *dma = ~0; - return kmalloc(bytes, gfp_flags); -} - -static void at91_ep_free_buffer( - struct usb_ep *ep, - void *buf, - dma_addr_t dma, - unsigned bytes) -{ - kfree(buf); -} - static int at91_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { @@ -788,8 +769,6 @@ static const struct usb_ep_ops at91_ep_ops = { .disable = at91_ep_disable, .alloc_request = at91_ep_alloc_request, .free_request = at91_ep_free_request, - .alloc_buffer = at91_ep_alloc_buffer, - .free_buffer = at91_ep_free_buffer, .queue = at91_ep_queue, .dequeue = at91_ep_dequeue, .set_halt = at91_ep_set_halt, diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index fcb5526cb08..f2fbdc7fe37 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -497,38 +497,6 @@ dummy_free_request (struct usb_ep *_ep, struct usb_request *_req) kfree (req); } -static void * -dummy_alloc_buffer ( - struct usb_ep *_ep, - unsigned bytes, - dma_addr_t *dma, - gfp_t mem_flags -) { - char *retval; - struct dummy_ep *ep; - struct dummy *dum; - - ep = usb_ep_to_dummy_ep (_ep); - dum = ep_to_dummy (ep); - - if (!dum->driver) - return NULL; - retval = kmalloc (bytes, mem_flags); - *dma = (dma_addr_t) retval; - return retval; -} - -static void -dummy_free_buffer ( - struct usb_ep *_ep, - void *buf, - dma_addr_t dma, - unsigned bytes -) { - if (bytes) - kfree (buf); -} - static void fifo_complete (struct usb_ep *ep, struct usb_request *req) { @@ -659,10 +627,6 @@ static const struct usb_ep_ops dummy_ep_ops = { .alloc_request = dummy_alloc_request, .free_request = dummy_free_request, - .alloc_buffer = dummy_alloc_buffer, - .free_buffer = dummy_free_buffer, - /* map, unmap, ... eventually hook the "generic" dma calls */ - .queue = dummy_queue, .dequeue = dummy_dequeue, @@ -1784,8 +1748,7 @@ static int dummy_bus_resume (struct usb_hcd *hcd) spin_lock_irq (&dum->lock); if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { - dev_warn (&hcd->self.root_hub->dev, "HC isn't running!\n"); - rc = -ENODEV; + rc = -ESHUTDOWN; } else { dum->rh_state = DUMMY_RH_RUNNING; set_link_state (dum); diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 325bf7cfb83..dbaf867436d 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -277,7 +277,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif -#ifdef CONFIG_USB_GADGET_HUSB2DEV +#ifdef CONFIG_USB_GADGET_ATMEL_USBA #define DEV_CONFIG_CDC #endif @@ -292,7 +292,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_SUBSET #endif -#ifdef CONFIG_USB_GADGET_SH +#ifdef CONFIG_USB_GADGET_SUPERH #define DEV_CONFIG_SUBSET #endif @@ -301,6 +301,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_SUBSET #endif +#ifdef CONFIG_USB_GADGET_M66592 +#define DEV_CONFIG_CDC +#endif + /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index c6b6479fa4d..be7a1bd2823 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -686,7 +686,6 @@ struct fsg_dev { int thread_wakeup_needed; struct completion thread_notifier; struct task_struct *thread_task; - sigset_t thread_signal_mask; int cmnd_size; u8 cmnd[MAX_COMMAND_SIZE]; @@ -3277,8 +3276,7 @@ static void handle_exception(struct fsg_dev *fsg) /* Clear the existing signals. Anything but SIGUSR1 is converted * into a high-priority EXIT exception. */ for (;;) { - sig = dequeue_signal_lock(current, &fsg->thread_signal_mask, - &info); + sig = dequeue_signal_lock(current, ¤t->blocked, &info); if (!sig) break; if (sig != SIGUSR1) { @@ -3431,10 +3429,13 @@ static int fsg_main_thread(void *fsg_) /* Allow the thread to be killed by a signal, but set the signal mask * to block everything but INT, TERM, KILL, and USR1. */ - siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) | - sigmask(SIGTERM) | sigmask(SIGKILL) | - sigmask(SIGUSR1)); - sigprocmask(SIG_SETMASK, &fsg->thread_signal_mask, NULL); + allow_signal(SIGINT); + allow_signal(SIGTERM); + allow_signal(SIGKILL); + allow_signal(SIGUSR1); + + /* Allow the thread to be frozen */ + set_freezable(); /* Arrange for userspace references to be interpreted as kernel * pointers. That way we can pass a kernel pointer to a routine @@ -3735,19 +3736,12 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) } /* Free the data buffers */ - for (i = 0; i < NUM_BUFFERS; ++i) { - struct fsg_buffhd *bh = &fsg->buffhds[i]; - - if (bh->buf) - usb_ep_free_buffer(fsg->bulk_in, bh->buf, bh->dma, - mod_data.buflen); - } + for (i = 0; i < NUM_BUFFERS; ++i) + kfree(fsg->buffhds[i].buf); /* Free the request and buffer for endpoint 0 */ if (req) { - if (req->buf) - usb_ep_free_buffer(fsg->ep0, req->buf, - req->dma, EP0_BUFSIZE); + kfree(req->buf); usb_ep_free_request(fsg->ep0, req); } @@ -3965,8 +3959,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) #endif if (gadget->is_otg) { - otg_desc.bmAttributes |= USB_OTG_HNP, - config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + otg_desc.bmAttributes |= USB_OTG_HNP; } rc = -ENOMEM; @@ -3975,8 +3968,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL); if (!req) goto out; - req->buf = usb_ep_alloc_buffer(fsg->ep0, EP0_BUFSIZE, - &req->dma, GFP_KERNEL); + req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL); if (!req->buf) goto out; req->complete = ep0_complete; @@ -3988,8 +3980,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) /* Allocate for the bulk-in endpoint. We assume that * the buffer will also work with the bulk-out (and * interrupt-in) endpoint. */ - bh->buf = usb_ep_alloc_buffer(fsg->bulk_in, mod_data.buflen, - &bh->dma, GFP_KERNEL); + bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL); if (!bh->buf) goto out; bh->next = bh + 1; diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index 3ca2b3159f0..10b2b33b869 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -228,7 +228,7 @@ static int dr_controller_setup(struct fsl_udc *udc) /* Config PHY interface */ portctrl = fsl_readl(&dr_regs->portsc1); - portctrl &= ~(PORTSCX_PHY_TYPE_SEL & PORTSCX_PORT_WIDTH); + portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH); switch (udc->phy_mode) { case FSL_USB2_PHY_ULPI: portctrl |= PORTSCX_PTS_ULPI; @@ -601,39 +601,6 @@ static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req) kfree(req); } -/*------------------------------------------------------------------ - * Allocate an I/O buffer -*---------------------------------------------------------------------*/ -static void *fsl_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, gfp_t gfp_flags) -{ - struct fsl_ep *ep; - - if (!_ep) - return NULL; - - ep = container_of(_ep, struct fsl_ep, ep); - - return dma_alloc_coherent(ep->udc->gadget.dev.parent, - bytes, dma, gfp_flags); -} - -/*------------------------------------------------------------------ - * frees an i/o buffer -*---------------------------------------------------------------------*/ -static void fsl_free_buffer(struct usb_ep *_ep, void *buf, - dma_addr_t dma, unsigned bytes) -{ - struct fsl_ep *ep; - - if (!_ep) - return; - - ep = container_of(_ep, struct fsl_ep, ep); - - dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma); -} - /*-------------------------------------------------------------------------*/ static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) { @@ -1047,9 +1014,6 @@ static struct usb_ep_ops fsl_ep_ops = { .alloc_request = fsl_alloc_request, .free_request = fsl_free_request, - .alloc_buffer = fsl_alloc_buffer, - .free_buffer = fsl_free_buffer, - .queue = fsl_ep_queue, .dequeue = fsl_ep_dequeue, @@ -2189,27 +2153,19 @@ static void fsl_udc_release(struct device *dev) * init resource for globle controller * Return the udc handle on success or NULL on failure ------------------------------------------------------------------*/ -static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev) +static int __init struct_udc_setup(struct fsl_udc *udc, + struct platform_device *pdev) { - struct fsl_udc *udc; struct fsl_usb2_platform_data *pdata; size_t size; - udc = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); - if (udc == NULL) { - ERR("malloc udc failed\n"); - return NULL; - } - pdata = pdev->dev.platform_data; udc->phy_mode = pdata->phy_mode; - /* max_ep_nr is bidirectional ep number, max_ep doubles the number */ - udc->max_ep = pdata->max_ep_nr * 2; udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL); if (!udc->eps) { ERR("malloc fsl_ep failed\n"); - goto cleanup; + return -1; } /* initialized QHs, take care of alignment */ @@ -2225,7 +2181,7 @@ static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev) if (!udc->ep_qh) { ERR("malloc QHs for udc failed\n"); kfree(udc->eps); - goto cleanup; + return -1; } udc->ep_qh_size = size; @@ -2244,11 +2200,7 @@ static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev) udc->remote_wakeup = 0; /* default to 0 on reset */ spin_lock_init(&udc->lock); - return udc; - -cleanup: - kfree(udc); - return NULL; + return 0; } /*---------------------------------------------------------------- @@ -2287,35 +2239,37 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index, } /* Driver probe function - * all intialize operations implemented here except enabling usb_intr reg + * all intialization operations implemented here except enabling usb_intr reg + * board setup should have been done in the platform code */ static int __init fsl_udc_probe(struct platform_device *pdev) { struct resource *res; int ret = -ENODEV; unsigned int i; + u32 dccparams; if (strcmp(pdev->name, driver_name)) { VDBG("Wrong device\n"); return -ENODEV; } - /* board setup should have been done in the platform code */ - - /* Initialize the udc structure including QH member and other member */ - udc_controller = struct_udc_setup(pdev); - if (!udc_controller) { - VDBG("udc_controller is NULL \n"); + udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); + if (udc_controller == NULL) { + ERR("malloc udc failed\n"); return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) + if (!res) { + kfree(udc_controller); return -ENXIO; + } if (!request_mem_region(res->start, res->end - res->start + 1, driver_name)) { ERR("request mem region for %s failed \n", pdev->name); + kfree(udc_controller); return -EBUSY; } @@ -2328,13 +2282,24 @@ static int __init fsl_udc_probe(struct platform_device *pdev) usb_sys_regs = (struct usb_sys_interface *) ((u32)dr_regs + USB_DR_SYS_OFFSET); + /* Read Device Controller Capability Parameters register */ + dccparams = fsl_readl(&dr_regs->dccparams); + if (!(dccparams & DCCPARAMS_DC)) { + ERR("This SOC doesn't support device role\n"); + ret = -ENODEV; + goto err2; + } + /* Get max device endpoints */ + /* DEN is bidirectional ep number, max_ep doubles the number */ + udc_controller->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2; + udc_controller->irq = platform_get_irq(pdev, 0); if (!udc_controller->irq) { ret = -ENODEV; goto err2; } - ret = request_irq(udc_controller->irq, fsl_udc_irq, SA_SHIRQ, + ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED, driver_name, udc_controller); if (ret != 0) { ERR("cannot request irq %d err %d \n", @@ -2342,6 +2307,13 @@ static int __init fsl_udc_probe(struct platform_device *pdev) goto err2; } + /* Initialize the udc structure including QH member and other member */ + if (struct_udc_setup(udc_controller, pdev)) { + ERR("Can't initialize udc data structure\n"); + ret = -ENOMEM; + goto err3; + } + /* initialize usb hw reg except for regs for EP, * leave usbintr reg untouched */ dr_controller_setup(udc_controller); @@ -2403,6 +2375,7 @@ err2: iounmap(dr_regs); err1: release_mem_region(res->start, res->end - res->start + 1); + kfree(udc_controller); return ret; } diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index c6291e04650..832ab82b488 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -101,6 +101,10 @@ struct usb_sys_interface { #define WAIT_FOR_OUT_STATUS 3 #define DATA_STATE_RECV 4 +/* Device Controller Capability Parameter register */ +#define DCCPARAMS_DC 0x00000080 +#define DCCPARAMS_DEN_MASK 0x0000001f + /* Frame Index Register Bit Masks */ #define USB_FRINDEX_MASKS 0x3fff /* USB CMD Register Bit Masks */ diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index d041b919e7b..53e9139ba38 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -8,6 +8,8 @@ * (And avoiding all runtime comparisons in typical one-choice configs!) * * NOTE: some of these controller drivers may not be available yet. + * Some are available on 2.4 kernels; several are available, but not + * yet pushed in the 2.6 mainline tree. */ #ifdef CONFIG_USB_GADGET_NET2280 #define gadget_is_net2280(g) !strcmp("net2280", (g)->name) @@ -33,12 +35,14 @@ #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 @@ -51,6 +55,7 @@ #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 @@ -63,22 +68,24 @@ #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) #else #define gadget_is_pxa27x(g) 0 #endif -#ifdef CONFIG_USB_GADGET_HUSB2DEV -#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name) +#ifdef CONFIG_USB_GADGET_ATMEL_USBA +#define gadget_is_atmel_usba(g) !strcmp("atmel_usba_udc", (g)->name) #else -#define gadget_is_husb2dev(g) 0 +#define gadget_is_atmel_usba(g) 0 #endif #ifdef CONFIG_USB_GADGET_S3C2410 @@ -93,6 +100,7 @@ #define gadget_is_at91(g) 0 #endif +/* status unclear */ #ifdef CONFIG_USB_GADGET_IMX #define gadget_is_imx(g) !strcmp("imx_udc", (g)->name) #else @@ -106,6 +114,7 @@ #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 @@ -119,12 +128,20 @@ #define gadget_is_musbhdrc(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 +#define gadget_is_m66592(g) 0 +#endif + + // CONFIG_USB_GADGET_SX2 // CONFIG_USB_GADGET_AU1X00 // ... @@ -181,9 +198,11 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x16; else if (gadget_is_mpc8272(gadget)) return 0x17; - else if (gadget_is_husb2dev(gadget)) + else if (gadget_is_atmel_usba(gadget)) return 0x18; else if (gadget_is_fsl_usb2(gadget)) return 0x19; + else if (gadget_is_m66592(gadget)) + return 0x20; return -ENOENT; } diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index d08a8d0e642..1c5aa49d743 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -1248,17 +1248,11 @@ autoconf_fail: tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev); /* preallocate control response and buffer */ - dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); + dev->req = alloc_ep_req(gadget->ep0, USB_BUFSIZ); if (!dev->req) { err = -ENOMEM; goto fail; } - dev->req->buf = usb_ep_alloc_buffer(gadget->ep0, USB_BUFSIZ, - &dev->req->dma, GFP_KERNEL); - if (!dev->req->buf) { - err = -ENOMEM; - goto fail; - } dev->req->complete = gmidi_setup_complete; diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index ae931af05ce..d6c5f1150ae 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -20,7 +20,6 @@ * - DMA works with ep1 (OUT transfers) and ep2 (IN transfers). */ -#undef DEBUG // #define VERBOSE /* extra debug messages (success too) */ // #define USB_TRACE /* packet-level success messages */ @@ -296,51 +295,6 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req) /*-------------------------------------------------------------------------*/ -/* allocating buffers this way eliminates dma mapping overhead, which - * on some platforms will mean eliminating a per-io buffer copy. with - * some kinds of system caches, further tweaks may still be needed. - */ -static void * -goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, gfp_t gfp_flags) -{ - void *retval; - struct goku_ep *ep; - - ep = container_of(_ep, struct goku_ep, ep); - if (!_ep) - return NULL; - *dma = DMA_ADDR_INVALID; - - if (ep->dma) { - /* the main problem with this call is that it wastes memory - * on typical 1/N page allocations: it allocates 1-N pages. - */ -#warning Using dma_alloc_coherent even with buffers smaller than a page. - retval = dma_alloc_coherent(&ep->dev->pdev->dev, - bytes, dma, gfp_flags); - } else - retval = kmalloc(bytes, gfp_flags); - return retval; -} - -static void -goku_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma, unsigned bytes) -{ - /* free memory into the right allocator */ - if (dma != DMA_ADDR_INVALID) { - struct goku_ep *ep; - - ep = container_of(_ep, struct goku_ep, ep); - if (!_ep) - return; - dma_free_coherent(&ep->dev->pdev->dev, bytes, buf, dma); - } else - kfree (buf); -} - -/*-------------------------------------------------------------------------*/ - static void done(struct goku_ep *ep, struct goku_request *req, int status) { @@ -485,7 +439,7 @@ top: /* use ep1/ep2 double-buffering for OUT */ if (!(size & PACKET_ACTIVE)) size = readl(®s->EPxSizeLB[ep->num]); - if (!(size & PACKET_ACTIVE)) // "can't happen" + if (!(size & PACKET_ACTIVE)) /* "can't happen" */ break; size &= DATASIZE; /* EPxSizeH == 0 */ @@ -1026,9 +980,6 @@ static struct usb_ep_ops goku_ep_ops = { .alloc_request = goku_alloc_request, .free_request = goku_free_request, - .alloc_buffer = goku_alloc_buffer, - .free_buffer = goku_free_buffer, - .queue = goku_queue, .dequeue = goku_dequeue, @@ -1140,17 +1091,17 @@ udc_proc_read(char *buffer, char **start, off_t off, int count, is_usb_connected ? ((tmp & PW_PULLUP) ? "full speed" : "powered") : "disconnected", - ({char *tmp; + ({char *state; switch(dev->ep0state){ - case EP0_DISCONNECT: tmp = "ep0_disconnect"; break; - case EP0_IDLE: tmp = "ep0_idle"; break; - case EP0_IN: tmp = "ep0_in"; break; - case EP0_OUT: tmp = "ep0_out"; break; - case EP0_STATUS: tmp = "ep0_status"; break; - case EP0_STALL: tmp = "ep0_stall"; break; - case EP0_SUSPEND: tmp = "ep0_suspend"; break; - default: tmp = "ep0_?"; break; - } tmp; }) + case EP0_DISCONNECT: state = "ep0_disconnect"; break; + case EP0_IDLE: state = "ep0_idle"; break; + case EP0_IN: state = "ep0_in"; break; + case EP0_OUT: state = "ep0_out"; break; + case EP0_STATUS: state = "ep0_status"; break; + case EP0_STALL: state = "ep0_stall"; break; + case EP0_SUSPEND: state = "ep0_suspend"; break; + default: state = "ep0_?"; break; + } state; }) ); size -= t; next += t; @@ -1195,7 +1146,6 @@ udc_proc_read(char *buffer, char **start, off_t off, int count, for (i = 0; i < 4; i++) { struct goku_ep *ep = &dev->ep [i]; struct goku_request *req; - int t; if (i && !ep->desc) continue; @@ -1283,7 +1233,7 @@ done: static void udc_reinit (struct goku_udc *dev) { static char *names [] = { "ep0", "ep1-bulk", "ep2-bulk", "ep3-bulk" }; - + unsigned i; INIT_LIST_HEAD (&dev->gadget.ep_list); @@ -1896,9 +1846,9 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* done */ the_controller = dev; - device_register(&dev->gadget.dev); - - return 0; + retval = device_register(&dev->gadget.dev); + if (retval == 0) + return 0; done: if (dev) @@ -1910,8 +1860,8 @@ done: /*-------------------------------------------------------------------------*/ static struct pci_device_id pci_ids [] = { { - .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), - .class_mask = ~0, + .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), + .class_mask = ~0, .vendor = 0x102f, /* Toshiba */ .device = 0x0107, /* this UDC */ .subvendor = PCI_ANY_ID, diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h index ea8c8e58cab..bc4eb1e0b50 100644 --- a/drivers/usb/gadget/goku_udc.h +++ b/drivers/usb/gadget/goku_udc.h @@ -41,8 +41,10 @@ struct goku_udc_regs { #define INT_SYSERROR 0x40000 #define INT_PWRDETECT 0x80000 -#define INT_DEVWIDE (INT_PWRDETECT|INT_SYSERROR/*|INT_ERR*/|INT_USBRESET|INT_SUSPEND) -#define INT_EP0 (INT_SETUP|INT_ENDPOINT0/*|INT_STATUS*/|INT_STATUSNAK) +#define INT_DEVWIDE \ + (INT_PWRDETECT|INT_SYSERROR/*|INT_ERR*/|INT_USBRESET|INT_SUSPEND) +#define INT_EP0 \ + (INT_SETUP|INT_ENDPOINT0/*|INT_STATUS*/|INT_STATUSNAK) u32 dma_master; #define MST_EOPB_DIS 0x0800 @@ -231,7 +233,7 @@ struct goku_request { enum ep0state { EP0_DISCONNECT, /* no host */ EP0_IDLE, /* between STATUS ack and SETUP report */ - EP0_IN, EP0_OUT, /* data stage */ + EP0_IN, EP0_OUT, /* data stage */ EP0_STATUS, /* status stage */ EP0_STALL, /* data or status stages */ EP0_SUSPEND, /* usb suspend */ @@ -242,7 +244,7 @@ struct goku_udc { struct usb_gadget gadget; spinlock_t lock; struct goku_ep ep[4]; - struct usb_gadget_driver *driver; + struct usb_gadget_driver *driver; enum ep0state ep0state; unsigned got_irq:1, diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 46d0e525274..e60745ffaf8 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -37,7 +37,7 @@ #include <linux/device.h> #include <linux/moduleparam.h> -#include <linux/usb_gadgetfs.h> +#include <linux/usb/gadgetfs.h> #include <linux/usb_gadget.h> @@ -923,7 +923,7 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req) struct dev_data *dev = ep->driver_data; if (req->buf != dev->rbuf) { - usb_ep_free_buffer (ep, req->buf, req->dma, req->length); + kfree(req->buf); req->buf = dev->rbuf; req->dma = DMA_ADDR_INVALID; } @@ -963,7 +963,7 @@ static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len) return -EBUSY; } if (len > sizeof (dev->rbuf)) - req->buf = usb_ep_alloc_buffer (ep, len, &req->dma, GFP_ATOMIC); + req->buf = kmalloc(len, GFP_ATOMIC); if (req->buf == 0) { req->buf = dev->rbuf; return -ENOMEM; @@ -1505,7 +1505,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) } break; -#ifndef CONFIG_USB_GADGETFS_PXA2XX +#ifndef CONFIG_USB_GADGET_PXA2XX /* PXA automagically handles this request too */ case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != 0x80) diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index a0a73c08a34..e78c2ddc1f8 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -75,10 +75,6 @@ static int lh7a40x_ep_enable(struct usb_ep *ep, static int lh7a40x_ep_disable(struct usb_ep *ep); static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, gfp_t); static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *); -static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned, dma_addr_t *, - gfp_t); -static void lh7a40x_free_buffer(struct usb_ep *ep, void *, dma_addr_t, - unsigned); static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, gfp_t); static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *); static int lh7a40x_set_halt(struct usb_ep *ep, int); @@ -104,9 +100,6 @@ static struct usb_ep_ops lh7a40x_ep_ops = { .alloc_request = lh7a40x_alloc_request, .free_request = lh7a40x_free_request, - .alloc_buffer = lh7a40x_alloc_buffer, - .free_buffer = lh7a40x_free_buffer, - .queue = lh7a40x_queue, .dequeue = lh7a40x_dequeue, @@ -1134,26 +1127,6 @@ static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req) kfree(req); } -static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes, - dma_addr_t * dma, gfp_t gfp_flags) -{ - char *retval; - - DEBUG("%s (%p, %d, %d)\n", __FUNCTION__, ep, bytes, gfp_flags); - - retval = kmalloc(bytes, gfp_flags & ~(__GFP_DMA | __GFP_HIGHMEM)); - if (retval) - *dma = virt_to_bus(retval); - return retval; -} - -static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma, - unsigned bytes) -{ - DEBUG("%s, %p\n", __FUNCTION__, ep); - kfree(buf); -} - /** Queue one request * Kickstart transfer if needed * NOTE: Sets INDEX register diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c new file mode 100644 index 00000000000..0174a322e00 --- /dev/null +++ b/drivers/usb/gadget/m66592-udc.c @@ -0,0 +1,1634 @@ +/* + * M66592 UDC (USB gadget) + * + * Copyright (C) 2006-2007 Renesas Solutions Corp. + * + * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/usb/ch9.h> +#include <linux/usb_gadget.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> + +#include "m66592-udc.h" + +MODULE_DESCRIPTION("M66592 USB gadget driiver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Yoshihiro Shimoda"); + +#define DRIVER_VERSION "29 May 2007" + +/* module parameters */ +static unsigned short clock = M66592_XTAL24; +module_param(clock, ushort, 0644); +MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=16384)"); +static unsigned short vif = M66592_LDRV; +module_param(vif, ushort, 0644); +MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)"); +static unsigned short endian = 0; +module_param(endian, ushort, 0644); +MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)"); +static unsigned short irq_sense = M66592_INTL; +module_param(irq_sense, ushort, 0644); +MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0(default=2)"); + +static const char udc_name[] = "m66592_udc"; +static const char *m66592_ep_name[] = { + "ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7" +}; + +static void disable_controller(struct m66592 *m66592); +static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req); +static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req); +static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req, + gfp_t gfp_flags); + +static void transfer_complete(struct m66592_ep *ep, + struct m66592_request *req, + int status); +/*-------------------------------------------------------------------------*/ +static inline u16 get_usb_speed(struct m66592 *m66592) +{ + return (m66592_read(m66592, M66592_DVSTCTR) & M66592_RHST); +} + +static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum, + unsigned long reg) +{ + u16 tmp; + + tmp = m66592_read(m66592, M66592_INTENB0); + m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE, + M66592_INTENB0); + m66592_bset(m66592, (1 << pipenum), reg); + m66592_write(m66592, tmp, M66592_INTENB0); +} + +static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum, + unsigned long reg) +{ + u16 tmp; + + tmp = m66592_read(m66592, M66592_INTENB0); + m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE, + M66592_INTENB0); + m66592_bclr(m66592, (1 << pipenum), reg); + m66592_write(m66592, tmp, M66592_INTENB0); +} + +static void m66592_usb_connect(struct m66592 *m66592) +{ + m66592_bset(m66592, M66592_CTRE, M66592_INTENB0); + m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL, + M66592_INTENB0); + m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0); + + m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG); +} + +static void m66592_usb_disconnect(struct m66592 *m66592) +{ + m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0); + m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL, + M66592_INTENB0); + m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0); + m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); + + m66592->gadget.speed = USB_SPEED_UNKNOWN; + spin_unlock(&m66592->lock); + m66592->driver->disconnect(&m66592->gadget); + spin_lock(&m66592->lock); + + disable_controller(m66592); + INIT_LIST_HEAD(&m66592->ep[0].queue); +} + +static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum) +{ + u16 pid = 0; + unsigned long offset; + + if (pipenum == 0) + pid = m66592_read(m66592, M66592_DCPCTR) & M66592_PID; + else if (pipenum < M66592_MAX_NUM_PIPE) { + offset = get_pipectr_addr(pipenum); + pid = m66592_read(m66592, offset) & M66592_PID; + } else + printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum); + + return pid; +} + +static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum, + u16 pid) +{ + unsigned long offset; + + if (pipenum == 0) + m66592_mdfy(m66592, pid, M66592_PID, M66592_DCPCTR); + else if (pipenum < M66592_MAX_NUM_PIPE) { + offset = get_pipectr_addr(pipenum); + m66592_mdfy(m66592, pid, M66592_PID, offset); + } else + printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum); +} + +static inline void pipe_start(struct m66592 *m66592, u16 pipenum) +{ + control_reg_set_pid(m66592, pipenum, M66592_PID_BUF); +} + +static inline void pipe_stop(struct m66592 *m66592, u16 pipenum) +{ + control_reg_set_pid(m66592, pipenum, M66592_PID_NAK); +} + +static inline void pipe_stall(struct m66592 *m66592, u16 pipenum) +{ + control_reg_set_pid(m66592, pipenum, M66592_PID_STALL); +} + +static inline u16 control_reg_get(struct m66592 *m66592, u16 pipenum) +{ + u16 ret = 0; + unsigned long offset; + + if (pipenum == 0) + ret = m66592_read(m66592, M66592_DCPCTR); + else if (pipenum < M66592_MAX_NUM_PIPE) { + offset = get_pipectr_addr(pipenum); + ret = m66592_read(m66592, offset); + } else + printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum); + + return ret; +} + +static inline void control_reg_sqclr(struct m66592 *m66592, u16 pipenum) +{ + unsigned long offset; + + pipe_stop(m66592, pipenum); + + if (pipenum == 0) + m66592_bset(m66592, M66592_SQCLR, M66592_DCPCTR); + else if (pipenum < M66592_MAX_NUM_PIPE) { + offset = get_pipectr_addr(pipenum); + m66592_bset(m66592, M66592_SQCLR, offset); + } else + printk(KERN_ERR "unexpect pipe num(%d)\n", pipenum); +} + +static inline int get_buffer_size(struct m66592 *m66592, u16 pipenum) +{ + u16 tmp; + int size; + + if (pipenum == 0) { + tmp = m66592_read(m66592, M66592_DCPCFG); + if ((tmp & M66592_CNTMD) != 0) + size = 256; + else { + tmp = m66592_read(m66592, M66592_DCPMAXP); + size = tmp & M66592_MAXP; + } + } else { + m66592_write(m66592, pipenum, M66592_PIPESEL); + tmp = m66592_read(m66592, M66592_PIPECFG); + if ((tmp & M66592_CNTMD) != 0) { + tmp = m66592_read(m66592, M66592_PIPEBUF); + size = ((tmp >> 10) + 1) * 64; + } else { + tmp = m66592_read(m66592, M66592_PIPEMAXP); + size = tmp & M66592_MXPS; + } + } + + return size; +} + +static inline void pipe_change(struct m66592 *m66592, u16 pipenum) +{ + struct m66592_ep *ep = m66592->pipenum2ep[pipenum]; + + if (ep->use_dma) + return; + + m66592_mdfy(m66592, pipenum, M66592_CURPIPE, ep->fifosel); + + ndelay(450); + + m66592_bset(m66592, M66592_MBW, ep->fifosel); +} + +static int pipe_buffer_setting(struct m66592 *m66592, + struct m66592_pipe_info *info) +{ + u16 bufnum = 0, buf_bsize = 0; + u16 pipecfg = 0; + + if (info->pipe == 0) + return -EINVAL; + + m66592_write(m66592, info->pipe, M66592_PIPESEL); + + if (info->dir_in) + pipecfg |= M66592_DIR; + pipecfg |= info->type; + pipecfg |= info->epnum; + switch (info->type) { + case M66592_INT: + bufnum = 4 + (info->pipe - M66592_BASE_PIPENUM_INT); + buf_bsize = 0; + break; + case M66592_BULK: + bufnum = m66592->bi_bufnum + + (info->pipe - M66592_BASE_PIPENUM_BULK) * 16; + m66592->bi_bufnum += 16; + buf_bsize = 7; + pipecfg |= M66592_DBLB; + if (!info->dir_in) + pipecfg |= M66592_SHTNAK; + break; + case M66592_ISO: + bufnum = m66592->bi_bufnum + + (info->pipe - M66592_BASE_PIPENUM_ISOC) * 16; + m66592->bi_bufnum += 16; + buf_bsize = 7; + break; + } + if (m66592->bi_bufnum > M66592_MAX_BUFNUM) { + printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n", + m66592->bi_bufnum); + return -ENOMEM; + } + + m66592_write(m66592, pipecfg, M66592_PIPECFG); + m66592_write(m66592, (buf_bsize << 10) | (bufnum), M66592_PIPEBUF); + m66592_write(m66592, info->maxpacket, M66592_PIPEMAXP); + if (info->interval) + info->interval--; + m66592_write(m66592, info->interval, M66592_PIPEPERI); + + return 0; +} + +static void pipe_buffer_release(struct m66592 *m66592, + struct m66592_pipe_info *info) +{ + if (info->pipe == 0) + return; + + switch (info->type) { + case M66592_BULK: + if (is_bulk_pipe(info->pipe)) + m66592->bi_bufnum -= 16; + break; + case M66592_ISO: + if (is_isoc_pipe(info->pipe)) + m66592->bi_bufnum -= 16; + break; + } + + if (is_bulk_pipe(info->pipe)) { + m66592->bulk--; + } else if (is_interrupt_pipe(info->pipe)) + m66592->interrupt--; + else if (is_isoc_pipe(info->pipe)) { + m66592->isochronous--; + if (info->type == M66592_BULK) + m66592->bulk--; + } else + printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n", + info->pipe); +} + +static void pipe_initialize(struct m66592_ep *ep) +{ + struct m66592 *m66592 = ep->m66592; + + m66592_mdfy(m66592, 0, M66592_CURPIPE, ep->fifosel); + + m66592_write(m66592, M66592_ACLRM, ep->pipectr); + m66592_write(m66592, 0, ep->pipectr); + m66592_write(m66592, M66592_SQCLR, ep->pipectr); + if (ep->use_dma) { + m66592_mdfy(m66592, ep->pipenum, M66592_CURPIPE, ep->fifosel); + + ndelay(450); + + m66592_bset(m66592, M66592_MBW, ep->fifosel); + } +} + +static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, + const struct usb_endpoint_descriptor *desc, + u16 pipenum, int dma) +{ + if ((pipenum != 0) && dma) { + if (m66592->num_dma == 0) { + m66592->num_dma++; + ep->use_dma = 1; + ep->fifoaddr = M66592_D0FIFO; + ep->fifosel = M66592_D0FIFOSEL; + ep->fifoctr = M66592_D0FIFOCTR; + ep->fifotrn = M66592_D0FIFOTRN; + } else if (m66592->num_dma == 1) { + m66592->num_dma++; + ep->use_dma = 1; + ep->fifoaddr = M66592_D1FIFO; + ep->fifosel = M66592_D1FIFOSEL; + ep->fifoctr = M66592_D1FIFOCTR; + ep->fifotrn = M66592_D1FIFOTRN; + } else { + ep->use_dma = 0; + ep->fifoaddr = M66592_CFIFO; + ep->fifosel = M66592_CFIFOSEL; + ep->fifoctr = M66592_CFIFOCTR; + ep->fifotrn = 0; + } + } else { + ep->use_dma = 0; + ep->fifoaddr = M66592_CFIFO; + ep->fifosel = M66592_CFIFOSEL; + ep->fifoctr = M66592_CFIFOCTR; + ep->fifotrn = 0; + } + + ep->pipectr = get_pipectr_addr(pipenum); + ep->pipenum = pipenum; + ep->ep.maxpacket = desc->wMaxPacketSize; + m66592->pipenum2ep[pipenum] = ep; + m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep; + INIT_LIST_HEAD(&ep->queue); +} + +static void m66592_ep_release(struct m66592_ep *ep) +{ + struct m66592 *m66592 = ep->m66592; + u16 pipenum = ep->pipenum; + + if (pipenum == 0) + return; + + if (ep->use_dma) + m66592->num_dma--; + ep->pipenum = 0; + ep->busy = 0; + ep->use_dma = 0; +} + +static int alloc_pipe_config(struct m66592_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + struct m66592 *m66592 = ep->m66592; + struct m66592_pipe_info info; + int dma = 0; + int *counter; + int ret; + + ep->desc = desc; + + BUG_ON(ep->pipenum); + + switch(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_BULK: + if (m66592->bulk >= M66592_MAX_NUM_BULK) { + if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { + printk(KERN_ERR "bulk pipe is insufficient\n"); + return -ENODEV; + } else { + info.pipe = M66592_BASE_PIPENUM_ISOC + + m66592->isochronous; + counter = &m66592->isochronous; + } + } else { + info.pipe = M66592_BASE_PIPENUM_BULK + m66592->bulk; + counter = &m66592->bulk; + } + info.type = M66592_BULK; + dma = 1; + break; + case USB_ENDPOINT_XFER_INT: + if (m66592->interrupt >= M66592_MAX_NUM_INT) { + printk(KERN_ERR "interrupt pipe is insufficient\n"); + return -ENODEV; + } + info.pipe = M66592_BASE_PIPENUM_INT + m66592->interrupt; + info.type = M66592_INT; + counter = &m66592->interrupt; + break; + case USB_ENDPOINT_XFER_ISOC: + if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { + printk(KERN_ERR "isochronous pipe is insufficient\n"); + return -ENODEV; + } + info.pipe = M66592_BASE_PIPENUM_ISOC + m66592->isochronous; + info.type = M66592_ISO; + counter = &m66592->isochronous; + break; + default: + printk(KERN_ERR "unexpect xfer type\n"); + return -EINVAL; + } + ep->type = info.type; + + info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + info.maxpacket = desc->wMaxPacketSize; + info.interval = desc->bInterval; + if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + info.dir_in = 1; + else + info.dir_in = 0; + + ret = pipe_buffer_setting(m66592, &info); + if (ret < 0) { + printk(KERN_ERR "pipe_buffer_setting fail\n"); + return ret; + } + + (*counter)++; + if ((counter == &m66592->isochronous) && info.type == M66592_BULK) + m66592->bulk++; + + m66592_ep_setting(m66592, ep, desc, info.pipe, dma); + pipe_initialize(ep); + + return 0; +} + +static int free_pipe_config(struct m66592_ep *ep) +{ + struct m66592 *m66592 = ep->m66592; + struct m66592_pipe_info info; + + info.pipe = ep->pipenum; + info.type = ep->type; + pipe_buffer_release(m66592, &info); + m66592_ep_release(ep); + + return 0; +} + +/*-------------------------------------------------------------------------*/ +static void pipe_irq_enable(struct m66592 *m66592, u16 pipenum) +{ + enable_irq_ready(m66592, pipenum); + enable_irq_nrdy(m66592, pipenum); +} + +static void pipe_irq_disable(struct m66592 *m66592, u16 pipenum) +{ + disable_irq_ready(m66592, pipenum); + disable_irq_nrdy(m66592, pipenum); +} + +/* if complete is true, gadget driver complete function is not call */ +static void control_end(struct m66592 *m66592, unsigned ccpl) +{ + m66592->ep[0].internal_ccpl = ccpl; + pipe_start(m66592, 0); + m66592_bset(m66592, M66592_CCPL, M66592_DCPCTR); +} + +static void start_ep0_write(struct m66592_ep *ep, struct m66592_request *req) +{ + struct m66592 *m66592 = ep->m66592; + + pipe_change(m66592, ep->pipenum); + m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0, + (M66592_ISEL | M66592_CURPIPE), + M66592_CFIFOSEL); + m66592_write(m66592, M66592_BCLR, ep->fifoctr); + if (req->req.length == 0) { + m66592_bset(m66592, M66592_BVAL, ep->fifoctr); + pipe_start(m66592, 0); + transfer_complete(ep, req, 0); + } else { + m66592_write(m66592, ~M66592_BEMP0, M66592_BEMPSTS); + irq_ep0_write(ep, req); + } +} + +static void start_packet_write(struct m66592_ep *ep, struct m66592_request *req) +{ + struct m66592 *m66592 = ep->m66592; + u16 tmp; + + pipe_change(m66592, ep->pipenum); + disable_irq_empty(m66592, ep->pipenum); + pipe_start(m66592, ep->pipenum); + + tmp = m66592_read(m66592, ep->fifoctr); + if (unlikely((tmp & M66592_FRDY) == 0)) + pipe_irq_enable(m66592, ep->pipenum); + else + irq_packet_write(ep, req); +} + +static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req) +{ + struct m66592 *m66592 = ep->m66592; + u16 pipenum = ep->pipenum; + + if (ep->pipenum == 0) { + m66592_mdfy(m66592, M66592_PIPE0, + (M66592_ISEL | M66592_CURPIPE), + M66592_CFIFOSEL); + m66592_write(m66592, M66592_BCLR, ep->fifoctr); + pipe_start(m66592, pipenum); + pipe_irq_enable(m66592, pipenum); + } else { + if (ep->use_dma) { + m66592_bset(m66592, M66592_TRCLR, ep->fifosel); + pipe_change(m66592, pipenum); + m66592_bset(m66592, M66592_TRENB, ep->fifosel); + m66592_write(m66592, + (req->req.length + ep->ep.maxpacket - 1) / + ep->ep.maxpacket, ep->fifotrn); + } + pipe_start(m66592, pipenum); /* trigger once */ + pipe_irq_enable(m66592, pipenum); + } +} + +static void start_packet(struct m66592_ep *ep, struct m66592_request *req) +{ + if (ep->desc->bEndpointAddress & USB_DIR_IN) + start_packet_write(ep, req); + else + start_packet_read(ep, req); +} + +static void start_ep0(struct m66592_ep *ep, struct m66592_request *req) +{ + u16 ctsq; + + ctsq = m66592_read(ep->m66592, M66592_INTSTS0) & M66592_CTSQ; + + switch (ctsq) { + case M66592_CS_RDDS: + start_ep0_write(ep, req); + break; + case M66592_CS_WRDS: + start_packet_read(ep, req); + break; + + case M66592_CS_WRND: + control_end(ep->m66592, 0); + break; + default: + printk(KERN_ERR "start_ep0: unexpect ctsq(%x)\n", ctsq); + break; + } +} + +static void init_controller(struct m66592 *m66592) +{ + m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND), + M66592_PINCFG); + m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ + m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG); + + m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG); + m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); + m66592_bset(m66592, M66592_USBE, M66592_SYSCFG); + + m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG); + + msleep(3); + + m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG); + + msleep(1); + + m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG); + + m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1); + m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR, + M66592_DMA0CFG); +} + +static void disable_controller(struct m66592 *m66592) +{ + m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG); + udelay(1); + m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG); + udelay(1); + m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG); + udelay(1); + m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG); +} + +static void m66592_start_xclock(struct m66592 *m66592) +{ + u16 tmp; + + tmp = m66592_read(m66592, M66592_SYSCFG); + if (!(tmp & M66592_XCKE)) + m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG); +} + +/*-------------------------------------------------------------------------*/ +static void transfer_complete(struct m66592_ep *ep, + struct m66592_request *req, + int status) +{ + int restart = 0; + + if (unlikely(ep->pipenum == 0)) { + if (ep->internal_ccpl) { + ep->internal_ccpl = 0; + return; + } + } + + list_del_init(&req->queue); + if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN) + req->req.status = -ESHUTDOWN; + else + req->req.status = status; + + if (!list_empty(&ep->queue)) + restart = 1; + + if (likely(req->req.complete)) + req->req.complete(&ep->ep, &req->req); + + if (restart) { + req = list_entry(ep->queue.next, struct m66592_request, queue); + if (ep->desc) + start_packet(ep, req); + } +} + +static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req) +{ + int i; + volatile u16 tmp; + unsigned bufsize; + size_t size; + void *buf; + u16 pipenum = ep->pipenum; + struct m66592 *m66592 = ep->m66592; + + pipe_change(m66592, pipenum); + m66592_bset(m66592, M66592_ISEL, ep->fifosel); + + i = 0; + do { + tmp = m66592_read(m66592, ep->fifoctr); + if (i++ > 100000) { + printk(KERN_ERR "pipe0 is busy. maybe cpu i/o bus" + "conflict. please power off this controller."); + return; + } + ndelay(1); + } while ((tmp & M66592_FRDY) == 0); + + /* prepare parameters */ + bufsize = get_buffer_size(m66592, pipenum); + buf = req->req.buf + req->req.actual; + size = min(bufsize, req->req.length - req->req.actual); + + /* write fifo */ + if (req->req.buf) { + if (size > 0) + m66592_write_fifo(m66592, ep->fifoaddr, buf, size); + if ((size == 0) || ((size % ep->ep.maxpacket) != 0)) + m66592_bset(m66592, M66592_BVAL, ep->fifoctr); + } + + /* update parameters */ + req->req.actual += size; + + /* check transfer finish */ + if ((!req->req.zero && (req->req.actual == req->req.length)) || + (size % ep->ep.maxpacket) || (size == 0)) { + disable_irq_ready(m66592, pipenum); + disable_irq_empty(m66592, pipenum); + } else { + disable_irq_ready(m66592, pipenum); + enable_irq_empty(m66592, pipenum); + } + pipe_start(m66592, pipenum); +} + +static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req) +{ + u16 tmp; + unsigned bufsize; + size_t size; + void *buf; + u16 pipenum = ep->pipenum; + struct m66592 *m66592 = ep->m66592; + + pipe_change(m66592, pipenum); + tmp = m66592_read(m66592, ep->fifoctr); + if (unlikely((tmp & M66592_FRDY) == 0)) { + pipe_stop(m66592, pipenum); + pipe_irq_disable(m66592, pipenum); + printk(KERN_ERR "write fifo not ready. pipnum=%d\n", pipenum); + return; + } + + /* prepare parameters */ + bufsize = get_buffer_size(m66592, pipenum); + buf = req->req.buf + req->req.actual; + size = min(bufsize, req->req.length - req->req.actual); + + /* write fifo */ + if (req->req.buf) { + m66592_write_fifo(m66592, ep->fifoaddr, buf, size); + if ((size == 0) || ((size % ep->ep.maxpacket) != 0) || + ((bufsize != ep->ep.maxpacket) && (bufsize > size))) + m66592_bset(m66592, M66592_BVAL, ep->fifoctr); + } + + /* update parameters */ + req->req.actual += size; + /* check transfer finish */ + if ((!req->req.zero && (req->req.actual == req->req.length)) || + (size % ep->ep.maxpacket) || (size == 0)) { + disable_irq_ready(m66592, pipenum); + enable_irq_empty(m66592, pipenum); + } else { + disable_irq_empty(m66592, pipenum); + pipe_irq_enable(m66592, pipenum); + } +} + +static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req) +{ + u16 tmp; + int rcv_len, bufsize, req_len; + int size; + void *buf; + u16 pipenum = ep->pipenum; + struct m66592 *m66592 = ep->m66592; + int finish = 0; + + pipe_change(m66592, pipenum); + tmp = m66592_read(m66592, ep->fifoctr); + if (unlikely((tmp & M66592_FRDY) == 0)) { + req->req.status = -EPIPE; + pipe_stop(m66592, pipenum); + pipe_irq_disable(m66592, pipenum); + printk(KERN_ERR "read fifo not ready"); + return; + } + + /* prepare parameters */ + rcv_len = tmp & M66592_DTLN; + bufsize = get_buffer_size(m66592, pipenum); + + buf = req->req.buf + req->req.actual; + req_len = req->req.length - req->req.actual; + if (rcv_len < bufsize) + size = min(rcv_len, req_len); + else + size = min(bufsize, req_len); + + /* update parameters */ + req->req.actual += size; + + /* check transfer finish */ + if ((!req->req.zero && (req->req.actual == req->req.length)) || + (size % ep->ep.maxpacket) || (size == 0)) { + pipe_stop(m66592, pipenum); + pipe_irq_disable(m66592, pipenum); + finish = 1; + } + + /* read fifo */ + if (req->req.buf) { + if (size == 0) + m66592_write(m66592, M66592_BCLR, ep->fifoctr); + else + m66592_read_fifo(m66592, ep->fifoaddr, buf, size); + } + + if ((ep->pipenum != 0) && finish) + transfer_complete(ep, req, 0); +} + +static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb) +{ + u16 check; + u16 pipenum; + struct m66592_ep *ep; + struct m66592_request *req; + + if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) { + m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS); + m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE, + M66592_CFIFOSEL); + + ep = &m66592->ep[0]; + req = list_entry(ep->queue.next, struct m66592_request, queue); + irq_packet_read(ep, req); + } else { + for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) { + check = 1 << pipenum; + if ((status & check) && (enb & check)) { + m66592_write(m66592, ~check, M66592_BRDYSTS); + ep = m66592->pipenum2ep[pipenum]; + req = list_entry(ep->queue.next, + struct m66592_request, queue); + if (ep->desc->bEndpointAddress & USB_DIR_IN) + irq_packet_write(ep, req); + else + irq_packet_read(ep, req); + } + } + } +} + +static void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb) +{ + u16 tmp; + u16 check; + u16 pipenum; + struct m66592_ep *ep; + struct m66592_request *req; + + if ((status & M66592_BEMP0) && (enb & M66592_BEMP0)) { + m66592_write(m66592, ~M66592_BEMP0, M66592_BEMPSTS); + + ep = &m66592->ep[0]; + req = list_entry(ep->queue.next, struct m66592_request, queue); + irq_ep0_write(ep, req); + } else { + for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) { + check = 1 << pipenum; + if ((status & check) && (enb & check)) { + m66592_write(m66592, ~check, M66592_BEMPSTS); + tmp = control_reg_get(m66592, pipenum); + if ((tmp & M66592_INBUFM) == 0) { + disable_irq_empty(m66592, pipenum); + pipe_irq_disable(m66592, pipenum); + pipe_stop(m66592, pipenum); + ep = m66592->pipenum2ep[pipenum]; + req = list_entry(ep->queue.next, + struct m66592_request, + queue); + if (!list_empty(&ep->queue)) + transfer_complete(ep, req, 0); + } + } + } + } +} + +static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) +{ + struct m66592_ep *ep; + u16 pid; + u16 status = 0; + + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + status = 1; /* selfpower */ + break; + case USB_RECIP_INTERFACE: + status = 0; + break; + case USB_RECIP_ENDPOINT: + ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK]; + pid = control_reg_get_pid(m66592, ep->pipenum); + if (pid == M66592_PID_STALL) + status = 1; + else + status = 0; + break; + default: + pipe_stall(m66592, 0); + return; /* exit */ + } + + *m66592->ep0_buf = status; + m66592->ep0_req->buf = m66592->ep0_buf; + m66592->ep0_req->length = 2; + /* AV: what happens if we get called again before that gets through? */ + m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL); +} + +static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) +{ + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + control_end(m66592, 1); + break; + case USB_RECIP_INTERFACE: + control_end(m66592, 1); + break; + case USB_RECIP_ENDPOINT: { + struct m66592_ep *ep; + struct m66592_request *req; + + ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK]; + pipe_stop(m66592, ep->pipenum); + control_reg_sqclr(m66592, ep->pipenum); + + control_end(m66592, 1); + + req = list_entry(ep->queue.next, + struct m66592_request, queue); + if (ep->busy) { + ep->busy = 0; + if (list_empty(&ep->queue)) + break; + start_packet(ep, req); + } else if (!list_empty(&ep->queue)) + pipe_start(m66592, ep->pipenum); + } + break; + default: + pipe_stall(m66592, 0); + break; + } +} + +static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) +{ + + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + control_end(m66592, 1); + break; + case USB_RECIP_INTERFACE: + control_end(m66592, 1); + break; + case USB_RECIP_ENDPOINT: { + struct m66592_ep *ep; + + ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK]; + pipe_stall(m66592, ep->pipenum); + + control_end(m66592, 1); + } + break; + default: + pipe_stall(m66592, 0); + break; + } +} + +/* if return value is true, call class driver's setup() */ +static int setup_packet(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) +{ + u16 *p = (u16 *)ctrl; + unsigned long offset = M66592_USBREQ; + int i, ret = 0; + + /* read fifo */ + m66592_write(m66592, ~M66592_VALID, M66592_INTSTS0); + + for (i = 0; i < 4; i++) + p[i] = m66592_read(m66592, offset + i*2); + + /* check request */ + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { + switch (ctrl->bRequest) { + case USB_REQ_GET_STATUS: + get_status(m66592, ctrl); + break; + case USB_REQ_CLEAR_FEATURE: + clear_feature(m66592, ctrl); + break; + case USB_REQ_SET_FEATURE: + set_feature(m66592, ctrl); + break; + default: + ret = 1; + break; + } + } else + ret = 1; + return ret; +} + +static void m66592_update_usb_speed(struct m66592 *m66592) +{ + u16 speed = get_usb_speed(m66592); + + switch (speed) { + case M66592_HSMODE: + m66592->gadget.speed = USB_SPEED_HIGH; + break; + case M66592_FSMODE: + m66592->gadget.speed = USB_SPEED_FULL; + break; + default: + m66592->gadget.speed = USB_SPEED_UNKNOWN; + printk(KERN_ERR "USB speed unknown\n"); + } +} + +static void irq_device_state(struct m66592 *m66592) +{ + u16 dvsq; + + dvsq = m66592_read(m66592, M66592_INTSTS0) & M66592_DVSQ; + m66592_write(m66592, ~M66592_DVST, M66592_INTSTS0); + + if (dvsq == M66592_DS_DFLT) { /* bus reset */ + m66592->driver->disconnect(&m66592->gadget); + m66592_update_usb_speed(m66592); + } + if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG) + m66592_update_usb_speed(m66592); + if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) && + m66592->gadget.speed == USB_SPEED_UNKNOWN) + m66592_update_usb_speed(m66592); + + m66592->old_dvsq = dvsq; +} + +static void irq_control_stage(struct m66592 *m66592) +{ + struct usb_ctrlrequest ctrl; + u16 ctsq; + + ctsq = m66592_read(m66592, M66592_INTSTS0) & M66592_CTSQ; + m66592_write(m66592, ~M66592_CTRT, M66592_INTSTS0); + + switch (ctsq) { + case M66592_CS_IDST: { + struct m66592_ep *ep; + struct m66592_request *req; + ep = &m66592->ep[0]; + req = list_entry(ep->queue.next, struct m66592_request, queue); + transfer_complete(ep, req, 0); + } + break; + + case M66592_CS_RDDS: + case M66592_CS_WRDS: + case M66592_CS_WRND: + if (setup_packet(m66592, &ctrl)) { + if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0) + pipe_stall(m66592, 0); + } + break; + case M66592_CS_RDSS: + case M66592_CS_WRSS: + control_end(m66592, 0); + break; + default: + printk(KERN_ERR "ctrl_stage: unexpect ctsq(%x)\n", ctsq); + break; + } +} + +static irqreturn_t m66592_irq(int irq, void *_m66592) +{ + struct m66592 *m66592 = _m66592; + u16 intsts0; + u16 intenb0; + u16 brdysts, nrdysts, bempsts; + u16 brdyenb, nrdyenb, bempenb; + u16 savepipe; + u16 mask0; + + intsts0 = m66592_read(m66592, M66592_INTSTS0); + intenb0 = m66592_read(m66592, M66592_INTENB0); + + savepipe = m66592_read(m66592, M66592_CFIFOSEL); + + mask0 = intsts0 & intenb0; + if (mask0) { + brdysts = m66592_read(m66592, M66592_BRDYSTS); + nrdysts = m66592_read(m66592, M66592_NRDYSTS); + bempsts = m66592_read(m66592, M66592_BEMPSTS); + brdyenb = m66592_read(m66592, M66592_BRDYENB); + nrdyenb = m66592_read(m66592, M66592_NRDYENB); + bempenb = m66592_read(m66592, M66592_BEMPENB); + + if (mask0 & M66592_VBINT) { + m66592_write(m66592, (u16)~M66592_VBINT, + M66592_INTSTS0); + m66592_start_xclock(m66592); + + /* start vbus sampling */ + m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0) + & M66592_VBSTS; + m66592->scount = M66592_MAX_SAMPLING; + + mod_timer(&m66592->timer, + jiffies + msecs_to_jiffies(50)); + } + if (intsts0 & M66592_DVSQ) + irq_device_state(m66592); + + if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) && + (brdysts & brdyenb)) { + irq_pipe_ready(m66592, brdysts, brdyenb); + } + if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) && + (bempsts & bempenb)) { + irq_pipe_empty(m66592, bempsts, bempenb); + } + + if (intsts0 & M66592_CTRT) + irq_control_stage(m66592); + } + + m66592_write(m66592, savepipe, M66592_CFIFOSEL); + + return IRQ_HANDLED; +} + +static void m66592_timer(unsigned long _m66592) +{ + struct m66592 *m66592 = (struct m66592 *)_m66592; + unsigned long flags; + u16 tmp; + + spin_lock_irqsave(&m66592->lock, flags); + tmp = m66592_read(m66592, M66592_SYSCFG); + if (!(tmp & M66592_RCKE)) { + m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG); + udelay(10); + m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG); + } + if (m66592->scount > 0) { + tmp = m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS; + if (tmp == m66592->old_vbus) { + m66592->scount--; + if (m66592->scount == 0) { + if (tmp == M66592_VBSTS) + m66592_usb_connect(m66592); + else + m66592_usb_disconnect(m66592); + } else { + mod_timer(&m66592->timer, + jiffies + msecs_to_jiffies(50)); + } + } else { + m66592->scount = M66592_MAX_SAMPLING; + m66592->old_vbus = tmp; + mod_timer(&m66592->timer, + jiffies + msecs_to_jiffies(50)); + } + } + spin_unlock_irqrestore(&m66592->lock, flags); +} + +/*-------------------------------------------------------------------------*/ +static int m66592_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct m66592_ep *ep; + + ep = container_of(_ep, struct m66592_ep, ep); + return alloc_pipe_config(ep, desc); +} + +static int m66592_disable(struct usb_ep *_ep) +{ + struct m66592_ep *ep; + struct m66592_request *req; + unsigned long flags; + + ep = container_of(_ep, struct m66592_ep, ep); + BUG_ON(!ep); + + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct m66592_request, queue); + spin_lock_irqsave(&ep->m66592->lock, flags); + transfer_complete(ep, req, -ECONNRESET); + spin_unlock_irqrestore(&ep->m66592->lock, flags); + } + + pipe_irq_disable(ep->m66592, ep->pipenum); + return free_pipe_config(ep); +} + +static struct usb_request *m66592_alloc_request(struct usb_ep *_ep, + gfp_t gfp_flags) +{ + struct m66592_request *req; + + req = kzalloc(sizeof(struct m66592_request), gfp_flags); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->queue); + + return &req->req; +} + +static void m66592_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct m66592_request *req; + + req = container_of(_req, struct m66592_request, req); + kfree(req); +} + +static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req, + gfp_t gfp_flags) +{ + struct m66592_ep *ep; + struct m66592_request *req; + unsigned long flags; + int request = 0; + + ep = container_of(_ep, struct m66592_ep, ep); + req = container_of(_req, struct m66592_request, req); + + if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + spin_lock_irqsave(&ep->m66592->lock, flags); + + if (list_empty(&ep->queue)) + request = 1; + + list_add_tail(&req->queue, &ep->queue); + req->req.actual = 0; + req->req.status = -EINPROGRESS; + + if (ep->desc == 0) /* control */ + start_ep0(ep, req); + else { + if (request && !ep->busy) + start_packet(ep, req); + } + + spin_unlock_irqrestore(&ep->m66592->lock, flags); + + return 0; +} + +static int m66592_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct m66592_ep *ep; + struct m66592_request *req; + unsigned long flags; + + ep = container_of(_ep, struct m66592_ep, ep); + req = container_of(_req, struct m66592_request, req); + + spin_lock_irqsave(&ep->m66592->lock, flags); + if (!list_empty(&ep->queue)) + transfer_complete(ep, req, -ECONNRESET); + spin_unlock_irqrestore(&ep->m66592->lock, flags); + + return 0; +} + +static int m66592_set_halt(struct usb_ep *_ep, int value) +{ + struct m66592_ep *ep; + struct m66592_request *req; + unsigned long flags; + int ret = 0; + + ep = container_of(_ep, struct m66592_ep, ep); + req = list_entry(ep->queue.next, struct m66592_request, queue); + + spin_lock_irqsave(&ep->m66592->lock, flags); + if (!list_empty(&ep->queue)) { + ret = -EAGAIN; + goto out; + } + if (value) { + ep->busy = 1; + pipe_stall(ep->m66592, ep->pipenum); + } else { + ep->busy = 0; + pipe_stop(ep->m66592, ep->pipenum); + } + +out: + spin_unlock_irqrestore(&ep->m66592->lock, flags); + return ret; +} + +static int m66592_fifo_status(struct usb_ep *_ep) +{ + return -EOPNOTSUPP; +} + +static void m66592_fifo_flush(struct usb_ep *_ep) +{ + struct m66592_ep *ep; + unsigned long flags; + + ep = container_of(_ep, struct m66592_ep, ep); + spin_lock_irqsave(&ep->m66592->lock, flags); + if (list_empty(&ep->queue) && !ep->busy) { + pipe_stop(ep->m66592, ep->pipenum); + m66592_bclr(ep->m66592, M66592_BCLR, ep->fifoctr); + } + spin_unlock_irqrestore(&ep->m66592->lock, flags); +} + +static struct usb_ep_ops m66592_ep_ops = { + .enable = m66592_enable, + .disable = m66592_disable, + + .alloc_request = m66592_alloc_request, + .free_request = m66592_free_request, + + .queue = m66592_queue, + .dequeue = m66592_dequeue, + + .set_halt = m66592_set_halt, + .fifo_status = m66592_fifo_status, + .fifo_flush = m66592_fifo_flush, +}; + +/*-------------------------------------------------------------------------*/ +static struct m66592 *the_controller; + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct m66592 *m66592 = the_controller; + int retval; + + if (!driver || + driver->speed != USB_SPEED_HIGH || + !driver->bind || + !driver->unbind || + !driver->setup) + return -EINVAL; + if (!m66592) + return -ENODEV; + if (m66592->driver) + return -EBUSY; + + /* hook up the driver */ + driver->driver.bus = NULL; + m66592->driver = driver; + m66592->gadget.dev.driver = &driver->driver; + + retval = device_add(&m66592->gadget.dev); + if (retval) { + printk(KERN_ERR "device_add error (%d)\n", retval); + goto error; + } + + retval = driver->bind (&m66592->gadget); + if (retval) { + printk(KERN_ERR "bind to driver error (%d)\n", retval); + device_del(&m66592->gadget.dev); + goto error; + } + + m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); + if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) { + m66592_start_xclock(m66592); + /* start vbus sampling */ + m66592->old_vbus = m66592_read(m66592, + M66592_INTSTS0) & M66592_VBSTS; + m66592->scount = M66592_MAX_SAMPLING; + mod_timer(&m66592->timer, + jiffies + msecs_to_jiffies(50)); + } + + return 0; + +error: + m66592->driver = NULL; + m66592->gadget.dev.driver = NULL; + + return retval; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct m66592 *m66592 = the_controller; + unsigned long flags; + + spin_lock_irqsave(&m66592->lock, flags); + if (m66592->gadget.speed != USB_SPEED_UNKNOWN) + m66592_usb_disconnect(m66592); + spin_unlock_irqrestore(&m66592->lock, flags); + + m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); + + driver->unbind(&m66592->gadget); + + init_controller(m66592); + disable_controller(m66592); + + device_del(&m66592->gadget.dev); + m66592->driver = NULL; + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +/*-------------------------------------------------------------------------*/ +static int m66592_get_frame(struct usb_gadget *_gadget) +{ + struct m66592 *m66592 = gadget_to_m66592(_gadget); + return m66592_read(m66592, M66592_FRMNUM) & 0x03FF; +} + +static struct usb_gadget_ops m66592_gadget_ops = { + .get_frame = m66592_get_frame, +}; + +#if defined(CONFIG_PM) +static int m66592_suspend(struct platform_device *pdev, pm_message_t state) +{ + pdev->dev.power.power_state = state; + return 0; +} + +static int m66592_resume(struct platform_device *pdev) +{ + pdev->dev.power.power_state = PMSG_ON; + return 0; +} +#else /* if defined(CONFIG_PM) */ +#define m66592_suspend NULL +#define m66592_resume NULL +#endif + +static int __init_or_module m66592_remove(struct platform_device *pdev) +{ + struct m66592 *m66592 = dev_get_drvdata(&pdev->dev); + + del_timer_sync(&m66592->timer); + iounmap(m66592->reg); + free_irq(platform_get_irq(pdev, 0), m66592); + kfree(m66592); + return 0; +} + +#define resource_len(r) (((r)->end - (r)->start) + 1) +static int __init m66592_probe(struct platform_device *pdev) +{ + struct resource *res = NULL; + int irq = -1; + void __iomem *reg = NULL; + struct m66592 *m66592 = NULL; + int ret = 0; + int i; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + (char *)udc_name); + if (!res) { + ret = -ENODEV; + printk(KERN_ERR "platform_get_resource_byname error.\n"); + goto clean_up; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = -ENODEV; + printk(KERN_ERR "platform_get_irq error.\n"); + goto clean_up; + } + + reg = ioremap(res->start, resource_len(res)); + if (reg == NULL) { + ret = -ENOMEM; + printk(KERN_ERR "ioremap error.\n"); + goto clean_up; + } + + /* initialize ucd */ + m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL); + if (m66592 == NULL) { + printk(KERN_ERR "kzalloc error\n"); + goto clean_up; + } + + spin_lock_init(&m66592->lock); + dev_set_drvdata(&pdev->dev, m66592); + + m66592->gadget.ops = &m66592_gadget_ops; + device_initialize(&m66592->gadget.dev); + strcpy(m66592->gadget.dev.bus_id, "gadget"); + m66592->gadget.is_dualspeed = 1; + m66592->gadget.dev.parent = &pdev->dev; + m66592->gadget.dev.dma_mask = pdev->dev.dma_mask; + m66592->gadget.dev.release = pdev->dev.release; + m66592->gadget.name = udc_name; + + init_timer(&m66592->timer); + m66592->timer.function = m66592_timer; + m66592->timer.data = (unsigned long)m66592; + m66592->reg = reg; + + m66592->bi_bufnum = M66592_BASE_BUFNUM; + + ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED, + udc_name, m66592); + if (ret < 0) { + printk(KERN_ERR "request_irq error (%d)\n", ret); + goto clean_up; + } + + INIT_LIST_HEAD(&m66592->gadget.ep_list); + m66592->gadget.ep0 = &m66592->ep[0].ep; + INIT_LIST_HEAD(&m66592->gadget.ep0->ep_list); + for (i = 0; i < M66592_MAX_NUM_PIPE; i++) { + struct m66592_ep *ep = &m66592->ep[i]; + + if (i != 0) { + INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list); + list_add_tail(&m66592->ep[i].ep.ep_list, + &m66592->gadget.ep_list); + } + ep->m66592 = m66592; + INIT_LIST_HEAD(&ep->queue); + ep->ep.name = m66592_ep_name[i]; + ep->ep.ops = &m66592_ep_ops; + ep->ep.maxpacket = 512; + } + m66592->ep[0].ep.maxpacket = 64; + m66592->ep[0].pipenum = 0; + m66592->ep[0].fifoaddr = M66592_CFIFO; + m66592->ep[0].fifosel = M66592_CFIFOSEL; + m66592->ep[0].fifoctr = M66592_CFIFOCTR; + m66592->ep[0].fifotrn = 0; + m66592->ep[0].pipectr = get_pipectr_addr(0); + m66592->pipenum2ep[0] = &m66592->ep[0]; + m66592->epaddr2ep[0] = &m66592->ep[0]; + + the_controller = m66592; + + /* AV: leaks */ + m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL); + if (m66592->ep0_req == NULL) + goto clean_up; + /* AV: leaks, and do we really need it separately allocated? */ + m66592->ep0_buf = kzalloc(2, GFP_KERNEL); + if (m66592->ep0_buf == NULL) + goto clean_up; + + init_controller(m66592); + + printk("driver %s, %s\n", udc_name, DRIVER_VERSION); + return 0; + +clean_up: + if (m66592) { + if (m66592->ep0_req) + m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); + kfree(m66592); + } + if (reg) + iounmap(reg); + + return ret; +} + +/*-------------------------------------------------------------------------*/ +static struct platform_driver m66592_driver = { + .probe = m66592_probe, + .remove = m66592_remove, + .suspend = m66592_suspend, + .resume = m66592_resume, + .driver = { + .name = (char *) udc_name, + }, +}; + +static int __init m66592_udc_init(void) +{ + return platform_driver_register(&m66592_driver); +} +module_init(m66592_udc_init); + +static void __exit m66592_udc_cleanup(void) +{ + platform_driver_unregister(&m66592_driver); +} +module_exit(m66592_udc_cleanup); + diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h new file mode 100644 index 00000000000..26b54f8b894 --- /dev/null +++ b/drivers/usb/gadget/m66592-udc.h @@ -0,0 +1,577 @@ +/* + * M66592 UDC (USB gadget) + * + * Copyright (C) 2006-2007 Renesas Solutions Corp. + * + * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __M66592_UDC_H__ +#define __M66592_UDC_H__ + +#define M66592_SYSCFG 0x00 +#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */ +#define M66592_XTAL48 0x8000 /* 48MHz */ +#define M66592_XTAL24 0x4000 /* 24MHz */ +#define M66592_XTAL12 0x0000 /* 12MHz */ +#define M66592_XCKE 0x2000 /* b13: External clock enable */ +#define M66592_RCKE 0x1000 /* b12: Register clock enable */ +#define M66592_PLLC 0x0800 /* b11: PLL control */ +#define M66592_SCKE 0x0400 /* b10: USB clock enable */ +#define M66592_ATCKM 0x0100 /* b8: Automatic supply functional enable */ +#define M66592_HSE 0x0080 /* b7: Hi-speed enable */ +#define M66592_DCFM 0x0040 /* b6: Controller function select */ +#define M66592_DMRPD 0x0020 /* b5: D- pull down control */ +#define M66592_DPRPU 0x0010 /* b4: D+ pull up control */ +#define M66592_FSRPC 0x0004 /* b2: Full-speed receiver enable */ +#define M66592_PCUT 0x0002 /* b1: Low power sleep enable */ +#define M66592_USBE 0x0001 /* b0: USB module operation enable */ + +#define M66592_SYSSTS 0x02 +#define M66592_LNST 0x0003 /* b1-0: D+, D- line status */ +#define M66592_SE1 0x0003 /* SE1 */ +#define M66592_KSTS 0x0002 /* K State */ +#define M66592_JSTS 0x0001 /* J State */ +#define M66592_SE0 0x0000 /* SE0 */ + +#define M66592_DVSTCTR 0x04 +#define M66592_WKUP 0x0100 /* b8: Remote wakeup */ +#define M66592_RWUPE 0x0080 /* b7: Remote wakeup sense */ +#define M66592_USBRST 0x0040 /* b6: USB reset enable */ +#define M66592_RESUME 0x0020 /* b5: Resume enable */ +#define M66592_UACT 0x0010 /* b4: USB bus enable */ +#define M66592_RHST 0x0003 /* b1-0: Reset handshake status */ +#define M66592_HSMODE 0x0003 /* Hi-Speed mode */ +#define M66592_FSMODE 0x0002 /* Full-Speed mode */ +#define M66592_HSPROC 0x0001 /* HS handshake is processing */ + +#define M66592_TESTMODE 0x06 +#define M66592_UTST 0x000F /* b4-0: Test select */ +#define M66592_H_TST_PACKET 0x000C /* HOST TEST Packet */ +#define M66592_H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */ +#define M66592_H_TST_K 0x000A /* HOST TEST K */ +#define M66592_H_TST_J 0x0009 /* HOST TEST J */ +#define M66592_H_TST_NORMAL 0x0000 /* HOST Normal Mode */ +#define M66592_P_TST_PACKET 0x0004 /* PERI TEST Packet */ +#define M66592_P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */ +#define M66592_P_TST_K 0x0002 /* PERI TEST K */ +#define M66592_P_TST_J 0x0001 /* PERI TEST J */ +#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */ + +#define M66592_PINCFG 0x0A +#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */ +#define M66592_BIGEND 0x0100 /* b8: Big endian mode */ + +#define M66592_DMA0CFG 0x0C +#define M66592_DMA1CFG 0x0E +#define M66592_DREQA 0x4000 /* b14: Dreq active select */ +#define M66592_BURST 0x2000 /* b13: Burst mode */ +#define M66592_DACKA 0x0400 /* b10: Dack active select */ +#define M66592_DFORM 0x0380 /* b9-7: DMA mode select */ +#define M66592_CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */ +#define M66592_CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */ +#define M66592_CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */ +#define M66592_SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */ +#define M66592_SPLIT_DACK_DSTB 0x0300 /* DACK + DSTB0 mode (SPLIT bus) */ +#define M66592_DENDA 0x0040 /* b6: Dend active select */ +#define M66592_PKTM 0x0020 /* b5: Packet mode */ +#define M66592_DENDE 0x0010 /* b4: Dend enable */ +#define M66592_OBUS 0x0004 /* b2: OUTbus mode */ + +#define M66592_CFIFO 0x10 +#define M66592_D0FIFO 0x14 +#define M66592_D1FIFO 0x18 + +#define M66592_CFIFOSEL 0x1E +#define M66592_D0FIFOSEL 0x24 +#define M66592_D1FIFOSEL 0x2A +#define M66592_RCNT 0x8000 /* b15: Read count mode */ +#define M66592_REW 0x4000 /* b14: Buffer rewind */ +#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */ +#define M66592_DREQE 0x1000 /* b12: DREQ output enable */ +#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO access */ +#define M66592_MBW_8 0x0000 /* 8bit */ +#define M66592_MBW_16 0x0400 /* 16bit */ +#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */ +#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */ +#define M66592_DEZPM 0x0080 /* b7: Zero-length packet additional mode */ +#define M66592_ISEL 0x0020 /* b5: DCP FIFO port direction select */ +#define M66592_CURPIPE 0x0007 /* b2-0: PIPE select */ + +#define M66592_CFIFOCTR 0x20 +#define M66592_D0FIFOCTR 0x26 +#define M66592_D1FIFOCTR 0x2c +#define M66592_BVAL 0x8000 /* b15: Buffer valid flag */ +#define M66592_BCLR 0x4000 /* b14: Buffer clear */ +#define M66592_FRDY 0x2000 /* b13: FIFO ready */ +#define M66592_DTLN 0x0FFF /* b11-0: FIFO received data length */ + +#define M66592_CFIFOSIE 0x22 +#define M66592_TGL 0x8000 /* b15: Buffer toggle */ +#define M66592_SCLR 0x4000 /* b14: Buffer clear */ +#define M66592_SBUSY 0x2000 /* b13: SIE_FIFO busy */ + +#define M66592_D0FIFOTRN 0x28 +#define M66592_D1FIFOTRN 0x2E +#define M66592_TRNCNT 0xFFFF /* b15-0: Transaction counter */ + +#define M66592_INTENB0 0x30 +#define M66592_VBSE 0x8000 /* b15: VBUS interrupt */ +#define M66592_RSME 0x4000 /* b14: Resume interrupt */ +#define M66592_SOFE 0x2000 /* b13: Frame update interrupt */ +#define M66592_DVSE 0x1000 /* b12: Device state transition interrupt */ +#define M66592_CTRE 0x0800 /* b11: Control transfer stage transition interrupt */ +#define M66592_BEMPE 0x0400 /* b10: Buffer empty interrupt */ +#define M66592_NRDYE 0x0200 /* b9: Buffer not ready interrupt */ +#define M66592_BRDYE 0x0100 /* b8: Buffer ready interrupt */ +#define M66592_URST 0x0080 /* b7: USB reset detected interrupt */ +#define M66592_SADR 0x0040 /* b6: Set address executed interrupt */ +#define M66592_SCFG 0x0020 /* b5: Set configuration executed interrupt */ +#define M66592_SUSP 0x0010 /* b4: Suspend detected interrupt */ +#define M66592_WDST 0x0008 /* b3: Control write data stage completed interrupt */ +#define M66592_RDST 0x0004 /* b2: Control read data stage completed interrupt */ +#define M66592_CMPL 0x0002 /* b1: Control transfer complete interrupt */ +#define M66592_SERR 0x0001 /* b0: Sequence error interrupt */ + +#define M66592_INTENB1 0x32 +#define M66592_BCHGE 0x4000 /* b14: USB us chenge interrupt */ +#define M66592_DTCHE 0x1000 /* b12: Detach sense interrupt */ +#define M66592_SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */ +#define M66592_SACKE 0x0010 /* b4: SETUP ACK interrupt */ +#define M66592_BRDYM 0x0004 /* b2: BRDY clear timing */ +#define M66592_INTL 0x0002 /* b1: Interrupt sense select */ +#define M66592_PCSE 0x0001 /* b0: PCUT enable by CS assert */ + +#define M66592_BRDYENB 0x36 +#define M66592_BRDYSTS 0x46 +#define M66592_BRDY7 0x0080 /* b7: PIPE7 */ +#define M66592_BRDY6 0x0040 /* b6: PIPE6 */ +#define M66592_BRDY5 0x0020 /* b5: PIPE5 */ +#define M66592_BRDY4 0x0010 /* b4: PIPE4 */ +#define M66592_BRDY3 0x0008 /* b3: PIPE3 */ +#define M66592_BRDY2 0x0004 /* b2: PIPE2 */ +#define M66592_BRDY1 0x0002 /* b1: PIPE1 */ +#define M66592_BRDY0 0x0001 /* b1: PIPE0 */ + +#define M66592_NRDYENB 0x38 +#define M66592_NRDYSTS 0x48 +#define M66592_NRDY7 0x0080 /* b7: PIPE7 */ +#define M66592_NRDY6 0x0040 /* b6: PIPE6 */ +#define M66592_NRDY5 0x0020 /* b5: PIPE5 */ +#define M66592_NRDY4 0x0010 /* b4: PIPE4 */ +#define M66592_NRDY3 0x0008 /* b3: PIPE3 */ +#define M66592_NRDY2 0x0004 /* b2: PIPE2 */ +#define M66592_NRDY1 0x0002 /* b1: PIPE1 */ +#define M66592_NRDY0 0x0001 /* b1: PIPE0 */ + +#define M66592_BEMPENB 0x3A +#define M66592_BEMPSTS 0x4A +#define M66592_BEMP7 0x0080 /* b7: PIPE7 */ +#define M66592_BEMP6 0x0040 /* b6: PIPE6 */ +#define M66592_BEMP5 0x0020 /* b5: PIPE5 */ +#define M66592_BEMP4 0x0010 /* b4: PIPE4 */ +#define M66592_BEMP3 0x0008 /* b3: PIPE3 */ +#define M66592_BEMP2 0x0004 /* b2: PIPE2 */ +#define M66592_BEMP1 0x0002 /* b1: PIPE1 */ +#define M66592_BEMP0 0x0001 /* b0: PIPE0 */ + +#define M66592_SOFCFG 0x3C +#define M66592_SOFM 0x000C /* b3-2: SOF palse mode */ +#define M66592_SOF_125US 0x0008 /* SOF OUT 125us uFrame Signal */ +#define M66592_SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */ +#define M66592_SOF_DISABLE 0x0000 /* SOF OUT Disable */ + +#define M66592_INTSTS0 0x40 +#define M66592_VBINT 0x8000 /* b15: VBUS interrupt */ +#define M66592_RESM 0x4000 /* b14: Resume interrupt */ +#define M66592_SOFR 0x2000 /* b13: SOF frame update interrupt */ +#define M66592_DVST 0x1000 /* b12: Device state transition interrupt */ +#define M66592_CTRT 0x0800 /* b11: Control transfer stage transition interrupt */ +#define M66592_BEMP 0x0400 /* b10: Buffer empty interrupt */ +#define M66592_NRDY 0x0200 /* b9: Buffer not ready interrupt */ +#define M66592_BRDY 0x0100 /* b8: Buffer ready interrupt */ +#define M66592_VBSTS 0x0080 /* b7: VBUS input port */ +#define M66592_DVSQ 0x0070 /* b6-4: Device state */ +#define M66592_DS_SPD_CNFG 0x0070 /* Suspend Configured */ +#define M66592_DS_SPD_ADDR 0x0060 /* Suspend Address */ +#define M66592_DS_SPD_DFLT 0x0050 /* Suspend Default */ +#define M66592_DS_SPD_POWR 0x0040 /* Suspend Powered */ +#define M66592_DS_SUSP 0x0040 /* Suspend */ +#define M66592_DS_CNFG 0x0030 /* Configured */ +#define M66592_DS_ADDS 0x0020 /* Address */ +#define M66592_DS_DFLT 0x0010 /* Default */ +#define M66592_DS_POWR 0x0000 /* Powered */ +#define M66592_DVSQS 0x0030 /* b5-4: Device state */ +#define M66592_VALID 0x0008 /* b3: Setup packet detected flag */ +#define M66592_CTSQ 0x0007 /* b2-0: Control transfer stage */ +#define M66592_CS_SQER 0x0006 /* Sequence error */ +#define M66592_CS_WRND 0x0005 /* Control write nodata status stage */ +#define M66592_CS_WRSS 0x0004 /* Control write status stage */ +#define M66592_CS_WRDS 0x0003 /* Control write data stage */ +#define M66592_CS_RDSS 0x0002 /* Control read status stage */ +#define M66592_CS_RDDS 0x0001 /* Control read data stage */ +#define M66592_CS_IDST 0x0000 /* Idle or setup stage */ + +#define M66592_INTSTS1 0x42 +#define M66592_BCHG 0x4000 /* b14: USB bus chenge interrupt */ +#define M66592_DTCH 0x1000 /* b12: Detach sense interrupt */ +#define M66592_SIGN 0x0020 /* b5: SETUP IGNORE interrupt */ +#define M66592_SACK 0x0010 /* b4: SETUP ACK interrupt */ + +#define M66592_FRMNUM 0x4C +#define M66592_OVRN 0x8000 /* b15: Overrun error */ +#define M66592_CRCE 0x4000 /* b14: Received data error */ +#define M66592_SOFRM 0x0800 /* b11: SOF output mode */ +#define M66592_FRNM 0x07FF /* b10-0: Frame number */ + +#define M66592_UFRMNUM 0x4E +#define M66592_UFRNM 0x0007 /* b2-0: Micro frame number */ + +#define M66592_RECOVER 0x50 +#define M66592_STSRECOV 0x0700 /* Status recovery */ +#define M66592_STSR_HI 0x0400 /* FULL(0) or HI(1) Speed */ +#define M66592_STSR_DEFAULT 0x0100 /* Default state */ +#define M66592_STSR_ADDRESS 0x0200 /* Address state */ +#define M66592_STSR_CONFIG 0x0300 /* Configured state */ +#define M66592_USBADDR 0x007F /* b6-0: USB address */ + +#define M66592_USBREQ 0x54 +#define M66592_bRequest 0xFF00 /* b15-8: bRequest */ +#define M66592_GET_STATUS 0x0000 +#define M66592_CLEAR_FEATURE 0x0100 +#define M66592_ReqRESERVED 0x0200 +#define M66592_SET_FEATURE 0x0300 +#define M66592_ReqRESERVED1 0x0400 +#define M66592_SET_ADDRESS 0x0500 +#define M66592_GET_DESCRIPTOR 0x0600 +#define M66592_SET_DESCRIPTOR 0x0700 +#define M66592_GET_CONFIGURATION 0x0800 +#define M66592_SET_CONFIGURATION 0x0900 +#define M66592_GET_INTERFACE 0x0A00 +#define M66592_SET_INTERFACE 0x0B00 +#define M66592_SYNCH_FRAME 0x0C00 +#define M66592_bmRequestType 0x00FF /* b7-0: bmRequestType */ +#define M66592_bmRequestTypeDir 0x0080 /* b7 : Data transfer direction */ +#define M66592_HOST_TO_DEVICE 0x0000 +#define M66592_DEVICE_TO_HOST 0x0080 +#define M66592_bmRequestTypeType 0x0060 /* b6-5: Type */ +#define M66592_STANDARD 0x0000 +#define M66592_CLASS 0x0020 +#define M66592_VENDOR 0x0040 +#define M66592_bmRequestTypeRecip 0x001F /* b4-0: Recipient */ +#define M66592_DEVICE 0x0000 +#define M66592_INTERFACE 0x0001 +#define M66592_ENDPOINT 0x0002 + +#define M66592_USBVAL 0x56 +#define M66592_wValue 0xFFFF /* b15-0: wValue */ +/* Standard Feature Selector */ +#define M66592_ENDPOINT_HALT 0x0000 +#define M66592_DEVICE_REMOTE_WAKEUP 0x0001 +#define M66592_TEST_MODE 0x0002 +/* Descriptor Types */ +#define M66592_DT_TYPE 0xFF00 +#define M66592_GET_DT_TYPE(v) (((v) & DT_TYPE) >> 8) +#define M66592_DT_DEVICE 0x01 +#define M66592_DT_CONFIGURATION 0x02 +#define M66592_DT_STRING 0x03 +#define M66592_DT_INTERFACE 0x04 +#define M66592_DT_ENDPOINT 0x05 +#define M66592_DT_DEVICE_QUALIFIER 0x06 +#define M66592_DT_OTHER_SPEED_CONFIGURATION 0x07 +#define M66592_DT_INTERFACE_POWER 0x08 +#define M66592_DT_INDEX 0x00FF +#define M66592_CONF_NUM 0x00FF +#define M66592_ALT_SET 0x00FF + +#define M66592_USBINDEX 0x58 +#define M66592_wIndex 0xFFFF /* b15-0: wIndex */ +#define M66592_TEST_SELECT 0xFF00 /* b15-b8: Test Mode Selectors */ +#define M66592_TEST_J 0x0100 /* Test_J */ +#define M66592_TEST_K 0x0200 /* Test_K */ +#define M66592_TEST_SE0_NAK 0x0300 /* Test_SE0_NAK */ +#define M66592_TEST_PACKET 0x0400 /* Test_Packet */ +#define M66592_TEST_FORCE_ENABLE 0x0500 /* Test_Force_Enable */ +#define M66592_TEST_STSelectors 0x0600 /* Standard test selectors */ +#define M66592_TEST_Reserved 0x4000 /* Reserved */ +#define M66592_TEST_VSTModes 0xC000 /* Vendor-specific test modes */ +#define M66592_EP_DIR 0x0080 /* b7: Endpoint Direction */ +#define M66592_EP_DIR_IN 0x0080 +#define M66592_EP_DIR_OUT 0x0000 + +#define M66592_USBLENG 0x5A +#define M66592_wLength 0xFFFF /* b15-0: wLength */ + +#define M66592_DCPCFG 0x5C +#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode select */ +#define M66592_DIR 0x0010 /* b4: Control transfer DIR select */ + +#define M66592_DCPMAXP 0x5E +#define M66592_DEVSEL 0xC000 /* b15-14: Device address select */ +#define M66592_DEVICE_0 0x0000 /* Device address 0 */ +#define M66592_DEVICE_1 0x4000 /* Device address 1 */ +#define M66592_DEVICE_2 0x8000 /* Device address 2 */ +#define M66592_DEVICE_3 0xC000 /* Device address 3 */ +#define M66592_MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */ + +#define M66592_DCPCTR 0x60 +#define M66592_BSTS 0x8000 /* b15: Buffer status */ +#define M66592_SUREQ 0x4000 /* b14: Send USB request */ +#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */ +#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */ +#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */ +#define M66592_CCPL 0x0004 /* b2: Enable control transfer complete */ +#define M66592_PID 0x0003 /* b1-0: Response PID */ +#define M66592_PID_STALL 0x0002 /* STALL */ +#define M66592_PID_BUF 0x0001 /* BUF */ +#define M66592_PID_NAK 0x0000 /* NAK */ + +#define M66592_PIPESEL 0x64 +#define M66592_PIPENM 0x0007 /* b2-0: Pipe select */ +#define M66592_PIPE0 0x0000 /* PIPE 0 */ +#define M66592_PIPE1 0x0001 /* PIPE 1 */ +#define M66592_PIPE2 0x0002 /* PIPE 2 */ +#define M66592_PIPE3 0x0003 /* PIPE 3 */ +#define M66592_PIPE4 0x0004 /* PIPE 4 */ +#define M66592_PIPE5 0x0005 /* PIPE 5 */ +#define M66592_PIPE6 0x0006 /* PIPE 6 */ +#define M66592_PIPE7 0x0007 /* PIPE 7 */ + +#define M66592_PIPECFG 0x66 +#define M66592_TYP 0xC000 /* b15-14: Transfer type */ +#define M66592_ISO 0xC000 /* Isochronous */ +#define M66592_INT 0x8000 /* Interrupt */ +#define M66592_BULK 0x4000 /* Bulk */ +#define M66592_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */ +#define M66592_DBLB 0x0200 /* b9: Double buffer mode select */ +#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode select */ +#define M66592_SHTNAK 0x0080 /* b7: Transfer end NAK */ +#define M66592_DIR 0x0010 /* b4: Transfer direction select */ +#define M66592_DIR_H_OUT 0x0010 /* HOST OUT */ +#define M66592_DIR_P_IN 0x0010 /* PERI IN */ +#define M66592_DIR_H_IN 0x0000 /* HOST IN */ +#define M66592_DIR_P_OUT 0x0000 /* PERI OUT */ +#define M66592_EPNUM 0x000F /* b3-0: Eendpoint number select */ +#define M66592_EP1 0x0001 +#define M66592_EP2 0x0002 +#define M66592_EP3 0x0003 +#define M66592_EP4 0x0004 +#define M66592_EP5 0x0005 +#define M66592_EP6 0x0006 +#define M66592_EP7 0x0007 +#define M66592_EP8 0x0008 +#define M66592_EP9 0x0009 +#define M66592_EP10 0x000A +#define M66592_EP11 0x000B +#define M66592_EP12 0x000C +#define M66592_EP13 0x000D +#define M66592_EP14 0x000E +#define M66592_EP15 0x000F + +#define M66592_PIPEBUF 0x68 +#define M66592_BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */ +#define M66592_BUF_SIZE(x) ((((x) / 64) - 1) << 10) +#define M66592_BUFNMB 0x00FF /* b7-0: Pipe buffer number */ + +#define M66592_PIPEMAXP 0x6A +#define M66592_MXPS 0x07FF /* b10-0: Maxpacket size */ + +#define M66592_PIPEPERI 0x6C +#define M66592_IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */ +#define M66592_IITV 0x0007 /* b2-0: Isochronous interval */ + +#define M66592_PIPE1CTR 0x70 +#define M66592_PIPE2CTR 0x72 +#define M66592_PIPE3CTR 0x74 +#define M66592_PIPE4CTR 0x76 +#define M66592_PIPE5CTR 0x78 +#define M66592_PIPE6CTR 0x7A +#define M66592_PIPE7CTR 0x7C +#define M66592_BSTS 0x8000 /* b15: Buffer status */ +#define M66592_INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */ +#define M66592_ACLRM 0x0200 /* b9: Out buffer auto clear mode */ +#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */ +#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */ +#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */ +#define M66592_PID 0x0003 /* b1-0: Response PID */ + +#define M66592_INVALID_REG 0x7E + + +#define __iomem + +#define get_pipectr_addr(pipenum) (M66592_PIPE1CTR + (pipenum - 1) * 2) + +#define M66592_MAX_SAMPLING 10 + +#define M66592_MAX_NUM_PIPE 8 +#define M66592_MAX_NUM_BULK 3 +#define M66592_MAX_NUM_ISOC 2 +#define M66592_MAX_NUM_INT 2 + +#define M66592_BASE_PIPENUM_BULK 3 +#define M66592_BASE_PIPENUM_ISOC 1 +#define M66592_BASE_PIPENUM_INT 6 + +#define M66592_BASE_BUFNUM 6 +#define M66592_MAX_BUFNUM 0x4F + +struct m66592_pipe_info { + u16 pipe; + u16 epnum; + u16 maxpacket; + u16 type; + u16 interval; + u16 dir_in; +}; + +struct m66592_request { + struct usb_request req; + struct list_head queue; +}; + +struct m66592_ep { + struct usb_ep ep; + struct m66592 *m66592; + + struct list_head queue; + unsigned busy:1; + unsigned internal_ccpl:1; /* use only control */ + + /* this member can able to after m66592_enable */ + unsigned use_dma:1; + u16 pipenum; + u16 type; + const struct usb_endpoint_descriptor *desc; + /* register address */ + unsigned long fifoaddr; + unsigned long fifosel; + unsigned long fifoctr; + unsigned long fifotrn; + unsigned long pipectr; +}; + +struct m66592 { + spinlock_t lock; + void __iomem *reg; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + + struct m66592_ep ep[M66592_MAX_NUM_PIPE]; + struct m66592_ep *pipenum2ep[M66592_MAX_NUM_PIPE]; + struct m66592_ep *epaddr2ep[16]; + + struct usb_request *ep0_req; /* for internal request */ + u16 *ep0_buf; /* for internal request */ + + struct timer_list timer; + + u16 old_vbus; + int scount; + + int old_dvsq; + + /* pipe config */ + int bulk; + int interrupt; + int isochronous; + int num_dma; + int bi_bufnum; /* bulk and isochronous's bufnum */ +}; + +#define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget) +#define m66592_to_gadget(m66592) (&m66592->gadget) + +#define is_bulk_pipe(pipenum) \ + ((pipenum >= M66592_BASE_PIPENUM_BULK) && \ + (pipenum < (M66592_BASE_PIPENUM_BULK + M66592_MAX_NUM_BULK))) +#define is_interrupt_pipe(pipenum) \ + ((pipenum >= M66592_BASE_PIPENUM_INT) && \ + (pipenum < (M66592_BASE_PIPENUM_INT + M66592_MAX_NUM_INT))) +#define is_isoc_pipe(pipenum) \ + ((pipenum >= M66592_BASE_PIPENUM_ISOC) && \ + (pipenum < (M66592_BASE_PIPENUM_ISOC + M66592_MAX_NUM_ISOC))) + +#define enable_irq_ready(m66592, pipenum) \ + enable_pipe_irq(m66592, pipenum, M66592_BRDYENB) +#define disable_irq_ready(m66592, pipenum) \ + disable_pipe_irq(m66592, pipenum, M66592_BRDYENB) +#define enable_irq_empty(m66592, pipenum) \ + enable_pipe_irq(m66592, pipenum, M66592_BEMPENB) +#define disable_irq_empty(m66592, pipenum) \ + disable_pipe_irq(m66592, pipenum, M66592_BEMPENB) +#define enable_irq_nrdy(m66592, pipenum) \ + enable_pipe_irq(m66592, pipenum, M66592_NRDYENB) +#define disable_irq_nrdy(m66592, pipenum) \ + disable_pipe_irq(m66592, pipenum, M66592_NRDYENB) + +/*-------------------------------------------------------------------------*/ +static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset) +{ + return inw((unsigned long)m66592->reg + offset); +} + +static inline void m66592_read_fifo(struct m66592 *m66592, + unsigned long offset, + void *buf, unsigned long len) +{ + unsigned long fifoaddr = (unsigned long)m66592->reg + offset; + + len = (len + 1) / 2; + insw(fifoaddr, buf, len); +} + +static inline void m66592_write(struct m66592 *m66592, u16 val, + unsigned long offset) +{ + outw(val, (unsigned long)m66592->reg + offset); +} + +static inline void m66592_write_fifo(struct m66592 *m66592, + unsigned long offset, + void *buf, unsigned long len) +{ + unsigned long fifoaddr = (unsigned long)m66592->reg + offset; + unsigned long odd = len & 0x0001; + + len = len / 2; + outsw(fifoaddr, buf, len); + if (odd) { + unsigned char *p = buf + len*2; + outb(*p, fifoaddr); + } +} + +static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, + unsigned long offset) +{ + u16 tmp; + tmp = m66592_read(m66592, offset); + tmp = tmp & (~pat); + tmp = tmp | val; + m66592_write(m66592, tmp, offset); +} + +#define m66592_bclr(m66592, val, offset) \ + m66592_mdfy(m66592, 0, val, offset) +#define m66592_bset(m66592, val, offset) \ + m66592_mdfy(m66592, val, 0, offset) + +#endif /* ifndef __M66592_UDC_H__ */ + + diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index d975ecf18e0..c3d364ecd4f 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -450,100 +450,6 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req) /*-------------------------------------------------------------------------*/ -/* - * dma-coherent memory allocation (for dma-capable endpoints) - * - * NOTE: the dma_*_coherent() API calls suck. Most implementations are - * (a) page-oriented, so small buffers lose big; and (b) asymmetric with - * respect to calls with irqs disabled: alloc is safe, free is not. - * We currently work around (b), but not (a). - */ - -static void * -net2280_alloc_buffer ( - struct usb_ep *_ep, - unsigned bytes, - dma_addr_t *dma, - gfp_t gfp_flags -) -{ - void *retval; - struct net2280_ep *ep; - - ep = container_of (_ep, struct net2280_ep, ep); - if (!_ep) - return NULL; - *dma = DMA_ADDR_INVALID; - - if (ep->dma) - retval = dma_alloc_coherent(&ep->dev->pdev->dev, - bytes, dma, gfp_flags); - else - retval = kmalloc(bytes, gfp_flags); - return retval; -} - -static DEFINE_SPINLOCK(buflock); -static LIST_HEAD(buffers); - -struct free_record { - struct list_head list; - struct device *dev; - unsigned bytes; - dma_addr_t dma; -}; - -static void do_free(unsigned long ignored) -{ - spin_lock_irq(&buflock); - while (!list_empty(&buffers)) { - struct free_record *buf; - - buf = list_entry(buffers.next, struct free_record, list); - list_del(&buf->list); - spin_unlock_irq(&buflock); - - dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma); - - spin_lock_irq(&buflock); - } - spin_unlock_irq(&buflock); -} - -static DECLARE_TASKLET(deferred_free, do_free, 0); - -static void -net2280_free_buffer ( - struct usb_ep *_ep, - void *address, - dma_addr_t dma, - unsigned bytes -) { - /* free memory into the right allocator */ - if (dma != DMA_ADDR_INVALID) { - struct net2280_ep *ep; - struct free_record *buf = address; - unsigned long flags; - - ep = container_of(_ep, struct net2280_ep, ep); - if (!_ep) - return; - - ep = container_of (_ep, struct net2280_ep, ep); - buf->dev = &ep->dev->pdev->dev; - buf->bytes = bytes; - buf->dma = dma; - - spin_lock_irqsave(&buflock, flags); - list_add_tail(&buf->list, &buffers); - tasklet_schedule(&deferred_free); - spin_unlock_irqrestore(&buflock, flags); - } else - kfree (address); -} - -/*-------------------------------------------------------------------------*/ - /* load a packet into the fifo we use for usb IN transfers. * works for all endpoints. * @@ -1392,9 +1298,6 @@ static const struct usb_ep_ops net2280_ep_ops = { .alloc_request = net2280_alloc_request, .free_request = net2280_free_request, - .alloc_buffer = net2280_alloc_buffer, - .free_buffer = net2280_free_buffer, - .queue = net2280_queue, .dequeue = net2280_dequeue, @@ -2964,7 +2867,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) , &dev->pci->pcimstctl); /* erratum 0115 shouldn't appear: Linux inits PCI_LATENCY_TIMER */ pci_set_master (pdev); - pci_set_mwi (pdev); + pci_try_set_mwi (pdev); /* ... also flushes any posted pci writes */ dev->chiprev = get_idx_reg (dev->regs, REG_CHIPREV) & 0xffff; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index c4975a6cf77..9b0f0925ddd 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -296,111 +296,6 @@ omap_free_request(struct usb_ep *ep, struct usb_request *_req) /*-------------------------------------------------------------------------*/ -/* - * dma-coherent memory allocation (for dma-capable endpoints) - * - * NOTE: the dma_*_coherent() API calls suck. Most implementations are - * (a) page-oriented, so small buffers lose big; and (b) asymmetric with - * respect to calls with irqs disabled: alloc is safe, free is not. - * We currently work around (b), but not (a). - */ - -static void * -omap_alloc_buffer( - struct usb_ep *_ep, - unsigned bytes, - dma_addr_t *dma, - gfp_t gfp_flags -) -{ - void *retval; - struct omap_ep *ep; - - if (!_ep) - return NULL; - - ep = container_of(_ep, struct omap_ep, ep); - if (use_dma && ep->has_dma) { - static int warned; - if (!warned && bytes < PAGE_SIZE) { - dev_warn(ep->udc->gadget.dev.parent, - "using dma_alloc_coherent for " - "small allocations wastes memory\n"); - warned++; - } - return dma_alloc_coherent(ep->udc->gadget.dev.parent, - bytes, dma, gfp_flags); - } - - retval = kmalloc(bytes, gfp_flags); - if (retval) - *dma = virt_to_phys(retval); - return retval; -} - -static DEFINE_SPINLOCK(buflock); -static LIST_HEAD(buffers); - -struct free_record { - struct list_head list; - struct device *dev; - unsigned bytes; - dma_addr_t dma; -}; - -static void do_free(unsigned long ignored) -{ - spin_lock_irq(&buflock); - while (!list_empty(&buffers)) { - struct free_record *buf; - - buf = list_entry(buffers.next, struct free_record, list); - list_del(&buf->list); - spin_unlock_irq(&buflock); - - dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma); - - spin_lock_irq(&buflock); - } - spin_unlock_irq(&buflock); -} - -static DECLARE_TASKLET(deferred_free, do_free, 0); - -static void omap_free_buffer( - struct usb_ep *_ep, - void *buf, - dma_addr_t dma, - unsigned bytes -) -{ - if (!_ep) { - WARN_ON(1); - return; - } - - /* free memory into the right allocator */ - if (dma != DMA_ADDR_INVALID) { - struct omap_ep *ep; - struct free_record *rec = buf; - unsigned long flags; - - ep = container_of(_ep, struct omap_ep, ep); - - rec->dev = ep->udc->gadget.dev.parent; - rec->bytes = bytes; - rec->dma = dma; - - spin_lock_irqsave(&buflock, flags); - list_add_tail(&rec->list, &buffers); - tasklet_schedule(&deferred_free); - spin_unlock_irqrestore(&buflock, flags); - } else - kfree(buf); -} - -/*-------------------------------------------------------------------------*/ - static void done(struct omap_ep *ep, struct omap_req *req, int status) { @@ -1271,9 +1166,6 @@ static struct usb_ep_ops omap_ep_ops = { .alloc_request = omap_alloc_request, .free_request = omap_free_request, - .alloc_buffer = omap_alloc_buffer, - .free_buffer = omap_free_buffer, - .queue = omap_ep_queue, .dequeue = omap_ep_dequeue, diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 84392e835d5..63b9521c132 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -24,9 +24,9 @@ * */ -#undef DEBUG // #define VERBOSE DBG_VERBOSE +#include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/ioport.h> @@ -46,19 +46,17 @@ #include <asm/byteorder.h> #include <asm/dma.h> +#include <asm/gpio.h> #include <asm/io.h> #include <asm/system.h> #include <asm/mach-types.h> #include <asm/unaligned.h> #include <asm/hardware.h> -#ifdef CONFIG_ARCH_PXA -#include <asm/arch/pxa-regs.h> -#endif #include <linux/usb/ch9.h> #include <linux/usb_gadget.h> -#include <asm/arch/udc.h> +#include <asm/mach/udc_pxa2xx.h> /* @@ -76,9 +74,17 @@ * it constrains the sorts of USB configuration change events that work. * The errata for these chips are misleading; some "fixed" bugs from * pxa250 a0/a1 b0/b1/b2 sure act like they're still there. + * + * Note that the UDC hardware supports DMA (except on IXP) but that's + * not used here. IN-DMA (to host) is simple enough, when the data is + * suitably aligned (16 bytes) ... the network stack doesn't do that, + * other software can. OUT-DMA is buggy in most chip versions, as well + * as poorly designed (data toggle not automatic). So this driver won't + * bother using DMA. (Mostly-working IN-DMA support was available in + * kernels before 2.6.23, but was never enabled or well tested.) */ -#define DRIVER_VERSION "4-May-2005" +#define DRIVER_VERSION "30-June-2007" #define DRIVER_DESC "PXA 25x USB Device Controller driver" @@ -87,12 +93,9 @@ static const char driver_name [] = "pxa2xx_udc"; static const char ep0name [] = "ep0"; -// #define USE_DMA -// #define USE_OUT_DMA // #define DISABLE_TEST_MODE #ifdef CONFIG_ARCH_IXP4XX -#undef USE_DMA /* cpu-specific register addresses are compiled in to this code */ #ifdef CONFIG_ARCH_PXA @@ -104,25 +107,6 @@ static const char ep0name [] = "ep0"; #include "pxa2xx_udc.h" -#ifdef USE_DMA -static int use_dma = 1; -module_param(use_dma, bool, 0); -MODULE_PARM_DESC (use_dma, "true to use dma"); - -static void dma_nodesc_handler (int dmach, void *_ep); -static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req); - -#ifdef USE_OUT_DMA -#define DMASTR " (dma support)" -#else -#define DMASTR " (dma in)" -#endif - -#else /* !USE_DMA */ -#define DMASTR " (pio only)" -#undef USE_OUT_DMA -#endif - #ifdef CONFIG_USB_PXA2XX_SMALL #define SIZE_STR " (small)" #else @@ -155,7 +139,7 @@ static int is_vbus_present(void) struct pxa2xx_udc_mach_info *mach = the_controller->mach; if (mach->gpio_vbus) - return udc_gpio_get(mach->gpio_vbus); + return gpio_get_value(mach->gpio_vbus); if (mach->udc_is_connected) return mach->udc_is_connected(); return 1; @@ -167,7 +151,7 @@ static void pullup_off(void) struct pxa2xx_udc_mach_info *mach = the_controller->mach; if (mach->gpio_pullup) - udc_gpio_set(mach->gpio_pullup, 0); + gpio_set_value(mach->gpio_pullup, 0); else if (mach->udc_command) mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); } @@ -177,7 +161,7 @@ static void pullup_on(void) struct pxa2xx_udc_mach_info *mach = the_controller->mach; if (mach->gpio_pullup) - udc_gpio_set(mach->gpio_pullup, 1); + gpio_set_value(mach->gpio_pullup, 1); else if (mach->udc_command) mach->udc_command(PXA2XX_UDC_CMD_CONNECT); } @@ -281,9 +265,8 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep, } ep->desc = desc; - ep->dma = -1; ep->stopped = 0; - ep->pio_irqs = ep->dma_irqs = 0; + ep->pio_irqs = 0; ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize); /* flush fifo (mostly for OUT buffers) */ @@ -291,30 +274,6 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep, /* ... reset halt state too, if we could ... */ -#ifdef USE_DMA - /* for (some) bulk and ISO endpoints, try to get a DMA channel and - * bind it to the endpoint. otherwise use PIO. - */ - switch (ep->bmAttributes) { - case USB_ENDPOINT_XFER_ISOC: - if (le16_to_cpu(desc->wMaxPacketSize) % 32) - break; - // fall through - case USB_ENDPOINT_XFER_BULK: - if (!use_dma || !ep->reg_drcmr) - break; - ep->dma = pxa_request_dma ((char *)_ep->name, - (le16_to_cpu (desc->wMaxPacketSize) > 64) - ? DMA_PRIO_MEDIUM /* some iso */ - : DMA_PRIO_LOW, - dma_nodesc_handler, ep); - if (ep->dma >= 0) { - *ep->reg_drcmr = DRCMR_MAPVLD | ep->dma; - DMSG("%s using dma%d\n", _ep->name, ep->dma); - } - } -#endif - DBG(DBG_VERBOSE, "enabled %s\n", _ep->name); return 0; } @@ -334,14 +293,6 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) nuke (ep, -ESHUTDOWN); -#ifdef USE_DMA - if (ep->dma >= 0) { - *ep->reg_drcmr = 0; - pxa_free_dma (ep->dma); - ep->dma = -1; - } -#endif - /* flush fifo (mostly for IN buffers) */ pxa2xx_ep_fifo_flush (_ep); @@ -390,35 +341,6 @@ pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req) kfree(req); } - -/* PXA cache needs flushing with DMA I/O (it's dma-incoherent), but there's - * no device-affinity and the heap works perfectly well for i/o buffers. - * It wastes much less memory than dma_alloc_coherent() would, and even - * prevents cacheline (32 bytes wide) sharing problems. - */ -static void * -pxa2xx_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, gfp_t gfp_flags) -{ - char *retval; - - retval = kmalloc (bytes, gfp_flags & ~(__GFP_DMA|__GFP_HIGHMEM)); - if (retval) -#ifdef USE_DMA - *dma = virt_to_bus (retval); -#else - *dma = (dma_addr_t)~0; -#endif - return retval; -} - -static void -pxa2xx_ep_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma, - unsigned bytes) -{ - kfree (buf); -} - /*-------------------------------------------------------------------------*/ /* @@ -518,18 +440,8 @@ write_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req) /* requests complete when all IN data is in the FIFO */ if (is_last) { done (ep, req, 0); - if (list_empty(&ep->queue) || unlikely(ep->dma >= 0)) { + if (list_empty(&ep->queue)) pio_irq_disable (ep->bEndpointAddress); -#ifdef USE_DMA - /* unaligned data and zlps couldn't use dma */ - if (unlikely(!list_empty(&ep->queue))) { - req = list_entry(ep->queue.next, - struct pxa2xx_request, queue); - kick_dma(ep,req); - return 0; - } -#endif - } return 1; } @@ -728,182 +640,6 @@ read_ep0_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req) return 0; } -#ifdef USE_DMA - -#define MAX_IN_DMA ((DCMD_LENGTH + 1) - BULK_FIFO_SIZE) - -static void -start_dma_nodesc(struct pxa2xx_ep *ep, struct pxa2xx_request *req, int is_in) -{ - u32 dcmd = req->req.length; - u32 buf = req->req.dma; - u32 fifo = io_v2p ((u32)ep->reg_uddr); - - /* caller guarantees there's a packet or more remaining - * - IN may end with a short packet (TSP set separately), - * - OUT is always full length - */ - buf += req->req.actual; - dcmd -= req->req.actual; - ep->dma_fixup = 0; - - /* no-descriptor mode can be simple for bulk-in, iso-in, iso-out */ - DCSR(ep->dma) = DCSR_NODESC; - if (is_in) { - DSADR(ep->dma) = buf; - DTADR(ep->dma) = fifo; - if (dcmd > MAX_IN_DMA) - dcmd = MAX_IN_DMA; - else - ep->dma_fixup = (dcmd % ep->ep.maxpacket) != 0; - dcmd |= DCMD_BURST32 | DCMD_WIDTH1 - | DCMD_FLOWTRG | DCMD_INCSRCADDR; - } else { -#ifdef USE_OUT_DMA - DSADR(ep->dma) = fifo; - DTADR(ep->dma) = buf; - if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC) - dcmd = ep->ep.maxpacket; - dcmd |= DCMD_BURST32 | DCMD_WIDTH1 - | DCMD_FLOWSRC | DCMD_INCTRGADDR; -#endif - } - DCMD(ep->dma) = dcmd; - DCSR(ep->dma) = DCSR_RUN | DCSR_NODESC - | (unlikely(is_in) - ? DCSR_STOPIRQEN /* use dma_nodesc_handler() */ - : 0); /* use handle_ep() */ -} - -static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req) -{ - int is_in = ep->bEndpointAddress & USB_DIR_IN; - - if (is_in) { - /* unaligned tx buffers and zlps only work with PIO */ - if ((req->req.dma & 0x0f) != 0 - || unlikely((req->req.length - req->req.actual) - == 0)) { - pio_irq_enable(ep->bEndpointAddress); - if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0) - (void) write_fifo(ep, req); - } else { - start_dma_nodesc(ep, req, USB_DIR_IN); - } - } else { - if ((req->req.length - req->req.actual) < ep->ep.maxpacket) { - DMSG("%s short dma read...\n", ep->ep.name); - /* we're always set up for pio out */ - read_fifo (ep, req); - } else { - *ep->reg_udccs = UDCCS_BO_DME - | (*ep->reg_udccs & UDCCS_BO_FST); - start_dma_nodesc(ep, req, USB_DIR_OUT); - } - } -} - -static void cancel_dma(struct pxa2xx_ep *ep) -{ - struct pxa2xx_request *req; - u32 tmp; - - if (DCSR(ep->dma) == 0 || list_empty(&ep->queue)) - return; - - DCSR(ep->dma) = 0; - while ((DCSR(ep->dma) & DCSR_STOPSTATE) == 0) - cpu_relax(); - - req = list_entry(ep->queue.next, struct pxa2xx_request, queue); - tmp = DCMD(ep->dma) & DCMD_LENGTH; - req->req.actual = req->req.length - (tmp & DCMD_LENGTH); - - /* the last tx packet may be incomplete, so flush the fifo. - * FIXME correct req.actual if we can - */ - if (ep->bEndpointAddress & USB_DIR_IN) - *ep->reg_udccs = UDCCS_BI_FTF; -} - -/* dma channel stopped ... normal tx end (IN), or on error (IN/OUT) */ -static void dma_nodesc_handler(int dmach, void *_ep) -{ - struct pxa2xx_ep *ep = _ep; - struct pxa2xx_request *req; - u32 tmp, completed; - - local_irq_disable(); - - req = list_entry(ep->queue.next, struct pxa2xx_request, queue); - - ep->dma_irqs++; - ep->dev->stats.irqs++; - HEX_DISPLAY(ep->dev->stats.irqs); - - /* ack/clear */ - tmp = DCSR(ep->dma); - DCSR(ep->dma) = tmp; - if ((tmp & DCSR_STOPSTATE) == 0 - || (DDADR(ep->dma) & DDADR_STOP) != 0) { - DBG(DBG_VERBOSE, "%s, dcsr %08x ddadr %08x\n", - ep->ep.name, DCSR(ep->dma), DDADR(ep->dma)); - goto done; - } - DCSR(ep->dma) = 0; /* clear DCSR_STOPSTATE */ - - /* update transfer status */ - completed = tmp & DCSR_BUSERR; - if (ep->bEndpointAddress & USB_DIR_IN) - tmp = DSADR(ep->dma); - else - tmp = DTADR(ep->dma); - req->req.actual = tmp - req->req.dma; - - /* FIXME seems we sometimes see partial transfers... */ - - if (unlikely(completed != 0)) - req->req.status = -EIO; - else if (req->req.actual) { - /* these registers have zeroes in low bits; they miscount - * some (end-of-transfer) short packets: tx 14 as tx 12 - */ - if (ep->dma_fixup) - req->req.actual = min(req->req.actual + 3, - req->req.length); - - tmp = (req->req.length - req->req.actual); - completed = (tmp == 0); - if (completed && (ep->bEndpointAddress & USB_DIR_IN)) { - - /* maybe validate final short packet ... */ - if ((req->req.actual % ep->ep.maxpacket) != 0) - *ep->reg_udccs = UDCCS_BI_TSP/*|UDCCS_BI_TPC*/; - - /* ... or zlp, using pio fallback */ - else if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK - && req->req.zero) { - DMSG("%s zlp terminate ...\n", ep->ep.name); - completed = 0; - } - } - } - - if (likely(completed)) { - done(ep, req, 0); - - /* maybe re-activate after completion */ - if (ep->stopped || list_empty(&ep->queue)) - goto done; - req = list_entry(ep->queue.next, struct pxa2xx_request, queue); - } - kick_dma(ep, req); -done: - local_irq_enable(); -} - -#endif - /*-------------------------------------------------------------------------*/ static int @@ -942,19 +678,8 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) (ep->desc->wMaxPacketSize))) return -EMSGSIZE; -#ifdef USE_DMA - // FIXME caller may already have done the dma mapping - if (ep->dma >= 0) { - _req->dma = dma_map_single(dev->dev, - _req->buf, _req->length, - ((ep->bEndpointAddress & USB_DIR_IN) != 0) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - } -#endif - DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n", - _ep->name, _req, _req->length, _req->buf); + _ep->name, _req, _req->length, _req->buf); local_irq_save(flags); @@ -1002,11 +727,6 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) local_irq_restore (flags); return -EL2HLT; } -#ifdef USE_DMA - /* either start dma or prime pio pump */ - } else if (ep->dma >= 0) { - kick_dma(ep, req); -#endif /* can the FIFO can satisfy the request immediately? */ } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) { if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0 @@ -1017,7 +737,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) req = NULL; } - if (likely (req && ep->desc) && ep->dma < 0) + if (likely (req && ep->desc)) pio_irq_enable(ep->bEndpointAddress); } @@ -1038,10 +758,6 @@ static void nuke(struct pxa2xx_ep *ep, int status) struct pxa2xx_request *req; /* called with irqs blocked */ -#ifdef USE_DMA - if (ep->dma >= 0 && !ep->stopped) - cancel_dma(ep); -#endif while (!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct pxa2xx_request, @@ -1076,19 +792,7 @@ static int pxa2xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) return -EINVAL; } -#ifdef USE_DMA - if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) { - cancel_dma(ep); - done(ep, req, -ECONNRESET); - /* restart i/o */ - if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct pxa2xx_request, queue); - kick_dma(ep, req); - } - } else -#endif - done(ep, req, -ECONNRESET); + done(ep, req, -ECONNRESET); local_irq_restore(flags); return 0; @@ -1203,9 +907,6 @@ static struct usb_ep_ops pxa2xx_ep_ops = { .alloc_request = pxa2xx_ep_alloc_request, .free_request = pxa2xx_ep_free_request, - .alloc_buffer = pxa2xx_ep_alloc_buffer, - .free_buffer = pxa2xx_ep_free_buffer, - .queue = pxa2xx_ep_queue, .dequeue = pxa2xx_ep_dequeue, @@ -1325,7 +1026,7 @@ udc_proc_read(char *page, char **start, off_t off, int count, /* basic device status */ t = scnprintf(next, size, DRIVER_DESC "\n" "%s version: %s\nGadget driver: %s\nHost %s\n\n", - driver_name, DRIVER_VERSION SIZE_STR DMASTR, + driver_name, DRIVER_VERSION SIZE_STR "(pio)", dev->driver ? dev->driver->driver.name : "(none)", is_vbus_present() ? "full speed" : "disconnected"); size -= t; @@ -1390,7 +1091,6 @@ udc_proc_read(char *page, char **start, off_t off, int count, for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { struct pxa2xx_ep *ep = &dev->ep [i]; struct pxa2xx_request *req; - int t; if (i != 0) { const struct usb_endpoint_descriptor *d; @@ -1400,10 +1100,9 @@ udc_proc_read(char *page, char **start, off_t off, int count, continue; tmp = *dev->ep [i].reg_udccs; t = scnprintf(next, size, - "%s max %d %s udccs %02x irqs %lu/%lu\n", + "%s max %d %s udccs %02x irqs %lu\n", ep->ep.name, le16_to_cpu (d->wMaxPacketSize), - (ep->dma >= 0) ? "dma" : "pio", tmp, - ep->pio_irqs, ep->dma_irqs); + "pio", tmp, ep->pio_irqs); /* TODO translate all five groups of udccs bits! */ } else /* ep0 should only have one transfer queued */ @@ -1423,19 +1122,7 @@ udc_proc_read(char *page, char **start, off_t off, int count, continue; } list_for_each_entry(req, &ep->queue, queue) { -#ifdef USE_DMA - if (ep->dma >= 0 && req->queue.prev == &ep->queue) - t = scnprintf(next, size, - "\treq %p len %d/%d " - "buf %p (dma%d dcmd %08x)\n", - &req->req, req->req.actual, - req->req.length, req->req.buf, - ep->dma, DCMD(ep->dma) - // low 13 bits == bytes-to-go - ); - else -#endif - t = scnprintf(next, size, + t = scnprintf(next, size, "\treq %p len %d/%d buf %p\n", &req->req, req->req.actual, req->req.length, req->req.buf); @@ -1488,7 +1175,6 @@ static void udc_disable(struct pxa2xx_udc *dev) ep0_idle (dev); dev->gadget.speed = USB_SPEED_UNKNOWN; - LED_CONNECTED_OFF; } @@ -1514,7 +1200,7 @@ static void udc_reinit(struct pxa2xx_udc *dev) ep->desc = NULL; ep->stopped = 0; INIT_LIST_HEAD (&ep->queue); - ep->pio_irqs = ep->dma_irqs = 0; + ep->pio_irqs = 0; } /* the rest was statically initialized, and is read-only */ @@ -1666,7 +1352,6 @@ stop_activity(struct pxa2xx_udc *dev, struct usb_gadget_driver *driver) del_timer_sync(&dev->timer); /* report disconnect; the driver is already quiesced */ - LED_CONNECTED_OFF; if (driver) driver->disconnect(&dev->gadget); @@ -1715,16 +1400,13 @@ lubbock_vbus_irq(int irq, void *_dev) int vbus; dev->stats.irqs++; - HEX_DISPLAY(dev->stats.irqs); switch (irq) { case LUBBOCK_USB_IRQ: - LED_CONNECTED_ON; vbus = 1; disable_irq(LUBBOCK_USB_IRQ); enable_irq(LUBBOCK_USB_DISC_IRQ); break; case LUBBOCK_USB_DISC_IRQ: - LED_CONNECTED_OFF; vbus = 0; disable_irq(LUBBOCK_USB_DISC_IRQ); enable_irq(LUBBOCK_USB_IRQ); @@ -1742,7 +1424,7 @@ lubbock_vbus_irq(int irq, void *_dev) static irqreturn_t udc_vbus_irq(int irq, void *_dev) { struct pxa2xx_udc *dev = _dev; - int vbus = udc_gpio_get(dev->mach->gpio_vbus); + int vbus = gpio_get_value(dev->mach->gpio_vbus); pxa2xx_udc_vbus_session(&dev->gadget, vbus); return IRQ_HANDLED; @@ -2040,18 +1722,6 @@ static void handle_ep(struct pxa2xx_ep *ep) /* fifos can hold packets, ready for reading... */ if (likely(req)) { -#ifdef USE_OUT_DMA -// TODO didn't yet debug out-dma. this approach assumes -// the worst about short packets and RPC; it might be better. - - if (likely(ep->dma >= 0)) { - if (!(udccs & UDCCS_BO_RSP)) { - *ep->reg_udccs = UDCCS_BO_RPC; - ep->dma_irqs++; - return; - } - } -#endif completed = read_fifo(ep, req); } else pio_irq_disable (ep->bEndpointAddress); @@ -2074,7 +1744,6 @@ pxa2xx_udc_irq(int irq, void *_dev) int handled; dev->stats.irqs++; - HEX_DISPLAY(dev->stats.irqs); do { u32 udccr = UDCCR; @@ -2125,7 +1794,6 @@ pxa2xx_udc_irq(int irq, void *_dev) } else { DBG(DBG_VERBOSE, "USB reset end\n"); dev->gadget.speed = USB_SPEED_FULL; - LED_CONNECTED_ON; memset(&dev->stats, 0, sizeof dev->stats); /* driver and endpoints are still reset */ } @@ -2217,7 +1885,6 @@ static struct pxa2xx_udc memory = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .reg_udccs = &UDCCS1, .reg_uddr = &UDDR1, - drcmr (25) }, .ep[2] = { .ep = { @@ -2232,7 +1899,6 @@ static struct pxa2xx_udc memory = { .reg_udccs = &UDCCS2, .reg_ubcr = &UBCR2, .reg_uddr = &UDDR2, - drcmr (26) }, #ifndef CONFIG_USB_PXA2XX_SMALL .ep[3] = { @@ -2247,7 +1913,6 @@ static struct pxa2xx_udc memory = { .bmAttributes = USB_ENDPOINT_XFER_ISOC, .reg_udccs = &UDCCS3, .reg_uddr = &UDDR3, - drcmr (27) }, .ep[4] = { .ep = { @@ -2262,7 +1927,6 @@ static struct pxa2xx_udc memory = { .reg_udccs = &UDCCS4, .reg_ubcr = &UBCR4, .reg_uddr = &UDDR4, - drcmr (28) }, .ep[5] = { .ep = { @@ -2291,7 +1955,6 @@ static struct pxa2xx_udc memory = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .reg_udccs = &UDCCS6, .reg_uddr = &UDDR6, - drcmr (30) }, .ep[7] = { .ep = { @@ -2306,7 +1969,6 @@ static struct pxa2xx_udc memory = { .reg_udccs = &UDCCS7, .reg_ubcr = &UBCR7, .reg_uddr = &UDDR7, - drcmr (31) }, .ep[8] = { .ep = { @@ -2320,7 +1982,6 @@ static struct pxa2xx_udc memory = { .bmAttributes = USB_ENDPOINT_XFER_ISOC, .reg_udccs = &UDCCS8, .reg_uddr = &UDDR8, - drcmr (32) }, .ep[9] = { .ep = { @@ -2335,7 +1996,6 @@ static struct pxa2xx_udc memory = { .reg_udccs = &UDCCS9, .reg_ubcr = &UBCR9, .reg_uddr = &UDDR9, - drcmr (33) }, .ep[10] = { .ep = { @@ -2364,7 +2024,6 @@ static struct pxa2xx_udc memory = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .reg_udccs = &UDCCS11, .reg_uddr = &UDDR11, - drcmr (35) }, .ep[12] = { .ep = { @@ -2379,7 +2038,6 @@ static struct pxa2xx_udc memory = { .reg_udccs = &UDCCS12, .reg_ubcr = &UBCR12, .reg_uddr = &UDDR12, - drcmr (36) }, .ep[13] = { .ep = { @@ -2393,7 +2051,6 @@ static struct pxa2xx_udc memory = { .bmAttributes = USB_ENDPOINT_XFER_ISOC, .reg_udccs = &UDCCS13, .reg_uddr = &UDDR13, - drcmr (37) }, .ep[14] = { .ep = { @@ -2408,7 +2065,6 @@ static struct pxa2xx_udc memory = { .reg_udccs = &UDCCS14, .reg_ubcr = &UBCR14, .reg_uddr = &UDDR14, - drcmr (38) }, .ep[15] = { .ep = { @@ -2466,7 +2122,7 @@ static struct pxa2xx_udc memory = { static int __init pxa2xx_udc_probe(struct platform_device *pdev) { struct pxa2xx_udc *dev = &memory; - int retval, out_dma = 1, vbus_irq, irq; + int retval, vbus_irq, irq; u32 chiprev; /* insist on Intel/ARM/XScale */ @@ -2489,7 +2145,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) case PXA250_B2: case PXA210_B2: case PXA250_B1: case PXA210_B1: case PXA250_B0: case PXA210_B0: - out_dma = 0; + /* OUT-DMA is broken ... */ /* fall through */ case PXA250_C0: case PXA210_C0: break; @@ -2498,11 +2154,9 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) case IXP425_B0: case IXP465_AD: dev->has_cfr = 1; - out_dma = 0; break; #endif default: - out_dma = 0; printk(KERN_ERR "%s: unrecognized processor: %08x\n", driver_name, chiprev); /* iop3xx, ixp4xx, ... */ @@ -2513,36 +2167,41 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) if (irq < 0) return -ENODEV; - pr_debug("%s: IRQ %d%s%s%s\n", driver_name, irq, + pr_debug("%s: IRQ %d%s%s\n", driver_name, irq, dev->has_cfr ? "" : " (!cfr)", - out_dma ? "" : " (broken dma-out)", - SIZE_STR DMASTR + SIZE_STR "(pio)" ); -#ifdef USE_DMA -#ifndef USE_OUT_DMA - out_dma = 0; -#endif - /* pxa 250 erratum 130 prevents using OUT dma (fixed C0) */ - if (!out_dma) { - DMSG("disabled OUT dma\n"); - dev->ep[ 2].reg_drcmr = dev->ep[ 4].reg_drcmr = 0; - dev->ep[ 7].reg_drcmr = dev->ep[ 9].reg_drcmr = 0; - dev->ep[12].reg_drcmr = dev->ep[14].reg_drcmr = 0; - } -#endif - /* other non-static parts of init */ dev->dev = &pdev->dev; dev->mach = pdev->dev.platform_data; + if (dev->mach->gpio_vbus) { - udc_gpio_init_vbus(dev->mach->gpio_vbus); - vbus_irq = udc_gpio_to_irq(dev->mach->gpio_vbus); + if ((retval = gpio_request(dev->mach->gpio_vbus, + "pxa2xx_udc GPIO VBUS"))) { + dev_dbg(&pdev->dev, + "can't get vbus gpio %d, err: %d\n", + dev->mach->gpio_vbus, retval); + return -EBUSY; + } + gpio_direction_input(dev->mach->gpio_vbus); + vbus_irq = gpio_to_irq(dev->mach->gpio_vbus); set_irq_type(vbus_irq, IRQT_BOTHEDGE); } else vbus_irq = 0; - if (dev->mach->gpio_pullup) - udc_gpio_init_pullup(dev->mach->gpio_pullup); + + if (dev->mach->gpio_pullup) { + if ((retval = gpio_request(dev->mach->gpio_pullup, + "pca2xx_udc GPIO PULLUP"))) { + dev_dbg(&pdev->dev, + "can't get pullup gpio %d, err: %d\n", + dev->mach->gpio_pullup, retval); + if (dev->mach->gpio_vbus) + gpio_free(dev->mach->gpio_vbus); + return -EBUSY; + } + gpio_direction_output(dev->mach->gpio_pullup, 0); + } init_timer(&dev->timer); dev->timer.function = udc_watchdog; @@ -2566,6 +2225,10 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) if (retval != 0) { printk(KERN_ERR "%s: can't get irq %d, err %d\n", driver_name, irq, retval); + if (dev->mach->gpio_pullup) + gpio_free(dev->mach->gpio_pullup); + if (dev->mach->gpio_vbus) + gpio_free(dev->mach->gpio_vbus); return -EBUSY; } dev->got_irq = 1; @@ -2581,6 +2244,10 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) driver_name, LUBBOCK_USB_DISC_IRQ, retval); lubbock_fail0: free_irq(irq, dev); + if (dev->mach->gpio_pullup) + gpio_free(dev->mach->gpio_pullup); + if (dev->mach->gpio_vbus) + gpio_free(dev->mach->gpio_vbus); return -EBUSY; } retval = request_irq(LUBBOCK_USB_IRQ, @@ -2593,11 +2260,6 @@ lubbock_fail0: free_irq(LUBBOCK_USB_DISC_IRQ, dev); goto lubbock_fail0; } -#ifdef DEBUG - /* with U-Boot (but not BLOB), hex is off by default */ - HEX_DISPLAY(dev->stats.irqs); - LUB_DISC_BLNK_LED &= 0xff; -#endif } else #endif if (vbus_irq) { @@ -2608,6 +2270,10 @@ lubbock_fail0: printk(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name, vbus_irq, retval); free_irq(irq, dev); + if (dev->mach->gpio_pullup) + gpio_free(dev->mach->gpio_pullup); + if (dev->mach->gpio_vbus) + gpio_free(dev->mach->gpio_vbus); return -EBUSY; } } @@ -2641,8 +2307,13 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev) free_irq(LUBBOCK_USB_IRQ, dev); } #endif - if (dev->mach->gpio_vbus) - free_irq(IRQ_GPIO(dev->mach->gpio_vbus), dev); + if (dev->mach->gpio_vbus) { + free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev); + gpio_free(dev->mach->gpio_vbus); + } + if (dev->mach->gpio_pullup) + gpio_free(dev->mach->gpio_pullup); + platform_set_drvdata(pdev, NULL); the_controller = NULL; return 0; diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index 773e549aff3..0e5d0e6fb0e 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -54,8 +54,6 @@ struct pxa2xx_ep { const struct usb_endpoint_descriptor *desc; struct list_head queue; unsigned long pio_irqs; - unsigned long dma_irqs; - short dma; unsigned short fifo_size; u8 bEndpointAddress; @@ -63,7 +61,7 @@ struct pxa2xx_ep { unsigned stopped : 1; unsigned dma_fixup : 1; - + /* UDCCS = UDC Control/Status for this EP * UBCR = UDC Byte Count Remaining (contents of OUT fifo) * UDDR = UDC Endpoint Data Register (the fifo) @@ -72,12 +70,6 @@ struct pxa2xx_ep { volatile u32 *reg_udccs; volatile u32 *reg_ubcr; volatile u32 *reg_uddr; -#ifdef USE_DMA - volatile u32 *reg_drcmr; -#define drcmr(n) .reg_drcmr = & DRCMR ## n , -#else -#define drcmr(n) -#endif }; struct pxa2xx_request { @@ -85,7 +77,7 @@ struct pxa2xx_request { struct list_head queue; }; -enum ep0_state { +enum ep0_state { EP0_IDLE, EP0_IN_DATA_PHASE, EP0_OUT_DATA_PHASE, @@ -108,7 +100,6 @@ struct udc_stats { #ifdef CONFIG_USB_PXA2XX_SMALL /* when memory's tight, SMALL config saves code+data. */ -#undef USE_DMA #define PXA_UDC_NUM_ENDPOINTS 3 #endif @@ -144,37 +135,8 @@ struct pxa2xx_udc { #ifdef CONFIG_ARCH_LUBBOCK #include <asm/arch/lubbock.h> /* lubbock can also report usb connect/disconnect irqs */ - -#ifdef DEBUG -#define HEX_DISPLAY(n) if (machine_is_lubbock()) { LUB_HEXLED = (n); } #endif -#endif - -/*-------------------------------------------------------------------------*/ - -/* LEDs are only for debug */ -#ifndef HEX_DISPLAY -#define HEX_DISPLAY(n) do {} while(0) -#endif - -#ifdef DEBUG -#include <asm/leds.h> - -#define LED_CONNECTED_ON leds_event(led_green_on) -#define LED_CONNECTED_OFF do { \ - leds_event(led_green_off); \ - HEX_DISPLAY(0); \ - } while(0) -#endif - -#ifndef LED_CONNECTED_ON -#define LED_CONNECTED_ON do {} while(0) -#define LED_CONNECTED_OFF do {} while(0) -#endif - -/*-------------------------------------------------------------------------*/ - static struct pxa2xx_udc *the_controller; /*-------------------------------------------------------------------------*/ @@ -204,7 +166,7 @@ static const char *state_name[] = { # define UDC_DEBUG DBG_NORMAL #endif -static void __attribute__ ((__unused__)) +static void __maybe_unused dump_udccr(const char *label) { u32 udccr = UDCCR; @@ -220,7 +182,7 @@ dump_udccr(const char *label) (udccr & UDCCR_UDE) ? " ude" : ""); } -static void __attribute__ ((__unused__)) +static void __maybe_unused dump_udccs0(const char *label) { u32 udccs0 = UDCCS0; @@ -237,7 +199,7 @@ dump_udccs0(const char *label) (udccs0 & UDCCS0_OPR) ? " opr" : ""); } -static void __attribute__ ((__unused__)) +static void __maybe_unused dump_state(struct pxa2xx_udc *dev) { u32 tmp; diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 708657c8913..db1b2bfcee4 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -53,7 +53,7 @@ */ #if 0 -#define DEBUG(str,args...) do { \ +#define DBG(str,args...) do { \ if (rndis_debug) \ printk(KERN_DEBUG str , ## args ); \ } while (0) @@ -65,7 +65,7 @@ MODULE_PARM_DESC (rndis_debug, "enable debugging"); #else #define rndis_debug 0 -#define DEBUG(str,args...) do{}while(0) +#define DBG(str,args...) do{}while(0) #endif #define RNDIS_MAX_CONFIGS 1 @@ -183,9 +183,9 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, if (!resp) return -ENOMEM; if (buf_len && rndis_debug > 1) { - DEBUG("query OID %08x value, len %d:\n", OID, buf_len); + DBG("query OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) { - DEBUG ("%03d: %08x %08x %08x %08x\n", i, + DBG("%03d: %08x %08x %08x %08x\n", i, le32_to_cpu(get_unaligned((__le32 *) &buf[i])), le32_to_cpu(get_unaligned((__le32 *) @@ -207,7 +207,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_SUPPORTED_LIST: - DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__); + DBG("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__); length = sizeof (oid_supported_list); count = length / sizeof (u32); for (i = 0; i < count; i++) @@ -217,7 +217,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_HARDWARE_STATUS: - DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__); + DBG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__); /* Bogus question! * Hardware must be ready to receive high level protocols. * BTW: @@ -230,14 +230,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_MEDIA_SUPPORTED: - DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__); + DBG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__); *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); retval = 0; break; /* mandatory */ case OID_GEN_MEDIA_IN_USE: - DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__); + DBG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__); /* one medium, one transport... (maybe you do it better) */ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); retval = 0; @@ -245,7 +245,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_MAXIMUM_FRAME_SIZE: - DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__); + DBG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); @@ -256,7 +256,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_LINK_SPEED: if (rndis_debug > 1) - DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__); + DBG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__); if (rndis_per_dev_params [configNr].media_state == NDIS_MEDIA_STATE_DISCONNECTED) *outbuf = __constant_cpu_to_le32 (0); @@ -268,7 +268,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_TRANSMIT_BLOCK_SIZE: - DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__); + DBG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); @@ -278,7 +278,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_RECEIVE_BLOCK_SIZE: - DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__); + DBG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); @@ -288,7 +288,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_VENDOR_ID: - DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__); + DBG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__); *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].vendorID); retval = 0; @@ -296,7 +296,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_VENDOR_DESCRIPTION: - DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__); + DBG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__); length = strlen (rndis_per_dev_params [configNr].vendorDescr); memcpy (outbuf, rndis_per_dev_params [configNr].vendorDescr, length); @@ -304,7 +304,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_GEN_VENDOR_DRIVER_VERSION: - DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__); + DBG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__); /* Created as LE */ *outbuf = rndis_driver_version; retval = 0; @@ -312,14 +312,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_CURRENT_PACKET_FILTER: - DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__); + DBG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__); *outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter); retval = 0; break; /* mandatory */ case OID_GEN_MAXIMUM_TOTAL_SIZE: - DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__); + DBG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE); retval = 0; break; @@ -327,14 +327,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_MEDIA_CONNECT_STATUS: if (rndis_debug > 1) - DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__); + DBG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__); *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .media_state); retval = 0; break; case OID_GEN_PHYSICAL_MEDIUM: - DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__); + DBG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; @@ -344,7 +344,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, * versions emit undefined RNDIS messages. DOCUMENT ALL THESE! */ case OID_GEN_MAC_OPTIONS: /* from WinME */ - DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__); + DBG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32( NDIS_MAC_OPTION_RECEIVE_SERIALIZED | NDIS_MAC_OPTION_FULL_DUPLEX); @@ -356,7 +356,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_XMIT_OK: if (rndis_debug > 1) - DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__); + DBG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].stats->tx_packets - @@ -369,7 +369,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_RCV_OK: if (rndis_debug > 1) - DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__); + DBG("%s: OID_GEN_RCV_OK\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].stats->rx_packets - @@ -382,7 +382,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_XMIT_ERROR: if (rndis_debug > 1) - DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__); + DBG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_errors); @@ -393,7 +393,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_RCV_ERROR: if (rndis_debug > 1) - DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__); + DBG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_errors); @@ -403,7 +403,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_RCV_NO_BUFFER: - DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__); + DBG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_dropped); @@ -413,7 +413,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, #ifdef RNDIS_OPTIONAL_STATS case OID_GEN_DIRECTED_BYTES_XMIT: - DEBUG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__); + DBG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__); /* * Aunt Tilly's size of shoes * minus antarctica count of penguins @@ -433,7 +433,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_GEN_DIRECTED_FRAMES_XMIT: - DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__); + DBG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__); /* dito */ if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 ( @@ -449,7 +449,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_GEN_MULTICAST_BYTES_XMIT: - DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__); + DBG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast*1234); @@ -458,7 +458,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_GEN_MULTICAST_FRAMES_XMIT: - DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__); + DBG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast); @@ -467,7 +467,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_GEN_BROADCAST_BYTES_XMIT: - DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__); + DBG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_packets/42*255); @@ -476,7 +476,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_GEN_BROADCAST_FRAMES_XMIT: - DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__); + DBG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_packets/42); @@ -485,19 +485,19 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_GEN_DIRECTED_BYTES_RCV: - DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__); + DBG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; case OID_GEN_DIRECTED_FRAMES_RCV: - DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__); + DBG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; case OID_GEN_MULTICAST_BYTES_RCV: - DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__); + DBG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast * 1111); @@ -506,7 +506,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_GEN_MULTICAST_FRAMES_RCV: - DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__); + DBG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast); @@ -515,7 +515,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_GEN_BROADCAST_BYTES_RCV: - DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__); + DBG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_packets/42*255); @@ -524,7 +524,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_GEN_BROADCAST_FRAMES_RCV: - DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__); + DBG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_packets/42); @@ -533,7 +533,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_GEN_RCV_CRC_ERROR: - DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__); + DBG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_crc_errors); @@ -542,7 +542,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_GEN_TRANSMIT_QUEUE_LENGTH: - DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__); + DBG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; @@ -552,7 +552,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_802_3_PERMANENT_ADDRESS: - DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__); + DBG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { length = ETH_ALEN; memcpy (outbuf, @@ -564,7 +564,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_802_3_CURRENT_ADDRESS: - DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__); + DBG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { length = ETH_ALEN; memcpy (outbuf, @@ -576,7 +576,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_802_3_MULTICAST_LIST: - DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); + DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); /* Multicast base address only */ *outbuf = __constant_cpu_to_le32 (0xE0000000); retval = 0; @@ -584,21 +584,21 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_802_3_MAXIMUM_LIST_SIZE: - DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__); + DBG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__); /* Multicast base address only */ *outbuf = __constant_cpu_to_le32 (1); retval = 0; break; case OID_802_3_MAC_OPTIONS: - DEBUG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__); + DBG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__); break; /* ieee802.3 statistics OIDs (table 4-4) */ /* mandatory */ case OID_802_3_RCV_ERROR_ALIGNMENT: - DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__); + DBG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_frame_errors); @@ -608,51 +608,51 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_802_3_XMIT_ONE_COLLISION: - DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__); + DBG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; /* mandatory */ case OID_802_3_XMIT_MORE_COLLISIONS: - DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__); + DBG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; #ifdef RNDIS_OPTIONAL_STATS case OID_802_3_XMIT_DEFERRED: - DEBUG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__); + DBG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__); /* TODO */ break; case OID_802_3_XMIT_MAX_COLLISIONS: - DEBUG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__); + DBG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__); /* TODO */ break; case OID_802_3_RCV_OVERRUN: - DEBUG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__); + DBG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__); /* TODO */ break; case OID_802_3_XMIT_UNDERRUN: - DEBUG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__); + DBG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__); /* TODO */ break; case OID_802_3_XMIT_HEARTBEAT_FAILURE: - DEBUG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__); + DBG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__); /* TODO */ break; case OID_802_3_XMIT_TIMES_CRS_LOST: - DEBUG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__); + DBG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__); /* TODO */ break; case OID_802_3_XMIT_LATE_COLLISIONS: - DEBUG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__); + DBG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__); /* TODO */ break; #endif /* RNDIS_OPTIONAL_STATS */ @@ -660,7 +660,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, #ifdef RNDIS_PM /* power management OIDs (table 4-5) */ case OID_PNP_CAPABILITIES: - DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__); + DBG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__); /* for now, no wakeup capabilities */ length = sizeof (struct NDIS_PNP_CAPABILITIES); @@ -668,7 +668,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, retval = 0; break; case OID_PNP_QUERY_POWER: - DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__, + DBG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__, le32_to_cpu(get_unaligned((__le32 *)buf)) - 1); /* only suspend is a real power state, and * it can't be entered by OID_PNP_SET_POWER... @@ -705,9 +705,9 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, return -ENOMEM; if (buf_len && rndis_debug > 1) { - DEBUG("set OID %08x value, len %d:\n", OID, buf_len); + DBG("set OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) { - DEBUG ("%03d: %08x %08x %08x %08x\n", i, + DBG("%03d: %08x %08x %08x %08x\n", i, le32_to_cpu(get_unaligned((__le32 *) &buf[i])), le32_to_cpu(get_unaligned((__le32 *) @@ -731,7 +731,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, */ *params->filter = (u16) le32_to_cpu(get_unaligned( (__le32 *)buf)); - DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", + DBG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", __FUNCTION__, *params->filter); /* this call has a significant side effect: it's @@ -756,7 +756,7 @@ update_linkstate: case OID_802_3_MULTICAST_LIST: /* I think we can ignore this */ - DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); + DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); retval = 0; break; #if 0 @@ -764,7 +764,7 @@ update_linkstate: { struct rndis_config_parameter *param; param = (struct rndis_config_parameter *) buf; - DEBUG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n", + DBG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n", __FUNCTION__, min(cpu_to_le32(param->ParameterNameLength),80), buf + param->ParameterNameOffset); @@ -781,7 +781,7 @@ update_linkstate: * FIXME ... then things go batty; Windows wedges itself. */ i = le32_to_cpu(get_unaligned((__le32 *)buf)); - DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1); + DBG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1); switch (i) { case NdisDeviceStateD0: *params->filter = params->saved_filter; @@ -858,7 +858,7 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf) rndis_query_cmplt_type *resp; rndis_resp_t *r; - // DEBUG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID)); + // DBG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID)); if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP; /* @@ -911,15 +911,15 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf) BufOffset = le32_to_cpu (buf->InformationBufferOffset); #ifdef VERBOSE - DEBUG("%s: Length: %d\n", __FUNCTION__, BufLength); - DEBUG("%s: Offset: %d\n", __FUNCTION__, BufOffset); - DEBUG("%s: InfoBuffer: ", __FUNCTION__); + DBG("%s: Length: %d\n", __FUNCTION__, BufLength); + DBG("%s: Offset: %d\n", __FUNCTION__, BufOffset); + DBG("%s: InfoBuffer: ", __FUNCTION__); for (i = 0; i < BufLength; i++) { - DEBUG ("%02x ", *(((u8 *) buf) + i + 8 + BufOffset)); + DBG("%02x ", *(((u8 *) buf) + i + 8 + BufOffset)); } - DEBUG ("\n"); + DBG("\n"); #endif resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT); @@ -1082,14 +1082,14 @@ int rndis_msg_parser (u8 configNr, u8 *buf) /* For USB: responses may take up to 10 seconds */ switch (MsgType) { case REMOTE_NDIS_INITIALIZE_MSG: - DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", + DBG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", __FUNCTION__ ); params->state = RNDIS_INITIALIZED; return rndis_init_response (configNr, (rndis_init_msg_type *) buf); case REMOTE_NDIS_HALT_MSG: - DEBUG("%s: REMOTE_NDIS_HALT_MSG\n", + DBG("%s: REMOTE_NDIS_HALT_MSG\n", __FUNCTION__ ); params->state = RNDIS_UNINITIALIZED; if (params->dev) { @@ -1107,7 +1107,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf) (rndis_set_msg_type *) buf); case REMOTE_NDIS_RESET_MSG: - DEBUG("%s: REMOTE_NDIS_RESET_MSG\n", + DBG("%s: REMOTE_NDIS_RESET_MSG\n", __FUNCTION__ ); return rndis_reset_response (configNr, (rndis_reset_msg_type *) buf); @@ -1115,7 +1115,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf) case REMOTE_NDIS_KEEPALIVE_MSG: /* For USB: host does this every 5 seconds */ if (rndis_debug > 1) - DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", + DBG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", __FUNCTION__ ); return rndis_keepalive_response (configNr, (rndis_keepalive_msg_type *) @@ -1132,7 +1132,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf) { unsigned i; for (i = 0; i < MsgLength; i += 16) { - DEBUG ("%03d: " + DBG("%03d: " " %02x %02x %02x %02x" " %02x %02x %02x %02x" " %02x %02x %02x %02x" @@ -1163,18 +1163,18 @@ int rndis_register (int (* rndis_control_ack) (struct net_device *)) if (!rndis_per_dev_params [i].used) { rndis_per_dev_params [i].used = 1; rndis_per_dev_params [i].ack = rndis_control_ack; - DEBUG("%s: configNr = %d\n", __FUNCTION__, i); + DBG("%s: configNr = %d\n", __FUNCTION__, i); return i; } } - DEBUG("failed\n"); + DBG("failed\n"); return -1; } void rndis_deregister (int configNr) { - DEBUG("%s: \n", __FUNCTION__ ); + DBG("%s: \n", __FUNCTION__ ); if (configNr >= RNDIS_MAX_CONFIGS) return; rndis_per_dev_params [configNr].used = 0; @@ -1186,7 +1186,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev, struct net_device_stats *stats, u16 *cdc_filter) { - DEBUG("%s:\n", __FUNCTION__ ); + DBG("%s:\n", __FUNCTION__ ); if (!dev || !stats) return -1; if (configNr >= RNDIS_MAX_CONFIGS) return -1; @@ -1199,7 +1199,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev, int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr) { - DEBUG("%s:\n", __FUNCTION__ ); + DBG("%s:\n", __FUNCTION__ ); if (!vendorDescr) return -1; if (configNr >= RNDIS_MAX_CONFIGS) return -1; @@ -1211,7 +1211,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr) int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed) { - DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed); + DBG("%s: %u %u\n", __FUNCTION__, medium, speed); if (configNr >= RNDIS_MAX_CONFIGS) return -1; rndis_per_dev_params [configNr].medium = medium; @@ -1390,7 +1390,7 @@ static int rndis_proc_write (struct file *file, const char __user *buffer, break; default: if (fl_speed) p->speed = speed; - else DEBUG ("%c is not valid\n", c); + else DBG("%c is not valid\n", c); break; } @@ -1419,12 +1419,12 @@ int __devinit rndis_init (void) if (!(rndis_connect_state [i] = create_proc_entry (name, 0660, NULL))) { - DEBUG ("%s :remove entries", __FUNCTION__); + DBG("%s :remove entries", __FUNCTION__); while (i) { sprintf (name, NAME_TEMPLATE, --i); remove_proc_entry (name, NULL); } - DEBUG ("\n"); + DBG("\n"); return -EIO; } diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c new file mode 100644 index 00000000000..0be80c635c4 --- /dev/null +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -0,0 +1,2045 @@ +/* + * linux/drivers/usb/gadget/s3c2410_udc.c + * + * Samsung S3C24xx series on-chip full speed USB device controllers + * + * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard + * Additional cleanups by Ben Dooks <ben-linux@fluff.org> + * + * 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, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/version.h> +#include <linux/clk.h> + +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +#include <linux/usb.h> +#include <linux/usb_gadget.h> + +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/unaligned.h> +#include <asm/arch/irqs.h> + +#include <asm/arch/hardware.h> +#include <asm/arch/regs-clock.h> +#include <asm/arch/regs-gpio.h> +#include <asm/arch/regs-udc.h> +#include <asm/arch/udc.h> + +#include <asm/mach-types.h> + +#include "s3c2410_udc.h" + +#define DRIVER_DESC "S3C2410 USB Device Controller Gadget" +#define DRIVER_VERSION "29 Apr 2007" +#define DRIVER_AUTHOR "Herbert Pötzl <herbert@13thfloor.at>, " \ + "Arnaud Patard <arnaud.patard@rtp-net.org>" + +static const char gadget_name[] = "s3c2410_udc"; +static const char driver_desc[] = DRIVER_DESC; + +static struct s3c2410_udc *the_controller; +static struct clk *udc_clock; +static struct clk *usb_bus_clock; +static void __iomem *base_addr; +static u64 rsrc_start; +static u64 rsrc_len; +static struct dentry *s3c2410_udc_debugfs_root; + +static inline u32 udc_read(u32 reg) +{ + return readb(base_addr + reg); +} + +static inline void udc_write(u32 value, u32 reg) +{ + writeb(value, base_addr + reg); +} + +static inline void udc_writeb(void __iomem *base, u32 value, u32 reg) +{ + writeb(value, base + reg); +} + +static struct s3c2410_udc_mach_info *udc_info; + +/*************************** DEBUG FUNCTION ***************************/ +#define DEBUG_NORMAL 1 +#define DEBUG_VERBOSE 2 + +#ifdef CONFIG_USB_S3C2410_DEBUG +#define USB_S3C2410_DEBUG_LEVEL 0 + +static uint32_t s3c2410_ticks = 0; + +static int dprintk(int level, const char *fmt, ...) +{ + static char printk_buf[1024]; + static long prevticks; + static int invocation; + va_list args; + int len; + + if (level > USB_S3C2410_DEBUG_LEVEL) + return 0; + + if (s3c2410_ticks != prevticks) { + prevticks = s3c2410_ticks; + invocation = 0; + } + + len = scnprintf(printk_buf, + sizeof(printk_buf), "%1lu.%02d USB: ", + prevticks, invocation++); + + va_start(args, fmt); + len = vscnprintf(printk_buf+len, + sizeof(printk_buf)-len, fmt, args); + va_end(args); + + return printk(KERN_DEBUG "%s", printk_buf); +} +#else +static int dprintk(int level, const char *fmt, ...) +{ + return 0; +} +#endif +static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p) +{ + u32 addr_reg,pwr_reg,ep_int_reg,usb_int_reg; + u32 ep_int_en_reg, usb_int_en_reg, ep0_csr; + u32 ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2; + u32 ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2; + + addr_reg = udc_read(S3C2410_UDC_FUNC_ADDR_REG); + pwr_reg = udc_read(S3C2410_UDC_PWR_REG); + ep_int_reg = udc_read(S3C2410_UDC_EP_INT_REG); + usb_int_reg = udc_read(S3C2410_UDC_USB_INT_REG); + ep_int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG); + usb_int_en_reg = udc_read(S3C2410_UDC_USB_INT_EN_REG); + udc_write(0, S3C2410_UDC_INDEX_REG); + ep0_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); + udc_write(1, S3C2410_UDC_INDEX_REG); + ep1_i_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); + ep1_i_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); + ep1_o_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); + ep1_o_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); + udc_write(2, S3C2410_UDC_INDEX_REG); + ep2_i_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); + ep2_i_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); + ep2_o_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); + ep2_o_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); + + seq_printf(m, "FUNC_ADDR_REG : 0x%04X\n" + "PWR_REG : 0x%04X\n" + "EP_INT_REG : 0x%04X\n" + "USB_INT_REG : 0x%04X\n" + "EP_INT_EN_REG : 0x%04X\n" + "USB_INT_EN_REG : 0x%04X\n" + "EP0_CSR : 0x%04X\n" + "EP1_I_CSR1 : 0x%04X\n" + "EP1_I_CSR2 : 0x%04X\n" + "EP1_O_CSR1 : 0x%04X\n" + "EP1_O_CSR2 : 0x%04X\n" + "EP2_I_CSR1 : 0x%04X\n" + "EP2_I_CSR2 : 0x%04X\n" + "EP2_O_CSR1 : 0x%04X\n" + "EP2_O_CSR2 : 0x%04X\n", + addr_reg,pwr_reg,ep_int_reg,usb_int_reg, + ep_int_en_reg, usb_int_en_reg, ep0_csr, + ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2, + ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2 + ); + + return 0; +} + +static int s3c2410_udc_debugfs_fops_open(struct inode *inode, + struct file *file) +{ + return single_open(file, s3c2410_udc_debugfs_seq_show, NULL); +} + +static const struct file_operations s3c2410_udc_debugfs_fops = { + .open = s3c2410_udc_debugfs_fops_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +/* io macros */ + +static inline void s3c2410_udc_clear_ep0_opr(void __iomem *base) +{ + udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); + udc_writeb(base, S3C2410_UDC_EP0_CSR_SOPKTRDY, + S3C2410_UDC_EP0_CSR_REG); +} + +static inline void s3c2410_udc_clear_ep0_sst(void __iomem *base) +{ + udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); + writeb(0x00, base + S3C2410_UDC_EP0_CSR_REG); +} + +static inline void s3c2410_udc_clear_ep0_se(void __iomem *base) +{ + udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); + udc_writeb(base, S3C2410_UDC_EP0_CSR_SSE, S3C2410_UDC_EP0_CSR_REG); +} + +static inline void s3c2410_udc_set_ep0_ipr(void __iomem *base) +{ + udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); + udc_writeb(base, S3C2410_UDC_EP0_CSR_IPKRDY, S3C2410_UDC_EP0_CSR_REG); +} + +static inline void s3c2410_udc_set_ep0_de(void __iomem *base) +{ + udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); + udc_writeb(base, S3C2410_UDC_EP0_CSR_DE, S3C2410_UDC_EP0_CSR_REG); +} + +inline void s3c2410_udc_set_ep0_ss(void __iomem *b) +{ + udc_writeb(b, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); + udc_writeb(b, S3C2410_UDC_EP0_CSR_SENDSTL, S3C2410_UDC_EP0_CSR_REG); +} + +static inline void s3c2410_udc_set_ep0_de_out(void __iomem *base) +{ + udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); + + udc_writeb(base,(S3C2410_UDC_EP0_CSR_SOPKTRDY + | S3C2410_UDC_EP0_CSR_DE), + S3C2410_UDC_EP0_CSR_REG); +} + +static inline void s3c2410_udc_set_ep0_sse_out(void __iomem *base) +{ + udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); + udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY + | S3C2410_UDC_EP0_CSR_SSE), + S3C2410_UDC_EP0_CSR_REG); +} + +static inline void s3c2410_udc_set_ep0_de_in(void __iomem *base) +{ + udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); + udc_writeb(base, (S3C2410_UDC_EP0_CSR_IPKRDY + | S3C2410_UDC_EP0_CSR_DE), + S3C2410_UDC_EP0_CSR_REG); +} + +/*------------------------- I/O ----------------------------------*/ + +/* + * s3c2410_udc_done + */ +static void s3c2410_udc_done(struct s3c2410_ep *ep, + struct s3c2410_request *req, int status) +{ + unsigned halted = ep->halted; + + list_del_init(&req->queue); + + if (likely (req->req.status == -EINPROGRESS)) + req->req.status = status; + else + status = req->req.status; + + ep->halted = 1; + req->req.complete(&ep->ep, &req->req); + ep->halted = halted; +} + +static void s3c2410_udc_nuke(struct s3c2410_udc *udc, + struct s3c2410_ep *ep, int status) +{ + /* Sanity check */ + if (&ep->queue == NULL) + return; + + while (!list_empty (&ep->queue)) { + struct s3c2410_request *req; + req = list_entry (ep->queue.next, struct s3c2410_request, + queue); + s3c2410_udc_done(ep, req, status); + } +} + +static inline void s3c2410_udc_clear_ep_state(struct s3c2410_udc *dev) +{ + unsigned i; + + /* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint + * fifos, and pending transactions mustn't be continued in any case. + */ + + for (i = 1; i < S3C2410_ENDPOINTS; i++) + s3c2410_udc_nuke(dev, &dev->ep[i], -ECONNABORTED); +} + +static inline int s3c2410_udc_fifo_count_out(void) +{ + int tmp; + + tmp = udc_read(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8; + tmp |= udc_read(S3C2410_UDC_OUT_FIFO_CNT1_REG); + return tmp; +} + +/* + * s3c2410_udc_write_packet + */ +static inline int s3c2410_udc_write_packet(int fifo, + struct s3c2410_request *req, + unsigned max) +{ + unsigned len = min(req->req.length - req->req.actual, max); + u8 *buf = req->req.buf + req->req.actual; + + prefetch(buf); + + dprintk(DEBUG_VERBOSE, "%s %d %d %d %d\n", __func__, + req->req.actual, req->req.length, len, req->req.actual + len); + + req->req.actual += len; + + udelay(5); + writesb(base_addr + fifo, buf, len); + return len; +} + +/* + * s3c2410_udc_write_fifo + * + * return: 0 = still running, 1 = completed, negative = errno + */ +static int s3c2410_udc_write_fifo(struct s3c2410_ep *ep, + struct s3c2410_request *req) +{ + unsigned count; + int is_last; + u32 idx; + int fifo_reg; + u32 ep_csr; + + idx = ep->bEndpointAddress & 0x7F; + switch (idx) { + default: + idx = 0; + case 0: + fifo_reg = S3C2410_UDC_EP0_FIFO_REG; + break; + case 1: + fifo_reg = S3C2410_UDC_EP1_FIFO_REG; + break; + case 2: + fifo_reg = S3C2410_UDC_EP2_FIFO_REG; + break; + case 3: + fifo_reg = S3C2410_UDC_EP3_FIFO_REG; + break; + case 4: + fifo_reg = S3C2410_UDC_EP4_FIFO_REG; + break; + } + + count = s3c2410_udc_write_packet(fifo_reg, req, ep->ep.maxpacket); + + /* last packet is often short (sometimes a zlp) */ + if (count != ep->ep.maxpacket) + is_last = 1; + else if (req->req.length != req->req.actual || req->req.zero) + is_last = 0; + else + is_last = 2; + + /* Only ep0 debug messages are interesting */ + if (idx == 0) + dprintk(DEBUG_NORMAL, + "Written ep%d %d.%d of %d b [last %d,z %d]\n", + idx, count, req->req.actual, req->req.length, + is_last, req->req.zero); + + if (is_last) { + /* The order is important. It prevents sending 2 packets + * at the same time */ + + if (idx == 0) { + /* Reset signal => no need to say 'data sent' */ + if (! (udc_read(S3C2410_UDC_USB_INT_REG) + & S3C2410_UDC_USBINT_RESET)) + s3c2410_udc_set_ep0_de_in(base_addr); + ep->dev->ep0state=EP0_IDLE; + } else { + udc_write(idx, S3C2410_UDC_INDEX_REG); + ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); + udc_write(idx, S3C2410_UDC_INDEX_REG); + udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY, + S3C2410_UDC_IN_CSR1_REG); + } + + s3c2410_udc_done(ep, req, 0); + is_last = 1; + } else { + if (idx == 0) { + /* Reset signal => no need to say 'data sent' */ + if (! (udc_read(S3C2410_UDC_USB_INT_REG) + & S3C2410_UDC_USBINT_RESET)) + s3c2410_udc_set_ep0_ipr(base_addr); + } else { + udc_write(idx, S3C2410_UDC_INDEX_REG); + ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); + udc_write(idx, S3C2410_UDC_INDEX_REG); + udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY, + S3C2410_UDC_IN_CSR1_REG); + } + } + + return is_last; +} + +static inline int s3c2410_udc_read_packet(int fifo, u8 *buf, + struct s3c2410_request *req, unsigned avail) +{ + unsigned len; + + len = min(req->req.length - req->req.actual, avail); + req->req.actual += len; + + readsb(fifo + base_addr, buf, len); + return len; +} + +/* + * return: 0 = still running, 1 = queue empty, negative = errno + */ +static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep, + struct s3c2410_request *req) +{ + u8 *buf; + u32 ep_csr; + unsigned bufferspace; + int is_last=1; + unsigned avail; + int fifo_count = 0; + u32 idx; + int fifo_reg; + + idx = ep->bEndpointAddress & 0x7F; + + switch (idx) { + default: + idx = 0; + case 0: + fifo_reg = S3C2410_UDC_EP0_FIFO_REG; + break; + case 1: + fifo_reg = S3C2410_UDC_EP1_FIFO_REG; + break; + case 2: + fifo_reg = S3C2410_UDC_EP2_FIFO_REG; + break; + case 3: + fifo_reg = S3C2410_UDC_EP3_FIFO_REG; + break; + case 4: + fifo_reg = S3C2410_UDC_EP4_FIFO_REG; + break; + } + + if (!req->req.length) + return 1; + + buf = req->req.buf + req->req.actual; + bufferspace = req->req.length - req->req.actual; + if (!bufferspace) { + dprintk(DEBUG_NORMAL, "%s: buffer full!\n", __func__); + return -1; + } + + udc_write(idx, S3C2410_UDC_INDEX_REG); + + fifo_count = s3c2410_udc_fifo_count_out(); + dprintk(DEBUG_NORMAL, "%s fifo count : %d\n", __func__, fifo_count); + + if (fifo_count > ep->ep.maxpacket) + avail = ep->ep.maxpacket; + else + avail = fifo_count; + + fifo_count = s3c2410_udc_read_packet(fifo_reg, buf, req, avail); + + /* checking this with ep0 is not accurate as we already + * read a control request + **/ + if (idx != 0 && fifo_count < ep->ep.maxpacket) { + is_last = 1; + /* overflowed this request? flush extra data */ + if (fifo_count != avail) + req->req.status = -EOVERFLOW; + } else { + is_last = (req->req.length <= req->req.actual) ? 1 : 0; + } + + udc_write(idx, S3C2410_UDC_INDEX_REG); + fifo_count = s3c2410_udc_fifo_count_out(); + + /* Only ep0 debug messages are interesting */ + if (idx == 0) + dprintk(DEBUG_VERBOSE, "%s fifo count : %d [last %d]\n", + __func__, fifo_count,is_last); + + if (is_last) { + if (idx == 0) { + s3c2410_udc_set_ep0_de_out(base_addr); + ep->dev->ep0state = EP0_IDLE; + } else { + udc_write(idx, S3C2410_UDC_INDEX_REG); + ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG); + udc_write(idx, S3C2410_UDC_INDEX_REG); + udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY, + S3C2410_UDC_OUT_CSR1_REG); + } + + s3c2410_udc_done(ep, req, 0); + } else { + if (idx == 0) { + s3c2410_udc_clear_ep0_opr(base_addr); + } else { + udc_write(idx, S3C2410_UDC_INDEX_REG); + ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG); + udc_write(idx, S3C2410_UDC_INDEX_REG); + udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY, + S3C2410_UDC_OUT_CSR1_REG); + } + } + + return is_last; +} + +static int s3c2410_udc_read_fifo_crq(struct usb_ctrlrequest *crq) +{ + unsigned char *outbuf = (unsigned char*)crq; + int bytes_read = 0; + + udc_write(0, S3C2410_UDC_INDEX_REG); + + bytes_read = s3c2410_udc_fifo_count_out(); + + dprintk(DEBUG_NORMAL, "%s: fifo_count=%d\n", __func__, bytes_read); + + if (bytes_read > sizeof(struct usb_ctrlrequest)) + bytes_read = sizeof(struct usb_ctrlrequest); + + readsb(S3C2410_UDC_EP0_FIFO_REG + base_addr, outbuf, bytes_read); + + dprintk(DEBUG_VERBOSE, "%s: len=%d %02x:%02x {%x,%x,%x}\n", __func__, + bytes_read, crq->bRequest, crq->bRequestType, + crq->wValue, crq->wIndex, crq->wLength); + + return bytes_read; +} + +static int s3c2410_udc_get_status(struct s3c2410_udc *dev, + struct usb_ctrlrequest *crq) +{ + u16 status = 0; + u8 ep_num = crq->wIndex & 0x7F; + u8 is_in = crq->wIndex & USB_DIR_IN; + + switch (crq->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_INTERFACE: + break; + + case USB_RECIP_DEVICE: + status = dev->devstatus; + break; + + case USB_RECIP_ENDPOINT: + if (ep_num > 4 || crq->wLength > 2) + return 1; + + if (ep_num == 0) { + udc_write(0, S3C2410_UDC_INDEX_REG); + status = udc_read(S3C2410_UDC_IN_CSR1_REG); + status = status & S3C2410_UDC_EP0_CSR_SENDSTL; + } else { + udc_write(ep_num, S3C2410_UDC_INDEX_REG); + if (is_in) { + status = udc_read(S3C2410_UDC_IN_CSR1_REG); + status = status & S3C2410_UDC_ICSR1_SENDSTL; + } else { + status = udc_read(S3C2410_UDC_OUT_CSR1_REG); + status = status & S3C2410_UDC_OCSR1_SENDSTL; + } + } + + status = status ? 1 : 0; + break; + + default: + return 1; + } + + /* Seems to be needed to get it working. ouch :( */ + udelay(5); + udc_write(status & 0xFF, S3C2410_UDC_EP0_FIFO_REG); + udc_write(status >> 8, S3C2410_UDC_EP0_FIFO_REG); + s3c2410_udc_set_ep0_de_in(base_addr); + + return 0; +} +/*------------------------- usb state machine -------------------------------*/ +static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value); + +static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev, + struct s3c2410_ep *ep, + struct usb_ctrlrequest *crq, + u32 ep0csr) +{ + int len, ret, tmp; + + /* start control request? */ + if (!(ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY)) + return; + + s3c2410_udc_nuke(dev, ep, -EPROTO); + + len = s3c2410_udc_read_fifo_crq(crq); + if (len != sizeof(*crq)) { + dprintk(DEBUG_NORMAL, "setup begin: fifo READ ERROR" + " wanted %d bytes got %d. Stalling out...\n", + sizeof(*crq), len); + s3c2410_udc_set_ep0_ss(base_addr); + return; + } + + dprintk(DEBUG_NORMAL, "bRequest = %d bRequestType %d wLength = %d\n", + crq->bRequest, crq->bRequestType, crq->wLength); + + /* cope with automagic for some standard requests. */ + dev->req_std = (crq->bRequestType & USB_TYPE_MASK) + == USB_TYPE_STANDARD; + dev->req_config = 0; + dev->req_pending = 1; + + switch (crq->bRequest) { + case USB_REQ_SET_CONFIGURATION: + dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ... \n"); + + if (crq->bRequestType == USB_RECIP_DEVICE) { + dev->req_config = 1; + s3c2410_udc_set_ep0_de_out(base_addr); + } + break; + + case USB_REQ_SET_INTERFACE: + dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ... \n"); + + if (crq->bRequestType == USB_RECIP_INTERFACE) { + dev->req_config = 1; + s3c2410_udc_set_ep0_de_out(base_addr); + } + break; + + case USB_REQ_SET_ADDRESS: + dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ... \n"); + + if (crq->bRequestType == USB_RECIP_DEVICE) { + tmp = crq->wValue & 0x7F; + dev->address = tmp; + udc_write((tmp | S3C2410_UDC_FUNCADDR_UPDATE), + S3C2410_UDC_FUNC_ADDR_REG); + s3c2410_udc_set_ep0_de_out(base_addr); + return; + } + break; + + case USB_REQ_GET_STATUS: + dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ... \n"); + s3c2410_udc_clear_ep0_opr(base_addr); + + if (dev->req_std) { + if (!s3c2410_udc_get_status(dev, crq)) { + return; + } + } + break; + + case USB_REQ_CLEAR_FEATURE: + s3c2410_udc_clear_ep0_opr(base_addr); + + if (crq->bRequestType != USB_RECIP_ENDPOINT) + break; + + if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0) + break; + + s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 0); + s3c2410_udc_set_ep0_de_out(base_addr); + return; + + case USB_REQ_SET_FEATURE: + s3c2410_udc_clear_ep0_opr(base_addr); + + if (crq->bRequestType != USB_RECIP_ENDPOINT) + break; + + if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0) + break; + + s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 1); + s3c2410_udc_set_ep0_de_out(base_addr); + return; + + default: + s3c2410_udc_clear_ep0_opr(base_addr); + break; + } + + if (crq->bRequestType & USB_DIR_IN) + dev->ep0state = EP0_IN_DATA_PHASE; + else + dev->ep0state = EP0_OUT_DATA_PHASE; + + ret = dev->driver->setup(&dev->gadget, crq); + if (ret < 0) { + if (dev->req_config) { + dprintk(DEBUG_NORMAL, "config change %02x fail %d?\n", + crq->bRequest, ret); + return; + } + + if (ret == -EOPNOTSUPP) + dprintk(DEBUG_NORMAL, "Operation not supported\n"); + else + dprintk(DEBUG_NORMAL, + "dev->driver->setup failed. (%d)\n", ret); + + udelay(5); + s3c2410_udc_set_ep0_ss(base_addr); + s3c2410_udc_set_ep0_de_out(base_addr); + dev->ep0state = EP0_IDLE; + /* deferred i/o == no response yet */ + } else if (dev->req_pending) { + dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?\n"); + dev->req_pending=0; + } + + dprintk(DEBUG_VERBOSE, "ep0state %s\n", ep0states[dev->ep0state]); +} + +static void s3c2410_udc_handle_ep0(struct s3c2410_udc *dev) +{ + u32 ep0csr; + struct s3c2410_ep *ep = &dev->ep[0]; + struct s3c2410_request *req; + struct usb_ctrlrequest crq; + + if (list_empty(&ep->queue)) + req = NULL; + else + req = list_entry(ep->queue.next, struct s3c2410_request, queue); + + /* We make the assumption that S3C2410_UDC_IN_CSR1_REG equal to + * S3C2410_UDC_EP0_CSR_REG when index is zero */ + + udc_write(0, S3C2410_UDC_INDEX_REG); + ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG); + + dprintk(DEBUG_NORMAL, "ep0csr %x ep0state %s\n", + ep0csr, ep0states[dev->ep0state]); + + /* clear stall status */ + if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) { + s3c2410_udc_nuke(dev, ep, -EPIPE); + dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n"); + s3c2410_udc_clear_ep0_sst(base_addr); + dev->ep0state = EP0_IDLE; + return; + } + + /* clear setup end */ + if (ep0csr & S3C2410_UDC_EP0_CSR_SE) { + dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...\n"); + s3c2410_udc_nuke(dev, ep, 0); + s3c2410_udc_clear_ep0_se(base_addr); + dev->ep0state = EP0_IDLE; + } + + switch (dev->ep0state) { + case EP0_IDLE: + s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr); + break; + + case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ + dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n"); + if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) { + s3c2410_udc_write_fifo(ep, req); + } + break; + + case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ + dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n"); + if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req ) { + s3c2410_udc_read_fifo(ep,req); + } + break; + + case EP0_END_XFER: + dprintk(DEBUG_NORMAL, "EP0_END_XFER ... what now?\n"); + dev->ep0state = EP0_IDLE; + break; + + case EP0_STALL: + dprintk(DEBUG_NORMAL, "EP0_STALL ... what now?\n"); + dev->ep0state = EP0_IDLE; + break; + } +} + +/* + * handle_ep - Manage I/O endpoints + */ + +static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep) +{ + struct s3c2410_request *req; + int is_in = ep->bEndpointAddress & USB_DIR_IN; + u32 ep_csr1; + u32 idx; + + if (likely (!list_empty(&ep->queue))) + req = list_entry(ep->queue.next, + struct s3c2410_request, queue); + else + req = NULL; + + idx = ep->bEndpointAddress & 0x7F; + + if (is_in) { + udc_write(idx, S3C2410_UDC_INDEX_REG); + ep_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); + dprintk(DEBUG_VERBOSE, "ep%01d write csr:%02x %d\n", + idx, ep_csr1, req ? 1 : 0); + + if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) { + dprintk(DEBUG_VERBOSE, "st\n"); + udc_write(idx, S3C2410_UDC_INDEX_REG); + udc_write(ep_csr1 & ~S3C2410_UDC_ICSR1_SENTSTL, + S3C2410_UDC_IN_CSR1_REG); + return; + } + + if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req) { + s3c2410_udc_write_fifo(ep,req); + } + } else { + udc_write(idx, S3C2410_UDC_INDEX_REG); + ep_csr1 = udc_read(S3C2410_UDC_OUT_CSR1_REG); + dprintk(DEBUG_VERBOSE, "ep%01d rd csr:%02x\n", idx, ep_csr1); + + if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) { + udc_write(idx, S3C2410_UDC_INDEX_REG); + udc_write(ep_csr1 & ~S3C2410_UDC_OCSR1_SENTSTL, + S3C2410_UDC_OUT_CSR1_REG); + return; + } + + if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) { + s3c2410_udc_read_fifo(ep,req); + } + } +} + +#include <asm/arch/regs-irq.h> + +/* + * s3c2410_udc_irq - interrupt handler + */ +static irqreturn_t s3c2410_udc_irq(int irq, void *_dev) +{ + struct s3c2410_udc *dev = _dev; + int usb_status; + int usbd_status; + int pwr_reg; + int ep0csr; + int i; + u32 idx; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + + /* Driver connected ? */ + if (!dev->driver) { + /* Clear interrupts */ + udc_write(udc_read(S3C2410_UDC_USB_INT_REG), + S3C2410_UDC_USB_INT_REG); + udc_write(udc_read(S3C2410_UDC_EP_INT_REG), + S3C2410_UDC_EP_INT_REG); + } + + /* Save index */ + idx = udc_read(S3C2410_UDC_INDEX_REG); + + /* Read status registers */ + usb_status = udc_read(S3C2410_UDC_USB_INT_REG); + usbd_status = udc_read(S3C2410_UDC_EP_INT_REG); + pwr_reg = udc_read(S3C2410_UDC_PWR_REG); + + udc_writeb(base_addr, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); + ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG); + + dprintk(DEBUG_NORMAL, "usbs=%02x, usbds=%02x, pwr=%02x ep0csr=%02x\n", + usb_status, usbd_status, pwr_reg, ep0csr); + + /* + * Now, handle interrupts. There's two types : + * - Reset, Resume, Suspend coming -> usb_int_reg + * - EP -> ep_int_reg + */ + + /* RESET */ + if (usb_status & S3C2410_UDC_USBINT_RESET) { + /* two kind of reset : + * - reset start -> pwr reg = 8 + * - reset end -> pwr reg = 0 + **/ + dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %x\n", + ep0csr, pwr_reg); + + dev->gadget.speed = USB_SPEED_UNKNOWN; + udc_write(0x00, S3C2410_UDC_INDEX_REG); + udc_write((dev->ep[0].ep.maxpacket & 0x7ff) >> 3, + S3C2410_UDC_MAXP_REG); + dev->address = 0; + + dev->ep0state = EP0_IDLE; + dev->gadget.speed = USB_SPEED_FULL; + + /* clear interrupt */ + udc_write(S3C2410_UDC_USBINT_RESET, + S3C2410_UDC_USB_INT_REG); + + udc_write(idx, S3C2410_UDC_INDEX_REG); + spin_unlock_irqrestore(&dev->lock, flags); + return IRQ_HANDLED; + } + + /* RESUME */ + if (usb_status & S3C2410_UDC_USBINT_RESUME) { + dprintk(DEBUG_NORMAL, "USB resume\n"); + + /* clear interrupt */ + udc_write(S3C2410_UDC_USBINT_RESUME, + S3C2410_UDC_USB_INT_REG); + + if (dev->gadget.speed != USB_SPEED_UNKNOWN + && dev->driver + && dev->driver->resume) + dev->driver->resume(&dev->gadget); + } + + /* SUSPEND */ + if (usb_status & S3C2410_UDC_USBINT_SUSPEND) { + dprintk(DEBUG_NORMAL, "USB suspend\n"); + + /* clear interrupt */ + udc_write(S3C2410_UDC_USBINT_SUSPEND, + S3C2410_UDC_USB_INT_REG); + + if (dev->gadget.speed != USB_SPEED_UNKNOWN + && dev->driver + && dev->driver->suspend) + dev->driver->suspend(&dev->gadget); + + dev->ep0state = EP0_IDLE; + } + + /* EP */ + /* control traffic */ + /* check on ep0csr != 0 is not a good idea as clearing in_pkt_ready + * generate an interrupt + */ + if (usbd_status & S3C2410_UDC_INT_EP0) { + dprintk(DEBUG_VERBOSE, "USB ep0 irq\n"); + /* Clear the interrupt bit by setting it to 1 */ + udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG); + s3c2410_udc_handle_ep0(dev); + } + + /* endpoint data transfers */ + for (i = 1; i < S3C2410_ENDPOINTS; i++) { + u32 tmp = 1 << i; + if (usbd_status & tmp) { + dprintk(DEBUG_VERBOSE, "USB ep%d irq\n", i); + + /* Clear the interrupt bit by setting it to 1 */ + udc_write(tmp, S3C2410_UDC_EP_INT_REG); + s3c2410_udc_handle_ep(&dev->ep[i]); + } + } + + dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", irq); + + /* Restore old index */ + udc_write(idx, S3C2410_UDC_INDEX_REG); + + spin_unlock_irqrestore(&dev->lock, flags); + + return IRQ_HANDLED; +} +/*------------------------- s3c2410_ep_ops ----------------------------------*/ + +static inline struct s3c2410_ep *to_s3c2410_ep(struct usb_ep *ep) +{ + return container_of(ep, struct s3c2410_ep, ep); +} + +static inline struct s3c2410_udc *to_s3c2410_udc(struct usb_gadget *gadget) +{ + return container_of(gadget, struct s3c2410_udc, gadget); +} + +static inline struct s3c2410_request *to_s3c2410_req(struct usb_request *req) +{ + return container_of(req, struct s3c2410_request, req); +} + +/* + * s3c2410_udc_ep_enable + */ +static int s3c2410_udc_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct s3c2410_udc *dev; + struct s3c2410_ep *ep; + u32 max, tmp; + unsigned long flags; + u32 csr1,csr2; + u32 int_en_reg; + + ep = to_s3c2410_ep(_ep); + + if (!_ep || !desc || ep->desc + || _ep->name == ep0name + || desc->bDescriptorType != USB_DT_ENDPOINT) + return -EINVAL; + + dev = ep->dev; + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff; + + local_irq_save (flags); + _ep->maxpacket = max & 0x7ff; + ep->desc = desc; + ep->halted = 0; + ep->bEndpointAddress = desc->bEndpointAddress; + + /* set max packet */ + udc_write(ep->num, S3C2410_UDC_INDEX_REG); + udc_write(max >> 3, S3C2410_UDC_MAXP_REG); + + /* set type, direction, address; reset fifo counters */ + if (desc->bEndpointAddress & USB_DIR_IN) { + csr1 = S3C2410_UDC_ICSR1_FFLUSH|S3C2410_UDC_ICSR1_CLRDT; + csr2 = S3C2410_UDC_ICSR2_MODEIN|S3C2410_UDC_ICSR2_DMAIEN; + + udc_write(ep->num, S3C2410_UDC_INDEX_REG); + udc_write(csr1, S3C2410_UDC_IN_CSR1_REG); + udc_write(ep->num, S3C2410_UDC_INDEX_REG); + udc_write(csr2, S3C2410_UDC_IN_CSR2_REG); + } else { + /* don't flush in fifo or it will cause endpoint interrupt */ + csr1 = S3C2410_UDC_ICSR1_CLRDT; + csr2 = S3C2410_UDC_ICSR2_DMAIEN; + + udc_write(ep->num, S3C2410_UDC_INDEX_REG); + udc_write(csr1, S3C2410_UDC_IN_CSR1_REG); + udc_write(ep->num, S3C2410_UDC_INDEX_REG); + udc_write(csr2, S3C2410_UDC_IN_CSR2_REG); + + csr1 = S3C2410_UDC_OCSR1_FFLUSH | S3C2410_UDC_OCSR1_CLRDT; + csr2 = S3C2410_UDC_OCSR2_DMAIEN; + + udc_write(ep->num, S3C2410_UDC_INDEX_REG); + udc_write(csr1, S3C2410_UDC_OUT_CSR1_REG); + udc_write(ep->num, S3C2410_UDC_INDEX_REG); + udc_write(csr2, S3C2410_UDC_OUT_CSR2_REG); + } + + /* enable irqs */ + int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG); + udc_write(int_en_reg | (1 << ep->num), S3C2410_UDC_EP_INT_EN_REG); + + /* print some debug message */ + tmp = desc->bEndpointAddress; + dprintk (DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n", + _ep->name,ep->num, tmp, + desc->bEndpointAddress & USB_DIR_IN ? "in" : "out", max); + + local_irq_restore (flags); + s3c2410_udc_set_halt(_ep, 0); + + return 0; +} + +/* + * s3c2410_udc_ep_disable + */ +static int s3c2410_udc_ep_disable(struct usb_ep *_ep) +{ + struct s3c2410_ep *ep = to_s3c2410_ep(_ep); + unsigned long flags; + u32 int_en_reg; + + if (!_ep || !ep->desc) { + dprintk(DEBUG_NORMAL, "%s not enabled\n", + _ep ? ep->ep.name : NULL); + return -EINVAL; + } + + local_irq_save(flags); + + dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name); + + ep->desc = NULL; + ep->halted = 1; + + s3c2410_udc_nuke (ep->dev, ep, -ESHUTDOWN); + + /* disable irqs */ + int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG); + udc_write(int_en_reg & ~(1<<ep->num), S3C2410_UDC_EP_INT_EN_REG); + + local_irq_restore(flags); + + dprintk(DEBUG_NORMAL, "%s disabled\n", _ep->name); + + return 0; +} + +/* + * s3c2410_udc_alloc_request + */ +static struct usb_request * +s3c2410_udc_alloc_request(struct usb_ep *_ep, gfp_t mem_flags) +{ + struct s3c2410_request *req; + + dprintk(DEBUG_VERBOSE,"%s(%p,%d)\n", __func__, _ep, mem_flags); + + if (!_ep) + return NULL; + + req = kzalloc (sizeof(struct s3c2410_request), mem_flags); + if (!req) + return NULL; + + INIT_LIST_HEAD (&req->queue); + return &req->req; +} + +/* + * s3c2410_udc_free_request + */ +static void +s3c2410_udc_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct s3c2410_ep *ep = to_s3c2410_ep(_ep); + struct s3c2410_request *req = to_s3c2410_req(_req); + + dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req); + + if (!ep || !_req || (!ep->desc && _ep->name != ep0name)) + return; + + WARN_ON (!list_empty (&req->queue)); + kfree(req); +} + +/* + * s3c2410_udc_queue + */ +static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req, + gfp_t gfp_flags) +{ + struct s3c2410_request *req = to_s3c2410_req(_req); + struct s3c2410_ep *ep = to_s3c2410_ep(_ep); + struct s3c2410_udc *dev; + u32 ep_csr = 0; + int fifo_count = 0; + unsigned long flags; + + if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { + dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__); + return -EINVAL; + } + + dev = ep->dev; + if (unlikely (!dev->driver + || dev->gadget.speed == USB_SPEED_UNKNOWN)) { + return -ESHUTDOWN; + } + + local_irq_save (flags); + + if (unlikely(!_req || !_req->complete + || !_req->buf || !list_empty(&req->queue))) { + if (!_req) + dprintk(DEBUG_NORMAL, "%s: 1 X X X\n", __func__); + else { + dprintk(DEBUG_NORMAL, "%s: 0 %01d %01d %01d\n", + __func__, !_req->complete,!_req->buf, + !list_empty(&req->queue)); + } + + local_irq_restore(flags); + return -EINVAL; + } + + _req->status = -EINPROGRESS; + _req->actual = 0; + + dprintk(DEBUG_VERBOSE, "%s: ep%x len %d\n", + __func__, ep->bEndpointAddress, _req->length); + + if (ep->bEndpointAddress) { + udc_write(ep->bEndpointAddress & 0x7F, S3C2410_UDC_INDEX_REG); + + ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN) + ? S3C2410_UDC_IN_CSR1_REG + : S3C2410_UDC_OUT_CSR1_REG); + fifo_count = s3c2410_udc_fifo_count_out(); + } else { + udc_write(0, S3C2410_UDC_INDEX_REG); + ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); + fifo_count = s3c2410_udc_fifo_count_out(); + } + + /* kickstart this i/o queue? */ + if (list_empty(&ep->queue) && !ep->halted) { + if (ep->bEndpointAddress == 0 /* ep0 */) { + switch (dev->ep0state) { + case EP0_IN_DATA_PHASE: + if (!(ep_csr&S3C2410_UDC_EP0_CSR_IPKRDY) + && s3c2410_udc_write_fifo(ep, + req)) { + dev->ep0state = EP0_IDLE; + req = NULL; + } + break; + + case EP0_OUT_DATA_PHASE: + if ((!_req->length) + || ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY) + && s3c2410_udc_read_fifo(ep, + req))) { + dev->ep0state = EP0_IDLE; + req = NULL; + } + break; + + default: + local_irq_restore(flags); + return -EL2HLT; + } + } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0 + && (!(ep_csr&S3C2410_UDC_OCSR1_PKTRDY)) + && s3c2410_udc_write_fifo(ep, req)) { + req = NULL; + } else if ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY) + && fifo_count + && s3c2410_udc_read_fifo(ep, req)) { + req = NULL; + } + } + + /* pio or dma irq handler advances the queue. */ + if (likely (req != 0)) + list_add_tail(&req->queue, &ep->queue); + + local_irq_restore(flags); + + dprintk(DEBUG_VERBOSE, "%s ok\n", __func__); + return 0; +} + +/* + * s3c2410_udc_dequeue + */ +static int s3c2410_udc_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct s3c2410_ep *ep = to_s3c2410_ep(_ep); + struct s3c2410_udc *udc; + int retval = -EINVAL; + unsigned long flags; + struct s3c2410_request *req = NULL; + + dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req); + + if (!the_controller->driver) + return -ESHUTDOWN; + + if (!_ep || !_req) + return retval; + + udc = to_s3c2410_udc(ep->gadget); + + local_irq_save (flags); + + list_for_each_entry (req, &ep->queue, queue) { + if (&req->req == _req) { + list_del_init (&req->queue); + _req->status = -ECONNRESET; + retval = 0; + break; + } + } + + if (retval == 0) { + dprintk(DEBUG_VERBOSE, + "dequeued req %p from %s, len %d buf %p\n", + req, _ep->name, _req->length, _req->buf); + + s3c2410_udc_done(ep, req, -ECONNRESET); + } + + local_irq_restore (flags); + return retval; +} + +/* + * s3c2410_udc_set_halt + */ +static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value) +{ + struct s3c2410_ep *ep = to_s3c2410_ep(_ep); + u32 ep_csr = 0; + unsigned long flags; + u32 idx; + + if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { + dprintk(DEBUG_NORMAL, "%s: inval 2\n", __func__); + return -EINVAL; + } + + local_irq_save (flags); + + idx = ep->bEndpointAddress & 0x7F; + + if (idx == 0) { + s3c2410_udc_set_ep0_ss(base_addr); + s3c2410_udc_set_ep0_de_out(base_addr); + } else { + udc_write(idx, S3C2410_UDC_INDEX_REG); + ep_csr = udc_read((ep->bEndpointAddress &USB_DIR_IN) + ? S3C2410_UDC_IN_CSR1_REG + : S3C2410_UDC_OUT_CSR1_REG); + + if ((ep->bEndpointAddress & USB_DIR_IN) != 0) { + if (value) + udc_write(ep_csr | S3C2410_UDC_ICSR1_SENDSTL, + S3C2410_UDC_IN_CSR1_REG); + else { + ep_csr &= ~S3C2410_UDC_ICSR1_SENDSTL; + udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG); + ep_csr |= S3C2410_UDC_ICSR1_CLRDT; + udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG); + } + } else { + if (value) + udc_write(ep_csr | S3C2410_UDC_OCSR1_SENDSTL, + S3C2410_UDC_OUT_CSR1_REG); + else { + ep_csr &= ~S3C2410_UDC_OCSR1_SENDSTL; + udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG); + ep_csr |= S3C2410_UDC_OCSR1_CLRDT; + udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG); + } + } + } + + ep->halted = value ? 1 : 0; + local_irq_restore (flags); + + return 0; +} + +static const struct usb_ep_ops s3c2410_ep_ops = { + .enable = s3c2410_udc_ep_enable, + .disable = s3c2410_udc_ep_disable, + + .alloc_request = s3c2410_udc_alloc_request, + .free_request = s3c2410_udc_free_request, + + .queue = s3c2410_udc_queue, + .dequeue = s3c2410_udc_dequeue, + + .set_halt = s3c2410_udc_set_halt, +}; + +/*------------------------- usb_gadget_ops ----------------------------------*/ + +/* + * s3c2410_udc_get_frame + */ +static int s3c2410_udc_get_frame(struct usb_gadget *_gadget) +{ + int tmp; + + dprintk(DEBUG_VERBOSE, "%s()\n", __func__); + + tmp = udc_read(S3C2410_UDC_FRAME_NUM2_REG) << 8; + tmp |= udc_read(S3C2410_UDC_FRAME_NUM1_REG); + return tmp; +} + +/* + * s3c2410_udc_wakeup + */ +static int s3c2410_udc_wakeup(struct usb_gadget *_gadget) +{ + dprintk(DEBUG_NORMAL, "%s()\n", __func__); + return 0; +} + +/* + * s3c2410_udc_set_selfpowered + */ +static int s3c2410_udc_set_selfpowered(struct usb_gadget *gadget, int value) +{ + struct s3c2410_udc *udc = to_s3c2410_udc(gadget); + + dprintk(DEBUG_NORMAL, "%s()\n", __func__); + + if (value) + udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED); + else + udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); + + return 0; +} + +static void s3c2410_udc_disable(struct s3c2410_udc *dev); +static void s3c2410_udc_enable(struct s3c2410_udc *dev); + +static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on) +{ + dprintk(DEBUG_NORMAL, "%s()\n", __func__); + + if (udc_info && udc_info->udc_command) { + if (is_on) + s3c2410_udc_enable(udc); + else { + if (udc->gadget.speed != USB_SPEED_UNKNOWN) { + if (udc->driver && udc->driver->disconnect) + udc->driver->disconnect(&udc->gadget); + + } + s3c2410_udc_disable(udc); + } + } + else + return -EOPNOTSUPP; + + return 0; +} + +static int s3c2410_udc_vbus_session(struct usb_gadget *gadget, int is_active) +{ + struct s3c2410_udc *udc = to_s3c2410_udc(gadget); + + dprintk(DEBUG_NORMAL, "%s()\n", __func__); + + udc->vbus = (is_active != 0); + s3c2410_udc_set_pullup(udc, is_active); + return 0; +} + +static int s3c2410_udc_pullup(struct usb_gadget *gadget, int is_on) +{ + struct s3c2410_udc *udc = to_s3c2410_udc(gadget); + + dprintk(DEBUG_NORMAL, "%s()\n", __func__); + + s3c2410_udc_set_pullup(udc, is_on ? 0 : 1); + return 0; +} + +static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev) +{ + struct s3c2410_udc *dev = _dev; + unsigned int value; + + dprintk(DEBUG_NORMAL, "%s()\n", __func__); + value = s3c2410_gpio_getpin(udc_info->vbus_pin); + + if (udc_info->vbus_pin_inverted) + value = !value; + + if (value != dev->vbus) + s3c2410_udc_vbus_session(&dev->gadget, value); + + return IRQ_HANDLED; +} + +static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma) +{ + dprintk(DEBUG_NORMAL, "%s()\n", __func__); + + if (udc_info && udc_info->vbus_draw) { + udc_info->vbus_draw(ma); + return 0; + } + + return -ENOTSUPP; +} + +static const struct usb_gadget_ops s3c2410_ops = { + .get_frame = s3c2410_udc_get_frame, + .wakeup = s3c2410_udc_wakeup, + .set_selfpowered = s3c2410_udc_set_selfpowered, + .pullup = s3c2410_udc_pullup, + .vbus_session = s3c2410_udc_vbus_session, + .vbus_draw = s3c2410_vbus_draw, +}; + +/*------------------------- gadget driver handling---------------------------*/ +/* + * s3c2410_udc_disable + */ +static void s3c2410_udc_disable(struct s3c2410_udc *dev) +{ + dprintk(DEBUG_NORMAL, "%s()\n", __func__); + + /* Disable all interrupts */ + udc_write(0x00, S3C2410_UDC_USB_INT_EN_REG); + udc_write(0x00, S3C2410_UDC_EP_INT_EN_REG); + + /* Clear the interrupt registers */ + udc_write(S3C2410_UDC_USBINT_RESET + | S3C2410_UDC_USBINT_RESUME + | S3C2410_UDC_USBINT_SUSPEND, + S3C2410_UDC_USB_INT_REG); + + udc_write(0x1F, S3C2410_UDC_EP_INT_REG); + + /* Good bye, cruel world */ + if (udc_info && udc_info->udc_command) + udc_info->udc_command(S3C2410_UDC_P_DISABLE); + + /* Set speed to unknown */ + dev->gadget.speed = USB_SPEED_UNKNOWN; +} + +/* + * s3c2410_udc_reinit + */ +static void s3c2410_udc_reinit(struct s3c2410_udc *dev) +{ + u32 i; + + /* device/ep0 records init */ + INIT_LIST_HEAD (&dev->gadget.ep_list); + INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); + dev->ep0state = EP0_IDLE; + + for (i = 0; i < S3C2410_ENDPOINTS; i++) { + struct s3c2410_ep *ep = &dev->ep[i]; + + if (i != 0) + list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); + + ep->dev = dev; + ep->desc = NULL; + ep->halted = 0; + INIT_LIST_HEAD (&ep->queue); + } +} + +/* + * s3c2410_udc_enable + */ +static void s3c2410_udc_enable(struct s3c2410_udc *dev) +{ + int i; + + dprintk(DEBUG_NORMAL, "s3c2410_udc_enable called\n"); + + /* dev->gadget.speed = USB_SPEED_UNKNOWN; */ + dev->gadget.speed = USB_SPEED_FULL; + + /* Set MAXP for all endpoints */ + for (i = 0; i < S3C2410_ENDPOINTS; i++) { + udc_write(i, S3C2410_UDC_INDEX_REG); + udc_write((dev->ep[i].ep.maxpacket & 0x7ff) >> 3, + S3C2410_UDC_MAXP_REG); + } + + /* Set default power state */ + udc_write(DEFAULT_POWER_STATE, S3C2410_UDC_PWR_REG); + + /* Enable reset and suspend interrupt interrupts */ + udc_write(S3C2410_UDC_USBINT_RESET | S3C2410_UDC_USBINT_SUSPEND, + S3C2410_UDC_USB_INT_EN_REG); + + /* Enable ep0 interrupt */ + udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG); + + /* time to say "hello, world" */ + if (udc_info && udc_info->udc_command) + udc_info->udc_command(S3C2410_UDC_P_ENABLE); +} + +/* + * usb_gadget_register_driver + */ +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct s3c2410_udc *udc = the_controller; + int retval; + + dprintk(DEBUG_NORMAL, "usb_gadget_register_driver() '%s'\n", + driver->driver.name); + + /* Sanity checks */ + if (!udc) + return -ENODEV; + + if (udc->driver) + return -EBUSY; + + if (!driver->bind || !driver->setup + || driver->speed != USB_SPEED_FULL) { + printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n", + driver->bind, driver->setup, driver->speed); + return -EINVAL; + } +#if defined(MODULE) + if (!driver->unbind) { + printk(KERN_ERR "Invalid driver: no unbind method\n"); + return -EINVAL; + } +#endif + + /* Hook the driver */ + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + + /* Bind the driver */ + if ((retval = device_add(&udc->gadget.dev)) != 0) { + printk(KERN_ERR "Error in device_add() : %d\n",retval); + goto register_error; + } + + dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n", + driver->driver.name); + + if ((retval = driver->bind (&udc->gadget)) != 0) { + device_del(&udc->gadget.dev); + goto register_error; + } + + /* Enable udc */ + s3c2410_udc_enable(udc); + + return 0; + +register_error: + udc->driver = NULL; + udc->gadget.dev.driver = NULL; + return retval; +} + +/* + * usb_gadget_unregister_driver + */ +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct s3c2410_udc *udc = the_controller; + + if (!udc) + return -ENODEV; + + if (!driver || driver != udc->driver || !driver->unbind) + return -EINVAL; + + dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n", + driver->driver.name); + + if (driver->disconnect) + driver->disconnect(&udc->gadget); + + device_del(&udc->gadget.dev); + udc->driver = NULL; + + /* Disable udc */ + s3c2410_udc_disable(udc); + + return 0; +} + +/*---------------------------------------------------------------------------*/ +static struct s3c2410_udc memory = { + .gadget = { + .ops = &s3c2410_ops, + .ep0 = &memory.ep[0].ep, + .name = gadget_name, + .dev = { + .bus_id = "gadget", + }, + }, + + /* control endpoint */ + .ep[0] = { + .num = 0, + .ep = { + .name = ep0name, + .ops = &s3c2410_ep_ops, + .maxpacket = EP0_FIFO_SIZE, + }, + .dev = &memory, + }, + + /* first group of endpoints */ + .ep[1] = { + .num = 1, + .ep = { + .name = "ep1-bulk", + .ops = &s3c2410_ep_ops, + .maxpacket = EP_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = EP_FIFO_SIZE, + .bEndpointAddress = 1, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + }, + .ep[2] = { + .num = 2, + .ep = { + .name = "ep2-bulk", + .ops = &s3c2410_ep_ops, + .maxpacket = EP_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = EP_FIFO_SIZE, + .bEndpointAddress = 2, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + }, + .ep[3] = { + .num = 3, + .ep = { + .name = "ep3-bulk", + .ops = &s3c2410_ep_ops, + .maxpacket = EP_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = EP_FIFO_SIZE, + .bEndpointAddress = 3, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + }, + .ep[4] = { + .num = 4, + .ep = { + .name = "ep4-bulk", + .ops = &s3c2410_ep_ops, + .maxpacket = EP_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = EP_FIFO_SIZE, + .bEndpointAddress = 4, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + } + +}; + +/* + * probe - binds to the platform device + */ +static int s3c2410_udc_probe(struct platform_device *pdev) +{ + struct s3c2410_udc *udc = &memory; + struct device *dev = &pdev->dev; + int retval; + unsigned int irq; + + dev_dbg(dev, "%s()\n", __func__); + + usb_bus_clock = clk_get(NULL, "usb-bus-gadget"); + if (IS_ERR(usb_bus_clock)) { + dev_err(dev, "failed to get usb bus clock source\n"); + return PTR_ERR(usb_bus_clock); + } + + clk_enable(usb_bus_clock); + + udc_clock = clk_get(NULL, "usb-device"); + if (IS_ERR(udc_clock)) { + dev_err(dev, "failed to get udc clock source\n"); + return PTR_ERR(udc_clock); + } + + clk_enable(udc_clock); + + mdelay(10); + + dev_dbg(dev, "got and enabled clocks\n"); + + if (strncmp(pdev->name, "s3c2440", 7) == 0) { + dev_info(dev, "S3C2440: increasing FIFO to 128 bytes\n"); + memory.ep[1].fifo_size = S3C2440_EP_FIFO_SIZE; + memory.ep[2].fifo_size = S3C2440_EP_FIFO_SIZE; + memory.ep[3].fifo_size = S3C2440_EP_FIFO_SIZE; + memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE; + } + + spin_lock_init (&udc->lock); + udc_info = pdev->dev.platform_data; + + rsrc_start = S3C2410_PA_USBDEV; + rsrc_len = S3C24XX_SZ_USBDEV; + + if (!request_mem_region(rsrc_start, rsrc_len, gadget_name)) + return -EBUSY; + + base_addr = ioremap(rsrc_start, rsrc_len); + if (!base_addr) { + retval = -ENOMEM; + goto err_mem; + } + + device_initialize(&udc->gadget.dev); + udc->gadget.dev.parent = &pdev->dev; + udc->gadget.dev.dma_mask = pdev->dev.dma_mask; + + the_controller = udc; + platform_set_drvdata(pdev, udc); + + s3c2410_udc_disable(udc); + s3c2410_udc_reinit(udc); + + /* irq setup after old hardware state is cleaned up */ + retval = request_irq(IRQ_USBD, s3c2410_udc_irq, + IRQF_DISABLED, gadget_name, udc); + + if (retval != 0) { + dev_err(dev, "cannot get irq %i, err %d\n", IRQ_USBD, retval); + retval = -EBUSY; + goto err_map; + } + + dev_dbg(dev, "got irq %i\n", IRQ_USBD); + + if (udc_info && udc_info->vbus_pin > 0) { + irq = s3c2410_gpio_getirq(udc_info->vbus_pin); + retval = request_irq(irq, s3c2410_udc_vbus_irq, + IRQF_DISABLED | IRQF_TRIGGER_RISING + | IRQF_TRIGGER_FALLING, + gadget_name, udc); + + if (retval != 0) { + dev_err(dev, "can't get vbus irq %i, err %d\n", + irq, retval); + retval = -EBUSY; + goto err_int; + } + + dev_dbg(dev, "got irq %i\n", irq); + } else { + udc->vbus = 1; + } + + if (s3c2410_udc_debugfs_root) { + udc->regs_info = debugfs_create_file("registers", S_IRUGO, + s3c2410_udc_debugfs_root, + udc, &s3c2410_udc_debugfs_fops); + if (IS_ERR(udc->regs_info)) { + dev_warn(dev, "debugfs file creation failed %ld\n", + PTR_ERR(udc->regs_info)); + udc->regs_info = NULL; + } + } + + dev_dbg(dev, "probe ok\n"); + + return 0; + +err_int: + free_irq(IRQ_USBD, udc); +err_map: + iounmap(base_addr); +err_mem: + release_mem_region(rsrc_start, rsrc_len); + + return retval; +} + +/* + * s3c2410_udc_remove + */ +static int s3c2410_udc_remove(struct platform_device *pdev) +{ + struct s3c2410_udc *udc = platform_get_drvdata(pdev); + unsigned int irq; + + dev_dbg(&pdev->dev, "%s()\n", __func__); + if (udc->driver) + return -EBUSY; + + debugfs_remove(udc->regs_info); + + if (udc_info && udc_info->vbus_pin > 0) { + irq = s3c2410_gpio_getirq(udc_info->vbus_pin); + free_irq(irq, udc); + } + + free_irq(IRQ_USBD, udc); + + iounmap(base_addr); + release_mem_region(rsrc_start, rsrc_len); + + platform_set_drvdata(pdev, NULL); + + if (!IS_ERR(udc_clock) && udc_clock != NULL) { + clk_disable(udc_clock); + clk_put(udc_clock); + udc_clock = NULL; + } + + if (!IS_ERR(usb_bus_clock) && usb_bus_clock != NULL) { + clk_disable(usb_bus_clock); + clk_put(usb_bus_clock); + usb_bus_clock = NULL; + } + + dev_dbg(&pdev->dev, "%s: remove ok\n", __func__); + return 0; +} + +#ifdef CONFIG_PM +static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message) +{ + if (udc_info && udc_info->udc_command) + udc_info->udc_command(S3C2410_UDC_P_DISABLE); + + return 0; +} + +static int s3c2410_udc_resume(struct platform_device *pdev) +{ + if (udc_info && udc_info->udc_command) + udc_info->udc_command(S3C2410_UDC_P_ENABLE); + + return 0; +} +#else +#define s3c2410_udc_suspend NULL +#define s3c2410_udc_resume NULL +#endif + +static struct platform_driver udc_driver_2410 = { + .driver = { + .name = "s3c2410-usbgadget", + .owner = THIS_MODULE, + }, + .probe = s3c2410_udc_probe, + .remove = s3c2410_udc_remove, + .suspend = s3c2410_udc_suspend, + .resume = s3c2410_udc_resume, +}; + +static struct platform_driver udc_driver_2440 = { + .driver = { + .name = "s3c2440-usbgadget", + .owner = THIS_MODULE, + }, + .probe = s3c2410_udc_probe, + .remove = s3c2410_udc_remove, + .suspend = s3c2410_udc_suspend, + .resume = s3c2410_udc_resume, +}; + +static int __init udc_init(void) +{ + int retval; + + dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION); + + s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL); + if (IS_ERR(s3c2410_udc_debugfs_root)) { + printk(KERN_ERR "%s: debugfs dir creation failed %ld\n", + gadget_name, PTR_ERR(s3c2410_udc_debugfs_root)); + s3c2410_udc_debugfs_root = NULL; + } + + retval = platform_driver_register(&udc_driver_2410); + if (retval) + goto err; + + retval = platform_driver_register(&udc_driver_2440); + if (retval) + goto err; + + return 0; + +err: + debugfs_remove(s3c2410_udc_debugfs_root); + return retval; +} + +static void __exit udc_exit(void) +{ + platform_driver_unregister(&udc_driver_2410); + platform_driver_unregister(&udc_driver_2440); + debugfs_remove(s3c2410_udc_debugfs_root); +} + +EXPORT_SYMBOL(usb_gadget_unregister_driver); +EXPORT_SYMBOL(usb_gadget_register_driver); + +module_init(udc_init); +module_exit(udc_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/s3c2410_udc.h new file mode 100644 index 00000000000..9e0bece4f24 --- /dev/null +++ b/drivers/usb/gadget/s3c2410_udc.h @@ -0,0 +1,110 @@ +/* + * linux/drivers/usb/gadget/s3c2410_udc.h + * Samsung on-chip full speed USB device controllers + * + * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard + * Additional cleanups by Ben Dooks <ben-linux@fluff.org> + * + * 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, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _S3C2410_UDC_H +#define _S3C2410_UDC_H + +struct s3c2410_ep { + struct list_head queue; + unsigned long last_io; /* jiffies timestamp */ + struct usb_gadget *gadget; + struct s3c2410_udc *dev; + const struct usb_endpoint_descriptor *desc; + struct usb_ep ep; + u8 num; + + unsigned short fifo_size; + u8 bEndpointAddress; + u8 bmAttributes; + + unsigned halted : 1; + unsigned already_seen : 1; + unsigned setup_stage : 1; +}; + + +/* Warning : ep0 has a fifo of 16 bytes */ +/* Don't try to set 32 or 64 */ +/* also testusb 14 fails wit 16 but is */ +/* fine with 8 */ +#define EP0_FIFO_SIZE 8 +#define EP_FIFO_SIZE 64 +#define DEFAULT_POWER_STATE 0x00 + +#define S3C2440_EP_FIFO_SIZE 128 + +static const char ep0name [] = "ep0"; + +static const char *const ep_name[] = { + ep0name, /* everyone has ep0 */ + /* s3c2410 four bidirectional bulk endpoints */ + "ep1-bulk", "ep2-bulk", "ep3-bulk", "ep4-bulk", +}; + +#define S3C2410_ENDPOINTS ARRAY_SIZE(ep_name) + +struct s3c2410_request { + struct list_head queue; /* ep's requests */ + struct usb_request req; +}; + +enum ep0_state { + EP0_IDLE, + EP0_IN_DATA_PHASE, + EP0_OUT_DATA_PHASE, + EP0_END_XFER, + EP0_STALL, +}; + +static const char *ep0states[]= { + "EP0_IDLE", + "EP0_IN_DATA_PHASE", + "EP0_OUT_DATA_PHASE", + "EP0_END_XFER", + "EP0_STALL", +}; + +struct s3c2410_udc { + spinlock_t lock; + + struct s3c2410_ep ep[S3C2410_ENDPOINTS]; + int address; + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct s3c2410_request fifo_req; + u8 fifo_buf[EP_FIFO_SIZE]; + u16 devstatus; + + u32 port_status; + int ep0state; + + unsigned got_irq : 1; + + unsigned req_std : 1; + unsigned req_config : 1; + unsigned req_pending : 1; + u8 vbus; + struct dentry *regs_info; +}; + +#endif diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index f847c3414be..dd33ff0ae4c 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -2215,7 +2215,7 @@ static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags) * * Free the buffer and all associated memory. */ -void gs_buf_free(struct gs_buf *gb) +static void gs_buf_free(struct gs_buf *gb) { if (gb) { kfree(gb->buf_buf); @@ -2228,7 +2228,7 @@ void gs_buf_free(struct gs_buf *gb) * * Clear out all data in the circular buffer. */ -void gs_buf_clear(struct gs_buf *gb) +static void gs_buf_clear(struct gs_buf *gb) { if (gb != NULL) gb->buf_get = gb->buf_put; @@ -2241,7 +2241,7 @@ void gs_buf_clear(struct gs_buf *gb) * Return the number of bytes of data available in the circular * buffer. */ -unsigned int gs_buf_data_avail(struct gs_buf *gb) +static unsigned int gs_buf_data_avail(struct gs_buf *gb) { if (gb != NULL) return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size; @@ -2255,7 +2255,7 @@ unsigned int gs_buf_data_avail(struct gs_buf *gb) * Return the number of bytes of space available in the circular * buffer. */ -unsigned int gs_buf_space_avail(struct gs_buf *gb) +static unsigned int gs_buf_space_avail(struct gs_buf *gb) { if (gb != NULL) return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size; @@ -2271,7 +2271,8 @@ unsigned int gs_buf_space_avail(struct gs_buf *gb) * * Return the number of bytes copied. */ -unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count) +static unsigned int +gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count) { unsigned int len; @@ -2309,7 +2310,8 @@ unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count) * * Return the number of bytes copied. */ -unsigned int gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count) +static unsigned int +gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count) { unsigned int len; diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 7078374d0b7..a2e6e3fc8c8 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -481,8 +481,7 @@ alloc_ep_req (struct usb_ep *ep, unsigned length) req = usb_ep_alloc_request (ep, GFP_ATOMIC); if (req) { req->length = length; - req->buf = usb_ep_alloc_buffer (ep, length, - &req->dma, GFP_ATOMIC); + req->buf = kmalloc(length, GFP_ATOMIC); if (!req->buf) { usb_ep_free_request (ep, req); req = NULL; @@ -493,8 +492,7 @@ alloc_ep_req (struct usb_ep *ep, unsigned length) static void free_ep_req (struct usb_ep *ep, struct usb_request *req) { - if (req->buf) - usb_ep_free_buffer (ep, req->buf, req->dma, req->length); + kfree(req->buf); usb_ep_free_request (ep, req); } @@ -1199,8 +1197,7 @@ autoconf_fail: dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); if (!dev->req) goto enomem; - dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ, - &dev->req->dma, GFP_KERNEL); + dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL); if (!dev->req->buf) goto enomem; |