android-kernel usb gadget框架

什么是usb gadget?

当把pad/手机插到pc上时,可以作为u盘、网卡等usb功能设备呈现,这个就叫做gadget。可以理解为usb 从设备端,和host对应。

一 Gadget框架结构

 

kernel/drivers/usb/gadget,这个目录是android下usbgadget的主要目录。

      Gadget功能组织单元:主要文件android.c,usb gadget功能的统领文件,负责组织usb 复合设备的功能,与上层应用提供交互的接口,面向市场需求的产品规划部门。

      复合设备逻辑处理单元(复合设备管理单元):主要文件:composite.c,这个文件类似于一个项目管理组,负责各个单元的接口对接,资源整理。针对拥有多个usb功能的复合设备,这部分负责将支持的各个功能组织到一起,协助各个功能与UDC控制器单元建立联系。

      具体功能单元:以U盘为例,f_mass_storge.c文件,用来完成具体的功能。这个部分是一个功能性很强的部分,将与UDC控制器单元直接对话,完成数据的传输。

UDC控制器单元:只做一件事情,收发usb数据,将数据透明的传递出去。


二、gadget功能组织单元


2.1一个重要的结构体

下面这个结构体就是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;//是否连接host

       boolsw_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的配置。

 

2.2功能组织文件 Android.c

a)创建android_usb设备,启动团队的组建工作,通过usb_composite_probe进入到gadget复合设备的逻辑处理部分,去完成整个gadget框架的搭建工作。

static int __init init(void)

{

       struct android_dev *dev;

       int err;

 

       android_class = class_create(THIS_MODULE,"android_usb");

       if (IS_ERR(android_class))

               return PTR_ERR(android_class);

 

       dev = kzalloc(sizeof(*dev), GFP_KERNEL);

       if (!dev)

               return-ENOMEM;

 

       dev->functions = supported_functions;

       INIT_LIST_HEAD(&dev->enabled_functions);

       INIT_WORK(&dev->work,android_work);

       mutex_init(&dev->mutex);

 

       err = android_create_device(dev);

       if (err) {

               class_destroy(android_class);

               kfree(dev);

               return err;

       }

 

       _android_dev = dev;

 

       

       composite_driver.setup = android_setup;

       composite_driver.disconnect = android_disconnect;

  

       return usb_composite_probe(&android_usb_driver,android_bind);

}

 


 

b) functions_store

添加当前场景需要使用的gadget功能,调用android_enable_function将需要使用的功能加入到android_dev的enabled_functions链表中。

c) enable_store

 

当使能gadget功能后,将依次调用各function的bind_config,将各个功能的配置信息加入到复合设备信息中,例如向描述符信息中加入对应的接口描述符。

每个功能需要什么样的端点,只有该功能知道,所以向udc控制器申请端点的动作也发生在各个function的bind_config动作里。

usb_gadget_connect和usb_gadget_disconnect配合enable_store进行断开/连接的动作。



三gadget复合设备管理单元


3.1复合设备管理文件Composite.c


这个文件主要用来完成复合设备,各种描述符等信息的组装。另外这个单元是一个重要的纽带,将其它三个部分联系在一起,堪称公司的ODT。

a)向gadget udc控制器层注册composite驱动,会在udc的probe函数中启动composite的bind函数。

int usb_composite_probe(structusb_composite_driver *driver,

                              int(*bind)(struct usb_composite_dev *cdev))

{

       if (!driver || !driver->dev || !bind ||composite)

               return -EINVAL;

 

       //Added for USB Develpment debug, more log for more debuginghelp

       xlog_printk(ANDROID_LOG_DEBUG, "USB20", "%s:driver->name = %s", __func__,driver->name);

       //Added for USB Develpment debug, more log for more debuginghelp

 

       if (!driver->name)

               driver->name = "composite";

       if (!driver->iProduct)

               driver->iProduct =driver->name;

       composite_driver.function =  (char *)driver->name;

       composite_driver.driver.name =driver->name;

       composite = driver;//传进来的usb_composite_driver类型的驱动

       composite_gadget_bind = bind;

 

       return usb_gadget_probe_driver(&composite_driver,composite_bind);

}

 

static int composite_bind(struct usb_gadget*gadget)

{

……………………

 

   status =composite_gadget_bind(cdev);

……………………

}

 

流程android.c init-- usb_composite_probe--usb_gadget_probe_driver---

composite_bind---composite_gadget_bind(android_bind)

 

3.2几个重要结构变量

a)composite_driver

static struct usb_gadget_driver composite_driver = {

  .speed           = USB_SPEED_HIGH,

 

  .unbind          = composite_unbind,

 

  .setup            = composite_setup,

  .disconnect    = composite_disconnect,

 

  .suspend  = composite_suspend,

  .resume         = composite_resume,

 

  .driver    = {

         .owner          = THIS_MODULE,

   },

};

b) composite

static struct usb_composite_driver *composite;

struct usb_composite_driver {

  const char * name;

  const char *iProduct;

  const char *iManufacturer;

  const structusb_device_descriptor * dev;

  struct usb_gadget_strings **strings;

  unsignedneeds_serial:1;

  int (* unbind) (structusb_composite_dev *);

  void (* disconnect) (structusb_composite_dev *);

  void (* suspend) (structusb_composite_dev *);

  void (* resume) (structusb_composite_dev *);

};

static struct usb_composite_driver android_usb_driver = {

       .name          = "android_usb",

       .dev           = &device_desc,

       .strings       = dev_strings,

       .unbind        = android_usb_unbind,

};

 

通过这些结构体之间的bind操作,建立了usb复合设备在基本操作上和udc控制器的渠道关系。

那么这个复合设备的function最初是在哪里建立的呢?如adb/mass storage等。

Todo:这个文件需要再看,整个gadget的逻辑都体现

四 gadget功能单元

以mass storage 功能为例,了解usb功能的工作流程,文件f_mass_storage.c。

4.1半通用流程

android_bind---->android_init_functions--->mass_storage_function_init---->fsg_common_init(创建fsg_main_thread线程)。

这个动作完成所有android gadget支持的功能的初始化动作,准备工作。

 

如果使能了usb gadget功能就会被调用enable_store,发生如下的流程:enable_store--->usb_add_config--->android_bind_config---->android_bind_enabled_functions---->mass_storage_function_bind_config---->fsg_bind_config--->usb_add_function--->fsg_bind

 

  所谓使能某个功能,就是将这个功能添加到复合设备的功能上,而这个添加的动作最终是需要每个function自己来完成部分工作的,因为每个function需要什么资源、描述符的信息等,其他部分是不知道的,所以最后有fsg_bind来最终完成和udc控制器的交互,获取到合适的端点,并挂载上端点的处理函数。

如:

   ep =usb_ep_autoconfig(gadget,&fsg_fs_bulk_in_desc);

   if(!ep)

         goto autoconf_fail;

  ep->driver_data =fsg->common; 

  fsg->bulk_in = ep;

 

4.2mass_storage专有流程

Mass_storage功能的主要工作流程在fsg_main_thread函数。

 

对于特定的usb功能不做深入讲解,这部分kernel中的结构,基本不会改动,只做了解即可。

五 usb控制器驱动

  这部分工作有芯片厂商完成,只做了解,用来实现usb的总线协议。

Mtk的代码放置在mediatek目录下,source目录放置IP控制器驱动,而platform下面是芯片级别相关的驱动。

Usb控制器驱动:

musb_core.c:130:#defineMUSB_DRIVER_NAME "mt_usb"

A2107/mediatek/source/kernel/drivers/usb20

 

该平台下usb控制器设备:

mt6575_devs.c:81:.name              = "mt_usb",

A2107/mediatek/platform/mt6575/kernel/core

 

平台初始化文件: mt6575_board.c

A2107/mediatek/platform/mt6575/kernel/core

 

Usb的代码只存在2个目录下:

mediatek/source/kernel/drivers/usb20

mediatek/platform/mt6575/kernel/drivers/usb20这个目录下的usb20.c是针对不同的芯片需要改动的代码,比如寄存器映射地址等,而不同的芯片使用的IP核可能是一样的,所以驱动是不用改动的,就是mediatek/source/kernel/drivers/usb20下的代码。

 

六 uevent消息处理

6.1Android.c中的event发送

static void android_work(struct work_struct*data)

{

   structandroid_dev *dev = container_of(data, struct android_dev,work);

   structusb_composite_dev *cdev = dev->cdev;

   char*disconnected[2] = { "USB_STATE=DISCONNECTED", NULL };

   char*connected[2]   = { "USB_STATE=CONNECTED", NULL };

   char*configured[2]   = {"USB_STATE=CONFIGURED", NULL };

 

   //Add forHW/SW connect

   char*hwdisconnected[2] = { "USB_STATE=HWDISCONNECTED", NULL};

   char*hwconnected[2]   = { "USB_STATE=HWCONNECTED", NULL };

   //Add forHW/SW connect

……………………………………

……………………………………

   if(uevent_envp) {

         下面这个动作就是kernel向用户空间发送uevent消息

         kobject_uevent_env(&dev->dev->kobj,KOBJ_CHANGE, uevent_envp);

        pr_info("%s: sent uevent %s\n", __func__,uevent_envp[0]);

   } else{

         pr_info("%s: did not send uevent (%d %d %p)\n",__func__,

                 dev->connected,dev->sw_connected,cdev->config);

   }

}

6.2android层的接收

   

   private final UEventObservermUEventObserver = newUEventObserver() {

       @Override

       public void onUEvent(UEventObserver.UEvent event) {

           if (DEBUG) Slog.v(TAG, "USB UEVENT: " +event.toString());

 

           String state = event.get("USB_STATE");

           String accessory = event.get("ACCESSORY");

           if (state != null) {

               mHandler.updateState(state);

           } else if ("START".equals(accessory)) {

               if(DEBUG) Slog.d(TAG, "got accessory start");

               setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY,false);

           }

       }

   };

 

在类初始化时会调用下面的动作,启动监听动作。

               mUEventObserver.startObserving(USB_STATE_MATCH);

 

最终会调用到UEventObserver的addObserver:

privateArrayList<Object> mObservers = newArrayList<Object>();

publicvoid addObserver(String match, UEventObserver observer){

 synchronized(mObservers) {

 mObservers.add(match);

 mObservers.add(observer);

 }

}

 

   private static final String USB_STATE_MATCH =

           "DEVPATH=/devices/virtual/android_usb/android0";

该函数最终会将”DEVPATH=/devices/virtual/android_usb/android0”增加到匹配序列中,当kernel发送具有该字符串的数据时,就返回匹配成功,然后调用mUEventObserver 的onUEvent函数;

UeventObserver.java

  private static class UEventThreadextends Thread {

       

       private ArrayList<Object> mObservers= new ArrayList<Object>();

       

       UEventThread() {

           super("UEventObserver");

       }

       

       public void run() {

           native_setup();

 

           byte[] buffer = new byte[1024];

           int len;

           while (true) {

               len = next_event(buffer);

               if (len > 0) {

                   String bufferStr = new String(buffer, 0, len);  //easier to search a String

                   synchronized (mObservers) {

                       for (int i = 0; i < mObservers.size(); i += 2){

                           if (bufferStr.indexOf((String)mObservers.get(i)) != -1){

                               ((UEventObserver)mObservers.get(i+1))

                                       .onUEvent(new UEvent(bufferStr));

                           }

                       }

                   }

               }

           }

       }

详细参考<Linux uevent机制>


  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值