zoukankan      html  css  js  c++  java
  • Linux gadget驱动分析1驱动加载过程

      为了解决一个问题,简单看了一遍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

    int usb_composite_register(struct usb_composite_driver *driver)//zero_driver
    {
        if (!driver || !driver->dev || !driver->bind || composite)
            return -EINVAL;
    
        if (!driver->name)
            driver->name = "composite";
        composite_driver.function =  (char *) driver->name;
        composite_driver.driver.name = driver->name;
        composite = driver;
    
        return usb_gadget_register_driver(&composite_driver);
    }

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

    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 
    20         u8                usb_dma_dir;
    21 
    22         u8                usb_dma_trigger;//bool. dma triggered
    23         u8                usb_dma_trigger_next;//need trigger again
    24         u8                usb_less_mps;
    25         u32                usb_dma_cnt;//one dma transfer count
    26         u32                usb_dma_loop;//for short packet only;dma loop, each loop 32byte;
    27         u32                     usb_dma_owner;
    28 
    29         struct usb_ctrlrequest            crq;
    30         s32                setup_ret;
    31 
    32         u32                             irq_enbl;
    33 };

    这个结构中大部分不需要关注,需要关注的是第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:1;
     8     unsigned            is_otg:1;
     9     unsigned            is_a_peripheral:1;
    10     unsigned            b_hnp_enable:1;
    11     unsigned            a_hnp_support:1;
    12     unsigned            a_alt_hnp_support:1;
    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 < 0)
    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 0;
    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)

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

        if (loopdefault) {
            loopback_add(cdev, autoresume != 0);
            sourcesink_add(cdev, autoresume != 0);
        } else {
            sourcesink_add(cdev, autoresume != 0);
            loopback_add(cdev, autoresume != 0);
        }

    应该就是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 = 3,
    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 = 0;
    27 
    28     status = config->bind(config);
    29     if (status < 0) {
    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 = 0; 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 < 0) {
    20             list_del(&function->list);
    21             function->config = NULL;
    22         }
    23     } else
    24         value = 0;
    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 < 0)
    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 0;
    42 }

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

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

  • 相关阅读:
    sudo: 在加载插件“sudoers_policy”时在 /etc/sudo.conf 第 0 行出错 sudo: /usr/lib/sudo/sudoers.so 必须只对其所有者可写 sudo:
    ubuntu多版本Python和pip切换
    Ubuntu16.04下安装python3.6.4详细步骤
    oenstack firewalld ufw
    linux相关安全设置
    TransPose: Towards Explainable Human Pose Estimation by Transformer
    TransTrack: Multiple-Object Tracking with Transformer
    Rethinking Semantic Segmentation from a Sequence-to-Sequence Perspective with Transformers
    Adversarial Sparse Transformer for Time Series Forecasting
    Learning to Detect Objects with a 1 Megapixel Event Camera
  • 原文地址:https://www.cnblogs.com/fengeryi/p/3372717.html
Copyright © 2011-2022 走看看