📄 s3c2410_udc.c
字号:
return 0; retval = kmalloc (bytes, mem_flags); *dma = (dma_addr_t) retval; return retval;}/* * s3c2410_free_buffer */static voids3c2410_free_buffer ( struct usb_ep *_ep, void *buf, dma_addr_t dma, unsigned bytes){ printk("s3c2410_free_buffer()\n"); if (bytes) kfree (buf);}/* * s3c2410_queue */static ints3c2410_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags){ struct s3c2410_request *req; struct s3c2410_ep *ep; struct s3c2410_udc *dev; u32 ep_csr=0; int fifo_count=0; req = container_of(_req, struct s3c2410_request, req); if (unlikely (!_req || !_req->complete || !_req->buf || !list_empty(&req->queue))) { if (!_req) dprintk("s3c2410_queue: 1 X X X\n"); else { dprintk("s3c2410_queue: 0 %01d %01d %01d\n",!_req->complete,!_req->buf, !list_empty(&req->queue)); } return -EINVAL; } ep = container_of(_ep, struct s3c2410_ep, ep); if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { dprintk("s3c2410_queue: inval 2\n"); return -EINVAL; } dev = ep->dev; if (unlikely (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { return -ESHUTDOWN; } /* iso is always one packet per request, that's the only way * we can report per-packet status. that also helps with dma. */ if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC && req->req.length > le16_to_cpu (ep->desc->wMaxPacketSize))) return -EMSGSIZE; _req->status = -EINPROGRESS; _req->actual = 0; if (ep->bEndpointAddress) { __raw_writel(ep->bEndpointAddress&0x7F,S3C2410_UDC_INDEX_REG); ep_csr = __raw_readl(ep->bEndpointAddress&USB_DIR_IN ? S3C2410_UDC_IN_CSR1_REG : S3C2410_UDC_OUT_CSR1_REG); fifo_count=fifo_count_out(); } /* kickstart this i/o queue? */ if (list_empty(&ep->queue)) { if (ep->bEndpointAddress == 0 /* ep0 */) { switch (dev->ep0state) { case EP0_IN_DATA_PHASE: if (write_fifo(ep, req)) { req = 0; } break; case EP0_OUT_DATA_PHASE: /* nothing to do here */ dev->ep0state = EP0_IDLE; break; default: return -EL2HLT; } } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0 && (!(ep_csr&S3C2410_UDC_OCSR1_PKTRDY)) && write_fifo(ep, req)) { req = 0; } else if ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY) && fifo_count && read_fifo(ep, req)) { req = 0; } } /* pio or dma irq handler advances the queue. */ if (likely (req != 0)) list_add_tail(&req->queue, &ep->queue); dprintk("s3c2410_queue normal end\n"); return 0;}/* * s3c2410_dequeue */static int s3c2410_dequeue (struct usb_ep *_ep, struct usb_request *_req){ struct s3c2410_ep *ep; struct s3c2410_udc *udc; int retval = -EINVAL; unsigned long flags; struct s3c2410_request *req = 0; printk("s3c2410_dequeue(ep=%p,req=%p)\n", _ep, _req); if (!the_controller->driver) return -ESHUTDOWN; if (!_ep || !_req) return retval; ep = container_of (_ep, struct s3c2410_ep, ep); udc = container_of (ep->gadget, struct s3c2410_udc, gadget); spin_lock_irqsave (&udc->lock, flags); list_for_each_entry (req, &ep->queue, queue) { if (&req->req == _req) { list_del_init (&req->queue); _req->status = -ECONNRESET; retval = 0; break; } } spin_unlock_irqrestore (&udc->lock, flags); if (retval == 0) { dprintk( "dequeued req %p from %s, len %d buf %p\n", req, _ep->name, _req->length, _req->buf); _req->complete (_ep, _req); done(ep, req, -ECONNRESET); } return retval; return 0;}/* * s3c2410_set_halt */static ints3c2410_set_halt (struct usb_ep *_ep, int value){ return 0;}static const struct usb_ep_ops s3c2410_ep_ops = { .enable = s3c2410_ep_enable, .disable = s3c2410_ep_disable, .alloc_request = s3c2410_alloc_request, .free_request = s3c2410_free_request, .alloc_buffer = s3c2410_alloc_buffer, .free_buffer = s3c2410_free_buffer, .queue = s3c2410_queue, .dequeue = s3c2410_dequeue, .set_halt = s3c2410_set_halt,};/*------------------------- usb_gadget_ops ----------------------------------*//* * s3c2410_g_get_frame */static int s3c2410_g_get_frame (struct usb_gadget *_gadget){ int tmp; printk("s3c2410_g_get_frame()\n"); tmp = __raw_readl(S3C2410_UDC_FRAME_NUM2_REG) << 8; tmp |= __raw_readl(S3C2410_UDC_FRAME_NUM1_REG); return tmp & 0xffff;}/* * s3c2410_wakeup */static int s3c2410_wakeup (struct usb_gadget *_gadget){ printk("s3c2410_wakeup()\n"); return 0;}/* * s3c2410_set_selfpowered */static int s3c2410_set_selfpowered (struct usb_gadget *_gadget, int value){ struct s3c2410_udc *udc; printk("s3c2410_set_selfpowered()\n"); udc = container_of (_gadget, struct s3c2410_udc, gadget); if (value) udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED); else udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); return 0;} static const struct usb_gadget_ops s3c2410_ops = { .get_frame = s3c2410_g_get_frame, .wakeup = s3c2410_wakeup, .set_selfpowered = s3c2410_set_selfpowered,};/*------------------------- gadget driver handling---------------------------*//* * nop_release */static void nop_release (struct device *dev){ dprintk("%s %s\n", __FUNCTION__, dev->bus_id);}/* * usb_gadget_register_driver */intusb_gadget_register_driver (struct usb_gadget_driver *driver){ struct s3c2410_udc *udc = the_controller; int retval, i; printk("usb_gadget_register_driver() '%s'\n", driver->driver.name); if (!udc) return -ENODEV; if (udc->driver) return -EBUSY; if (!driver->bind || !driver->unbind || !driver->setup || driver->speed == USB_SPEED_UNKNOWN) return -EINVAL; udc->gadget.name = gadget_name; udc->gadget.ops = &s3c2410_ops; udc->gadget.is_dualspeed = 1; udc->gadget.dev.release = nop_release; udc->devstatus = 0; INIT_LIST_HEAD (&udc->gadget.ep_list); for (i = 0; i < S3C2410_ENDPOINTS; i++) { struct s3c2410_ep *ep = &udc->ep[i]; if (!ep_name[i]) break; ep->num = i; ep->ep.name = ep_name[i]; ep->ep.ops = &s3c2410_ep_ops; list_add_tail (&ep->ep.ep_list, &udc->gadget.ep_list); ep->halted = ep->already_seen = ep->setup_stage = 0; /* maxpacket differs between ep0 and others ep */ if (!i) ep->ep.maxpacket = EP0_FIFO_SIZE; else ep->ep.maxpacket = EP_FIFO_SIZE; ep->last_io = jiffies; ep->gadget = &udc->gadget; ep->dev = udc; ep->desc = 0; INIT_LIST_HEAD (&ep->queue); } udc->gadget.ep0 = &udc->ep[0].ep; udc->ep[0].ep.maxpacket = 8; list_del_init (&udc->ep[0].ep.ep_list); INIT_LIST_HEAD(&udc->fifo_req.queue); udc->driver = driver; udc->gadget.dev.driver = &driver->driver; dprintk( "binding gadget driver '%s'\n", driver->driver.name); if ((retval = driver->bind (&udc->gadget)) != 0) { udc->driver = 0; udc->gadget.dev.driver = 0; return retval; } driver->driver.bus = 0; udc_reinit(udc); return 0;}/* * usb_gadget_unregister_driver */intusb_gadget_unregister_driver (struct usb_gadget_driver *driver){ struct s3c2410_udc *udc = the_controller; if (!udc) return -ENODEV; if (!driver || driver != udc->driver) return -EINVAL; printk("usb_gadget_register_driver() '%s'\n", driver->driver.name); driver->unbind (&udc->gadget); udc->driver = 0; device_release_driver (&udc->gadget.dev); driver_unregister (&driver->driver); return 0;}/*---------------------------------------------------------------------------*//* * probe - binds to the platform device */static int __init s3c2410_udc_probe(struct device *_dev){ struct s3c2410_udc *udc = &memory; u32 int_en_reg; int retval; dprintk("s3c2410_udc_probe\n"); device_initialize(&udc->gadget.dev); udc->gadget.dev.parent = _dev; udc->gadget.dev.dma_mask = _dev->dma_mask; the_controller = udc; dev_set_drvdata(_dev, udc); spin_lock_init (&udc->lock); /* irq setup after old hardware state is cleaned up */ retval = request_irq(IRQ_USBD, s3c2410_udc_irq, SA_INTERRUPT, gadget_name, udc); if (retval != 0) { printk(KERN_ERR "%s: can't get irq %i, err %d\n", gadget_name, IRQ_USBD, retval); return -EBUSY; } dprintk("%s: got irq %i\n", gadget_name, IRQ_USBD); udc->got_irq = 1; /* Enable ep0 interrupts */ int_en_reg = __raw_readl(S3C2410_UDC_EP_INT_EN_REG); __raw_writel(int_en_reg | 1,S3C2410_UDC_EP_INT_EN_REG); return 0;}/* * s3c2410_udc_remove */static int __exit s3c2410_udc_remove(struct device *_dev){ struct s3c2410_udc *udc = _dev->driver_data; dprintk("s3c2410_udc_remove\n"); usb_gadget_unregister_driver(udc->driver); if (udc->got_irq) { free_irq(IRQ_USBD, udc); udc->got_irq = 0; } dev_set_drvdata(_dev, 0); kfree(udc); return 0;} static struct device_driver udc_driver = { .name = "s3c2410-usbgadget", .bus = &platform_bus_type, .probe = s3c2410_udc_probe, .remove = __exit_p(s3c2410_udc_remove), };static int __init udc_init(void){ dprintk("%s: version %s\n", gadget_name, DRIVER_VERSION); udc_clock = clk_get(NULL, "usb-device"); if (!udc_clock) { printk(KERN_INFO "failed to get udc clock source\n"); return -ENOENT; } clk_use(udc_clock); clk_enable(udc_clock); dprintk("got and enabled clock\n"); return driver_register(&udc_driver);}static void __exit udc_exit(void){ if (udc_clock) { clk_disable(udc_clock); clk_unuse(udc_clock); clk_put(udc_clock); udc_clock = NULL; } driver_unregister(&udc_driver);}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_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -