tizen 2.3 release
[framework/system/deviced.git] / src / usb / usb-host.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include "usb-host.h"
20 #include "core/device-notifier.h"
21
22 static dd_list *storage_list;
23 static dd_list *device_list;
24
25 static int noti_id = 0;
26
27 struct ticker_data {
28         char *name;
29         int type;
30 };
31
32 struct popup_data {
33         char *name;
34         char *method;
35         char *key1;
36         char *value1;
37         char *key2;
38         char *value2;
39 };
40
41 /* Do not handle usb host uevents if host_uevent_enable is false
42  * host_uevent_enable is set to true when usb host connector is connected first*/
43 static bool host_uevent_enabled = false;
44
45 bool is_host_uevent_enabled(void)
46 {
47         return host_uevent_enabled;
48 }
49
50 int get_storage_list_length(void)
51 {
52         return DD_LIST_LENGTH(storage_list);
53 }
54
55 dd_list *get_storage_list(void)
56 {
57         return storage_list;
58 }
59
60 dd_list *get_device_list(void)
61 {
62         return device_list;
63 }
64
65 void launch_ticker_notification(char *name)
66 {
67         struct ticker_data ticker;
68         const struct device_ops *ticker_ops = NULL;
69
70         if (!name) {
71                 _E("ticker noti name is NULL");
72                 return;
73         }
74
75         ticker.name = name;
76         ticker.type = 0; /* WITHOUT_QUEUE */
77
78         FIND_DEVICE_VOID(ticker_ops, "ticker");
79         if (ticker_ops && ticker_ops->init)
80                 ticker_ops->init(&ticker);
81         else
82                 _E("cannot find \"ticker\" ops");
83 }
84
85 void launch_host_syspopup(char *name, char *method,
86                 char *key1, char *value1,
87                 char *key2, char *value2)
88 {
89         struct popup_data params;
90         static const struct device_ops *apps = NULL;
91
92         if (!name || !method)
93                 return;
94
95         FIND_DEVICE_VOID(apps, "apps");
96         params.name = name;
97         params.method = method;
98         params.key1 = key1;
99         params.value1 = value1;
100         params.key2 = key2;
101         params.value2 = value2;
102
103         if (apps->init)
104                 apps->init(&params);
105 }
106
107 static int get_number_of_mounted_storages(void)
108 {
109         int num;
110         dd_list *l;
111         struct usb_device *dev;
112
113         if (!storage_list || DD_LIST_LENGTH(storage_list) == 0)
114                 return 0;
115
116         num = 0;
117         DD_LIST_FOREACH(storage_list, l, dev) {
118                 if (dev && dev->is_mounted)
119                         num++;
120         }
121
122         return num;
123 }
124
125 void update_usbhost_state(void)
126 {
127         int prev, curr;
128
129         if (vconf_get_int(VCONFKEY_SYSMAN_USB_HOST_STATUS, &prev) != 0)
130                 prev = -1;
131
132         if (get_number_of_mounted_storages() == 0
133                         && (!device_list || DD_LIST_LENGTH(device_list) == 0))
134                 curr = VCONFKEY_SYSMAN_USB_HOST_DISCONNECTED;
135         else
136                 curr = VCONFKEY_SYSMAN_USB_HOST_CONNECTED;
137
138         if (prev == curr)
139                 return;
140
141         if (vconf_set_int(VCONFKEY_SYSMAN_USB_HOST_STATUS, curr) != 0)
142                 _E("Failed to set vconf key");
143 }
144
145 bool check_same_mntpath(const char *mntpath)
146 {
147         dd_list *l;
148         struct usb_device *dev;
149
150         DD_LIST_FOREACH(storage_list, l, dev) {
151                 if (!strncmp(dev->mntpath, mntpath, strlen(dev->mntpath)))
152                         return true;
153         }
154         return false;
155 }
156
157 bool is_storage_mounted(const char *mntpath)
158 {
159         dd_list *l;
160         struct usb_device *dev;
161
162         DD_LIST_FOREACH(storage_list, l, dev) {
163                 if (!strncmp(dev->mntpath, mntpath, strlen(dev->mntpath)))
164                         break;
165         }
166         if (l && dev)
167                 return dev->is_mounted;
168         return false;
169 }
170
171 static int add_usb_host_device_to_list(int type,
172                 const char *name,
173                 const char *vendor,
174                 const char *model,
175                 const char *fstype,
176                 char *path)
177 {
178         struct usb_device *dev;
179         int id;
180
181         if (!name || type < 0)
182                 return -EINVAL;
183
184         if (type == USBHOST_STORAGE && !path)
185                 return -EINVAL;
186
187         dev = (struct usb_device *)malloc(sizeof(struct usb_device));
188         if (!dev) {
189                 _E("Failed to assign memory");
190                 return -ENOMEM;
191         }
192
193         dev->type = type;
194         dev->is_mounted = false;
195         dev->noti_id = 0;
196         snprintf(dev->name, sizeof(dev->name), "%s", name);
197         snprintf(dev->mntpath, sizeof(dev->mntpath), "%s", path);
198
199         if (model)
200                 snprintf(dev->model, sizeof(dev->model), "%s", model);
201         else
202                 memset(dev->model, 0, sizeof(dev->model));
203
204         if (vendor)
205                 snprintf(dev->vendor, sizeof(dev->vendor), "%s", vendor);
206         else
207                 memset(dev->vendor, 0, sizeof(dev->vendor));
208
209         if (fstype)
210                 snprintf(dev->fs, sizeof(dev->fs), "%s", fstype);
211         else
212                 memset(dev->fs, 0, sizeof(dev->fs));
213
214         if (type == USBHOST_STORAGE) {
215                 if (!check_same_mntpath(path))
216                         DD_LIST_APPEND(storage_list, dev);
217                 else
218                         free(dev);
219         } else {
220                 dev->noti_id = activate_device_notification(dev, DD_LIST_LENGTH(device_list));
221                 DD_LIST_APPEND(device_list, dev);
222                 if (send_device_added_info(dev) < 0)
223                         _E("Failed to send device info");
224         }
225
226         return 0;
227 }
228
229 int add_usb_storage_to_list(const char *name,
230                 const char *vendor,
231                 const char *model,
232                 const char *fstype)
233 {
234         char path[BUF_MAX];
235         int ret;
236
237         if (!name)
238                 return -EINVAL;
239
240         ret = get_mount_path(name, path, sizeof(path));
241         if (ret < 0) {
242                 _E("Failed to get mount path");
243                 return ret;
244         }
245
246         ret = add_usb_host_device_to_list(USBHOST_STORAGE,
247                         name, vendor, model, fstype, path);
248
249         update_usbhost_state();
250
251         return ret;
252 }
253
254 int add_usb_device_to_list(int type,
255                 const char *name,
256                 const char *vendor,
257                 const char *model)
258 {
259         int ret;
260
261         ret = add_usb_host_device_to_list(type,
262                         name, vendor, model, NULL, NULL);
263
264         update_usbhost_state();
265
266         return ret;
267 }
268
269 int remove_usb_storage_from_list(const char *name)
270 {
271         dd_list *l;
272         struct usb_device *dev;
273         bool found;
274
275         if (!name)
276                 return -EINVAL;
277
278         found = false;
279         DD_LIST_FOREACH(storage_list, l, dev) {
280                 if (strncmp(dev->name, name, strlen(name)))
281                         continue;
282
283                 found = true;
284                 break;
285         }
286         if (!found) {
287                 return -EINVAL;
288         }
289
290         DD_LIST_REMOVE(storage_list, dev);
291         free(dev);
292
293         update_usbhost_state();
294
295         return 0;
296 }
297
298 int remove_usb_device_from_list(const char *name, int type)
299 {
300         dd_list *l;
301         struct usb_device *dev;
302         bool found;
303         int len;
304
305         if (!name)
306                 return -EINVAL;
307
308         found = false;
309         DD_LIST_FOREACH(device_list, l, dev) {
310                 if (type == USBHOST_PRINTER) {
311                         if (!strstr(name, dev->name))
312                                 continue;
313                 } else {
314                         if (strncmp(dev->name, name, strlen(name)))
315                                 continue;
316                 }
317
318                 found = true;
319                 break;
320         }
321         if (!found) {
322                 return -EINVAL;
323         }
324
325         if (send_device_removed_info(dev) < 0)
326                 _E("Failed to send device info");
327
328         DD_LIST_REMOVE(device_list, dev);
329         free(dev);
330
331         len = DD_LIST_LENGTH(device_list);
332         if (len <= 0)
333                 dev = NULL;
334         else
335                 dev = DD_LIST_NTH(device_list, 0); /* First element */
336
337         if (deactivate_device_notification(dev, len))
338                 _E("Failed to remove notification");
339
340         update_usbhost_state();
341
342         return 0;
343 }
344
345 static void subsystem_host_changed (struct udev_device *dev)
346 {
347         const char *state = NULL;
348         int ret;
349         static int cradle;
350
351         state = udev_device_get_property_value(dev, UDEV_PROP_KEY_STATE);
352         if (!state)
353                 return;
354
355         if (!strncmp(state, UDEV_PROP_VALUE_ADD, strlen(UDEV_PROP_VALUE_ADD))) {
356                 _I("USB host connector is added");
357
358                 if (!host_uevent_enabled)
359                         host_uevent_enabled = true;
360
361                 cradle = get_cradle_status();
362                 if (cradle == 0) {
363                         launch_ticker_notification(TICKER_NAME_CONNECTOR_CONNECTED);
364                 }
365
366                 return;
367         }
368
369         if (!strncmp(state, UDEV_PROP_VALUE_REMOVE, strlen(UDEV_PROP_VALUE_REMOVE))) {
370                 _I("USB host connector is removed");
371
372                 if (cradle == 0) {
373                         launch_ticker_notification(TICKER_NAME_CONNECTOR_DISCONNECTED);
374                 } else {
375                         cradle = 0;
376                 }
377
378                 return;
379         }
380 }
381
382 const static struct uevent_handler uhs[] = {
383         { HOST_SUBSYSTEM       ,     subsystem_host_changed       ,    NULL    },
384 };
385
386 static int usbhost_init_booting_done(void *data)
387 {
388         int ret, i;
389
390         unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, usbhost_init_booting_done);
391
392         for (i = 0 ; i < ARRAY_SIZE(uhs) ; i++) {
393                 ret = register_uevent_control(&uhs[i]);
394                 if (ret < 0)
395                         _E("FAIL: reg_uevent_control()");
396         }
397
398         if (register_unmount_signal_handler() < 0)
399                 _E("Failed to register handler for unmount signal");
400
401         if (register_device_all_signal_handler() < 0)
402                 _E("Failed to register handler for device info");
403
404         if (register_usbhost_dbus_methods() < 0)
405                 _E("Failed to register dbus handler for usbhost");
406
407         return 0;
408 }
409
410 static void usbhost_init(void *data)
411 {
412         register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, usbhost_init_booting_done);
413 }
414
415 static void usbhost_exit(void *data)
416 {
417         int i;
418
419         for (i = 0 ; i < ARRAY_SIZE(uhs) ; i++) {
420                 unregister_uevent_control(&uhs[i]);
421         }
422 }
423
424 static const struct device_ops usbhost_device_ops = {
425         .priority = DEVICE_PRIORITY_NORMAL,
426         .name     = "usbhost",
427         .init     = usbhost_init,
428         .exit     = usbhost_exit,
429 };
430
431 DEVICE_OPS_REGISTER(&usbhost_device_ops)