oFono学习笔记——oFono设备发现机制

摘要

oFono支持动态的检测modem设备的插拔。本文主要讲解oFono如何实现对modem的插拔进行检测的。这篇文章也解释了plugin是如何扩展oFono功能而不是仅仅作为modem/atom驱动的容器。

1.modem设备检测分析

1.1初始化

当设备检测plugin被oFono载入到系统后,系统会对plugin进行初始化。

 1 static int detect_init(void)
 2 {
 3     udev_ctx = udev_new();
 4     if (udev_ctx == NULL) {
 5         ofono_error("Failed to create udev context");
 6         return -EIO;
 7     }
 8 
 9     udev_mon = udev_monitor_new_from_netlink(udev_ctx, "udev");
10     if (udev_mon == NULL) {
11         ofono_error("Failed to create udev monitor");
12         udev_unref(udev_ctx);
13         udev_ctx = NULL;
14         return -EIO;
15     }
16   /*创建hash table*/
17     modem_list = g_hash_table_new_full(g_str_hash, g_str_equal,
18                         NULL, destroy_modem);
19 
20     udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "tty", NULL);
21     udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "net", NULL);
22 
23     udev_monitor_filter_update(udev_mon);
24 
25     udev_start();
26 
27     return 0;
28 }

 

plugin进行初始化时会创建udev_monitor【1】,并初始化一个g_hash_table【2】,然后使能设备发现。

注:创建的hash table有一下的特点,modem节点被删除时,会自动调用destory_modem对modem进行析构。关于udev_monitor和g_hash_table的细节可以在最后的reference中找到。

 1 static void udev_start(void)
 2 {
 3     GIOChannel *channel;
 4     int fd;
 5 
 6     DBG("");
 7 
 8     if (udev_monitor_enable_receiving(udev_mon) < 0) {
 9         ofono_error("Failed to enable udev monitor");
10         return;
11     }
12   /*枚举当前系统下的所有USB modem*/
13     enumerate_devices(udev_ctx);
14 
15     fd = udev_monitor_get_fd(udev_mon);
16   /*创建一个设备监听通道*/
17     channel = g_io_channel_unix_new(fd);
18     if (channel == NULL)
19         return;
20   /*将设备监听通道读事件加入到时间循环当中*/
21     udev_watch = g_io_add_watch(channel,
22                 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
23                             udev_event, NULL);
24 
25     g_io_channel_unref(channel);
26 }

从代码来看设备发现的初始化主要做了一下三件事情:

1. 枚举出当前系统中已经存在的USB modem设备,并在oFono中创建对应的modem

2. 监听udev_monitor

3. 将udev_monitor读事件加入到主事件循环中去。

1.2 设备的插入/拔出

这一节将介绍当设备插入/拔出时,设备发现plugin所做的动作。我们知道在初始化之后,系统就会去检测udev_monitor的状态,一旦状态发生改变,就会出发udev_event函数来处理所发生的udev事件。

 1 static gboolean udev_event(GIOChannel *channel, GIOCondition cond,
 2                             gpointer user_data)
 3 {
 4     struct udev_device *device;
 5     const char *action;
 6 
 7     if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
 8         ofono_warn("Error with udev monitor channel");
 9         udev_watch = 0;
10         return FALSE;
11     }
12 
13     device = udev_monitor_receive_device(udev_mon);
14     if (device == NULL)
15         return TRUE;
16 
17     action = udev_device_get_action(device);
18     if (action == NULL)
19         return TRUE;
20   /*设备插入*/
21     if (g_str_equal(action, "add") == TRUE) {
22         if (udev_delay > 0)
23             g_source_remove(udev_delay);
24   /*检查设备合法性*/
25         check_device(device);
26   /*创建并注册modem到oFono中*/
27         udev_delay = g_timeout_add_seconds(1, check_modem_list, NULL);
28     } 
29   /*设备拔出*/
30 else if (g_str_equal(action, "remove") == TRUE)
31         remove_device(device);
32 
33     udev_device_unref(device);
34 
35     return TRUE;
36 }

 

1.2.1设备拔出

当检测到modem被拔出后,plugin会将这个modem device从系统中删除。

1.2.2设备插入

当检测到modem插入时,plugin会检查设备的合法性,然后调用check_modem_list将创建并注册合法的modem到oFono当中去。

需要注意的是,check_modem_list并不是马上执行的,而是会被推迟到1s之内没有新设备被发现之后才执行。这样做的目的是,很多USB modem都会虚拟出若干个串口分别适应不同的工作,这样如果不等所有串口初始化完毕就立马执行check_modem_list可能就会导致modem初始化失败。

2.最后

这就是我对oFono设备发现过程的理解,也许存在偏差和不对的地方,欢迎大家指正。

 

References:

【1】https://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/libudev-udev-monitor.html

【2】https://developer.gnome.org/glib/2.30/glib-Hash-Tables.html#g-hash-table-new-full

 

 

 

posted @ 2013-07-05 19:06  ZHX_1Q89  阅读(1256)  评论(0编辑  收藏  举报