Gadget AT91
注册了这样一个驱动
static struct platform_driver at91_udc_driver = {
.remove = __exit_p(at91udc_remove),
.shutdown = at91udc_shutdown,
.suspend = at91udc_suspend,
.resume = at91udc_resume,
.driver = {
.name = (char *) driver_name,
.owner = THIS_MODULE,
},
};
并且指定了probe函数at91udc_probe
现在看一下这个at91udc_probe
static int __init at91udc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct at91_udc *udc;
int retval;
struct resource *res;
if (!dev->platform_data) {
/* small (so we copy it) but critical! */
DBG("missing platform_data/n");
return -ENODEV;
}
如果这个设备没有platform_data 就直接返回
if (pdev->num_resources != 2) {
DBG("invalid num_resources");
return -ENODEV;
}
资源的数目必须是2,为内存资源和IRQ资源
if ((pdev->resource[0].flags != IORESOURCE_MEM)
|| (pdev->resource[1].flags != IORESOURCE_IRQ)) {
DBG("invalid resource type");
return -ENODEV;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
找出第一块内存资源
if (!res)
return -ENXIO;
请求一段内存空间
if (!request_mem_region(res->start,
res->end - res->start + 1,
driver_name)) {
DBG("someone's using UDC memory/n");
return -EBUSY;
}
看看这个结构体
struct at91_udc {
struct usb_gadget gadget;
struct at91_ep ep[NUM_ENDPOINTS];
struct usb_gadget_driver *driver;
unsigned vbus:1;
unsigned enabled:1;
unsigned clocked:1;
unsigned suspended:1;
unsigned req_pending:1;
unsigned wait_for_addr_ack:1;
unsigned wait_for_config_ack:1;
unsigned selfpowered:1;
unsigned active_suspend:1;
u8 addr;
struct at91_udc_data board;
struct clk *iclk, *fclk;
struct platform_device *pdev;
struct proc_dir_entry *pde;
void __iomem *udp_baseaddr;
int udp_irq;
};
/* init software state */
udc = &controller;
udc->gadget.dev.parent = dev;
udc->board = *(struct at91_udc_data *) dev->platform_data;
udc->pdev = pdev;
udc->enabled = 0;
初始化控制器
udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
if (!udc->udp_baseaddr) {
release_mem_region(res->start, res->end - res->start + 1);
return -ENOMEM;
}
将地址remap一下
udc_reinit(udc);
如下
static void udc_reinit(struct at91_udc *udc)
{
u32 i;
INIT_LIST_HEAD(&udc->gadget.ep_list);
INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
for (i = 0; i < NUM_ENDPOINTS; i++) {
struct at91_ep *ep = &udc->ep[i];
if (i != 0)
list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
ep->desc = NULL;
ep->stopped = 0;
ep->fifo_bank = 0;
ep->ep.maxpacket = ep->maxpacket;
ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);
// initialiser une queue par endpoint
INIT_LIST_HEAD(&ep->queue);
}
初始了6个节点
/* get interface and function clocks */
udc->iclk = clk_get(dev, "udc_clk");
udc->fclk = clk_get(dev, "udpck");
if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
DBG("clocks missing/n");
retval = -ENODEV;
goto fail0;
}
获取时钟
retval = device_register(&udc->gadget.dev);
if (retval < 0)
goto fail0;
开始设备注册
/* don't do anything until we have both gadget driver and VBUS */
clk_enable(udc->iclk);
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff);
/* Clear all pending interrupts - UDP may be used by bootloader. */
at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff);
clk_disable(udc->iclk);
/* request UDC and maybe VBUS irqs */
udc->udp_irq = platform_get_irq(pdev, 0);
if (request_irq(udc->udp_irq, at91_udc_irq,
IRQF_DISABLED, driver_name, udc)) {
DBG("request irq %d failed/n", udc->udp_irq);
retval = -EBUSY;
goto fail1;
}
请求IRQ资源 注册IRQ
if (udc->board.vbus_pin > 0) {
/*
* Get the initial state of VBUS - we cannot expect
* a pending interrupt.
*/
udc->vbus = at91_get_gpio_value(udc->board.vbus_pin);
if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
IRQF_DISABLED, driver_name, udc)) {
DBG("request vbus irq %d failed/n",
udc->board.vbus_pin);
free_irq(udc->udp_irq, udc);
retval = -EBUSY;
goto fail1;
}
} else {
DBG("no VBUS detection, assuming always-on/n");
udc->vbus = 1;
}
dev_set_drvdata(dev, udc);
device_init_wakeup(dev, 1);
create_debug_file(udc);
INFO("%s version %s/n", driver_name, DRIVER_VERSION);
return 0;
fail1:
device_unregister(&udc->gadget.dev);
fail0:
release_mem_region(res->start, res->end - res->start + 1);
DBG("%s probe failed, %d/n", driver_name, retval);
return retval;
}
看看刚才注册的平台驱动
static struct platform_driver at91_udc_driver = {
.remove = __exit_p(at91udc_remove),
.shutdown = at91udc_shutdown,
.suspend = at91udc_suspend,
.resume = at91udc_resume,
.driver = {
.name = (char *) driver_name,
.owner = THIS_MODULE,
},
};
看一下这些方法
移除
static int __exit at91udc_remove(struct platform_device *pdev)
{
struct at91_udc *udc = platform_get_drvdata(pdev);
struct resource *res;
获取驱动数据,该结构体在前面已经提到了
DBG("remove/n");
if (udc->driver)
return -EBUSY;
断开和hosts的连接
pullup(udc, 0);
device_init_wakeup(&pdev->dev, 0);
remove_debug_file(udc);
if (udc->board.vbus_pin > 0)
free_irq(udc->board.vbus_pin, udc);
free_irq(udc->udp_irq, udc);
device_unregister(&udc->gadget.dev);
iounmap(udc->udp_baseaddr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, res->end - res->start + 1);
clk_put(udc->iclk);
clk_put(udc->fclk);
释放irq资源 内存资源 和时钟资源
return 0;
}
static void at91udc_shutdown(struct platform_device *dev)
{
/* force disconnect on reboot */
pullup(platform_get_drvdata(dev), 0);
}
Shutdown 只是关闭了和host的连接
是如何关闭和host的连接的?
将各个节点中的request都处理完
调用gadaget 的disconnetct 方法
对寄存器进行设置