12d67ef0dcb1ba37b9b64619f285600a83fd34cb
[connman] / plugins / hal.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <sys/stat.h>
28
29 #include <dbus/dbus.h>
30 #include <hal/libhal.h>
31
32 #include <connman/plugin.h>
33 #include <connman/element.h>
34 #include <connman/log.h>
35
36 static struct {
37         const char *name;
38         enum connman_element_subtype subtype;
39 } capabilities[] = {
40         { "net.80203", CONNMAN_ELEMENT_SUBTYPE_ETHERNET },
41         { "net.80211", CONNMAN_ELEMENT_SUBTYPE_WIFI     },
42         { "net.wimax", CONNMAN_ELEMENT_SUBTYPE_WIMAX    },
43         { "modem",     CONNMAN_ELEMENT_SUBTYPE_MODEM    },
44         { }
45 };
46
47 static GStaticMutex element_mutex = G_STATIC_MUTEX_INIT;
48 static GSList *element_list = NULL;
49
50 static void device_info(LibHalContext *ctx, const char *udi,
51                                         struct connman_element *element)
52 {
53         char *parent, *subsys, *value;
54
55         parent = libhal_device_get_property_string(ctx, udi,
56                                                 "info.parent", NULL);
57
58         subsys = libhal_device_get_property_string(ctx, udi,
59                                                 "linux.subsystem", NULL);
60
61         value = libhal_device_get_property_string(ctx, udi,
62                                                 "info.linux.driver", NULL);
63         if (value == NULL) {
64                 value = libhal_device_get_property_string(ctx, parent,
65                                                 "info.linux.driver", NULL);
66                 if (value != NULL)
67                         connman_element_add_static_property(element,
68                                         "Driver", DBUS_TYPE_STRING, &value);
69         }
70
71         if (g_str_equal(subsys, "net") == TRUE ||
72                                         g_str_equal(subsys, "tty") == TRUE) {
73                 value = libhal_device_get_property_string(ctx, parent,
74                                                         "info.vendor", NULL);
75                 if (value != NULL)
76                         connman_element_add_static_property(element,
77                                         "Vendor", DBUS_TYPE_STRING, &value);
78
79                 value = libhal_device_get_property_string(ctx, parent,
80                                                         "info.product", NULL);
81                 if (value != NULL)
82                         connman_element_add_static_property(element,
83                                         "Product", DBUS_TYPE_STRING, &value);
84         }
85 }
86
87 static void device_netdev(LibHalContext *ctx, const char *udi,
88                                         struct connman_element *element)
89 {
90         if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_ETHERNET ||
91                         element->subtype == CONNMAN_ELEMENT_SUBTYPE_WIFI ||
92                         element->subtype == CONNMAN_ELEMENT_SUBTYPE_WIMAX) {
93                 element->index = libhal_device_get_property_int(ctx,
94                                                 udi, "net.linux.ifindex", NULL);
95
96                 element->name = libhal_device_get_property_string(ctx,
97                                                 udi, "net.interface", NULL);
98         }
99
100         if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_MODEM) {
101                 element->index = libhal_device_get_property_int(ctx,
102                                                 udi, "serial.port", NULL);
103
104                 element->name = libhal_device_get_property_string(ctx,
105                                                 udi, "serial.device", NULL);
106         }
107 }
108
109 static void create_element(LibHalContext *ctx, const char *udi,
110                                         enum connman_element_subtype subtype)
111 {
112         struct connman_element *element;
113
114         DBG("ctx %p udi %s", ctx, udi);
115
116         if (subtype == CONNMAN_ELEMENT_SUBTYPE_ETHERNET) {
117                 char *sysfs_path, wimax_path[PATH_MAX];
118                 struct stat st;
119
120                 sysfs_path = libhal_device_get_property_string(ctx, udi,
121                                                 "linux.sysfs_path", NULL);
122                 if (sysfs_path != NULL) {
123                         snprintf(wimax_path, PATH_MAX, "%s/wimax", sysfs_path);
124
125                         if (stat(wimax_path, &st) == 0 &&
126                                                 (st.st_mode & S_IFDIR))
127                                 subtype = CONNMAN_ELEMENT_SUBTYPE_WIMAX;
128                 }
129         }
130
131         element = connman_element_create(NULL);
132
133         element->type = CONNMAN_ELEMENT_TYPE_DEVICE;
134         element->subtype = subtype;
135
136         device_info(ctx, udi, element);
137         device_netdev(ctx, udi, element);
138
139         if (element->name == NULL) {
140                 element->name = g_path_get_basename(udi);
141                 if (element->name == NULL) {
142                         connman_element_unref(element);
143                         return;
144                 }
145         }
146
147         g_static_mutex_lock(&element_mutex);
148
149         connman_element_register(element, NULL);
150
151         element_list = g_slist_append(element_list, element);
152
153         g_static_mutex_unlock(&element_mutex);
154 }
155
156 static void device_added(LibHalContext *ctx, const char *udi)
157 {
158         int i;
159
160         DBG("ctx %p udi %s", ctx, udi);
161
162         for (i = 0; capabilities[i].name; i++) {
163                 if (libhal_device_query_capability(ctx, udi,
164                                         capabilities[i].name, NULL) == TRUE)
165                         create_element(ctx, udi, capabilities[i].subtype);
166         }
167 }
168
169 static void device_removed(LibHalContext *ctx, const char *udi)
170 {
171         struct connman_element *removal = NULL;
172         GSList *list;
173         gchar *name;
174
175         DBG("ctx %p udi %s", ctx, udi);
176
177         name = g_path_get_basename(udi);
178
179         g_static_mutex_lock(&element_mutex);
180
181         for (list = element_list; list; list = list->next) {
182                 struct connman_element *element = list->data;
183
184                 if (g_str_equal(element->name, name) == TRUE) {
185                         removal = element;
186                         break;
187                 }
188         }
189
190         if (removal != NULL) {
191                 element_list = g_slist_remove(element_list, removal);
192
193                 connman_element_unregister(removal);
194                 connman_element_unref(removal);
195         }
196
197         g_static_mutex_unlock(&element_mutex);
198
199         g_free(name);
200 }
201
202 static void probe_capability(LibHalContext *ctx, const char *capability,
203                                         enum connman_element_subtype subtype)
204 {
205         char **list;
206         int num;
207
208         DBG("ctx %p capability %s", ctx, capability);
209
210         list = libhal_find_device_by_capability(ctx, capability, &num, NULL);
211         if (list) {
212                 char **tmp = list;
213
214                 while (*tmp) {
215                         create_element(ctx, *tmp, subtype);
216                         tmp++;
217                 }
218
219                 libhal_free_string_array(list);
220         }
221 }
222
223 static void find_devices(LibHalContext *ctx)
224 {
225         int i;
226
227         DBG("ctx %p", ctx);
228
229         for (i = 0; capabilities[i].name; i++)
230                 probe_capability(ctx, capabilities[i].name,
231                                                 capabilities[i].subtype);
232 }
233
234 static LibHalContext *hal_ctx = NULL;
235
236 static void libhal_init(void *data)
237 {
238         DBusConnection *conn = data;
239
240         DBG("conn %p", conn);
241
242         if (hal_ctx != NULL)
243                 return;
244
245         hal_ctx = libhal_ctx_new();
246         if (hal_ctx == NULL)
247                 return;
248
249         if (libhal_ctx_set_dbus_connection(hal_ctx, conn) == FALSE) {
250                 libhal_ctx_free(hal_ctx);
251                 return;
252         }
253
254         if (libhal_ctx_init(hal_ctx, NULL) == FALSE) {
255                 libhal_ctx_free(hal_ctx);
256                 return ;
257         }
258
259         libhal_ctx_set_device_added(hal_ctx, device_added);
260         libhal_ctx_set_device_removed(hal_ctx, device_removed);
261
262         //libhal_ctx_set_device_new_capability(hal_ctx, new_capability);
263         //libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability);
264
265         find_devices(hal_ctx);
266 }
267
268 static void libhal_cleanup(void *data)
269 {
270         DBusConnection *conn = data;
271         GSList *list;
272
273         DBG("conn %p", conn);
274
275         g_static_mutex_lock(&element_mutex);
276
277         for (list = element_list; list; list = list->next) {
278                 struct connman_element *element = list->data;
279
280                 connman_element_unregister(element);
281                 connman_element_unref(element);
282         }
283
284         g_slist_free(element_list);
285         element_list = NULL;
286
287         g_static_mutex_unlock(&element_mutex);
288
289         if (hal_ctx == NULL)
290                 return;
291
292         libhal_ctx_shutdown(hal_ctx, NULL);
293
294         libhal_ctx_free(hal_ctx);
295
296         hal_ctx = NULL;
297 }
298
299 static int hal_init(void)
300 {
301         DBusConnection *conn;
302
303         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
304         if (conn == NULL)
305                 return -EIO;
306
307         libhal_init(conn);
308
309         return 0;
310 }
311
312 static void hal_exit(void)
313 {
314         DBusConnection *conn;
315
316         conn = libhal_ctx_get_dbus_connection(hal_ctx);
317         if (conn == NULL)
318                 return;
319
320         libhal_cleanup(conn);
321
322         dbus_connection_unref(conn);
323 }
324
325 CONNMAN_PLUGIN_DEFINE("hal", "Hardware detection plugin", VERSION,
326                                                         hal_init, hal_exit)