android usb 分析(2)

上次分析到 usb_composite_probe(&android_usb_driver, android_bind);

这里继续分析android_usb_driver 和 android_bind。

1. android_usb_driver

    static struct usb_composite_driver android_usb_driver = {
        .name = "android_usb",   //driver名
        .dev = &device_desc,     //usb_device_descriptor 内容
        .strings = dev_strings,
        .enable_function = android_enable_function,
    };
a. usb_composite_driver 数据结构原型定义在 include/linux/usb/composite.h 中

    /**
     * struct usb_composite_driver - groups configurations into a gadget
     * @name: For diagnostics, identifies the driver.
     * @iProduct: Used as iProduct override if @dev->iProduct is not set.
     * If NULL value of @name is taken.
     * @iManufacturer: Used as iManufacturer override if @dev->iManufacturer is
     * not set. If NULL a default "<system> <release> with <udc>" value
     * will be used.
     * @dev: Template descriptor for the device, including default device
     * identifiers.
     * @strings: tables of strings, keyed by identifiers assigned during bind()
     * and language IDs provided in control requests
     * @needs_serial: set to 1 if the gadget needs userspace to provide
     * a serial number. If one is not provided, warning will be printed.
     * @unbind: Reverses bind; called as a side effect of unregistering
     * this driver.
     * @disconnect: optional driver disconnect method
     * @suspend: Notifies when the host stops sending USB traffic,
     * after function notifications
     * @resume: Notifies configuration when the host restarts USB traffic,
     * before function notifications
     *
     * Devices default to reporting self powered operation. Devices which rely
     * on bus powered operation should report this in their @bind() method.
     *
     * Before returning from bind, various fields in the template descriptor
     * may be overridden. These include the idVendor/idProduct/bcdDevice values
     * normally to bind the appropriate host side driver, and the three strings
     * (iManufacturer, iProduct, iSerialNumber) normally used to provide user
     * meaningful device identifiers. (The strings will not be defined unless
     * they are defined in @dev and @strings.) The correct ep0 maxpacket size
     * is also reported, as defined by the underlying controller driver.
     */
    struct usb_composite_driver {
        const char *name;
        const char *iProduct;
        const char *iManufacturer;
        const struct usb_device_descriptor *dev;
        struct usb_gadget_strings **strings;
        unsigned needs_serial:1;
        struct class *class;
        atomic_t function_count;
        int (*unbind)(struct usb_composite_dev *);
        void (*disconnect)(struct usb_composite_dev *);
        /* global suspend hooks */
        void (*suspend)(struct usb_composite_dev *);
        void (*resume)(struct usb_composite_dev *);
        void (*enable_function)(struct usb_function *f, int enable);
    };
b. device_desc 设备描述声明:
    static struct usb_device_descriptor device_desc = {
        .bLength = sizeof(device_desc),
        .bDescriptorType = USB_DT_DEVICE,
        .bcdUSB = __constant_cpu_to_le16(0x0200),
        .bDeviceClass = USB_CLASS_PER_INTERFACE,
        .idVendor = __constant_cpu_to_le16(VENDOR_ID),
        .idProduct = __constant_cpu_to_le16(PRODUCT_ID),
        .bcdDevice = __constant_cpu_to_le16(0xffff),
        .bNumConfigurations = 1,
    };
c. dev_strings 设备的字符内容 声明:
    static struct usb_gadget_strings *dev_strings[] = {  //多个usb_gadget_string集合
        &stringtab_dev,    //具体一个usb_gadget_string
        NULL,
    };

    static struct usb_gadget_strings stringtab_dev = {
        .language = 0x0409, /* en-us */
        .strings = strings_dev,
    };

    /* String Table */
    static struct usb_string strings_dev[] = {
        /* These dummy values should be overridden by platform data */
        [STRING_MANUFACTURER_IDX].s = "Android",
        [STRING_PRODUCT_IDX].s = "Android",
        [STRING_SERIAL_IDX].s = "0123456789ABCDEF",
        { } /* end of list */
    };
2. android_enable_function() :
    void android_enable_function(struct usb_function *f, int enable)
    {
        struct android_dev *dev = _android_dev;   //获得全局变量 _android_dev
        int disable = !enable;
        int product_id;
        if (!!f->disabled != disable) {
            usb_function_set_enabled(f, !disable);    //使能usb function.
    #ifdef CONFIG_USB_ANDROID_RNDIS
            if (!strcmp(f->name, "rndis")) {
                struct usb_function *func;
                /* Windows does not support other interfaces when RNDIS is enabled,
                 * so we disable UMS and MTP when RNDIS is on.
                 */
                list_for_each_entry(func, &android_config_driver.functions, list) {
                    if (!strcmp(func->name, "usb_mass_storage")
                        || !strcmp(func->name, "mtp")) {
                        usb_function_set_enabled(func, !enable);
                    }
                }
            }
    #endif
            update_dev_desc(dev);  //更新设备描述
            product_id = get_product_id(dev);
            device_desc.idProduct = __constant_cpu_to_le16(product_id);
            if (dev->cdev)
                dev->cdev->desc.idProduct = device_desc.idProduct;
            usb_composite_force_reset(dev->cdev);    //reset
        }
    }
a. usb_function_set_enabled():
    void usb_function_set_enabled(struct usb_function *f, int enabled)
    {
        f->disabled = !enabled;
        kobject_uevent(&f->dev->kobj, KOBJ_CHANGE);
    }
b. update_dev_desc() : 更新设备描述符
    void update_dev_desc(struct android_dev *dev)
    {
        struct usb_function *f;
        struct usb_function *last_enabled_f = NULL;
        int num_enabled = 0;
        int has_iad = 0;
            
        dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE;
        dev->cdev->desc.bDeviceSubClass = 0x00;
        dev->cdev->desc.bDeviceProtocol = 0x00;
        list_for_each_entry(f, &android_config_driver.functions, list) {
            if (!f->disabled) {
                num_enabled++;
                last_enabled_f = f;
                if (f->descriptors[0]->bDescriptorType ==
                        USB_DT_INTERFACE_ASSOCIATION)
                    has_iad = 1;
            }
            if (num_enabled > 1 && has_iad) {
                dev->cdev->desc.bDeviceClass = USB_CLASS_MISC;
                dev->cdev->desc.bDeviceSubClass = 0x02;
                dev->cdev->desc.bDeviceProtocol = 0x01;
                break;
            }
        }
        if (num_enabled == 1) {
    #ifdef CONFIG_USB_ANDROID_RNDIS
            if (!strcmp(last_enabled_f->name, "rndis")) {
    #ifdef CONFIG_USB_ANDROID_RNDIS_WCEIS
                dev->cdev->desc.bDeviceClass =
                        USB_CLASS_WIRELESS_CONTROLLER;
    #else
                dev->cdev->desc.bDeviceClass = USB_CLASS_COMM;
    #endif
            }
    #endif
        }
    }
c. usb_composite_force_reset():  重置usb gadget.
    void usb_composite_force_reset(struct usb_composite_dev *cdev)
    {
        unsigned long flags;
        spin_lock_irqsave(&cdev->lock, flags);
        /* force reenumeration */
        if (cdev && cdev->gadget && cdev->gadget->speed != USB_SPEED_UNKNOWN) {
            spin_unlock_irqrestore(&cdev->lock, flags);
            usb_gadget_disconnect(cdev->gadget);
            msleep(10);
            usb_gadget_connect(cdev->gadget);
        } else {
            spin_unlock_irqrestore(&cdev->lock, flags);
        }
    }
3. android_bind():
    static int android_bind(struct usb_composite_dev *cdev)
    {
        struct android_dev *dev = _android_dev;
        struct usb_gadget *gadget = cdev->gadget;
        int gcnum, id, product_id, ret;
        printk(KERN_INFO "android_bind\n");
        /* Allocate string descriptor numbers ... note that string
         * contents can be overridden by the composite_dev glue.
         */
        id = usb_string_id(cdev); //allocate an unused string ID
        if (id < 0)
            return id;
        strings_dev[STRING_MANUFACTURER_IDX].id = id;
        device_desc.iManufacturer = id;
        id = usb_string_id(cdev);
        if (id < 0)
            return id;
        strings_dev[STRING_PRODUCT_IDX].id = id;
        device_desc.iProduct = id;
        id = usb_string_id(cdev);
        if (id < 0)
            return id;
        strings_dev[STRING_SERIAL_IDX].id = id;
        device_desc.iSerialNumber = id;
        /* register our configuration */
        ret = usb_add_config(cdev, &android_config_driver, android_bind_config); //add a configuration to a device.
        if (ret) {
            printk(KERN_ERR "usb_add_config failed\n");
            return ret;
        }
        gcnum = usb_gadget_controller_number(gadget); //support bcdDevice id convention.
        if (gcnum >= 0)
            device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
        else {
            /* gadget zero is so simple (for now, no altsettings) that
             * it SHOULD NOT have problems with bulk-capable hardware.
             * so just warn about unrcognized controllers -- don't panic.
             *
             * things like configuration and altsetting numbering
             * can need hardware-specific attention though.
             */
            pr_warning("%s: controller '%s' not recognized\n",
                longname, gadget->name);
            device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
        }
        usb_gadget_set_selfpowered(gadget); 
        dev->cdev = cdev;
        product_id = get_product_id(dev);
        device_desc.idProduct = __constant_cpu_to_le16(product_id);
        cdev->desc.idProduct = device_desc.idProduct;
        return 0;
    }
a. usb_string_id() :
    /**
     * usb_string_id() - allocate an unused string ID
     * @cdev: the device whose string descriptor IDs are being allocated
     * Context: single threaded during gadget setup
     *
     * @usb_string_id() is called from bind() callbacks to allocate
     * string IDs. Drivers for functions, configurations, or gadgets will
     * then store that ID in the appropriate descriptors and string table.
     *
     * All string identifier should be allocated using this,
     * @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure
     * that for example different functions don't wrongly assign different
     * meanings to the same identifier.
     */
    int usb_string_id(struct usb_composite_dev *cdev)
    {
        if (cdev->next_string_id < 254) {
            /* string id 0 is reserved by USB spec for list of
             * supported languages */
            /* 255 reserved as well? -- mina86 */
            cdev->next_string_id++;
            return cdev->next_string_id;
        }
        return -ENODEV;
    }
b. usb_add_config()
    /**
     * usb_add_config() - add a configuration to a device.
     * @cdev: wraps the USB gadget
     * @config: the configuration, with bConfigurationValue assigned
     * @bind: the configuration's bind function
     * Context: single threaded during gadget setup
     *
     * One of the main tasks of a composite @bind() routine is to
     * add each of the configurations it supports, using this routine.
     *
     * This function returns the value of the configuration's @bind(), which
     * is zero for success else a negative errno value. Binding configurations
     * assigns global resources including string IDs, and per-configuration
     * resources such as interface IDs and endpoints.
     */
    int usb_add_config(struct usb_composite_dev *cdev,
            struct usb_configuration *config,
            int (*bind)(struct usb_configuration *))
    {
        int status = -EINVAL;
        struct usb_configuration *c;
        DBG(cdev, "adding config #%u '%s'/%p\n",
                config->bConfigurationValue,
                config->label, config);
        
        if (!config->bConfigurationValue || !bind)
            goto done;
        
        /* Prevent duplicate configuration identifiers */
        list_for_each_entry(c, &cdev->configs, list) {
            if (c->bConfigurationValue == config->bConfigurationValue) {
                status = -EBUSY;
                goto done;
            }
        }
        
        config->cdev = cdev;
        list_add_tail(&config->list, &cdev->configs);
        INIT_LIST_HEAD(&config->functions);
        config->next_interface_id = 0;
        status = bind(config);
        if (status < 0) {
            list_del(&config->list);
            config->cdev = NULL;
        } else {
            unsigned i;
            DBG(cdev, "cfg %d/%p speeds:%s%s\n",
                config->bConfigurationValue, config,
                config->highspeed ? " high" : "",
                config->fullspeed
                    ? (gadget_is_dualspeed(cdev->gadget)
                        ? " full"
                        : " full/low")
                    : "");
            for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {
                struct usb_function *f = config->interface[i];
                if (!f)
                    continue;
                DBG(cdev, " interface %d = %s/%p\n",
                    i, f->name, f);
            }
        }
        /* set_alt(), or next bind(), sets up
         * ep->driver_data as needed.
         */
        usb_ep_autoconfig_reset(cdev->gadget);
    done:
        if (status)
            DBG(cdev, "added config '%s'/%u --> %d\n", config->label,
                    config->bConfigurationValue, status);
        return status;
    }
