在前文Android—— 4.2 Vold挂载管理_NetlinkManager (四)中有解析到Vold 是从kernel中获取uevent事件,来获取device信息,其中是通过一个Netlink的套接字,目前整个Vold机制也分析完了,
上篇 Android—— 4.2 Vold挂载管理_MountService (六) 分析了机制中最上层的,这里分析一下最下层的kernel uevent事件的发送,以USB设备为例!
撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/39006999
一.USB_HUB_EVENT:
usb driver在/drivers/usb/目录下,这个目录下有多个文件夹,具体编译使用的是哪一个就要看kernel的.config了,可查看目录下的Makefile中的CONFIG*宏是否有定义.
我这边的kernel version 3.1.10,根据config我的kernel用的驱动在/drivers/usb/core目录下,usb.c 为入口.
static int __init usb_init(void) { int retval; if (nousb) { pr_info("%s: USB support disabled\n", usbcore_name); return 0; } retval = usb_debugfs_init();//debug 文件的初始化 if (retval) goto out; retval = bus_register(&usb_bus_type); if (retval) goto bus_register_failed; retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb); if (retval) goto bus_notifier_failed; retval = usb_major_init(); // if (retval) goto major_init_failed; retval = usb_register(&usbfs_driver); if (retval) goto driver_register_failed; retval = usb_devio_init(); if (retval) goto usb_devio_init_failed; retval = usbfs_init(); if (retval) goto fs_init_failed; retval = usb_hub_init(); //循环监测的初始化 ... } subsys_initcall(usb_init);
可以看到初始入口即为usb_init,在里面初始化了usb相关各种参数配置,这里着重分析与插拔usb设备的usb_hub_init().
调用到/drivers/usb/core/hub.c中的usb_hub_init:
int usb_hub_init(void) { if (usb_register(&hub_driver) < 0) { printk(KERN_ERR "%s: can't register hub driver\n", usbcore_name); return -1; } khubd_task = kthread_run(hub_thread, NULL, "khubd");//创建一个线程,执行hub_thread函数,线程名为khubd if (!IS_ERR(khubd_task)) return 0; /* Fall through if kernel_thread failed */ usb_deregister(&hub_driver); printk(KERN_ERR "%s: can't start khubd\n", usbcore_name); return -1; }
看线程函数hub_thread:
static int hub_thread(void *__unused) { /* khubd needs to be freezable to avoid intefering with USB-PERSIST * port handover. Otherwise it might see that a full-speed device * was gone before the EHCI controller had handed its port over to * the companion full-speed controller. */ set_freezable(); do { hub_events(); //进入有条件的循环,持续监测 wait_event_freezable(khubd_wait, !list_empty(&hub_event_list) || kthread_should_stop()); } while (!kthread_should_stop() || !list_empty(&hub_event_list)); pr_debug("%s: khubd exiting\n", usbcore_name); return 0; }
再看hub_events:
static void hub_events(void) { struct list_head *tmp; struct usb_device *hdev; struct usb_interface *intf; struct usb_hub *hub; struct device *hub_dev; ... while (1) { /* Grab the first entry at the beginning of the list */ spin_lock_irq(&hub_event_lock); if (list_empty(&hub_event_list)) { spin_unlock_irq(&hub_event_lock); break; } ... /* deal with port status changes */ for (i = 1; i <= hub->descriptor->bNbrPorts; i++) { // 遍历usb的端口,检测端口状态 if (test_bit(i, hub->busy_bits)) continue; connect_change = test_bit(i, hub->change_bits); if (!test_and_clear_bit(i, hub->event_bits) && !connect_change) continue; ret = hub_port_status(hub, i, &portstatus, &portchange); // 依次判断端口状态是否被改变 if (ret < 0) continue; if (portchange & USB_PORT_STAT_C_CONNECTION) { //判断端口状态改变情况 clear_port_feature(hdev, i, USB_PORT_FEAT_C_CONNECTION); connect_change = 1; #if defined(ENABLE_BATTERY_CHARGE) && (MP_USB_MSTAR==1) if (hdev->parent == NULL) { usb_bc_enable(hcd, true); } #endif /* patch for DM always keep high issue */ #if (_USB_HS_CUR_DRIVE_DM_ALLWAYS_HIGH_PATCH) && (MP_USB_MSTAR==1) /* turn on overwrite mode */ if (hdev->parent == NULL) { writeb(readb((void*)(hcd->utmi_base+0x0*2)) | BIT1, (void*) (hcd->utmi_base+0x0*2)); //tern_ov = 1 } #endif } ... if (connect_change) hub_port_connect_change(hub, i, portstatus, portchange); // 处理变化的端口 ... } ... } }
通过对usb端口状态的循环监测,来处理usb设备的插拔!
端口处理就从检测到变化开始:
static void hub_port_connect_change(struct usb_hub *hub, int port1, u16 portstatus, u16 portchange) { struct usb_device *hdev = hub->hdev; struct device *hub_dev = hub->intfdev; struct usb_hcd *hcd = bus_to_hcd(hdev->bus); unsigned wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); struct usb_device *udev; ... for (i = 0; i < SET_CONFIG_TRIES; i++) { /* reallocate for each attempt, since references * to the previous one can escape in various ways */ udev = usb_alloc_dev(hdev, hdev->bus, port1); ... //一些初始赋值电流 速度什么的 /* reset (non-USB 3.0 devices) and get descriptor */ status = hub_port_init(hub, udev, port1, i); //对端口的初始操作 if (status < 0) goto loop; ... status = usb_new_device(udev); //定义一个新的usb设备 } ... }
usb driver的检测部分大体就是这样,主要是通过对port的监测!
二.kobject_uevent_env:
在上面的hub_event中分析了kernel对插入设备的检测与识别,到usb_new_device:
int usb_new_device(struct usb_device *udev) { int err; ... /* Tell the world! */ announce_device(udev); //打印出识别到的usb设备相关信息,包括 name idVendor idProduct 等 ... err = device_add(&udev->dev); //添加识别到的这个设备 ... }
再看device_add:
int device_add(struct device *dev) { struct device *parent = NULL; ... /* first, register with generic layer. */ /* we require the name to be set before, and pass NULL */ error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); ... kobject_uevent(&dev->kobj, KOBJ_ADD); //发送这个设备事件,事件类型为添加 ... }
最后调用到真正发送uevent事件的是/lib/kobject_uevent.c下的kobject_uevent_env
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp_ext[]) { struct kobj_uevent_env *env; const char *action_string = kobject_actions[action]; //根据定义数组 const char *devpath = NULL; const char *subsystem; ... /* originating subsystem */ if (uevent_ops && uevent_ops->name) subsystem = uevent_ops->name(kset, kobj); else subsystem = kobject_name(&kset->kobj); ... /* environment buffer */ env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); retval = add_uevent_var(env, "ACTION=%s", action_string);//按照格式添加到env中 if (retval) goto exit; retval = add_uevent_var(env, "DEVPATH=%s", devpath); if (retval) goto exit; retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem); if (retval) goto exit; ... /* send netlink message */ //从这里开始才是真正的发送操作,使用的是netlink的套接字 mutex_lock(&uevent_sock_mutex); list_for_each_entry(ue_sk, &uevent_sock_list, list) { struct sock *uevent_sock = ue_sk->sk; struct sk_buff *skb; size_t len; /* allocate message with the maximum possible size */ len = strlen(action_string) + strlen(devpath) + 2; skb = alloc_skb(len + env->buflen, GFP_KERNEL); if (skb) { char *scratch; /* add header */ scratch = skb_put(skb, len); sprintf(scratch, "%[email protected]%s", action_string, devpath); /* copy keys to our continuous event payload buffer */ for (i = 0; i < env->envp_idx; i++) { len = strlen(env->envp[i]) + 1; scratch = skb_put(skb, len); strcpy(scratch, env->envp[i]); } //抽取上面准备的数据 NETLINK_CB(skb).dst_group = 1; retval = netlink_broadcast_filtered(uevent_sock, skb, //发送函数 0, 1, GFP_KERNEL, kobj_bcast_filter, kobj); /* ENOBUFS should be handled in userspace */ if (retval == -ENOBUFS || retval == -ESRCH) retval = 0; } else retval = -ENOMEM; } mutex_unlock(&uevent_sock_mutex); ... }
最后通过netlink_broadcast_filtered发送设备uevent的信息,对于kernel中的usb driver 我接触的不多,这里只是简单解析了一下往Vold 发送uevent的流程,
其中很多复杂的流程我都没写,以后有机会学习usb driver时再研究!