📄 jz4740_udc.c
字号:
DEBUG_SETUP("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->bEndpointAddress |= USB_DIR_IN; } else { ep->bEndpointAddress &= ~USB_DIR_IN; } /* Handle some SETUP packets ourselves */ switch (ctrl.bRequest) { case USB_REQ_SET_ADDRESS: if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) break; DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue); udc_set_address(dev, ctrl.wValue); usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); return; case USB_REQ_SET_CONFIGURATION: if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) break; DEBUG_SETUP("USB_REQ_SET_CONFIGURATION (%d)\n", ctrl.wValue); usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); /* Enable RESUME and SUSPEND interrupts */ usb_setb(USB_REG_INTRUSBE, (USB_INTR_RESUME | USB_INTR_SUSPEND)); break; case USB_REQ_SET_INTERFACE: if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) break; DEBUG_SETUP("USB_REQ_SET_INTERFACE (%d)\n", ctrl.wValue); usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); break;// case USB_REQ_GET_STATUS:// if (jz4740_handle_get_status(dev, &ctrl) == 0)// return; case USB_REQ_CLEAR_FEATURE: case USB_REQ_SET_FEATURE: if (ctrl.bRequestType == USB_RECIP_ENDPOINT) { struct jz4740_ep *qep; int ep_num = (ctrl.wIndex & 0x0f); /* Support only HALT feature */ if (ctrl.wValue != 0 || ctrl.wLength != 0 || ep_num > 3 || ep_num < 1) break; qep = &dev->ep[ep_num]; spin_unlock(&dev->lock); if (ctrl.bRequest == USB_REQ_SET_FEATURE) { DEBUG_SETUP("SET_FEATURE (%d)\n", ep_num); jz4740_set_halt(&qep->ep, 1); } else { DEBUG_SETUP("CLR_FEATURE (%d)\n", ep_num); jz4740_set_halt(&qep->ep, 0); } spin_lock(&dev->lock); usb_set_index(0); /* Reply with a ZLP on next IN token */ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); return; } break; default: break; } /* gadget drivers see class/vendor specific requests, * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, * and more. */ if (likely((u32)dev->driver)) { /* device-2-host (IN) or no data setup command, process immediately */ spin_unlock(&dev->lock); i = dev->driver->setup(&dev->gadget, &ctrl); spin_lock(&dev->lock); if (unlikely(i < 0)) { /* setup processing failed, force stall */ DEBUG_SETUP (" --> ERROR: gadget setup FAILED (stalling), setup returned %d\n", i); usb_set_index(0); usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL)); /* ep->stopped = 1; */ dev->ep0state = WAIT_FOR_SETUP; } else { DEBUG_SETUP("gadget driver setup ok (%d)\n", ctrl.wLength); if (!ctrl.wLength) { usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY); } } }}/* * DATA_STATE_NEED_ZLP */static void jz4740_ep0_in_zlp(struct jz4740_udc *dev, u32 csr){ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); dev->ep0state = WAIT_FOR_SETUP;}/* * handle ep0 interrupt */static void jz4740_handle_ep0(struct jz4740_udc *dev, u32 intr){ struct jz4740_ep *ep = &dev->ep[0]; u32 csr; /* Set index 0 */ usb_set_index(0); csr = usb_readb(USB_REG_CSR0); DEBUG_EP0("%s: csr = %x state = \n", __FUNCTION__, csr);//, state_names[dev->ep0state]); /* * if SENT_STALL is set * - clear the SENT_STALL bit */ if (csr & USB_CSR0_SENTSTALL) { DEBUG_EP0("%s: USB_CSR0_SENTSTALL is set: %x\n", __FUNCTION__, csr); usb_clearb(USB_REG_CSR0, USB_CSR0_SENDSTALL | USB_CSR0_SENTSTALL); nuke(ep, -ECONNABORTED); dev->ep0state = WAIT_FOR_SETUP; return; } /* * if a transfer is in progress && INPKTRDY and OUTPKTRDY are clear * - fill EP0 FIFO * - if last packet * - set IN_PKT_RDY | DATA_END * - else * set IN_PKT_RDY */ if (!(csr & (USB_CSR0_INPKTRDY | USB_CSR0_OUTPKTRDY))) { DEBUG_EP0("%s: INPKTRDY and OUTPKTRDY are clear\n", __FUNCTION__); switch (dev->ep0state) { case DATA_STATE_XMIT: DEBUG_EP0("continue with DATA_STATE_XMIT\n"); jz4740_ep0_in(dev, csr); return; case DATA_STATE_NEED_ZLP: DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n"); jz4740_ep0_in_zlp(dev, csr); return; default: /* Stall? */// DEBUG_EP0("Odd state!! state = %s\n",// state_names[dev->ep0state]); dev->ep0state = WAIT_FOR_SETUP; /* nuke(ep, 0); */ /* usb_setb(ep->csr, USB_CSR0_SENDSTALL); */// break; return; } } /* * if SETUPEND is set * - abort the last transfer * - set SERVICED_SETUP_END_BIT */ if (csr & USB_CSR0_SETUPEND) { DEBUG_EP0("%s: USB_CSR0_SETUPEND is set: %x\n", __FUNCTION__, csr); usb_setb(USB_REG_CSR0, USB_CSR0_SVDSETUPEND); nuke(ep, 0); dev->ep0state = WAIT_FOR_SETUP; } /* * if USB_CSR0_OUTPKTRDY is set * - read data packet from EP0 FIFO * - decode command * - if error * set SVDOUTPKTRDY | DATAEND | SENDSTALL bits * - else * set SVDOUTPKTRDY | DATAEND bits */ if (csr & USB_CSR0_OUTPKTRDY) { DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__, csr); switch (dev->ep0state) { case WAIT_FOR_SETUP: DEBUG_EP0("WAIT_FOR_SETUP\n"); jz4740_ep0_setup(dev, csr); break; case DATA_STATE_RECV: DEBUG_EP0("DATA_STATE_RECV\n"); jz4740_ep0_out(dev, csr); break; default: /* send stall? */ DEBUG_EP0("strange state!! 2. send stall? state = %d\n", dev->ep0state); break; } }}static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep){ u32 csr; usb_set_index(0); csr = usb_readb(USB_REG_CSR0); DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); /* Clear "out packet ready" */ usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY); if (ep_is_in(ep)) { dev->ep0state = DATA_STATE_XMIT; jz4740_ep0_in(dev, csr); } else { dev->ep0state = DATA_STATE_RECV; jz4740_ep0_out(dev, csr); }}/** Handle USB RESET interrupt */static void jz4740_reset_irq(struct jz4740_udc *dev){ dev->gadget.speed = (usb_readb(USB_REG_POWER) & USB_POWER_HSMODE) ? USB_SPEED_HIGH : USB_SPEED_FULL; DEBUG_SETUP("%s: address = %d, speed = %s\n", __FUNCTION__, dev->usb_address, (dev->gadget.speed == USB_SPEED_HIGH) ? "HIGH":"FULL" );}/* * jz4740 usb device interrupt handler. */static irqreturn_t jz4740_udc_irq(int irq, void *_dev){ struct jz4740_udc *dev = _dev; u32 intr_usb = usb_readb(USB_REG_INTRUSB) & 0x7; /* mask SOF */ u32 intr_in = usb_readw(USB_REG_INTRIN); u32 intr_out = usb_readw(USB_REG_INTROUT); u32 intr_dma = usb_readb(USB_REG_INTR); if (!intr_usb && !intr_in && !intr_out && !intr_dma) return IRQ_HANDLED; DEBUG("intr_out = %x intr_in=%x intr_usb=%x\n", intr_out, intr_in, intr_usb); spin_lock(&dev->lock); /* Check for resume from suspend mode */ if ((intr_usb & USB_INTR_RESUME) && (usb_readb(USB_REG_INTRUSBE) & USB_INTR_RESUME)) { DEBUG("USB resume\n"); } /* Check for system interrupts */ if (intr_usb & USB_INTR_RESET) { DEBUG("USB reset\n");#ifdef CONFIG_JZ_UDC_HOTPLUG jz_udc_active = 1;#endif if (udc_debug) { /* We have tested the cable type, disable module and * disconnect from host right now. */ udc_disable(dev); spin_unlock(&dev->lock); return IRQ_HANDLED; } jz4740_reset_irq(dev); } /* Check for endpoint 0 interrupt */ if (intr_in & USB_INTR_EP0) { DEBUG("USB_INTR_EP0 (control)\n"); jz4740_handle_ep0(dev, intr_in); } /* Check for Bulk-IN DMA interrupt */ if (intr_dma & 0x1) { int ep_num; ep_num = (usb_readl(USB_REG_CNTL1) >> 4) & 0xf; jz4740_in_epn(dev, ep_num, intr_in); } /* Check for Bulk-OUT DMA interrupt */ if (intr_dma & 0x2) { int ep_num; ep_num = (usb_readl(USB_REG_CNTL2) >> 4) & 0xf; jz4740_out_epn(dev, ep_num, intr_out); } /* Check for each configured endpoint interrupt */ if (intr_in & USB_INTR_INEP1) { DEBUG("USB_INTR_INEP1\n"); jz4740_in_epn(dev, 1, intr_in); } if (intr_in & USB_INTR_INEP2) { DEBUG("USB_INTR_INEP2\n"); jz4740_in_epn(dev, 2, intr_in); } if (intr_out & USB_INTR_OUTEP1) { DEBUG("USB_INTR_OUTEP1\n"); jz4740_out_epn(dev, 1, intr_out); } /* Check for suspend mode */ if ((intr_usb & USB_INTR_SUSPEND) && (usb_readb(USB_REG_INTRUSBE) & USB_INTR_SUSPEND)) { DEBUG("USB suspend\n"); /* Host unloaded from us, can do something, such as flushing the NAND block cache etc. */ } spin_unlock(&dev->lock); return IRQ_HANDLED;}/*-------------------------------------------------------------------------*/static int jz4740_udc_get_frame(struct usb_gadget *_gadget){ DEBUG("%s, %p\n", __FUNCTION__, _gadget); return usb_readw(USB_REG_FRAME);}static int jz4740_udc_wakeup(struct usb_gadget *_gadget){ /* host may not have enabled remote wakeup */ /*if ((UDCCS0 & UDCCS0_DRWF) == 0) return -EHOSTUNREACH; udc_set_mask_UDCCR(UDCCR_RSM); */ return -ENOTSUPP;}static const struct usb_gadget_ops jz4740_udc_ops = { .get_frame = jz4740_udc_get_frame, .wakeup = jz4740_udc_wakeup, /* current versions must always be self-powered */};/*-------------------------------------------------------------------------*/static struct jz4740_udc udc_dev = { .usb_address = 0, .gadget = { .ops = &jz4740_udc_ops, .ep0 = &udc_dev.ep[0].ep, .name = driver_name, .dev = { .bus_id = "gadget", }, }, /* control endpoint */ .ep[0] = { .ep = { .name = ep0name, .ops = &jz4740_ep_ops, .maxpacket = EP0_MAXPACKETSIZE, }, .dev = &udc_dev, .bEndpointAddress = 0, .bmAttributes = 0, .ep_type = ep_control, .fifo = USB_FIFO_EP0, .csr = USB_REG_CSR0, }, /* bulk out endpoint */ .ep[1] = { .ep = { .name = "ep1out-bulk", .ops = &jz4740_ep_ops, .maxpacket = EPBULK_MAXPACKETSIZE, }, .dev = &udc_dev, .bEndpointAddress = 1, .bmAttributes = USB_ENDPOINT_XFER_BULK, .ep_type = ep_bulk_out, .fifo = USB_FIFO_EP1, .csr = USB_REG_OUTCSR, }, /* bulk in endpoint */ .ep[2] = { .ep = { .name = "ep1in-bulk", .ops = &jz4740_ep_ops, .maxpacket = EPBULK_MAXPACKETSIZE, }, .dev = &udc_dev, .bEndpointAddress = USB_DIR_IN | 1, .bmAttributes = USB_ENDPOINT_XFER_BULK, .ep_type = ep_bulk_in, .fifo = USB_FIFO_EP1, .csr = USB_REG_INCSR, }, /* interrupt in endpoint */ .ep[3] = { .ep = { .name = "ep2in-int", .ops = &jz4740_ep_ops, .maxpacket = EPINTR_MAXPACKETSIZE, }, .dev = &udc_dev, .bEndpointAddress = USB_DIR_IN | 2, .bmAttributes = USB_ENDPOINT_XFER_INT, .ep_type = ep_interrupt, .fifo = USB_FIFO_EP2, .csr = USB_REG_INCSR, },};static int jz4740_udc_probe(struct platform_device *pdev){ struct jz4740_udc *dev = &udc_dev; int rc; DEBUG("%s\n", __FUNCTION__); spin_lock_init(&dev->lock); the_controller = dev; dev->dev = &pdev->dev; device_initialize(&dev->gadget.dev); dev->gadget.dev.parent = &pdev->dev;// strcpy (dum->gadget.dev.bus_id, "gadget"); dev->gadget.dev.release = jz4740_udc_release; if ((rc = device_register (&dev->gadget.dev)) < 0) return rc; platform_set_drvdata(pdev, dev); udc_disable(dev); udc_reinit(dev); /* irq setup */ if (request_irq(IRQ_UDC, jz4740_udc_irq, IRQF_DISABLED,//SA_SHIRQ/*|SA_SAMPLE_RANDOM*/, driver_name, dev) != 0) { printk(KERN_INFO "request UDC interrupt %d failed\n", IRQ_UDC); return -EBUSY; } printk(KERN_INFO "%s\n", driver_desc); printk(KERN_INFO "version: " DRIVER_VERSION "\n"); return 0;}static int jz4740_udc_remove(struct platform_device *pdev){ struct jz4740_udc *dev = platform_get_drvdata(pdev); DEBUG("%s: %p\n", __FUNCTION__, dev); if (dev->driver) return -EBUSY; udc_disable(dev);#ifdef UDC_PROC_FILE remove_proc_entry(proc_node_name, NULL);#endif free_irq(IRQ_UDC, dev); platform_set_drvdata(pdev, 0); device_unregister(&dev->gadget.dev); the_controller = 0; return 0;}static struct platform_driver udc_driver = { .probe = jz4740_udc_probe, .remove = jz4740_udc_remove, .suspend = NULL, .resume = NULL, .driver = { .name = (char *) driver_name, .owner = THIS_MODULE, },};static struct platform_device the_udc_pdev = { .name = (char *) gadget_name, .id = -1, .dev = { .release = jz4740_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 + -