七、android-kernel gadget框架

转载 2013年12月04日 14:35:14

转自:http://blog.sina.com.cn/s/blog_6100a4f10101efoc.html

什么是usb gadget?

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

 Gadget框架结构

kernel/drivers/usb/gadget,这个目录是androidusb gadget的主要目录。

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

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

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

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

二、gadget功能组织单元

2.1 一个重要的结构体

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

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

        bool sw_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

 };

       通过这个结构体,可以想象出用户空间是如何控制androidgadget设备的功能切换及使能、禁能的。大概如下:将需要支持的功能注入到变量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_devenabled_functions链表中。

c) enable_store

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

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

usb_gadget_connectusb_gadget_disconnect配合enable_store进行断开/连接的动作。

gadget复合设备管理单元

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

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

a)gadget udc控制器层注册composite驱动,会在udcprobe函数中启动compositebind函数。

int usb_composite_probe(struct usb_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 debuging help

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

        //Added for USB Develpment debug, more log for more debuging help

        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 struct usb_device_descriptor * dev;

  struct usb_gadget_strings ** strings;

  unsigned needs_serial:1;

  int (* unbind) (struct usb_composite_dev *);

  void (* disconnect) (struct usb_composite_dev *);

  void (* suspend) (struct usb_composite_dev *);

  void (* resume) (struct usb_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.2 mass_storage专有流程

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

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

 usb控制器驱动

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

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

Usb控制器驱动:

musb_core.c:130:#define MUSB_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.1 Android.c中的event发送

static void android_work(struct work_struct *data)

{

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

   struct usb_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 for HW/SW connect

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

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

   //Add for HW/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.2 android层的接收

    private final UEventObserver mUEventObserver = new UEventObserver() {

        @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);

最终会调用到UEventObserveraddObserver

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

public void 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 UEventThread extends 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机制>


相关文章推荐

基于android4.0 USB gadget框架分析

基于android4.0 USB gadget框架分析 2012-04-13 11:57:48 分类: LINUX     转眼间,看usb gadget代码看的有一段时间了,把其中...

linux kernel X-tranx-Y : TTY to gadget

今天我们来看看linux kernel driver中的glue:u_serial.c。   这个文件把以TTY和USB Gadget设备驱动贴合在一起,实现了TTY(一般为串口)到Gadget设备...

分析android的usb-gadget

分析android的gadget: gadget部分的UDC和API基本上弄懂了,现在开始研究android上的USB-gadget实现,开始读代码 1:首先从init开始。 static ...

Android USB gadget probe流程

static struct android_usb_platform_data android_usb_pdata = { .vendor_id = S3C_VENDOR_ID, //18d1...

android usb gadget分析

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

Android Linux usb gadget configfs

Linux USB gadget configured through configfs 25th April 2013 OverviewA USB Linux Gadget...

Android—— 4.2 Vold挂载管理_Kernel_USB_Uevent (七)

在前文Android—— 4.2 Vold挂载管理_NetlinkManager (四)中有解析到Vold 是从kernel中获取uevent事件,来获取device信息,其中是通过一个Netlink...
  • jscese
  • jscese
  • 2014年09月02日 18:12
  • 2706

Linux Kernel media框架(二)

Entities,pads and links 实体,垫和链接 ------------------------   -Entities - 实体 Entitiesare repres...
  • htjacky
  • htjacky
  • 2017年02月03日 15:16
  • 522

无线传感网:ieee802154与6lowpan在kernel 3.0/4.0的框架分析

一  kernel 4.0 下ieee802154 与6lowpan的 框架 /////////////////////////////////////////////////////...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:七、android-kernel gadget框架
举报原因:
原因补充:

(最多只允许输入30个字)