AT91

来源:互联网 发布:uname linux 编辑:程序博客网 时间:2024/06/04 18:33

 

1  udc_init_module. 1

2     at91_udc_driver 5

 

 

Gadget  AT91

 

 

1  udc_init_module

 

 

  注册了这样一个驱动

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;

}

 

 

2         at91_udc_driver

 

看看刚才注册的平台驱动

 

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 方法

  对寄存器进行设置

 

 

 

 

原创粉丝点击