📄 s3c2410_udc.c
字号:
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(DEBUG_VERBOSE, "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; dprintk(DEBUG_NORMAL,"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(DEBUG_VERBOSE, "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; dprintk(DEBUG_VERBOSE,"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){ dprintk(DEBUG_NORMAL,"s3c2410_wakeup()\n"); return 0;}/* * s3c2410_set_selfpowered */static int s3c2410_set_selfpowered (struct usb_gadget *_gadget, int value){ struct s3c2410_udc *udc; dprintk(DEBUG_NORMAL, "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---------------------------*//* * udc_disable */static void udc_disable(struct s3c2410_udc *dev){ dprintk(DEBUG_NORMAL, "udc_disable called"); /* Good bye, cruel world */ if (udc_info && udc_info->udc_command) udc_info->udc_command(S3C2410_UDC_P_DISABLE); /* Set address to 0 */ __raw_writel( 0x80, S3C2410_UDC_FUNC_ADDR_REG); /* Disable all interrupts */ __raw_writel(0x00, S3C2410_UDC_USB_INT_EN_REG); __raw_writel(0x00, S3C2410_UDC_EP_INT_EN_REG); /* Set speed to unknown */ dev->gadget.speed = USB_SPEED_UNKNOWN;}/* * udc_reinit */static void 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 = 0; INIT_LIST_HEAD (&ep->queue); }}/* * udc_enable */static void udc_enable(struct s3c2410_udc *dev){ int i; dprintk(DEBUG_NORMAL, "udc_enable called"); dev->gadget.speed = USB_SPEED_UNKNOWN; /* Set MAXP for all endpoints */ for (i = 0; i < S3C2410_ENDPOINTS; i++) { __raw_writel(i, S3C2410_UDC_INDEX_REG); __raw_writel(0x0001,S3C2410_UDC_MAXP_REG); } /* Set default power state */ __raw_writel(DEFAULT_POWER_STATE, S3C2410_UDC_PWR_REG); /* Enable reset and suspend interrupt interrupts */ __raw_writel(1<<2 | 1<<0 ,S3C2410_UDC_USB_INT_EN_REG); /* Enable ep0 interrupt */ __raw_writel(0x01,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);}/* * nop_release */static void nop_release (struct device *dev){ dprintk(DEBUG_NORMAL, "%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; 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->unbind || !driver->setup || driver->speed == USB_SPEED_UNKNOWN) return -EINVAL; /* Hook the driver */ udc->driver = driver; udc->gadget.dev.driver = &driver->driver; /*Bind the driver */ device_add(&udc->gadget.dev); dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n", driver->driver.name); if ((retval = driver->bind (&udc->gadget)) != 0) { device_del(&udc->gadget.dev); udc->driver = 0; udc->gadget.dev.driver = 0; return retval; } /* driver->driver.bus = 0; */ /* Enable udc */ udc_enable(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; dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n", driver->driver.name); driver->unbind (&udc->gadget); device_del(&udc->gadget.dev); udc->driver = 0; device_release_driver (&udc->gadget.dev); driver_unregister (&driver->driver); /* Disable udc */ 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", .release = nop_release, }, }, /* 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 device *_dev){ struct s3c2410_udc *udc = &memory; int retval; dprintk(DEBUG_NORMAL,"s3c2410_udc_probe\n"); spin_lock_init (&udc->lock); udc_info = _dev->platform_data; 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); udc_disable(udc); udc_reinit(udc); /* 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(DEBUG_VERBOSE, "%s: got irq %i\n", gadget_name, IRQ_USBD);#ifdef ENABLE_SYSFS /* create device files */ device_create_file(_dev, &dev_attr_regs);#endif return 0;}/* * s3c2410_udc_remove */static int s3c2410_udc_remove(struct device *_dev){ struct s3c2410_udc *udc = _dev->driver_data; dprintk(DEBUG_NORMAL, "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 = s3c2410_udc_remove, };static int __init udc_init(void){ u32 tmp; dprintk(DEBUG_NORMAL, "%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_disable(udc_clock); tmp = ( 0x78 << S3C2410_PLLCON_MDIVSHIFT) | (0x02 << S3C2410_PLLCON_PDIVSHIFT) | (0x03 << S3C2410_PLLCON_SDIVSHIFT); __raw_writel(tmp, S3C2410_UPLLCON); clk_enable(udc_clock); mdelay(10); dprintk(DEBUG_VERBOSE, "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_VERSION(DRIVER_VERSION);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -