android 系统在 linux usb 模块中加入了 adb 功能,具体代码在 drivers/usb/gadget/android.c 中
1. init/exit:
- static int __init init(void)
- {
- struct android_dev *dev;
- printk(KERN_INFO "android init\n");
- dev = kzalloc(sizeof(*dev), GFP_KERNEL); //分配 android_dev 内存
- if (!dev)
- return -ENOMEM;
- /* set default values, which should be overridden by platform data */
- dev->product_id = PRODUCT_ID; //product_id
- _android_dev = dev; //_android_dev 是本地的全局变量
- return platform_driver_register(&android_platform_driver); //注册platform_driver
- }
- module_init(init);
- static void __exit cleanup(void)
- {
- usb_composite_unregister(&android_usb_driver);
- platform_driver_unregister(&android_platform_driver);
- kfree(_android_dev);
- _android_dev = NULL;
- }
- module_exit(cleanup);
static int __init init(void)
{
struct android_dev *dev;
printk(KERN_INFO "android init\n");
dev = kzalloc(sizeof(*dev), GFP_KERNEL); //分配 android_dev 内存
if (!dev)
return -ENOMEM;
/* set default values, which should be overridden by platform data */
dev->product_id = PRODUCT_ID; //product_id
_android_dev = dev; //_android_dev 是本地的全局变量
return platform_driver_register(&android_platform_driver); //注册platform_driver
}
module_init(init);
static void __exit cleanup(void)
{
usb_composite_unregister(&android_usb_driver);
platform_driver_unregister(&android_platform_driver);
kfree(_android_dev);
_android_dev = NULL;
}
module_exit(cleanup);
android_dev 定义:
- struct android_dev {
- struct usb_composite_dev *cdev;
- struct usb_configuration *config;
- int num_products;
- struct android_usb_product *products;
- int num_functions;
- char **functions;
- int product_id;
- int version;
- };
struct android_dev {
struct usb_composite_dev *cdev;
struct usb_configuration *config;
int num_products;
struct android_usb_product *products;
int num_functions;
char **functions;
int product_id;
int version;
};
_android_dev 是一个本地定义的全局变量:
- static struct android_dev *_android_dev;
static struct android_dev *_android_dev;
默认的 product_id 和 vendor_id 定义:
- /* Default vendor and product IDs, overridden by platform data */
- #define VENDOR_ID 0x18D1
- #define PRODUCT_ID 0x0001
/* Default vendor and product IDs, overridden by platform data */
#define VENDOR_ID 0x18D1
#define PRODUCT_ID 0x0001
struct android_platform_driver 定义:
- static struct platform_driver android_platform_driver = {
- .driver = { .name = "android_usb", },
- .probe = android_probe,
- };
static struct platform_driver android_platform_driver = {
.driver = { .name = "android_usb", },
.probe = android_probe,
};
2. android_probe()
- static int android_probe(struct platform_device *pdev)
- {
- struct android_usb_platform_data *pdata = pdev->dev.platform_data; //从platform_data中获取内容
- //platform_data中内容定义在board-xxx.c中,通过比较 .name (即android_usb) 来匹配。
- struct android_dev *dev = _android_dev;
- printk(KERN_INFO "android_probe pdata: %p\n", pdata);
- if (pdata) {
- dev->products = pdata->products; //android_usb_product
- dev->num_products = pdata->num_products;
- dev->functions = pdata->functions;
- dev->num_functions = pdata->num_functions;
- if (pdata->vendor_id)
- device_desc.idVendor = //vendor_id
- __constant_cpu_to_le16(pdata->vendor_id);
- if (pdata->product_id) { //product_id
- dev->product_id = pdata->product_id;
- device_desc.idProduct =
- __constant_cpu_to_le16(pdata->product_id);
- }
- if (pdata->version)
- dev->version = pdata->version;
- if (pdata->product_name)
- strings_dev[STRING_PRODUCT_IDX].s = pdata->product_name;
- if (pdata->manufacturer_name)
- strings_dev[STRING_MANUFACTURER_IDX].s =
- pdata->manufacturer_name;
- if (pdata->serial_number)
- strings_dev[STRING_SERIAL_IDX].s = pdata->serial_number;
- }
- return usb_composite_probe(&android_usb_driver, android_bind); //注册一个复杂的驱动
- }
static int android_probe(struct platform_device *pdev)
{
struct android_usb_platform_data *pdata = pdev->dev.platform_data; //从platform_data中获取内容
//platform_data中内容定义在board-xxx.c中,通过比较 .name (即android_usb) 来匹配。
struct android_dev *dev = _android_dev;
printk(KERN_INFO "android_probe pdata: %p\n", pdata);
if (pdata) {
dev->products = pdata->products; //android_usb_product
dev->num_products = pdata->num_products;
dev->functions = pdata->functions;
dev->num_functions = pdata->num_functions;
if (pdata->vendor_id)
device_desc.idVendor = //vendor_id
__constant_cpu_to_le16(pdata->vendor_id);
if (pdata->product_id) { //product_id
dev->product_id = pdata->product_id;
device_desc.idProduct =
__constant_cpu_to_le16(pdata->product_id);
}
if (pdata->version)
dev->version = pdata->version;
if (pdata->product_name)
strings_dev[STRING_PRODUCT_IDX].s = pdata->product_name;
if (pdata->manufacturer_name)
strings_dev[STRING_MANUFACTURER_IDX].s =
pdata->manufacturer_name;
if (pdata->serial_number)
strings_dev[STRING_SERIAL_IDX].s = pdata->serial_number;
}
return usb_composite_probe(&android_usb_driver, android_bind); //注册一个复杂的驱动
}
上面的 platform_data 内容定义在 board-xxx.c中:
- #ifdef CONFIG_USB_ANDROID //条件宏,如果没有可以不编译
- #define GOOGLE_VENDOR_ID 0x18d1
- #define GOOGLE_PRODUCT_ID 0x9018
- #define GOOGLE_ADB_PRODUCT_ID 0x9015
- static char *usb_functions_adb[] = { //所有的 function 只有一个 adb
- "adb",
- };
- static char *usb_functions_all[] = {
- "adb",
- };
- static struct android_usb_product usb_products[] = {
- {
- .product_id = GOOGLE_PRODUCT_ID,
- .num_functions = ARRAY_SIZE(usb_functions_adb),
- .functions = usb_functions_adb,
- },
- };
- static struct android_usb_platform_data android_usb_pdata = {
- .vendor_id = GOOGLE_VENDOR_ID,
- .product_id = GOOGLE_PRODUCT_ID,
- .functions = usb_functions_all,
- .products = usb_products,
- .version = 0x0100,
- .product_name = "rowboat gadget",
- .manufacturer_name = "rowboat",
- .serial_number = "20100720",
- .num_functions = ARRAY_SIZE(usb_functions_all),
- };
- static struct platform_device androidusb_device = {
- .name = "android_usb", //这个名字是device名字,和上面的driver名字必须一样,用来匹配。
- .id = -1,
- .dev = {
- .platform_data = &android_usb_pdata, //这个就是上面的platform_data
- },
- };
- static void omap3evm_android_gadget_init(void)
- {
- platform_device_register(&androidusb_device); //上面定义,这里注册 platform_device 设备
- }
- #endif
#ifdef CONFIG_USB_ANDROID //条件宏,如果没有可以不编译
#define GOOGLE_VENDOR_ID 0x18d1
#define GOOGLE_PRODUCT_ID 0x9018
#define GOOGLE_ADB_PRODUCT_ID 0x9015
static char *usb_functions_adb[] = { //所有的 function 只有一个 adb
"adb",
};
static char *usb_functions_all[] = {
"adb",
};
static struct android_usb_product usb_products[] = {
{
.product_id = GOOGLE_PRODUCT_ID,
.num_functions = ARRAY_SIZE(usb_functions_adb),
.functions = usb_functions_adb,
},
};
static struct android_usb_platform_data android_usb_pdata = {
.vendor_id = GOOGLE_VENDOR_ID,
.product_id = GOOGLE_PRODUCT_ID,
.functions = usb_functions_all,
.products = usb_products,
.version = 0x0100,
.product_name = "rowboat gadget",
.manufacturer_name = "rowboat",
.serial_number = "20100720",
.num_functions = ARRAY_SIZE(usb_functions_all),
};
static struct platform_device androidusb_device = {
.name = "android_usb", //这个名字是device名字,和上面的driver名字必须一样,用来匹配。
.id = -1,
.dev = {
.platform_data = &android_usb_pdata, //这个就是上面的platform_data
},
};
static void omap3evm_android_gadget_init(void)
{
platform_device_register(&androidusb_device); //上面定义,这里注册 platform_device 设备
}
#endif
3. usb_composite_probe(&android_usb_driver, android_bind);
- /**
- * usb_composite_probe() - register a composite driver
- * @driver: the driver to register
- * @bind: the callback used to allocate resources that are shared across the
- * whole device, such as string IDs, and add its configurations using
- * @usb_add_config(). This may fail by returning a negative errno
- * value; it should return zero on successful initialization.
- * Context: single threaded during gadget setup
- *
- * This function is used to register drivers using the composite driver
- * framework. The return value is zero, or a negative errno value.
- * Those values normally come from the driver's @bind method, which does
- * all the work of setting up the driver to match the hardware.
- *
- * On successful return, the gadget is ready to respond to requests from
- * the host, unless one of its components invokes usb_gadget_disconnect()
- * while it was binding. That would usually be done in order to wait for
- * some userspace participation.
- */
- extern int usb_composite_probe(struct usb_composite_driver *driver,
- int (*bind)(struct usb_composite_dev *cdev))
- {
- if (!driver || !driver->dev || !bind || composite)
- return -EINVAL;
- if (!driver->iProduct)
- driver->iProduct = driver->name;
- if (!driver->name)
- driver->name = "composite";
- composite_driver.function = (char *) driver->name;
- composite_driver.driver.name = driver->name;
- composite = driver;
- composite_gadget_bind = bind;
- driver->class = class_create(THIS_MODULE, "usb_composite"); //建立一新类 usb_composite
- if (IS_ERR(driver->class))
- return PTR_ERR(driver->class);
- driver->class->dev_uevent = composite_uevent;
- return usb_gadget_probe_driver(&composite_driver, composite_bind); //这里调到了musb模块
- }
/**
* usb_composite_probe() - register a composite driver
* @driver: the driver to register
* @bind: the callback used to allocate resources that are shared across the
* whole device, such as string IDs, and add its configurations using
* @usb_add_config(). This may fail by returning a negative errno
* value; it should return zero on successful initialization.
* Context: single threaded during gadget setup
*
* This function is used to register drivers using the composite driver
* framework. The return value is zero, or a negative errno value.
* Those values normally come from the driver's @bind method, which does
* all the work of setting up the driver to match the hardware.
*
* On successful return, the gadget is ready to respond to requests from
* the host, unless one of its components invokes usb_gadget_disconnect()
* while it was binding. That would usually be done in order to wait for
* some userspace participation.
*/
extern int usb_composite_probe(struct usb_composite_driver *driver,
int (*bind)(struct usb_composite_dev *cdev))
{
if (!driver || !driver->dev || !bind || composite)
return -EINVAL;
if (!driver->iProduct)
driver->iProduct = driver->name;
if (!driver->name)
driver->name = "composite";
composite_driver.function = (char *) driver->name;
composite_driver.driver.name = driver->name;
composite = driver;
composite_gadget_bind = bind;
driver->class = class_create(THIS_MODULE, "usb_composite"); //建立一新类 usb_composite
if (IS_ERR(driver->class))
return PTR_ERR(driver->class);
driver->class->dev_uevent = composite_uevent;
return usb_gadget_probe_driver(&composite_driver, composite_bind); //这里调到了musb模块
}
4. usb_gadget_probe_driver(&composite_driver, composite_bind);
这个函数定义在 drivers/usb/musb/musb_gadget.c 中.
musb是am3715中集成的usb模块,这usb模块好象是从Mentor Graphic Corporation公司买去的。
这个留到musb模块里去讨论了。
- /*
- * Register the gadget driver. Used by gadget drivers when
- * registering themselves with the controller.
- *
- * -EINVAL something went wrong (not driver)
- * -EBUSY another gadget is already using the controller
- * -ENOMEM no memory to perform the operation
- *
- * @param driver the gadget driver
- * @param bind the driver's bind function
- * @return <0 if error, 0 if everything is fine
- */
- int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
- {
- int retval;
- unsigned long flags;
- struct musb *musb = the_gadget;
- D_ENTER
- printk(KERN_INFO "xxha: --- enter musb");
- if (!driver
- || driver->speed != USB_SPEED_HIGH
- || !bind || !driver->setup)
- return -EINVAL;
- /* driver must be initialized to support peripheral mode */
- if (!musb) {
- DBG(1, "%s, no dev??\n", __func__);
- return -ENODEV;
- }
- DBG(3, "registering driver %s\n", driver->function);
- spin_lock_irqsave(&musb->lock, flags);
- if (musb->gadget_driver) {
- DBG(1, "%s is already bound to %s\n",
- musb_driver_name,
- musb->gadget_driver->driver.name);
- retval = -EBUSY;
- } else {
- musb->gadget_driver = driver;
- musb->g.dev.driver = &driver->driver;
- driver->driver.bus = NULL;
- musb->softconnect = 1;
- retval = 0;
- }
- spin_unlock_irqrestore(&musb->lock, flags);
- if (retval == 0) {
- retval = bind(&musb->g);
- if (retval != 0) {
- DBG(3, "bind to driver %s failed --> %d\n",
- driver->driver.name, retval);
- musb->gadget_driver = NULL;
- musb->g.dev.driver = NULL;
- }
- spin_lock_irqsave(&musb->lock, flags);
- otg_set_peripheral(musb->xceiv, &musb->g);
- musb->xceiv->state = OTG_STATE_B_IDLE;
- musb->is_active = 1;
- /* FIXME this ignores the softconnect flag. Drivers are
- * allowed hold the peripheral inactive until for example
- * userspace hooks up printer hardware or DSP codecs, so
- * hosts only see fully functional devices.
- */
- if (!is_otg_enabled(musb))
- musb_start(musb);
- otg_set_peripheral(musb->xceiv, &musb->g);
- spin_unlock_irqrestore(&musb->lock, flags);
- if (is_otg_enabled(musb)) {
- struct usb_hcd *hcd = musb_to_hcd(musb);
- DBG(3, "OTG startup...\n");
- /* REVISIT: funcall to other code, which also
- * handles power budgeting ... this way also
- * ensures HdrcStart is indirectly called.
- */
- retval = usb_add_hcd(musb_to_hcd(musb), -1, 0);
- if (retval < 0) {
- DBG(1, "add_hcd failed, %d\n", retval);
- spin_lock_irqsave(&musb->lock, flags);
- otg_set_peripheral(musb->xceiv, NULL);
- musb->gadget_driver = NULL;
- musb->g.dev.driver = NULL;
- spin_unlock_irqrestore(&musb->lock, flags);
- } else {
- hcd->self.uses_pio_for_control = 1;
- }
- }
- }
- return retval;
- }
- EXPORT_SYMBOL(usb_gadget_probe_driver);
这里继续分析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,
- };
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);
- };
/**
* 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,
- };
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 */
- };
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
- }
- }
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);
- }
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
- }
- }
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);
- }
- }
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;
- }
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;
- }
/**
* 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;
- }
/**
* 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;
- }
/**
* 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);
- }
/**
* 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 */
- };
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;
- }
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;
- }
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;
}