c. usb_gadget_controller_number() : support bcdDevice id convention.
    /**
     * usb_gadget_controller_number - support bcdDevice id convention
     * @gadget: the controller being driven
     *
     * Return a 2-digit BCD value associated with the peripheral controller,
     * suitable for use as part of a bcdDevice value, or a negative error code.
     *
     * NOTE: this convention is purely optional, and has no meaning in terms of
     * any USB specification. If you want to use a different convention in your
     * gadget driver firmware -- maybe a more formal revision ID -- feel free.
     *
     * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!)
     * to change their behavior accordingly. For example it might help avoiding
     * some chip bug.
     */
    static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
    {
        if (gadget_is_net2280(gadget))
            return 0x01;
        else if (gadget_is_dummy(gadget))
            return 0x02;
        else if (gadget_is_pxa(gadget))
            return 0x03;
        else if (gadget_is_goku(gadget))
            return 0x06;
        else if (gadget_is_omap(gadget))
            return 0x08;
        else if (gadget_is_lh7a40x(gadget))
            return 0x09;
        else if (gadget_is_pxa27x(gadget))
            return 0x11;
        else if (gadget_is_s3c2410(gadget))
            return 0x12;
        else if (gadget_is_at91(gadget))
            return 0x13;
        else if (gadget_is_imx(gadget))
            return 0x14;
        else if (gadget_is_musbhdrc(gadget))
            return 0x16;
        else if (gadget_is_atmel_usba(gadget))
            return 0x18;
        else if (gadget_is_fsl_usb2(gadget))
            return 0x19;
        else if (gadget_is_amd5536udc(gadget))
            return 0x20;
        else if (gadget_is_m66592(gadget))
            return 0x21;
        else if (gadget_is_fsl_qe(gadget))
            return 0x22;
        else if (gadget_is_ci13xxx(gadget))
            return 0x23;
        else if (gadget_is_langwell(gadget))
            return 0x24;
        else if (gadget_is_r8a66597(gadget))
            return 0x25;
        else if (gadget_is_s3c_hsotg(gadget))
            return 0x26;
        return -ENOENT;
    }
d. usb_gadget_set_selfpowered()
    /**
     * usb_gadget_set_selfpowered - sets the device selfpowered feature.
     * @gadget:the device being declared as self-powered
     *
     * this affects the device status reported by the hardware driver
     * to reflect that it now has a local power supply.
     *
     * returns zero on success, else negative errno.
     */
    static inline int usb_gadget_set_selfpowered(struct usb_gadget *gadget)
    {
        if (!gadget->ops->set_selfpowered)
            return -EOPNOTSUPP;
        return gadget->ops->set_selfpowered(gadget, 1);
    }
4. android_config_driver
    static struct usb_configuration android_config_driver = {
        .label = "android",
        .setup = android_setup_config,
        .bConfigurationValue = 1,
        .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
        .bMaxPower = 0xFA, /* 500ma */
    };
android_setup_config()
    static int android_setup_config(struct usb_configuration *c,
            const struct usb_ctrlrequest *ctrl)
    {
        int i;
        int ret = -EOPNOTSUPP;
        for (i = 0; i < android_config_driver.next_interface_id; i++) {
            if (android_config_driver.interface[i]->setup) {
                ret = android_config_driver.interface[i]->setup(
                    android_config_driver.interface[i], ctrl);
                if (ret >= 0)
                    return ret;
            }
        }
        return ret;
    }
5. android_bind_config()
    static int android_bind_config(struct usb_configuration *c)
    {
        struct android_dev *dev = _android_dev;
        printk(KERN_DEBUG "android_bind_config\n");
        dev->config = c;
        if (should_bind_functions(dev))
            bind_functions(dev);
        return 0;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值