Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c。这个文件实现USB的上层应用协议。
首先包含了一些系统级别的头文件,如模块、电源管理、of API等


#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/utsname.h>
#include <linux/platform_device.h>
#include <linux/pm_qos.h>
#include <linux/of.h>#include <linux/usb/ch9.h>
#include <linux/usb/composite.h>
#include <linux/usb/gadget.h>
#include <linux/usb/android.h>#include <mach/diag_dload.h>#include "gadget_chips.h"/** Kbuild is not very cooperative with respect to linking separately* compiled library objects into one module.  So for now we won't use* separate compilation ... ensuring init/exit sections work to shrink* the runtime footprint, and giving us at least some parts of what* a "gcc --combine ... part1.c part2.c part3.c ... " build would.*/
//实现上层USB应用协议的c文件
#include "usbstring.c"
#include "config.c"
#include "epautoconf.c"
#include "composite.c"#ifdef CONFIG_SND_RAWMIDI
#include "f_midi.c"
#endif
#include "f_diag.c"
#include "f_qdss.c"
#include "f_rmnet_smd.c"
#include "f_rmnet_sdio.c"
#include "f_rmnet_smd_sdio.c"
#include "f_rmnet.c"
#include "f_gps.c"
#ifdef CONFIG_SND_PCM   //宏 CONFIG_SND_PCM 有定义
#include "f_audio_source.c"
#endif
#include "f_fs.c"
#include "f_mass_storage.c"
#include "u_serial.c"
#include "u_sdio.c"
#include "u_smd.c"
#include "u_bam.c"
#include "u_rmnet_ctrl_smd.c"
#include "u_rmnet_ctrl_qti.c"
#include "u_ctrl_hsic.c"
#include "u_data_hsic.c"
#include "u_ctrl_hsuart.c"
#include "u_data_hsuart.c"
#include "f_serial.c"
#include "f_acm.c"
#include "f_adb.c"
#include "f_ccid.c"
#include "f_mtp.c"
#include "f_accessory.c"
#define USB_ETH_RNDIS y
#include "f_rndis.c"
#include "rndis.c"
#include "f_qc_ecm.c"
#include "f_mbim.c"
#include "u_bam_data.c"
#include "f_ecm.c"
#include "f_qc_rndis.c"
#include "u_ether.c"
#include "u_qc_ether.c"
#ifdef CONFIG_TARGET_CORE  //宏 CONFIG_TARGET_CORE 未定义
#include "f_tcm.c"
#endif
#ifdef CONFIG_SND_PCM
#include "u_uac1.c"
#include "f_uac1.c"
#endif
#include "f_ncm.c"//Linux驱动中常见的宏声明,定义了作者、描述、LICENSE、版本号
MODULE_AUTHOR("Mike Lockwood");
MODULE_DESCRIPTION("Android Composite USB Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");static const char longname[] = "Gadget Android";/* Default vendor and product IDs, overridden by userspace */
// Google自己申请的VID与PID的宏,可以在用户空间的init.**.usb.rc文件里被覆写
#define VENDOR_ID       0x18D1
#define PRODUCT_ID      0x0001#define ANDROID_DEVICE_NODE_NAME_LENGTH 11
/* f_midi configuration */
#define MIDI_INPUT_PORTS    1
#define MIDI_OUTPUT_PORTS   1
#define MIDI_BUFFER_SIZE    1024
#define MIDI_QUEUE_LENGTH   32

#define ANDROID_DEVICE_NODE_NAME_LENGTH 11 定义 /sys/class/android_usb/ 下的文件节点android0之类的文件名最大长度
结构体android_usb_function抽象了Android自定义的用来hook Linux USB驱动框架中的相应功能的功能函数

struct android_usb_function {char *name;void *config;struct device *dev;char *dev_name;struct device_attribute **attributes;struct android_dev *android_dev;/* Optional: initialization during gadget bind */int (*init)(struct android_usb_function *, struct usb_composite_dev *);/* Optional: cleanup during gadget unbind */void (*cleanup)(struct android_usb_function *);/* Optional: called when the function is added the list of*      enabled functions */void (*enable)(struct android_usb_function *);/* Optional: called when it is removed */void (*disable)(struct android_usb_function *);int (*bind_config)(struct android_usb_function *,struct usb_configuration *);/* Optional: called when the configuration is removed */void (*unbind_config)(struct android_usb_function *,struct usb_configuration *);/* Optional: handle ctrl requests before the device is configured */int (*ctrlrequest)(struct android_usb_function *,struct usb_composite_dev *,const struct usb_ctrlrequest *);
};

