Initialize Tizen 2.3
[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;
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         ticker_ops = find_device("ticker");
79
80         if (ticker_ops && ticker_ops->init)
81                 ticker_ops->init(&ticker);
82         else
83                 _E("cannot find \"ticker\" ops");
84 }
85
86 void launch_host_syspopup(char *name, char *method,
87                 char *key1, char *value1,
88                 char *key2, char *value2)
89 {
90         struct popup_data params;
91         static const struct device_ops *apps = NULL;
92
93         if (!name || !method)
94                 return;
95
96         if (apps == NULL) {
97                 apps = find_device("apps");
98                 if (apps == NULL)
99                         return;
100         }
101
102         params.name = name;
103         params.method = method;
104         params.key1 = key1;
105         params.value1 = value1;
106         params.key2 = key2;
107         params.value2 = value2;
108
109         if (apps->init)
110                 apps->init(&params);
111 }
112
113 static int get_number_of_mounted_storages(void)
114 {
115         int num;
116         dd_list *l;
117         struct usb_device *dev;
118
119         if (!storage_list || DD_LIST_LENGTH(storage_list) == 0)
120                 return 0;
121
122         num = 0;
123         DD_LIST_FOREACH(storage_list, l, dev) {
124                 if (dev && dev->is_mounted)
125                         num++;
126         }
127
128         return num;
129 }
130
131 void update_usbhost_state(void)
132 {
133         int prev, curr;
134
135         if (vconf_get_int(VCONFKEY_SYSMAN_USB_HOST_STATUS, &prev) != 0)
136                 prev = -1;
137
138         if (get_number_of_mounted_storages() == 0
139                         && (!device_list || DD_LIST_LENGTH(device_list) == 0))
140                 curr = VCONFKEY_SYSMAN_USB_HOST_DISCONNECTED;
141         else
142                 curr = VCONFKEY_SYSMAN_USB_HOST_CONNECTED;
143
144         if (prev == curr)
145                 return;
146
147         if (vconf_set_int(VCONFKEY_SYSMAN_USB_HOST_STATUS, curr) != 0)
148                 _E("Failed to set vconf key");
149 }
150
151 bool check_same_mntpath(const char *mntpath)
152 {
153         dd_list *l;
154         struct usb_device *dev;
155
156         DD_LIST_FOREACH(storage_list, l, dev) {
157                 if (!strncmp(dev->mntpath, mntpath, strlen(dev->mntpath)))
158                         return true;
159         }
160         return false;
161 }
162
163 bool is_storage_mounted(const char *mntpath)
164 {
165         dd_list *l;
166         struct usb_device *dev;
167
168         DD_LIST_FOREACH(storage_list, l, dev) {
169                 if (!strncmp(dev->mntpath, mntpath, strlen(dev->mntpath)))
170                         break;
171         }
172         if (l && dev)
173                 return dev->is_mounted;
174         return false;
175 }
176
177 static int add_usb_host_device_to_list(int type,
178                 const char *name,
179                 const char *vendor,
180                 const char *model,
181                 const char *fstype,
182                 char *path)
183 {
184         struct usb_device *dev;
185         int id;
186
187         if (!name || type < 0)
188                 return -EINVAL;
189
190         if (type == USBHOST_STORAGE && !path)
191                 return -EINVAL;
192
193         dev = (struct usb_device *)malloc(sizeof(struct usb_device));
194         if (!dev) {
195                 _E("Failed to assign memory");
196                 return -ENOMEM;
197         }
198
199         dev->type = type;
200         dev->is_mounted = false;
201         dev->noti_id = 0;
202         snprintf(dev->name, sizeof(dev->name), "%s", name);
203         snprintf(dev->mntpath, sizeof(dev->mntpath), "%s", path);
204
205         if (model)
206                 snprintf(dev->model, sizeof(dev->model), "%s", model);
207         else
208                 memset(dev->model, 0, sizeof(dev->model));
209
210         if (vendor)
211                 snprintf(dev->vendor, sizeof(dev->vendor), "%s", vendor);
212         else
213                 memset(dev->vendor, 0, sizeof(dev->vendor));
214
215         if (fstype)
216                 snprintf(dev->fs, sizeof(dev->fs), "%s", fstype);
217         else
218                 memset(dev->fs, 0, sizeof(dev->fs));
219
220         if (type == USBHOST_STORAGE) {
221                 if (!check_same_mntpath(path))
222                         DD_LIST_APPEND(storage_list, dev);
223                 else
224                         free(dev);
225         } else {
226                 dev->noti_id = activate_device_notification(dev, DD_LIST_LENGTH(device_list));
227                 DD_LIST_APPEND(device_list, dev);
228                 if (send_device_added_info(dev) < 0)
229                         _E("Failed to send device info");
230         }
231
232         return 0;
233 }
234
235 int add_usb_storage_to_list(const char *name,
236                 const char *vendor,
237                 const char *model,
238                 const char *fstype)
239 {
240         char path[BUF_MAX];
241         int ret;
242
243         if (!name)
244                 return -EINVAL;
245
246         ret = get_mount_path(name, path, sizeof(path));
247         if (ret < 0) {
248                 _E("Failed to get mount path");
249                 return ret;
250         }
251
252         ret = add_usb_host_device_to_list(USBHOST_STORAGE,
253                         name, vendor, model, fstype, path);
254
255         update_usbhost_state();
256
257         return ret;
258 }
259
260 int add_usb_device_to_list(int type,
261                 const char *name,
262                 const char *vendor,
263                 const char *model)
264 {
265         int ret;
266
267         ret = add_usb_host_device_to_list(type,
268                         name, vendor, model, NULL, NULL);
269
270         update_usbhost_state();
271
272         return ret;
273 }
274
275 int remove_usb_storage_from_list(const char *name)
276 {
277         dd_list *l;
278         struct usb_device *dev;
279         bool found;
280
281         if (!name)
282                 return -EINVAL;
283
284         found = false;
285         DD_LIST_FOREACH(storage_list, l, dev) {
286                 if (strncmp(dev->name, name, strlen(name)))
287                         continue;
288
289                 found = true;
290                 break;
291         }
292         if (!found) {
293                 return -EINVAL;
294         }
295
296         DD_LIST_REMOVE(storage_list, dev);
297         free(dev);
298
299         update_usbhost_state();
300
301         return 0;
302 }
303
304 int remove_usb_device_from_list(const char *name, int type)
305 {
306         dd_list *l;
307         struct usb_device *dev;
308         bool found;
309         int len;
310
311         if (!name)
312                 return -EINVAL;
313
314         found = false;
315         DD_LIST_FOREACH(device_list, l, dev) {
316                 if (type == USBHOST_PRINTER) {
317                         if (!strstr(name, dev->name))
318                                 continue;
319                 } else {
320                         if (strncmp(dev->name, name, strlen(name)))
321                                 continue;
322                 }
323
324                 found = true;
325                 break;
326         }
327         if (!found) {
328                 return -EINVAL;
329         }
330
331         if (send_device_removed_info(dev) < 0)
332                 _E("Failed to send device info");
333
334         DD_LIST_REMOVE(device_list, dev);
335         free(dev);
336
337         len = DD_LIST_LENGTH(device_list);
338         if (len <= 0)
339                 dev = NULL;
340         else
341                 dev = DD_LIST_NTH(device_list, 0); /* First element */
342
343         if (deactivate_device_notification(dev, len))
344                 _E("Failed to remove notification");
345
346         update_usbhost_state();
347
348         return 0;
349 }
350
351 static void subsystem_host_changed (struct udev_device *dev)
352 {
353         const char *state = NULL;
354         int ret;
355         static int cradle;
356
357         state = udev_device_get_property_value(dev, UDEV_PROP_KEY_STATE);
358         if (!state)
359                 return;
360
361         if (!strncmp(state, UDEV_PROP_VALUE_ADD, strlen(UDEV_PROP_VALUE_ADD))) {
362                 _I("USB host connector is added");
363
364                 if (!host_uevent_enabled)
365                         host_uevent_enabled = true;
366
367                 cradle = get_cradle_status();
368                 if (cradle == 0) {
369                         launch_ticker_notification(TICKER_NAME_CONNECTOR_CONNECTED);
370                 }
371
372                 return;
373         }
374
375         if (!strncmp(state, UDEV_PROP_VALUE_REMOVE, strlen(UDEV_PROP_VALUE_REMOVE))) {
376                 _I("USB host connector is removed");
377
378                 if (cradle == 0) {
379                         launch_ticker_notification(TICKER_NAME_CONNECTOR_DISCONNECTED);
380                 } else {
381                         cradle = 0;
382                 }
383
384                 return;
385         }
386 }
387
388 const static struct uevent_handler uhs[] = {
389         { HOST_SUBSYSTEM       ,     subsystem_host_changed       ,    NULL    },
390 };
391
392 static int usbhost_init_booting_done(void *data)
393 {
394         int ret, i;
395
396         unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, usbhost_init_booting_done);
397
398         for (i = 0 ; i < ARRAY_SIZE(uhs) ; i++) {
399                 ret = register_uevent_control(&uhs[i]);
400                 if (ret < 0)
401                         _E("FAIL: reg_uevent_control()");
402         }
403
404         if (register_unmount_signal_handler() < 0)
405                 _E("Failed to register handler for unmount signal");
406
407         if (register_device_all_signal_handler() < 0)
408                 _E("Failed to register handler for device info");
409
410         if (register_usbhost_dbus_methods() < 0)
411                 _E("Failed to register dbus handler for usbhost");
412
413         return 0;
414 }
415
416 static void usbhost_init(void *data)
417 {
418         register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, usbhost_init_booting_done);
419 }
420
421 static void usbhost_exit(void *data)
422 {
423         int i;
424
425         for (i = 0 ; i < ARRAY_SIZE(uhs) ; i++) {
426                 unregister_uevent_control(&uhs[i]);
427         }
428 }
429
430 static const struct device_ops usbhost_device_ops = {
431         .priority = DEVICE_PRIORITY_NORMAL,
432         .name     = "usbhost",
433         .init     = usbhost_init,
434         .exit     = usbhost_exit,
435 };
436
437 DEVICE_OPS_REGISTER(&usbhost_device_ops)