Chinaunix首页 | 论坛 | 博客
  • 博客访问: 403770
  • 博文数量: 53
  • 博客积分: 1910
  • 博客等级: 中尉
  • 技术积分: 1130
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-10 14:56
文章分类

全部博文(53)

文章存档

2013年(1)

2012年(17)

2011年(33)

2010年(2)

分类: Android平台

2013-03-29 17:13:38

   最近用Freescale 的cortex-M4 K60 MCU 做accessory 连接android 手机, K60这款M4 非常强大,丰富的外围设备,特别是免费的开源实时操作系统MQX ,
加上一个完全开源的usb host  stack ,使开发难度大大的降低了.
    开发过程中,分析了下android 端的连接过程,具体如下:

1. host 端发送ctrl request 0x35, 请求 start accessory. kernel android composite driver 开始响应
----------------kernel----------------
2. kernel android usb gadget driver android.c 中:

点击(此处)折叠或打开

  1. static int
  2. android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c)
  3. {
  4.     struct android_dev        *dev = _android_dev;
  5.     struct usb_composite_dev    *cdev = get_gadget_data(gadget);
  6.     struct usb_request        *req = cdev->req;
  7.     struct android_usb_function    *f;
  8.     int value = -EOPNOTSUPP;
  9.     unsigned long flags;

  10.     req->zero = 0;
  11.     req->complete = composite_setup_complete;
  12.     req->length = 0;
  13.     gadget->ep0->driver_data = cdev;

  14.     list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
  15.         if (f->ctrlrequest) {
  16.             value = f->ctrlrequest(f, cdev, c);
  17.             if (value >= 0)
  18.                 break;
  19.         }
  20.     }

  21.     /* Special case the accessory function.
  22.      * It needs to handle control requests before it is enabled.
  23.      */
  24.     if (value < 0)
  25.         value = acc_ctrlrequest(cdev, c); /* 处理 接收到的accessory 的ctrl request */

3. acc_ctrlrequest 函数在f_accessory.c :

点击(此处)折叠或打开

  1. static int acc_ctrlrequest(struct usb_composite_dev *cdev,
  2.                 const struct usb_ctrlrequest *ctrl)
  3.    ......
  4.     if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) {
  5.         if (b_request == ACCESSORY_START) { /* 这个就是处理 0x35 request ,并调度执行acc_work */
  6.             dev->start_requested = 1;
  7.             schedule_delayed_work(
  8.                 &dev->work, msecs_to_jiffies(10));
  9.             value = 0;
  10.         } else if (b_request == ACCESSORY_SEND_STRING) {/* 处理5个 string */
  11.             dev->string_index = w_index;
  12.             cdev->gadget->ep0->driver_data = dev;
  13.             cdev->req->complete = acc_complete_set_string;
  14.             value = w_length;
  15.         }
  16.     } else if (b_requestType == (USB_DIR_IN | USB_TYPE_VENDOR)) {
  17.         if (b_request == ACCESSORY_GET_PROTOCOL) {
  18.             *((u16 *)cdev->req->buf) = PROTOCOL_VERSION;
  19.             value = sizeof(u16);

  20.             /* clear any strings left over from a previous session */
  21.             memset(dev->manufacturer, 0, sizeof(dev->manufacturer));
  22.             memset(dev->model, 0, sizeof(dev->model));
  23.             memset(dev->description, 0, sizeof(dev->description));
  24.             memset(dev->version, 0, sizeof(dev->version));
  25.             memset(dev->uri, 0, sizeof(dev->uri));
  26.             memset(dev->serial, 0, sizeof(dev->serial));
  27.             dev->start_requested = 0;
  28.         }
  29.     }

  30.    ......
  31. }

4. acc_work 很简单, 发1个uevent ,接下来就进入android framework 部分处理了:

点击(此处)折叠或打开

  1. static void acc_work(struct work_struct *data)
  2. {
  3.  char *envp[2] = { "ACCESSORY=START", NULL };
  4.  kobject_uevent_env(&acc_device.this_device->kobj, KOBJ_CHANGE, envp);
  5. }
进入android 处理
----------------android----------------

5. frameworks\base\services\java\com\android\server\usb\UsbDeviceManager.java
中的uevent 监控函数处理ACCESSORY=START 的uevent

点击(此处)折叠或打开

  1. private final UEventObserver mUEventObserver = new UEventObserver() {
  2.         @Override
  3.         public void onUEvent(UEventObserver.UEvent event) {
  4.             if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());

  5.             String state = event.get("USB_STATE");
  6.             String accessory = event.get("ACCESSORY");
  7.             if (state != null) {
  8.                 mHandler.updateState(state);
  9.             } else if ("START".equals(accessory)) { /* 如果是accessory start uevent 交给setCurrentFunction 处理 */
  10.                 if (DEBUG) Slog.d(TAG, "got accessory start");
  11.                 setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false);

6.   setCurrentFunction 函数如其名,设置 名为UsbManager.USB_FUNCTION_ACCESSORY 为当前function
   UsbManager.USB_FUNCTION_ACCESSORY 就是string "accessory"
   它给   handleMessage(Message msg) 函数发1个MSG_SET_CURRENT_FUNCTION消息

点击(此处)折叠或打开

  1. public void setCurrentFunction(String function, boolean makeDefault) {
  2.         if (DEBUG) Slog.d(TAG, "setCurrentFunction(" + function + ") default: " + makeDefault);
  3.         mHandler.sendMessage(MSG_SET_CURRENT_FUNCTION, function, makeDefault);
  4.     }

7. 接下来到 public void handleMessage(Message msg) 的 MSG_SET_CURRENT_FUNCTION 分支部分

点击(此处)折叠或打开

  1. case MSG_SET_CURRENT_FUNCTION:
  2.                     String function = (String)msg.obj;
  3.                     boolean makeDefault = (msg.arg1 == 1);
  4.                     setEnabledFunctions(function, makeDefault); /* setEnabledFunctions("accessory",default);*/

8. private void setEnabledFunctions(String functions, boolean makeDefault)

点击(此处)折叠或打开

  1. if (!mDefaultFunctions.equals(functions)) {
  2.               if (!setUsbConfig("none")) { /* 先断开,然后再设置*/
  3.                 Slog.e(TAG, "Failed to disable USB");
  4.                 // revert to previous configuration if we fail

  5.                  setUsbConfig(mCurrentFunctions); /* 设置 accessory prop*/

9. setUsbConfig函数:

点击(此处)折叠或打开

  1. private boolean setUsbConfig(String config) {
  2.             if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
  3.             // set the new configuration

  4.             SystemProperties.set("sys.usb.config", config);
  5.             return waitForState(config);
  6.         }

10. SystemProperties.set("sys.usb.config", "accessory"); 后init.rc 中如下
on property 动作被执行


点击(此处)折叠或打开

  1. # USB accessory configuration
  2. on property:sys.usb.config=accessory
  3. write /sys/class/android_usb/android0/enable 0
  4. write /sys/class/android_usb/android0/idVendor 18d1
  5. write /sys/class/android_usb/android0/idProduct 2d00
  6. write /sys/class/android_usb/android0/functions $sys.usb.config
  7. write /sys/class/android_usb/android0/enable 1
  8. setprop sys.usb.state $sys.usb.config
注意
setprop sys.usb.config = "none" 所做的操作如下:
# Used to disable USB when switching states
on property:sys.usb.config=none
    stop adbd
    write /sys/class/android_usb/android0/enable 0
    write /sys/class/android_usb/android0/bDeviceClass 0
    setprop sys.usb.state $sys.usb.config

11. 下面两个sysfs 的写入会进入到kernel 中 做相应function bind 等动作,
    write /sys/class/android_usb/android0/functions $sys.usb.config
    进行function bing 动作
   
    write /sys/class/android_usb/android0/enable 1
    这个enanble 注意是设置gadget 底层driver 进行一组disconnect ,connnect 动作
    就是disable D+,D-, 告诉host 断开,然后 pullup D+ ,
    请求host重新开始枚举自己
 
    具体可跟下 kernel 的usb android.c中的
    functions_store, enable_store 函数,这里不展开了

    完成后 setprop sys.usb.state "accessory" 让setUsbConfig中的 return waitForState(config);
    可以继续执行下去

到kernel 去处理了
----------------kernel----------------

12. 接下来 host 会开始进行新的枚举,
   gadget driver 中的 收到setup 的irq 处理函数还是会调到
android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c){
 只是走的分支不同, 前面enanble 时 已经 更新了ivendor=18d1,iprodunct=2d00,
 还执行了acc_bind ,去创建endpoint,当然ep descript 也准备好了,
 
 android_setup 中下面部分会被执行到:
  if (value < 0)
  value = composite_setup(gadget, c);
执行标准的请求,其中GET despritct 请求时把accessory相关的描述符传给accessory主机,

13. 主机收到descprit 后,很满意,发来set config ,批准连接,
还是android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c)
处理:
    else if (c->bRequest == USB_REQ_SET_CONFIGURATION && cdev->config) {
  schedule_work(&dev->work);     /* 去执行android_work */     
 }
14. static void android_work(struct work_struct *data)
   执行
  kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp => USB_STATE=CONFIGURED);
  当然前面还有两个uevnent,USB_STATE=DISCONNECTED,USB_STATE=CONNECTED
----------------android----------------
15. 回到android 的
frameworks\base\services\java\com\android\server\usb\UsbDeviceManager.java
uevent 监视函数

点击(此处)折叠或打开

  1. private final UEventObserver mUEventObserver = new UEventObserver() {
  2.         @Override
  3.         public void onUEvent(UEventObserver.UEvent event) {
  4.             if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());

  5.             String state = event.get("USB_STATE");
  6.             String accessory = event.get("ACCESSORY");
  7.             if (state != null) {
  8.                 mHandler.updateState(state);/* 执行mHandler.updateState(“CONFIGURED”); */

16. mHandler.updateState(“CONFIGURED”); 的函数内容如下:

点击(此处)折叠或打开

  1. public void updateState(String state) {
  2.             int connected, configured;

  3.             if ("DISCONNECTED".equals(state)) {
  4.                 connected = 0;
  5.                 configured = 0;
  6.             } else if ("CONNECTED".equals(state)) {
  7.                 connected = 1;
  8.                 configured = 0;
  9.             } else if ("CONFIGURED".equals(state)) {
  10.                 connected = 1;
  11.                 configured = 1; /* 这是connected =1,configured 也 =1 */
  12.             } else {
  13.                 Slog.e(TAG, "unknown state " + state);
  14.                 return;
  15.             }
  16.             removeMessages(MSG_UPDATE_STATE);
  17.             Message msg = Message.obtain(this, MSG_UPDATE_STATE);
  18.             msg.arg1 = connected;
  19.             msg.arg2 = configured;
  20.             // debounce disconnects to avoid problems bringing up USB tethering
  21.             sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
  22.         }
  23.      通过sendMessageDelayed 发conected =1,configured =1 消息到handleMessage

17. handle configured Message :
     

点击(此处)折叠或打开

  1. public void handleMessage(Message msg) {
  2.             switch (msg.what) {
  3.                 case MSG_UPDATE_STATE:
  4.                     mConnected = (msg.arg1 == 1);
  5.                     mConfigured = (msg.arg2 == 1);
  6.                     updateUsbNotification();
  7.                     updateAdbNotification();
  8.                     if (containsFunction(mCurrentFunctions,
  9.                             UsbManager.USB_FUNCTION_ACCESSORY)) {
  10.                         updateCurrentAccessory(); /* 执行这里 */
  11.                     }

18.  private void updateCurrentAccessory() {

点击(此处)折叠或打开

  1. if (!mHasUsbAccessory) return;

  2.             if (mConfigured) {
  3.                 String[] strings = nativeGetAccessoryStrings(); /* open acc 去读 host 发来的并且已经保存到accssory function driver 中的 5个string */
  4.                 if (strings != null) {
  5.                     mCurrentAccessory = new UsbAccessory(strings); /* 执行这里去创建 UsbAccessory */
  6.         
  7.         
  8.                     Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
  9.                     // defer accessoryAttached if system is not ready
  10.                     if (mBootCompleted) { /* ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
  11.          判断android 启动完毕否 */
  12.                         mSettingsManager.accessoryAttached(mCurrentAccessory); /* 去执行attatch 动作,*/


19. accessoryAttached 函数在 :frameworks\base\services\java\com\android\server\usb\UsbSettingsManager.java :

点击(此处)折叠或打开

  1. public void accessoryAttached(UsbAccessory accessory) {
  2.         Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
  3.         intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
  4.         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
    发ACTION_USB_ACCESSORY_ATTACHED intent ,
    注意 apk 中的usb_accessory_filter.xml 中的内容要与host 发的string 匹配
    这样apk 中等待ACTION_USB_ACCESSORY_ATTACHED intend 的apk 启动了

apk 开始是连接界面,连接成功后会提示打开apk否,点确定进入home activiy:

确定后,



接下来 可以进入某项进行操作了


阅读(4717) | 评论(0) | 转发(0) |
0

上一篇:imx53RM, IPU 的显示端口部分阅读笔记(2)

下一篇:没有了

给主人留下些什么吧!~~