结构体 android_usb_function_holder 持有所有的当前支持的可以实现的USB设备

struct android_usb_function_holder {struct android_usb_function *f;/* for android_conf.enabled_functions */struct list_head enabled_list;
};

结构体android_dev抽象了android USB gadget device,即 /sys/class/android_usb下的 android0 等节点(目前就一个)


/**
* struct android_dev - represents android USB gadget device
* @name: device name.
* @functions: an array of all the supported USB function
*    drivers that this gadget support but not necessarily
*    added to one of the gadget configurations.
* @cdev: The internal composite device. Android gadget device
*    is a composite device, such that it can support configurations
*    with more than one function driver.
* @dev: The kernel device that represents this android device.
* @enabled: True if the android gadget is enabled, means all
*    the configurations were set and all function drivers were
*    bind and ready for USB enumeration.
* @disable_depth: Number of times the device was disabled, after
*    symmetrical number of enables the device willl be enabled.
*    Used for controlling ADB userspace disable/enable requests.
* @mutex: Internal mutex for protecting device member fields.
* @pdata: Platform data fetched from the kernel device platfrom data.
* @connected: True if got connect notification from the gadget UDC.
*    False if got disconnect notification from the gadget UDC.
* @sw_connected: Equal to 'connected' only after the connect
*    notification was handled by the android gadget work function.
* @suspended: True if got suspend notification from the gadget UDC.
*    False if got resume notification from the gadget UDC.
* @sw_suspended: Equal to 'suspended' only after the susped
*    notification was handled by the android gadget work function.
* @pm_qos: An attribute string that can be set by user space in order to
*    determine pm_qos policy. Set to 'high' for always demand pm_qos
*    when USB bus is connected and resumed. Set to 'low' for disable
*    any setting of pm_qos by this driver. Default = 'high'.
* @work: workqueue used for handling notifications from the gadget UDC.
* @configs: List of configurations currently configured into the device.
*    The android gadget supports more than one configuration. The host
*    may choose one configuration from the suggested.
* @configs_num: Number of configurations currently configured and existing
*    in the configs list.
* @list_item: This driver supports more than one android gadget device (for
*    example in order to support multiple USB cores), therefore this is
*    a item in a linked list of android devices.
*/
struct android_dev {const char *name;struct android_usb_function **functions;struct usb_composite_dev *cdev;struct device *dev;bool enabled;int disable_depth;struct mutex mutex;struct android_usb_platform_data *pdata;bool connected;bool sw_connected;bool suspended;bool sw_suspended;char pm_qos[5];struct pm_qos_request pm_qos_req_dma;struct work_struct work;/* A list of struct android_configuration */struct list_head configs;int configs_num;/* A list node inside the android_dev_list */struct list_head list_item;char ffs_aliases[256];
};

结构体 android_configuration 抽象USB设备传送给HOST的配置信息

struct android_configuration {struct usb_configuration usb_config;/* A list of the functions supported by this config */struct list_head enabled_functions;/* A list node inside the struct android_dev.configs list */struct list_head list_item;
};

下面的变量跟9006模式有关,即ramdupm(download)

struct dload_struct __iomem *diag_dload;

下面的变量是对Android USB的 /sys/class/android_usb 目录的抽象

static struct class *android_class;

下边的变量是android dev的list和数量,对应的是/sys/class/android_usb 目录下的“android0”之类的目录

static struct list_head android_dev_list;
static int android_dev_count;

下边的函数在bind config和unbind config是调用

static int android_bind_config(struct usb_configuration *c);
static void android_unbind_config(struct usb_configuration *c);

下边的函数转换usb_composite_devandroid_dev

static struct android_dev *cdev_to_android_dev(struct usb_composite_dev *cdev);

下边的函数分配和释放Android USB设备的configuration

static struct android_configuration *alloc_android_config(struct android_dev *dev);
static void free_android_config(struct android_dev *dev,struct android_configuration *conf);

下边的函数更新PID和USB串号

static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum);

下边的宏和变量跟VID、PID、串号相关,会形成String表,保存在跟device string相关的变量 usb_gadget_strings

/* string IDs are assigned dynamically */
#define STRING_MANUFACTURER_IDX     0
#define STRING_PRODUCT_IDX      1
#define STRING_SERIAL_IDX       2static char manufacturer_string[256];
static char product_string[256];
static char serial_string[256];  /* String Table */
static struct usb_string strings_dev[] = {[STRING_MANUFACTURER_IDX].s = manufacturer_string,[STRING_PRODUCT_IDX].s = product_string,[STRING_SERIAL_IDX].s = serial_string,{  }            /* end of list */
};static struct usb_gadget_strings stringtab_dev = {.language   = 0x0409,   /* en-us */.strings    = strings_dev,
};static struct usb_gadget_strings *dev_strings[] = {&stringtab_dev,NULL,
};

下边的结构体抽象出发送给HOST的USB设备描述符,可以通过文件节点 /sys/class/android_usb/android0下的相应节点来查看和改变

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,
};

下边的结构体抽象出跟USB OTG相关的描述符,使用OTG,手机进入HOST模式

static struct usb_otg_descriptor otg_descriptor = {.bLength =      sizeof otg_descriptor,.bDescriptorType =  USB_DT_OTG,.bmAttributes =     USB_OTG_SRP | USB_OTG_HNP,.bcdOTG               = __constant_cpu_to_le16(0x0200),
}; static const struct usb_descriptor_header *otg_desc[] = {(struct usb_descriptor_header *) &otg_descriptor,NULL,
};

枚举android_device_state描述设备的状态,有断开连接,连接,配置好,挂起,恢复 。工作时的状态是配置好

enum android_device_state {USB_DISCONNECTED,USB_CONNECTED,USB_CONFIGURED,USB_SUSPENDED,USB_RESUMED
};

下边的init函数在模块初始化时调用

static int __init init(void)
{int ret;/* Override composite driver functions */composite_driver.setup = android_setup;composite_driver.disconnect = android_disconnect;composite_driver.suspend = android_suspend;composite_driver.resume = android_resume;INIT_LIST_HEAD(&android_dev_list);android_dev_count = 0;ret = platform_driver_register(&android_platform_driver);if (ret) {pr_err("%s(): Failed to register android""platform driver\n", __func__);}return ret;
}

首先,初始化Android设备list android_dev_list和Android设备数 android_dev_count为0,然后注册platform driverandroid_platform_driver 。最后,hook Linux USB驱动框架的复口USB驱动的setup、suspend、resume函数为本文件中定义的android_xxxx函数。变量 android_usb_driverusb_composite_driver 类型结构体,用来hook系统的usb_composite框架下的相关函数,定义如下

static struct usb_composite_driver android_usb_driver = {.name       = "android_usb",.dev        = &device_desc,.strings    = dev_strings,.unbind     = android_usb_unbind,.max_speed  = USB_SPEED_SUPER
};

本文件中的platform_driver相关配置如下,字符串 “android_usb_hsic” 没用到


static const struct platform_device_id android_id_table[] __devinitconst = {{.name = "android_usb",},{.name = "android_usb_hsic",},
};static struct of_device_id usb_android_dt_match[] = {{   .compatible = "qcom,android-usb",},{}
};static struct platform_driver android_platform_driver = {.driver = {.name = "android_usb",.of_match_table = usb_android_dt_match,},.probe = android_probe,.remove = android_remove,.id_table = android_id_table,
};

probe函数如下,主要作用是分配相应私有、全局的data、list、mutex等变量,读取dts中的配置,设置到相应的结构体里去,在 /sys/class 下添加文件目录节点 ,将自身的驱动probe到usb composite框架中,并设置休眠唤醒参数


static int __devinit android_probe(struct platform_device *pdev)
{struct android_usb_platform_data *pdata;struct android_dev *android_dev;struct resource *res;int ret = 0, i, len = 0;if (pdev->dev.of_node) {dev_dbg(&pdev->dev, "device tree enabled\n");pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);if (!pdata) {pr_err("unable to allocate platform data\n");return -ENOMEM;}of_property_read_u32(pdev->dev.of_node,"qcom,android-usb-swfi-latency",&pdata->swfi_latency);pdata->cdrom = of_property_read_bool(pdev->dev.of_node,"qcom,android-usb-cdrom");pdata->internal_ums = of_property_read_bool(pdev->dev.of_node,"qcom,android-usb-internal-ums");len = of_property_count_strings(pdev->dev.of_node,"qcom,streaming-func");if (len > MAX_STREAMING_FUNCS) {pr_err("Invalid number of functions used.\n");return -EINVAL;}for (i = 0; i < len; i++) {const char *name = NULL;of_property_read_string_index(pdev->dev.of_node,"qcom,streaming-func", i, &name);if (!name)continue;if (sizeof(name) > FUNC_NAME_LEN) {pr_err("Function name is bigger than allowed.\n");continue;}strlcpy(pdata->streaming_func[i], name,sizeof(pdata->streaming_func[i]));pr_debug("name of streaming function:%s\n",pdata->streaming_func[i]);}pdata->streaming_func_count = len;ret = of_property_read_u32(pdev->dev.of_node,"qcom,android-usb-uicc-nluns",&pdata->uicc_nluns);} else {pdata = pdev->dev.platform_data;}if (!android_class) {android_class = class_create(THIS_MODULE, "android_usb");if (IS_ERR(android_class))return PTR_ERR(android_class);}android_dev = kzalloc(sizeof(*android_dev), GFP_KERNEL);if (!android_dev) {pr_err("%s(): Failed to alloc memory for android_dev\n",__func__);ret = -ENOMEM;goto err_alloc;}android_dev->name = pdev->name;android_dev->disable_depth = 1;android_dev->functions = supported_functions;android_dev->configs_num = 0;INIT_LIST_HEAD(&android_dev->configs);INIT_WORK(&android_dev->work, android_work);mutex_init(&android_dev->mutex);android_dev->pdata = pdata;list_add_tail(&android_dev->list_item, &android_dev_list);android_dev_count++;if (pdata)composite_driver.usb_core_id = pdata->usb_core_id;elsecomposite_driver.usb_core_id = 0; /*To backward compatibility*/res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (res) {diag_dload = devm_ioremap(&pdev->dev, res->start,resource_size(res));if (!diag_dload) {dev_err(&pdev->dev, "ioremap failed\n");ret = -ENOMEM;goto err_dev;}} else {dev_dbg(&pdev->dev, "failed to get mem resource\n");}ret = android_create_device(android_dev, composite_driver.usb_core_id);if (ret) {pr_err("%s(): android_create_device failed\n", __func__);goto err_dev;}ret = usb_composite_probe(&android_usb_driver, android_bind);if (ret) {pr_err("%s(): Failed to register android ""composite driver\n", __func__);goto err_probe;}/* pm qos request to prevent apps idle power collapse */if (pdata && pdata->swfi_latency)pm_qos_add_request(&android_dev->pm_qos_req_dma,PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);strlcpy(android_dev->pm_qos, "high", sizeof(android_dev->pm_qos));return ret;
err_probe:android_destroy_device(android_dev);
err_dev:list_del(&android_dev->list_item);android_dev_count--;kfree(android_dev);
err_alloc:if (list_empty(&android_dev_list)) {class_destroy(android_class);android_class = NULL;}return ret;
}

结构体 android_usb_platform_data是android usb platform driver的dev的private data。其定义位于androd/kerenl/include/linux/usb/andriod.h文件中,这文件首先包含了usb复口头文件composite.h

 #ifndef    __LINUX_USB_ANDROID_H#define    __LINUX_USB_ANDROID_H#include <linux/usb/composite.h>

然后定义了结构体 android_usb_platform_data 及其中数组的最大范围用到的宏

#define MAX_STREAMING_FUNCS 3
#define FUNC_NAME_LEN 10
 struct android_usb_platform_data {int (*update_pid_and_serial_num)(uint32_t, const char *);u32 pm_qos_latency[MAX_VOTES];u8 usb_core_id;char streaming_func[MAX_STREAMING_FUNCS][FUNC_NAME_LEN];int  streaming_func_count;u8 uicc_nluns;bool cdrom;};

回到 android_probe 函数,若相应的dev有of_node,即在dts中有定义,则获取相应的配置。Android USB在dts中的配置位于android/kernel/arc/arm(或arm64,都一样,arm64中的qcom目录是对arm的软链接)/boot/dts/qcom目录下的msm8916.dtsi和msm8916-qrd.dtsi中,内容如下

android_usb: android_usb@086000c8 {compatible = "qcom,android-usb";reg = <0x086000c8 0xc8>;qcom,android-usb-swfi-latency = <1>;qcom,streaming-func = "mtp";qcom,android-usb-uicc-nluns = /bits/ 8 <1>;};&android_usb {qcom,android-usb-cdrom;};

首先通过 devm_kzalloc函数为相应dev的private指针分配内存,其类型为android_usb_platform_data
然后读出qcom,android-usb-swfi-latency ,其值用在 pm_qos_update_request 函数中来定义投票级别,默认值是1。
然后读出qcom,streaming-func的个数,并在循环中读出stream func,传给platform data里的 streaming_funcstreaming_func_count 中,这里的值只有一个”mtp”。
然后读出qcom,android-usb-cdrom,根据其存在与否决定是否支持CDROM。
最后读出qcom,android-usb-uicc-nluns,其在dtsi中的写法规定其占8位,即一个字节,默认值为1。
若不存在dts文件,则用传统的platform_device
在配置好platform_data后,则调用 class_create函数创建 /sys/class下的文件节点。
然后分配android_dev的内存,有dev的name、disable的深度、支持的USB功能、配置的数量、初始化configs list和work对了,配置其执行函数为 android_work 、初始化相应的mutex、设定之前分配的pdata。添加list_item到全局的 android_dev_list 中,并将 android_dev_count加1。
支持的USB功能在变量 supported_functions 数组中,其类型为 android_usb_function,内容如下

static struct android_usb_function *supported_functions[] = {&ffs_function,&mbim_function,&ecm_qc_function,
#ifdef CONFIG_SND_PCM&audio_function,
#endif&rmnet_smd_function,&rmnet_sdio_function,&rmnet_smd_sdio_function,&rmnet_function,&gps_function,&diag_function,&qdss_function,&serial_function,&adb_function,&ccid_function,&acm_function,&mtp_function,&ptp_function,&rndis_function,&rndis_qc_function,&ecm_function,&ncm_function,&mass_storage_function,&accessory_function,
#ifdef CONFIG_SND_PCM&audio_source_function,
#endif&uasp_function,
#ifdef CONFIG_SND_RAWMIDI&midi_function,
#endifNULL
};

各个具体的功能定义如下。
第一个ffs就是adb

static struct android_usb_function ffs_function = {.name       = "ffs",.init       = ffs_function_init,.enable     = ffs_function_enable,.disable    = ffs_function_disable,.cleanup    = ffs_function_cleanup,.bind_config    = ffs_function_bind_config,.attributes = ffs_function_attributes,
};

其他的见其名字

static struct android_usb_function adb_function = {.name       = "adb",.enable     = adb_android_function_enable,.disable    = adb_android_function_disable,.init       = adb_function_init,.cleanup    = adb_function_cleanup,.bind_config    = adb_function_bind_config,
};
static struct android_usb_function mbim_function = {.name       = "usb_mbim",.cleanup    = mbim_function_cleanup,.bind_config    = mbim_function_bind_config,.init       = mbim_function_init,.ctrlrequest    = mbim_function_ctrlrequest,.attributes     = mbim_function_attributes,
}; static struct android_usb_function diag_function = {.name       = "diag",.init       = diag_function_init,.cleanup    = diag_function_cleanup,.bind_config    = diag_function_bind_config,.attributes = diag_function_attributes,
};
static struct android_usb_function rndis_function = {.name       = "rndis",.init       = rndis_function_init,.cleanup    = rndis_function_cleanup,.bind_config    = rndis_function_bind_config,.unbind_config  = rndis_function_unbind_config,.attributes = rndis_function_attributes,
};static struct android_usb_function rndis_qc_function = {.name       = "rndis_qc",.init       = rndis_qc_function_init,.cleanup    = rndis_qc_function_cleanup,.bind_config    = rndis_qc_function_bind_config,.unbind_config  = rndis_qc_function_unbind_config,.attributes = rndis_function_attributes,
};
static struct android_usb_function ecm_function = {.name       = "ecm",.init       = ecm_function_init,.cleanup    = ecm_function_cleanup,.bind_config    = ecm_function_bind_config,.unbind_config  = ecm_function_unbind_config,.attributes = ecm_function_attributes,
}; static struct android_usb_function mass_storage_function = {.name       = "mass_storage",.init       = mass_storage_function_init,.cleanup    = mass_storage_function_cleanup,.bind_config    = mass_storage_function_bind_config,.attributes = mass_storage_function_attributes,
}; static struct android_usb_function accessory_function = {.name       = "accessory",.init       = accessory_function_init,.cleanup    = accessory_function_cleanup,.bind_config    = accessory_function_bind_config,.ctrlrequest    = accessory_function_ctrlrequest,
};

然后申请分配给USB的IO空间地址,即 reg = <0x086000c80xc8>;,获取到后分配给diag_dload
然后调用andriod_create_device函数,创建sys下的文件节点,比如 /sys/class/android_usb/android0之类的 , android_dev_list 中的单项就对应这个, usb_core_id 为0(因为 devm_kzalloc里有个“z”,即用0初始化分配的内存)。
其函数如下

static int android_create_device(struct android_dev *dev, u8 usb_core_id)
{struct device_attribute **attrs = android_usb_attributes;struct device_attribute *attr;char device_node_name[ANDROID_DEVICE_NODE_NAME_LENGTH];int err;/** The primary usb core should always have usb_core_id=0, since* Android user space is currently interested in android0 events.*/snprintf(device_node_name, ANDROID_DEVICE_NODE_NAME_LENGTH,"android%d", usb_core_id);dev->dev = device_create(android_class, NULL,MKDEV(0, 0), NULL, device_node_name);if (IS_ERR(dev->dev))return PTR_ERR(dev->dev);dev_set_drvdata(dev->dev, dev);while ((attr = *attrs++)) {err = device_create_file(dev->dev, attr);if (err) {device_destroy(android_class, dev->dev->devt);return err;}}return 0;
}

初始化相应节点的名字后,调用 device_create函数创建节点 /sys/class/android_usb/android0 ,并设置创造出来的文件节点的dev的private data为dev。
然后在循环里在创造出来的目录下创建更多的节点,这些节点的定义位于android_usb_attributes 。若有错误,则销毁目录 /sys/class/android_usb/android0
android_usb_attributes内容如下


static struct device_attribute *android_usb_attributes[] = {&dev_attr_idVendor,&dev_attr_idProduct,&dev_attr_bcdDevice,&dev_attr_bDeviceClass,&dev_attr_bDeviceSubClass,&dev_attr_bDeviceProtocol,&dev_attr_iManufacturer,&dev_attr_iProduct,&dev_attr_iSerial,&dev_attr_functions,&dev_attr_enable,&dev_attr_pm_qos,&dev_attr_state,&dev_attr_remote_wakeup,NULL
};

实现这些文件节点是通过宏DESCRIPTOR_ATTRDESCRIPTOR_STRING_ATTR 自动实现相应节点的show和store函数的,这两个宏如下

#define DESCRIPTOR_ATTR(field, format_string)               \
static ssize_t                              \
field ## _show(struct device *dev, struct device_attribute *attr,   \char *buf)                      \
{                                   \return snprintf(buf, PAGE_SIZE,                 \format_string, device_desc.field);      \
}                                   \
static ssize_t                              \
field ## _store(struct device *dev, struct device_attribute *attr,  \const char *buf, size_t size)               \
{                                   \int value;                          \if (sscanf(buf, format_string, &value) == 1) {          \device_desc.field = value;              \return size;                        \}                               \return -1;                          \
}                                   \
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store);#define DESCRIPTOR_STRING_ATTR(field, buffer)               \
static ssize_t                              \
field ## _show(struct device *dev, struct device_attribute *attr,   \char *buf)                      \
{                                   \return snprintf(buf, PAGE_SIZE, "%s", buffer);          \
}                                   \
static ssize_t                              \
field ## _store(struct device *dev, struct device_attribute *attr,  \const char *buf, size_t size)               \
{                                   \if (size >= sizeof(buffer))                 \return -EINVAL;                     \strlcpy(buffer, buf, sizeof(buffer));               \strim(buffer);                          \return size;                            \
}                                   \
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store);

相应宏的定义如下


DESCRIPTOR_ATTR(idVendor, "%04x\n")
DESCRIPTOR_ATTR(idProduct, "%04x\n")
DESCRIPTOR_ATTR(bcdDevice, "%04x\n")
DESCRIPTOR_ATTR(bDeviceClass, "%d\n")
DESCRIPTOR_ATTR(bDeviceSubClass, "%d\n")
DESCRIPTOR_ATTR(bDeviceProtocol, "%d\n")
DESCRIPTOR_STRING_ATTR(iManufacturer, manufacturer_string)
DESCRIPTOR_STRING_ATTR(iProduct, product_string)
DESCRIPTOR_STRING_ATTR(iSerial, serial_string)

节点functionsenablepm_qosstateremote_wakeup的定义如下

static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show,functions_store);
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
static DEVICE_ATTR(pm_qos, S_IRUGO | S_IWUSR,pm_qos_show, pm_qos_store);
static DEVICE_ATTR(state, S_IRUGO, state_show, NULL);
static DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR,remote_wakeup_show, remote_wakeup_store);

然后 usb_composite_probe 函数会被手动调用,加载 android_usb_driver
最后发送添加pm qos请求,并设置 pm_qos为“High”,返回结果为0。
函数的最后有 “error_probe“,”err_dev“,”err_alloc” 三个标签,处理不同阶段的错误。

再看退出相关的函数
先是注册移除函数

static void __exit cleanup(void)
{platform_driver_unregister(&android_platform_driver);
}
module_exit(cleanup);

然后android_remove函数被框架自动调用


static int android_remove(struct platform_device *pdev)
{struct android_dev *dev = NULL;struct android_usb_platform_data *pdata = pdev->dev.platform_data;int usb_core_id = 0;if (pdata)usb_core_id = pdata->usb_core_id;/* Find the android dev from the list */list_for_each_entry(dev, &android_dev_list, list_item) {if (!dev->pdata)break; /*To backward compatibility*/if (dev->pdata->usb_core_id == usb_core_id)break;}if (dev) {android_destroy_device(dev);if (pdata && pdata->swfi_latency)pm_qos_remove_request(&dev->pm_qos_req_dma);list_del(&dev->list_item);android_dev_count--;kfree(dev);}if (list_empty(&android_dev_list)) {class_destroy(android_class);android_class = NULL;usb_composite_unregister(&android_usb_driver);}return 0;
}

先是遍历 android_dev_list ,相应的 dev 的 pdata 为空或者 usb_core_id相同时就打断循环,调用android_destroy_device 销毁设备,要是 swfi_latency不为0的话,移除pm qos请求,在列表中删除这个 dev , android_dev_count 减1,释放相应 dev 的内存。
android_destroy_device 函数如下


static void android_destroy_device(struct android_dev *dev)
{struct device_attribute **attrs = android_usb_attributes;struct device_attribute *attr;while ((attr = *attrs++))device_remove_file(dev->dev, attr);device_destroy(android_class, dev->dev->devt);
}

可以看到,其功能就是删除目录/sys/class/android_usb/android0下的文件节点和目录本身。
android_dev_list为空的话,就销毁目录/sys/class/android_usb,并调用函数 usb_composite_unregister移除 android_usb_driver ,最后返回0。

当用USB线把Android设备与HOST连接时,Android设备会枚举自己。
当把pad/手机插到pc上时,可以作为u盘、网卡等usb功能设备呈现,这个就叫做gadget。可以理解为usb 从设备端,和host对应。

kernel/drivers/usb/gadget,这个目录是Android下usbgadget的主要目录。
Gadget功能组织单元:主要文件android.cusb gadget功能的统领文件,负责组织usb 复合设备的功能,与上层应用提供交互的接口,面向市场需求的产品规划部门。
复合设备逻辑处理单元(复合设备管理单元):主要文件:composite.c,这个文件类似于一个项目管理组,负责各个单元的接口对接,资源整理。针对拥有多个usb功能的复合设备,这部分负责将支持的各个功能组织到一起,协助各个功能与UDC控制器单元建立联系。
具体功能单元:以U盘为例,f_mass_storge.c文件,用来完成具体的功能。这个部分是一个功能性很强的部分,将与UDC控制器单元直接对话,完成数据的传输。
UDC控制器单元:只做一件事情,收发usb数据,将数据透明的传递出去。

下面这个结构体就是android usb gadget复合设备的结构体,这个结构体的成员反映出了android下gadget的设计思路

 struct android_dev {struct android_usb_function **functions;    //gadget设备支持的功能struct list_head enabled_functions;    //链表,记录当前场景哪个功能被使能struct usb_composite_dev *cdev;       //复合设备,对外交流的代言人struct device *dev;bool enabled;        //是否启用gadget功能struct mutex mutex;     //互斥锁bool connected;            //是否连接hostboolsw_connected;            //软连接状态struct work_struct work;       //当状态发生改变时,向用户空间发送event消息(kobject_uevent_env)
};

struct android_usb_function**functions;这个结构成员用来记录当前软件版本中android gadget设备可以支持的usb function
Android 4.0 ICS支持的功能如下:

static struct android_usb_function*supported_functions[] = {&adb_function,&acm_function,&mtp_function,&ptp_function,&rndis_function,&mass_storage_function,&accessory_function,NULL};

通过这个结构体,可以想象出用户空间是如何控制android下gadget设备的功能切换及使能、禁能的。大概如下:将需要支持的功能注入到变量enabled_functions中,通过控制变量enable来启动/关闭gadget功能。
用户空间对android gadget设备的配置在init.usb.rc文件中,主要是对不同功能组合及vid/pid的配置。

android usb gadget分析相关推荐

  1. android挂载usb设备,android usb挂载分析---MountService启动

    在android usb挂载分析----vold启动,我们的vold模块已经启动了,通信的机制也已经建立起来了,接下来我们分析一下MountService的启动,也就是我们FrameWork层的启动, ...

  2. android usb挂载分析---MountService启动

    在android usb挂载分析----vold启动,我们的vold模块已经启动了,通信的机制也已经建立起来了,接下来我们分析一下MountService的启动,也就是我们FrameWork层的启动, ...

  3. Android USB gadget

    Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c.这个文件实现USB的上层应用协议. 首先包含了一些 ...

  4. Android USB Accessory分析

    转自:https://blog.csdn.net/yingzhao80/article/details/45511351 Android下USB Accessory的实现分析 摘要:本文介绍了USB ...

  5. android usb_disk2,Android USB gadget configfs学习笔记总结

    1.一个config_item 是通过显式用户空间mkdir操作创建的,通过rmdir销毁.属性(文件)在mkdir之后出现,可以通过read和write读取或修改属性文件.与sysfs一样,read ...

  6. Android USB Gadget复合设备驱动(打印机)测试方法

    启动Android打印机设备,并用USB线连接电脑主机及Android打印机. Android打印机系统启动完成后,在Windows设备管理器中,可以看到Android Phone设备和USB打印支持 ...

  7. Android USB驱动源码分析(-)

    Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c.这个文件实现USB的上层应用协议. 首先包含了一些 ...

  8. Android USB驱动源码分析

    Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c.这个文件实现USB的上层应用协议. 首先包含了一些 ...

  9. host速度 mtk usb_mtk-usb代码分析之usb gadget

    基于mt6750T,Android 7.0,kernel 3.18.35,本文主要从USB设备的角度进行分析.(代码部分有省略) 我们的android手机通过usb连入电脑,可以选择多种模式,例如传输 ...

最新文章

  1. 关于GUI_DOWNLOAD中下载excel等文档的乱码问题
  2. Flink 状态管理:算子状态、键值分区状态、状态后端、有状态算子的扩缩容
  3. 开源的全面胜利背后,那些被遗忘的人性问题
  4. 从零玩转Webpack4~5+实现原理笔记(二)
  5. JS中的语音识别——Speech Recognition API
  6. Go语言的指针的一些测试
  7. 控制算法简析3——LKA中PID控制的error选取
  8. html画表盘 随时间转动,HTML5 canvas圆形时钟指针平缓转动随机切换表盘颜色
  9. python一笔画五角星_一笔画五角星,有多少种方法?
  10. 【干货】python爬取《战狼2》电影短评论,生成图云
  11. HAL库 output level 和 pull up/ pull down 的区别
  12. 牛客OR36 .链表的回文结构
  13. In-memory Computing with SAP HANA读书笔记 - 第七章:Business continuity and resiliency for SAP HANA
  14. python阴(yin)阳(yang)谜题的分析
  15. 电脑上打开WORD总是出现microsoft Office Word 已停止工作,键盘ctrl+v 复制粘贴时崩溃问题解决办法
  16. 苏格拉底与柏拉图麦穗的故事
  17. mysql导入数据库dmp文件怎么打开_20181112-PostgreSQL数据库dmp文件导入(记录一次数据导入)...
  18. java两个时间相加_Java程序两个日期相加
  19. 图像正投影与重建初认识
  20. 玩转jenkins - 在自己的服务器上安装jenkins

热门文章

  1. Luogu P4915 帕秋莉的魔导书
  2. LED背光源运用在温控设备上
  3. 20201214c列出最简真分数序列
  4. SpringBoot————Flyway的使用
  5. 如何用r语言分析数据
  6. 根据《机器学习》(周志华)第五章内容,用Python实现标准BP算法
  7. 如何给电脑安装Windows双系统
  8. Shell 编程4(退出,测试,判断)
  9. sql语句条件判断函数(流程控制函数)
  10. mysql视图之创建可更新视图