最近用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 中:
-
static int
-
android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c)
-
{
-
struct android_dev *dev = _android_dev;
-
struct usb_composite_dev *cdev = get_gadget_data(gadget);
-
struct usb_request *req = cdev->req;
-
struct android_usb_function *f;
-
int value = -EOPNOTSUPP;
-
unsigned long flags;
-
-
req->zero = 0;
-
req->complete = composite_setup_complete;
-
req->length = 0;
-
gadget->ep0->driver_data = cdev;
-
-
list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
-
if (f->ctrlrequest) {
-
value = f->ctrlrequest(f, cdev, c);
-
if (value >= 0)
-
break;
-
}
-
}
-
-
/* Special case the accessory function.
-
* It needs to handle control requests before it is enabled.
-
*/
-
if (value < 0)
-
value = acc_ctrlrequest(cdev, c); /* 处理 接收到的accessory 的ctrl request */
3. acc_ctrlrequest 函数在f_accessory.c :
-
static int acc_ctrlrequest(struct usb_composite_dev *cdev,
-
const struct usb_ctrlrequest *ctrl)
-
......
-
if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) {
-
if (b_request == ACCESSORY_START) { /* 这个就是处理 0x35 request ,并调度执行acc_work */
-
dev->start_requested = 1;
-
schedule_delayed_work(
-
&dev->work, msecs_to_jiffies(10));
-
value = 0;
-
} else if (b_request == ACCESSORY_SEND_STRING) {/* 处理5个 string */
-
dev->string_index = w_index;
-
cdev->gadget->ep0->driver_data = dev;
-
cdev->req->complete = acc_complete_set_string;
-
value = w_length;
-
}
-
} else if (b_requestType == (USB_DIR_IN | USB_TYPE_VENDOR)) {
-
if (b_request == ACCESSORY_GET_PROTOCOL) {
-
*((u16 *)cdev->req->buf) = PROTOCOL_VERSION;
-
value = sizeof(u16);
-
-
/* clear any strings left over from a previous session */
-
memset(dev->manufacturer, 0, sizeof(dev->manufacturer));
-
memset(dev->model, 0, sizeof(dev->model));
-
memset(dev->description, 0, sizeof(dev->description));
-
memset(dev->version, 0, sizeof(dev->version));
-
memset(dev->uri, 0, sizeof(dev->uri));
-
memset(dev->serial, 0, sizeof(dev->serial));
-
dev->start_requested = 0;
-
}
-
}
-
-
......
-
}
4. acc_work 很简单, 发1个uevent ,接下来就进入android framework 部分处理了:
-
static void acc_work(struct work_struct *data)
-
{
-
char *envp[2] = { "ACCESSORY=START", NULL };
-
kobject_uevent_env(&acc_device.this_device->kobj, KOBJ_CHANGE, envp);
-
}
进入android 处理
----------------android----------------
5. frameworks\base\services\java\com\android\server\usb\UsbDeviceManager.java
中的uevent 监控函数处理ACCESSORY=START 的uevent
-
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)) { /* 如果是accessory start uevent 交给setCurrentFunction 处理 */
-
if (DEBUG) Slog.d(TAG, "got accessory start");
-
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消息
-
public void setCurrentFunction(String function, boolean makeDefault) {
-
if (DEBUG) Slog.d(TAG, "setCurrentFunction(" + function + ") default: " + makeDefault);
-
mHandler.sendMessage(MSG_SET_CURRENT_FUNCTION, function, makeDefault);
-
}
7. 接下来到 public void handleMessage(Message msg) 的 MSG_SET_CURRENT_FUNCTION 分支部分
-
case MSG_SET_CURRENT_FUNCTION:
-
String function = (String)msg.obj;
-
boolean makeDefault = (msg.arg1 == 1);
-
setEnabledFunctions(function, makeDefault); /* setEnabledFunctions("accessory",default);*/
8. private void setEnabledFunctions(String functions, boolean makeDefault)
-
if (!mDefaultFunctions.equals(functions)) {
-
if (!setUsbConfig("none")) { /* 先断开,然后再设置*/
-
Slog.e(TAG, "Failed to disable USB");
-
// revert to previous configuration if we fail
-
-
setUsbConfig(mCurrentFunctions); /* 设置 accessory prop*/
9. setUsbConfig函数:
-
private boolean setUsbConfig(String config) {
-
if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
-
// set the new configuration
-
-
SystemProperties.set("sys.usb.config", config);
-
return waitForState(config);
-
}
10. SystemProperties.set("sys.usb.config", "accessory"); 后init.rc 中如下
on property 动作被执行
-
# USB accessory configuration
-
on property:sys.usb.config=accessory
-
write /sys/class/android_usb/android0/enable 0
-
write /sys/class/android_usb/android0/idVendor 18d1
-
write /sys/class/android_usb/android0/idProduct 2d00
-
write /sys/class/android_usb/android0/functions $sys.usb.config
-
write /sys/class/android_usb/android0/enable 1
-
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 监视函数
-
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);/* 执行mHandler.updateState(“CONFIGURED”); */
16. mHandler.updateState(“CONFIGURED”); 的函数内容如下:
-
public void updateState(String state) {
-
int connected, configured;
-
-
if ("DISCONNECTED".equals(state)) {
-
connected = 0;
-
configured = 0;
-
} else if ("CONNECTED".equals(state)) {
-
connected = 1;
-
configured = 0;
-
} else if ("CONFIGURED".equals(state)) {
-
connected = 1;
-
configured = 1; /* 这是connected =1,configured 也 =1 */
-
} else {
-
Slog.e(TAG, "unknown state " + state);
-
return;
-
}
-
removeMessages(MSG_UPDATE_STATE);
-
Message msg = Message.obtain(this, MSG_UPDATE_STATE);
-
msg.arg1 = connected;
-
msg.arg2 = configured;
-
// debounce disconnects to avoid problems bringing up USB tethering
-
sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
-
}
-
通过sendMessageDelayed 发conected =1,configured =1 消息到handleMessage
17. handle configured Message :
-
public void handleMessage(Message msg) {
-
switch (msg.what) {
-
case MSG_UPDATE_STATE:
-
mConnected = (msg.arg1 == 1);
-
mConfigured = (msg.arg2 == 1);
-
updateUsbNotification();
-
updateAdbNotification();
-
if (containsFunction(mCurrentFunctions,
-
UsbManager.USB_FUNCTION_ACCESSORY)) {
-
updateCurrentAccessory(); /* 执行这里 */
-
}
18. private void updateCurrentAccessory() {
-
if (!mHasUsbAccessory) return;
-
-
if (mConfigured) {
-
String[] strings = nativeGetAccessoryStrings(); /* open acc 去读 host 发来的并且已经保存到accssory function driver 中的 5个string */
-
if (strings != null) {
-
mCurrentAccessory = new UsbAccessory(strings); /* 执行这里去创建 UsbAccessory */
-
-
-
Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
-
// defer accessoryAttached if system is not ready
-
if (mBootCompleted) { /* ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
-
判断android 启动完毕否 */
-
mSettingsManager.accessoryAttached(mCurrentAccessory); /* 去执行attatch 动作,*/
19. accessoryAttached 函数在 :frameworks\base\services\java\com\android\server\usb\UsbSettingsManager.java :
-
public void accessoryAttached(UsbAccessory accessory) {
-
Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
-
intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
-
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:
确定后,
接下来 可以进入某项进行操作了
阅读(4711) | 评论(0) | 转发(0) |