📄 jz4730_udc.c
字号:
if (likely(req->req.length != req->req.actual) || req->req.zero) is_last = 0; else is_last = 1; } DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__, ep->ep.name, count, is_last ? "/L" : "", req->req.length - req->req.actual, req); /* requests complete when all IN data is in the FIFO */ if (is_last) { done(ep, req, 0); return 1; } return 0;}/* * Simulate a USB_REQ_SET_CONFIGURATION to the function driver, * this is required to enable the endpoints of the function driver. * UDC should let software have the chance to handle this standard * request, unfortunately UDC can't do that. */static void psudo_set_config(void){ struct jz4730_udc *dev = (struct jz4730_udc *) the_controller; struct usb_ctrlrequest ctrl; int tmp; /* SETUP packet */ ctrl.bRequestType = 0x00; ctrl.bRequest = USB_REQ_SET_CONFIGURATION; ctrl.wValue = 1; ctrl.wIndex = 0; ctrl.wLength = 0; nuke(&dev->ep[0], 0); dev->ep[0].stopped = 0; if (likely(ctrl.bRequestType & USB_DIR_IN)) { dev->ep[0].is_in = 1; dev->ep0state = EP0_IN; } else { dev->ep[0].is_in = 0; dev->ep0state = EP0_OUT; } /* delegate everything to the gadget driver. * it may respond after this irq handler returns. */ spin_unlock (&dev->lock); tmp = dev->driver->setup(&dev->gadget, &ctrl); spin_lock (&dev->lock); if (unlikely(tmp < 0)) { DEBUG_EP0("req %02x.%02x protocol STALL; err %d\n", ctrl.bRequestType, ctrl.bRequest, tmp); dev->ep[0].stopped = 1; dev->ep0state = EP0_STALL; }}/* * Read 8 bytes setup packet from EP0 RX buffer */static void read_setup_packet(u8 *buf){ u32 *tmp = (u32 *)buf; *tmp++ = readl((unsigned int *)RXFIFO); *tmp++ = readl((unsigned int *)RXFIFO); REG32(UDC_RXCONFIRM);}static void jz4730_ep0_setup(struct jz4730_udc *dev){ struct jz4730_ep *ep = &dev->ep[0]; struct usb_ctrlrequest ctrl; int tmp; /* read control req from fifo (8 bytes) */ read_setup_packet((unsigned char *) &ctrl); DEBUG_EP0("SETUP %02x.%02x v%04x i%04x l%04x\n", ctrl.bRequestType, ctrl.bRequest, ctrl.wValue, ctrl.wIndex, ctrl.wLength); /* Set direction of EP0 */ if (likely(ctrl.bRequestType & USB_DIR_IN)) { ep->is_in = 1; dev->ep0state = EP0_IN; } else { ep->is_in = 0; dev->ep0state = EP0_OUT; } /* Nuke all previous transfers */ nuke(ep, 0); ep->stopped = 0; /* delegate everything to the gadget driver. * it may respond after this irq handler returns. */ if (likely((u32)dev->driver)) { /* device-2-host (IN) or no data setup command, process immediately */ spin_unlock(&dev->lock); tmp = dev->driver->setup(&dev->gadget, &ctrl); spin_lock(&dev->lock); if (unlikely(tmp < 0)) { /* setup processing failed, force stall */ DEBUG_EP0("req %02x.%02x protocol STALL; err %d\n", ctrl.bRequestType, ctrl.bRequest, tmp); dev->ep0state = EP0_STALL; } }}static int jz4730_ep0_in(struct jz4730_udc *dev){ struct jz4730_request *req; struct jz4730_ep *ep = &dev->ep[0]; int ret; if (list_empty(&ep->queue)) req = 0; else req = list_entry(ep->queue.next, struct jz4730_request, queue); if (!req) { DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__); return 0; } ret = write_fifo_ep0(ep, req); return ret;}static void jz4730_ep0_out(struct jz4730_udc *dev){ u32 epsr; struct jz4730_ep *ep = &dev->ep[0]; epsr = REG_UDC_EP0OutSR; REG_UDC_EP0OutSR &= ~UDC_EPSR_OUT_MASK; if (epsr & UDC_EPSR_OUT_RCVSETUP) { jz4730_ep0_setup(dev); } else if (epsr & UDC_EPSR_OUT_RCVDATA) { u32 count = __udc_ep0out_packet_size(); if (count == 0) { readl((unsigned int *)UDC_RXCONFIRM); // ack zero packet } else { /* EP0 OUT Data */ if (list_empty(&ep->queue)) { ep->irq_pending = 1; pio_irq_disable(ep); } else jz4730_epn_out(dev, 0, count); } }}static void handle_reset_irq(struct jz4730_udc *dev){ int i; /* clear any status */ REG_UDC_EPIntR = 0xffffffff; REG_UDC_DevIntR = 0xffffffff; /* reset udc */ udc_reset(dev); /* reset driver status */ for (i = 0; i < MAX_EP_NUM; i++) { struct jz4730_ep *ep = &dev->ep[i]; ep->irq_pending = 0;// nuke(ep, 0); nuke(ep, -ESHUTDOWN); }}static irqreturn_t jz4730_udc_irq(int irq, void *_dev){ struct jz4730_udc *dev = _dev; struct jz4730_ep *ep; u32 intr_dev, intr_ep, stats, count; spin_lock(&dev->lock); intr_dev = REG_UDC_DevIntR; intr_ep = REG_UDC_EPIntR; DEBUG("*** udc irq intr_dev=0x%x intr_ep=0x%x\n", intr_dev, intr_ep); if (!intr_dev && !intr_ep) { spin_unlock(&dev->lock); return IRQ_HANDLED; } if (udc_debug) {#ifdef CONFIG_JZ_UDC_HOTPLUG jz_udc_active = 1;#endif REG_UDC_DevIntR = intr_dev; REG_UDC_EPIntR = intr_ep; __harb_usb0_uhc(); __intc_mask_irq(IRQ_UDC); spin_unlock(&dev->lock); return IRQ_HANDLED; } if (intr_dev) { if (intr_dev & UDC_DevIntR_SC) { psudo_set_config(); udelay(100); } if (intr_dev & UDC_DevIntR_UR) {#ifdef CONFIG_JZ_UDC_HOTPLUG jz_udc_active = 1;#endif handle_reset_irq(dev); } REG_UDC_DevIntR = intr_dev; } if (intr_ep & UDC_EPIntR_OUTEP0) { REG_UDC_EPIntR = UDC_EPIntR_OUTEP0; jz4730_ep0_out(dev); } if (intr_ep & UDC_EPIntR_INEP0) { ep = &dev->ep[0]; if (list_empty(&ep->queue)) { pio_irq_disable(ep); } else { stats = REG_UDC_EP0InSR; if (stats & UDC_EPSR_IN) { REG_UDC_EPIntR = UDC_EPIntR_INEP0; REG_UDC_EP0InSR &= ~UDC_EPSR_IN; jz4730_ep0_in(dev); } } } if (intr_ep & UDC_EPIntR_OUTEP5) { REG_UDC_EPIntR = UDC_EPIntR_OUTEP5; ep = &dev->ep[5]; if (list_empty(&ep->queue)) { ep->irq_pending = 1; pio_irq_disable(ep); } else { stats = REG_UDC_EP5OutSR; if (stats & UDC_EPSR_OUT_RCVDATA) { REG_UDC_EP5OutSR &= ~UDC_EPSR_OUT_MASK; count = OUT_COUNT(stats); jz4730_epn_out(dev, 5, count); } } } if (intr_ep & UDC_EPIntR_INEP2) { ep = &dev->ep[2]; if (list_empty(&ep->queue)) { ep->irq_pending = 1; pio_irq_disable(ep); } else { stats = REG_UDC_EP2InSR; if (stats & UDC_EPSR_IN) { REG_UDC_EP2InSR &= ~UDC_EPSR_IN; jz4730_epn_in(dev, 2); } } REG_UDC_EPIntR = UDC_EPIntR_INEP2; } if (intr_ep & UDC_EPIntR_INEP1) { ep = &dev->ep[1]; if (list_empty(&ep->queue)) { ep->irq_pending = 1; pio_irq_disable(ep); } else { stats = REG_UDC_EP1InSR; if (stats & UDC_EPSR_IN) { REG_UDC_EP1InSR &= ~UDC_EPSR_IN; jz4730_epn_in(dev, 1); } } REG_UDC_EPIntR = UDC_EPIntR_INEP1; } spin_unlock(&dev->lock); return IRQ_HANDLED;}/*-------------------------------------------------------------------------*/static struct jz4730_udc udc_dev = { .usb_address = 0, .gadget = { .ops = &jz4730_ops, .ep0 = &udc_dev.ep[0].ep, .name = driver_name, .dev = { .bus_id = "gadget", }, }, /* control endpoint no need to init here!*/ /* control endpoint */};/* tear down the binding between this driver and the pci device */static int jz4730_udc_remove(struct platform_device *pdev){ struct jz4730_udc *dev = platform_get_drvdata(pdev); if (dev->driver) return -EBUSY; /* USB port0 as UHC */ __harb_usb0_uhc(); /* reset udc */ udc_reset(dev); /* clear any status */ REG_UDC_EPIntR = 0xffffffff; REG_UDC_DevIntR = 0xffffffff; /* disable all UDC interrupts */ REG_UDC_DevIntMR = 0xffffffff; REG_UDC_EPIntMR = 0xffffffff; free_irq(IRQ_UDC, dev); platform_set_drvdata(pdev, 0); device_unregister(&dev->gadget.dev); the_controller = 0; return 0;}static int jz4730_udc_probe(struct platform_device *pdev){ struct jz4730_udc *dev = &udc_dev; int retval,rc; /* if you want to support more than one controller in a system, * usb_gadget_driver_{register,unregister}() must change. */ if (the_controller) { printk("Check the_controller: %s\n", driver_name); return -EBUSY; } spin_lock_init(&dev->lock); device_initialize(&dev->gadget.dev); dev->gadget.dev.parent = &pdev->dev; //if no,can only insmod once!! dev->gadget.dev.release = jz4730_udc_release; rc = device_register (&dev->gadget.dev); if (rc < 0) return rc; platform_set_drvdata(pdev, dev); /* * Note: we just mask INTC irq but allow UDC irq. * This avoid that we miss any UDC irqs. */ /* To avoid any UDC irqs here, we call cli() first */// cli(); /* disable INTC irq */ __intc_mask_irq(IRQ_UDC); /* init to known state, then setup irqs */ udc_reset(dev); udc_reinit(dev); /* request UDC irq */ if (request_irq(IRQ_UDC, jz4730_udc_irq, IRQF_DISABLED, // SA_INTERRUPT, driver_name, dev) != 0) { printk(KERN_INFO "request UDC interrupt %d failed\n", IRQ_UDC); retval = -EBUSY; goto done; } /* disable INTC irq again since request_irq has enabled it */ __intc_mask_irq(IRQ_UDC); __intc_ack_irq(IRQ_UDC); /* Re-enable irqs */// sti(); printk(KERN_INFO "%s\n", driver_desc); printk(KERN_INFO "version: " DRIVER_VERSION "\n"); /* done */ the_controller = dev; return 0;done: if (dev) jz4730_udc_remove (pdev); return retval;}static struct platform_driver udc_driver = { .probe = jz4730_udc_probe, .remove = jz4730_udc_remove, .suspend = NULL, .resume = NULL, .driver = { .name = (char *) driver_name, .owner = THIS_MODULE, },};static struct platform_device the_udc_pdev = { .name = (char *) driver_name, .id = -1, .dev = { .release = jz4730_udc_release, },};/*-------------------------------------------------------------------------*/static int __init udc_init (void){ platform_driver_register(&udc_driver); return platform_device_register (&the_udc_pdev);}static void __exit udc_exit (void){ platform_driver_unregister(&udc_driver); platform_device_unregister(&the_udc_pdev);}module_init(udc_init);module_exit(udc_exit);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_AUTHOR("Wei Jianli <jlwei@ingenic.cn>");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -