📄 s3c2410_udc.c
字号:
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 | IRQF_SHARED, 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_PMstatic 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#endifstatic 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");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -