为了解决一个问题,简单看了一遍linux gadget驱动的加载流程.做一下记录.

  使用的内核为linux 2.6.35 硬件为芯唐NUC950. gadget是在UDC驱动上面的一层,如果要编写gadget驱动只需调用linux 的gadget API,不需设计底层的UDC驱动. 但要是分析驱动BUG,就需要了同时了解一下UDC.

  下面以简单的gadget zero驱动分析驱动的加载流程.

  主要是一系列的bind的调用,让gadget驱动一步步与硬件的端点联系起来.

  从insmod g_zero.ko开始.

zero.c

  1. static struct usb_composite_driver zero_driver = {
  2. .name = "zero",
  3. .dev = &device_desc,
  4. .strings = dev_strings,
  5. .bind = zero_bind,
  6. .unbind = zero_unbind,
  7. .suspend = zero_suspend,
  8. .resume = zero_resume,
  9. };

这个结构体是zero.c中的,如果是自己写的gadget驱动,这个结构体及这些函数需要自己实现.

先不去细看结构体中的具体内容,现在只关注注册流程.

  1. static int __init init(void)
  2. {
  3. return usb_composite_register(&zero_driver);
  4. }

调用
usb_composite_register(&zero_driver);

zero_driver作为参数传递,类型为struct usb_composite_driver

composite.c

  1. int usb_composite_register(struct usb_composite_driver *driver)//zero_driver
  2. {
  3. if (!driver || !driver->dev || !driver->bind || composite)
  4. return -EINVAL;
  5.  
  6. if (!driver->name)
  7. driver->name = "composite";
  8. composite_driver.function = (char *) driver->name;
  9. composite_driver.driver.name = driver->name;
  10. composite = driver;
  11.  
  12. return usb_gadget_register_driver(&composite_driver);
  13. }

composite_driver定义在composite.c中

  1. static struct usb_gadget_driver composite_driver = {
  2. .speed = USB_SPEED_HIGH,
  3.  
  4. .bind = composite_bind,
  5. .unbind = composite_unbind,
  6.  
  7. .setup = composite_setup,
  8. .disconnect = composite_disconnect,
  9.  
  10. .suspend = composite_suspend,
  11. .resume = composite_resume,
  12.  
  13. .driver = {
  14. .owner = THIS_MODULE,
  15. },
  16. };

composite = driver;

用全局指针指向zero_driver,后面用到compoite这个指针时候知道它的值在这里赋好了.

最后调用usb_gadget_register_driver(&composite_driver);

不同的芯片实现不同,但原理应该类似,一般在xxx_udc.c中

nuc950在nuc900_udc.c中:

  1. int usb_gadget_register_driver (struct usb_gadget_driver *driver)
  2. {
  3. struct nuc900_udc *udc = &controller;
  4. int retval;
  5.  
  6. printk("usb_gadget_register_driver() '%s'\n", driver->driver.name);
  7.  
  8. if (!udc)
  9. return -ENODEV;
  10.  
  11. if (udc->driver)
  12. return -EBUSY;
  13. if (!driver->bind || !driver->unbind || !driver->setup
  14. || driver->speed == USB_SPEED_UNKNOWN)
  15. return -EINVAL;
  16. printk("driver->speed=%d\n", driver->speed);
  17. udc->gadget.name = gadget_name;
  18. udc->gadget.ops = &nuc900_ops;
  19. udc->gadget.is_dualspeed = ;
  20. udc->gadget.speed = USB_SPEED_HIGH;//USB_SPEED_FULL;
  21. udc->ep0state = EP0_IDLE;
  22.  
  23. udc->gadget.dev.release = nop_release;
  24.  
  25. udc->driver = driver;
  26.  
  27. udc->gadget.dev.driver = &driver->driver;
  28.  
  29. printk( "binding gadget driver '%s'\n", driver->driver.name);
  30. if ((retval = driver->bind (&udc->gadget)) != ) {
  31. printk("bind fail\n");
  32. udc->driver = ;
  33. udc->gadget.dev.driver = ;
  34. return retval;
  35. }
  36. printk( "after driver bind:%p\n" , driver->bind);
  37.  
  38. mdelay();
  39. __raw_writel(__raw_readl(REG_PWRON) | 0x400, REG_PWRON);//power on usb D+ high
  40.  
  41. return ;
  42. }

controller是udc中很重要的一个变量,结构为

  1. struct nuc900_udc {
  2. spinlock_t lock;
  3.  
  4. struct nuc900_ep ep[NUC900_ENDPOINTS];
  5. struct usb_gadget gadget;
  6. struct usb_gadget_driver *driver;
  7. struct platform_device *pdev;
  8.  
  9. struct clk *clk;
  10. struct resource *res;
  11. void __iomem *reg;
  12. int irq;
  13.  
  14. enum ep0_state ep0state;
  15.  
  16. u8 usb_devstate;
  17. u8 usb_address;
  18.  
  19. u8 usb_dma_dir;
  20.  
  21. u8 usb_dma_trigger;//bool. dma triggered
  22. u8 usb_dma_trigger_next;//need trigger again
  23. u8 usb_less_mps;
  24. u32 usb_dma_cnt;//one dma transfer count
  25. u32 usb_dma_loop;//for short packet only;dma loop, each loop 32byte;
  26. u32 usb_dma_owner;
  27.  
  28. struct usb_ctrlrequest crq;
  29. s32 setup_ret;
  30.  
  31. u32 irq_enbl;
  32. };

这个结构中大部分不需要关注,需要关注的是第5行:

struct usb_gadget        gadget;
定义在gadget.h中,这linux标准的结构体:

  1. struct usb_gadget {
  2. /* readonly to gadget driver */
  3. const struct usb_gadget_ops *ops;
  4. struct usb_ep *ep0;
  5. struct list_head ep_list; /* of usb_ep */
  6. enum usb_device_speed speed;
  7. unsigned is_dualspeed:;
  8. unsigned is_otg:;
  9. unsigned is_a_peripheral:;
  10. unsigned b_hnp_enable:;
  11. unsigned a_hnp_support:;
  12. unsigned a_alt_hnp_support:;
  13. const char *name;
  14. struct device dev;
  15. };

大致先扫一下这个结构,然后回到

usb_gadget_register_driver函数。

大体意思就是对上面的结构体进行了一番赋值,具体意义再回头看

然后在31行调用

if ((retval = driver->bind (&udc->gadget)) != 0)

第一个bind被调用了。

继续贴代码

  1. static int composite_bind(struct usb_gadget *gadget)
  2. {
  3. struct usb_composite_dev *cdev;
  4. int status = -ENOMEM;
  5.  
  6. cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
  7. if (!cdev)
  8. return status;
  9.  
  10. spin_lock_init(&cdev->lock);
  11. cdev->gadget = gadget;
  12. set_gadget_data(gadget, cdev);
  13. INIT_LIST_HEAD(&cdev->configs);
  14.  
  15. /* preallocate control response and buffer */
  16. cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
  17. if (!cdev->req)
  18. goto fail;
  19. cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
  20. if (!cdev->req->buf)
  21. goto fail;
  22. cdev->req->complete = composite_setup_complete;
  23. gadget->ep0->driver_data = cdev;
  24.  
  25. cdev->bufsiz = USB_BUFSIZ;
  26. cdev->driver = composite;
  27.  
  28. usb_gadget_set_selfpowered(gadget);
  29.  
  30. /* interface and string IDs start at zero via kzalloc.
  31. * we force endpoints to start unassigned; few controller
  32. * drivers will zero ep->driver_data.
  33. */
  34. usb_ep_autoconfig_reset(cdev->gadget);
  35.  
  36. /* standardized runtime overrides for device ID data */
  37. if (idVendor)
  38. cdev->desc.idVendor = cpu_to_le16(idVendor);
  39. if (idProduct)
  40. cdev->desc.idProduct = cpu_to_le16(idProduct);
  41. if (bcdDevice)
  42. cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
  43.  
  44. /* composite gadget needs to assign strings for whole device (like
  45. * serial number), register function drivers, potentially update
  46. * power state and consumption, etc
  47. */
  48. status = composite->bind(cdev);
  49. if (status < )
  50. goto fail;
  51.  
  52. cdev->desc = *composite->dev;
  53. cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
  54.  
  55. /* strings can't be assigned before bind() allocates the
  56. * releavnt identifiers
  57. */
  58. if (cdev->desc.iManufacturer && iManufacturer)
  59. string_override(composite->strings,
  60. cdev->desc.iManufacturer, iManufacturer);
  61. if (cdev->desc.iProduct && iProduct)
  62. string_override(composite->strings,
  63. cdev->desc.iProduct, iProduct);
  64. if (cdev->desc.iSerialNumber && iSerialNumber)
  65. string_override(composite->strings,
  66. cdev->desc.iSerialNumber, iSerialNumber);
  67.  
  68. status = device_create_file(&gadget->dev, &dev_attr_suspended);
  69. if (status)
  70. goto fail;
  71.  
  72. INFO(cdev, "%s ready\n", composite->name);
  73. return ;
  74.  
  75. fail:
  76. composite_unbind(gadget);
  77. return status;
  78. }

还是简单分析

11~12行就是你中有我,我中有你

13行值得注意一下,初始化一个链表,config就是配置链表。

一个设备可能有多个配置

一个配置可能有多个接口

一个接口可能有多个端点或设置

15~23行 都与ep0这个控制端口有关,控制端口的相关内直接在设备bind的时候做也比较合理。

26行 cdev->driver = composite; //还记得composite指向的是谁,就是zero_driver

 这就bind好了吧。

直接看48行

status = composite->bind(cdev);

第二个bind被调用,

satic int __init zero_bind(struct usb_composite_dev *cdev)

这个函数需要关注的这几行

  1. if (loopdefault) {
  2. loopback_add(cdev, autoresume != );
  3. sourcesink_add(cdev, autoresume != );
  4. } else {
  5. sourcesink_add(cdev, autoresume != );
  6. loopback_add(cdev, autoresume != );
  7. }

应该就是gadget zero的两种配置 
sourcesink_add()在f_sourcesink.c中,是自己实现的

在此函数中调用

  1. return usb_add_config(cdev, &sourcesink_driver);
  1. static struct usb_configuration sourcesink_driver = {
  2. .label = "source/sink",
  3. .strings = sourcesink_strings,
  4. .bind = sourcesink_bind_config,
  5. .setup = sourcesink_setup,
  6. .bConfigurationValue = ,
  7. .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
  8. /* .iConfiguration = DYNAMIC */
  9. };

注意这个结构体中又出现一个bind

usb_add_config 在composite.c 中

  1. int usb_add_config(struct usb_composite_dev *cdev,
  2. struct usb_configuration *config)
  3. {
  4. int status = -EINVAL;
  5. struct usb_configuration *c;
  6.  
  7. DBG(cdev, "adding config #%u '%s'/%p\n",
  8. config->bConfigurationValue,
  9. config->label, config);
  10.  
  11. if (!config->bConfigurationValue || !config->bind)
  12. goto done;
  13.  
  14. /* Prevent duplicate configuration identifiers */
  15. list_for_each_entry(c, &cdev->configs, list) {
  16. if (c->bConfigurationValue == config->bConfigurationValue) {
  17. status = -EBUSY;
  18. goto done;
  19. }
  20. }
  21.  
  22. config->cdev = cdev;
  23. list_add_tail(&config->list, &cdev->configs);
  24.  
  25. INIT_LIST_HEAD(&config->functions);
  26. config->next_interface_id = ;
  27.  
  28. status = config->bind(config);
  29. if (status < ) {
  30. list_del(&config->list);
  31. config->cdev = NULL;
  32. } else {
  33. unsigned i;
  34.  
  35. DBG(cdev, "cfg %d/%p speeds:%s%s\n",
  36. config->bConfigurationValue, config,
  37. config->highspeed ? " high" : "",
  38. config->fullspeed
  39. ? (gadget_is_dualspeed(cdev->gadget)
  40. ? " full"
  41. : " full/low")
  42. : "");
  43.  
  44. for (i = ; i < MAX_CONFIG_INTERFACES; i++) {
  45. struct usb_function *f = config->interface[i];
  46.  
  47. if (!f)
  48. continue;
  49. DBG(cdev, " interface %d = %s/%p\n",
  50. i, f->name, f);
  51. }
  52. }
  53.  
  54. /* set_alt(), or next config->bind(), sets up
  55. * ep->driver_data as needed.
  56. */
  57. usb_ep_autoconfig_reset(cdev->gadget);
  58.  
  59. done:
  60. if (status)
  61. DBG(cdev, "added config '%s'/%u --> %d\n", config->label,
  62. config->bConfigurationValue, status);
  63. return status;
  64. }

23行,把配置插入链表。(bind设备的时候初始化的那个链表)

25行,又初始化一个function链表。(一个配置可以有多个接口)

28行,status = config->bind(config);
  第三次调用bind

找到config->bind的真身,在f_sourcesink.c中

  1. static int __init sourcesink_bind_config(struct usb_configuration *c)
  2. {
  3. struct f_sourcesink *ss;
  4. int status;
  5.  
  6. ss = kzalloc(sizeof *ss, GFP_KERNEL);
  7. if (!ss)
  8. return -ENOMEM;
  9. init_completion(&ss->gdt_completion);
  10. ss->function.name = "source/sink";
  11. ss->function.descriptors = fs_source_sink_descs;
  12. ss->function.bind = sourcesink_bind;
  13. ss->function.unbind = sourcesink_unbind;
  14. ss->function.set_alt = sourcesink_set_alt;
  15. ss->function.disable = sourcesink_disable;
  16.  
  17. status = usb_add_function(c, &ss->function);
  18. if (status)
  19. kfree(ss);
  20. return status;
  21. }

留意一下12行function.bind

17行status = usb_add_function(c, &ss->function);

函数在composite.c中

  1. int usb_add_function(struct usb_configuration *config,
  2. struct usb_function *function)
  3. {
  4. int value = -EINVAL;
  5.  
  6. DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
  7. function->name, function,
  8. config->label, config);
  9.  
  10. if (!function->set_alt || !function->disable)
  11. goto done;
  12.  
  13. function->config = config;
  14. list_add_tail(&function->list, &config->functions);
  15.  
  16. /* REVISIT *require* function->bind? */
  17. if (function->bind) {
  18. value = function->bind(config, function);
  19. if (value < ) {
  20. list_del(&function->list);
  21. function->config = NULL;
  22. }
  23. } else
  24. value = ;
  25.  
  26. /* We allow configurations that don't work at both speeds.
  27. * If we run into a lowspeed Linux system, treat it the same
  28. * as full speed ... it's the function drivers that will need
  29. * to avoid bulk and ISO transfers.
  30. */
  31. if (!config->fullspeed && function->descriptors)
  32. config->fullspeed = true;
  33. if (!config->highspeed && function->hs_descriptors)
  34. config->highspeed = true;
  35.  
  36. done:
  37. if (value)
  38. DBG(config->cdev, "adding '%s'/%p --> %d\n",
  39. function->name, function, value);
  40. return value;
  41. }

14行,同样把function插入链表

18行,第四次调用bind

回顾一下第一次bind设备,第二次bind配置,第三次bind接口,第四次该端点了

直接到f_sourcesink.c中:

  1. static int __init
  2. sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
  3. {
  4. struct usb_composite_dev *cdev = c->cdev;
  5. struct f_sourcesink *ss = func_to_ss(f);
  6. int id;
  7.  
  8. /* allocate interface ID(s) */
  9. id = usb_interface_id(c, f);
  10. if (id < )
  11. return id;
  12. source_sink_intf.bInterfaceNumber = id;
  13.  
  14. /* allocate endpoints */
  15. ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
  16. if (!ss->in_ep) {
  17. autoconf_fail:
  18. ERROR(cdev, "%s: can't autoconfigure on %s\n",
  19. f->name, cdev->gadget->name);
  20. return -ENODEV;
  21. }
  22. ss->in_ep->driver_data = cdev; /* claim */
  23.  
  24. ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
  25. if (!ss->out_ep)
  26. goto autoconf_fail;
  27. ss->out_ep->driver_data = cdev; /* claim */
  28.  
  29. /* support high speed hardware */
  30. if (gadget_is_dualspeed(c->cdev->gadget)) {
  31. hs_source_desc.bEndpointAddress =
  32. fs_source_desc.bEndpointAddress;
  33. hs_sink_desc.bEndpointAddress =
  34. fs_sink_desc.bEndpointAddress;
  35. f->hs_descriptors = hs_source_sink_descs;
  36. }
  37.  
  38. DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
  39. gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
  40. f->name, ss->in_ep->name, ss->out_ep->name);
  41. return ;
  42. }

15 和24 行分别获得了一个端口。 gadget zero设备使用了两个端口来收发数据。

以上差不多就是gadget驱动的注册和bind的过程。

Linux gadget驱动分析1------驱动加载过程的更多相关文章

  1. 第42天学习打卡(Class类 Class类的常用方法 内存分析 类的加载过程 类加载器 反射操作泛型 反射操作注解)

    Class类 对象照镜子后得到的信息:某个类的属性.方法和构造器.某个类到底实现了哪些接口.对于每个类而言,JRE都为其保留一个不变的Class类型的对象.一个Class对象包含了特定某个结构(cla ...

  2. linux内核启动以及文件系统的加载过程

    Linux 内核启动及文件系统加载过程 当u-boot 开始执行 bootcmd 命令,就进入 Linux 内核启动阶段.普通 Linux 内核的启动过程也可以分为两个阶段.本文以项目中使用的 lin ...

  3. Dubbo源码分析之ExtensionLoader加载过程解析

    ExtensionLoader加载机制阅读: Dubbo的类加载机制是模仿jdk的spi加载机制:  Jdk的SPI扩展加载机制:约定是当服务的提供者每增加一个接口的实现类时,需要在jar包的META ...

  4. 分析ELF的加载过程

    http://blog.chinaunix.net/uid-72446-id-2060538.html 对于可执行文件来说,段的加载位置是固定的,程序段表中如实反映了段的加载地址.对于共享库来?段的加 ...

  5. 重温.NET下Assembly的加载过程

    最近在工作中牵涉到了.NET下的一个古老的问题:Assembly的加载过程.虽然网上有很多文章介绍这部分内容,很多文章也是很久以前就已经出现了,但阅读之后发现,并没能解决我的问题,有些点写的不是特别详 ...

  6. 重温.NET下Assembly的加载过程 ASP.NET Core Web API下事件驱动型架构的实现(三):基于RabbitMQ的事件总线

    重温.NET下Assembly的加载过程   最近在工作中牵涉到了.NET下的一个古老的问题:Assembly的加载过程.虽然网上有很多文章介绍这部分内容,很多文章也是很久以前就已经出现了,但阅读之后 ...

  7. NET下Assembly的加载过程

    NET下Assembly的加载过程 最近在工作中牵涉到了.NET下的一个古老的问题:Assembly的加载过程.虽然网上有很多文章介绍这部分内容,很多文章也是很久以前就已经出现了,但阅读之后发现,并没 ...

  8. Linux驱动的两种加载方式过程分析

    一.概念简述 在Linux下可以通过两种方式加载驱动程序:静态加载和动态加载. 静态加载就是把驱动程序直接编译进内核,系统启动后可以直接调用.静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要重新 ...

  9. linux驱动动态与静态加载

    在Linux中驱动的加载方式有动态加载和静态加载.动态加载,即驱动不添加到内核中,在内核启动完成后,仅在用到这一驱动时才会进行加载静态加载,驱动编译进内核中,随内核的启动而完成驱动的加载.添加字符驱动 ...

随机推荐

  1. Mac sierra下 wget安装

    本文由@ray 出品,转载请注明出处.  文章链接:http://www.cnblogs.com/wolfray/p/8040699.html 没有Wget的日子是非常难过的,强大的Mac OS 下安 ...

  2. [原创]Toolbar setNavigationIcon无效

    最近在做一个Toolbar,setNavigationIcon()这个方法一直无效,说什么的都有,什么getSupportActionBar().setNavigationIcon()的,说设置sty ...

  3. PHP基础知识测试题及解析

      本试题共40道选择题,10道判断题,考试时间1个半小时 一:选择题(单项选择,每题2分): 1. LAMP具体结构不包含下面哪种(A ) A:Windows系统 B:Apache服务器 C:MyS ...

  4. jQuery——入口函数

    中文网 http://www.css88.com/jqapi-1.9/ 版本兼容问题 版本一:1.x版本,兼容IE678 版本二:2.x版本,不兼容IE678 入口函数区别 <script> ...

  5. SQL server 2005中无法新建作用(Job)的问题

    1.在使用sqlserver2005创建作业时,创建不了,提示 无法将类型为“Microsoft.SqlServer.Management.Smo.SimpleObjectKey”的对象强制转换为类型 ...

  6. Python语言之类

    1.一个空类 #Filename : emptyclass.py class Empty: pass e = Empty() print( e ) #<__main__.Empty object ...

  7. css图片高清适配

    同一张图片,在普通屏显示正常,但高清屏出现模糊.原因是原来一个像素的点分成的四个像素的点进行了显示. 解决方案:在高清屏中把图片变成二倍图,前提是二倍的高清图已经存在. .icon{ backgrou ...

  8. Postfix 故障记录

    1.postfix 目录/var/mail/USER文件大小限制报错 解决方式: 编辑 /etc/postfix/main.cf 文件添加以下内容 mailbox_size_limit = 51200 ...

  9. Java中File对象的常用方法

    创建: 1.createNewFile()指定位置创建一个空文件,成功就返回true,如果已存在就不创建,然后返回false. 2.mkdir() 在指定位置创建一个单级文件夹. 3.mkdirs() ...

  10. POJ 1088 滑雪(简单的记忆化dp)

    题目 又一道可以称之为dp的题目,虽然看了别人的代码,但是我的代码写的还是很挫,,,,,, //看了题解做的简单的记忆化dp #include<stdio.h> #include<a ...