Initialize Tizen 2.3
[framework/system/deviced.git] / src / usb / usb-client.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 <stdbool.h>
20 #include "usb-client.h"
21 #include "core/device-handler.h"
22 #include "core/edbus-handler.h"
23
24 #define USB_POPUP_NAME "usb-syspopup"
25
26 #ifndef VCONFKEY_USB_CONFIGURATION_ENABLED
27 #define VCONFKEY_USB_CONFIGURATION_ENABLED "memory/private/usb/conf_enabled"
28 #endif
29
30 struct popup_data {
31         char *name;
32         char *key;
33         char *value;
34 };
35
36 enum usb_enabled {
37         USB_CONF_DISABLED,
38         USB_CONF_ENABLED,
39 };
40
41 static bool client_mode = false;
42 static char *driver_version = NULL;
43 static bool wait_configured = false;
44
45 void launch_syspopup(char *str)
46 {
47         struct popup_data params;
48         static const struct device_ops *apps = NULL;
49
50         if (apps == NULL) {
51                 apps = find_device("apps");
52                 if (apps == NULL)
53                         return;
54         }
55
56         params.name = USB_POPUP_NAME;
57         params.key = POPUP_KEY_CONTENT;
58         params.value = str;
59
60         if (apps->init)
61                 apps->init(&params);
62 }
63
64 bool get_wait_configured(void)
65 {
66         return wait_configured;
67 }
68
69 int get_debug_mode(void)
70 {
71         int debug;
72         if (vconf_get_bool(VCONFKEY_SETAPPL_USB_DEBUG_MODE_BOOL, &debug) != 0)
73                 return 1; /* 0 means debug mode is on */
74
75         return debug;
76 }
77
78 int get_default_mode(void)
79 {
80         if (get_debug_mode() == 0)
81                 return SET_USB_DEFAULT;
82
83         return SET_USB_SDB;
84 }
85
86 int update_usb_state(int state)
87 {
88         return vconf_set_int(VCONFKEY_SYSMAN_USB_STATUS, state);
89 }
90
91 int update_current_usb_mode(int mode)
92 {
93         /*************************************************/
94         /* TODO: This legacy vconf key should be removed */
95         /* The legacy vconf key is used by mtp and OSP   */
96         int legacy;
97
98         switch(mode) {
99         case SET_USB_DEFAULT:
100         case SET_USB_SDB:
101         case SET_USB_SDB_DIAG:
102                 legacy = SETTING_USB_SAMSUNG_KIES;
103                 break;
104         case SET_USB_RNDIS:
105         case SET_USB_RNDIS_DIAG:
106         case SET_USB_RNDIS_SDB:
107                 legacy = SETTING_USB_DEBUG_MODE;
108                 break;
109         case SET_USB_RNDIS_TETHERING:
110                 legacy = SETTING_USB_TETHERING_MODE;
111                 break;
112         case SET_USB_NONE:
113         default:
114                 legacy = SETTING_USB_NONE_MODE;
115                 break;
116         }
117
118         if (vconf_set_int(VCONFKEY_SETAPPL_USB_MODE_INT, legacy) != 0)
119                 _E("Failed to set legacy vconf key for current usb mode");
120         /****************************************************/
121
122         return vconf_set_int(VCONFKEY_USB_CUR_MODE, mode);
123 }
124
125 int check_current_usb_state(void)
126 {
127         int ret;
128         int state;
129
130         ret = device_get_property(DEVICE_TYPE_EXTCON, PROP_EXTCON_USB_ONLINE, &state);
131         if (ret != 0)
132                 return -ENOMEM;
133
134         return state;
135 }
136
137 int get_current_usb_mode(void)
138 {
139         int ret;
140         int mode;
141
142         ret = vconf_get_int(VCONFKEY_USB_CUR_MODE, &mode);
143         if (ret != 0)
144                 return -ENOMEM;
145
146         return mode;
147 }
148
149 int get_selected_usb_mode(void)
150 {
151         int ret;
152         int mode;
153
154         ret = vconf_get_int(VCONFKEY_USB_SEL_MODE, &mode);
155         if (ret != 0)
156                 return -ENOMEM;
157
158         return mode;
159 }
160
161 int change_selected_usb_mode(int mode)
162 {
163         if (mode <= SET_USB_NONE)
164                 return -EINVAL;
165         return vconf_set_int(VCONFKEY_USB_SEL_MODE, mode);
166 }
167
168 static int notify_vconf_keys(void)
169 {
170         int ret;
171
172         ret = vconf_notify_key_changed(
173                         VCONFKEY_USB_SEL_MODE,
174                         client_mode_changed, NULL);
175         if (ret != 0) {
176                 _E("FAIL: vconf_notify_key_changed()");
177                 return ret;
178         }
179
180         ret = vconf_notify_key_changed(
181                         VCONFKEY_SETAPPL_USB_DEBUG_MODE_BOOL,
182                         debug_mode_changed, NULL);
183         if (ret != 0)
184                 _E("FAIL: vconf_notify_key_changed()");
185
186         ret = vconf_notify_key_changed(
187                         VCONFKEY_MOBILE_HOTSPOT_MODE,
188                         tethering_status_changed, NULL);
189         if (ret != 0)
190                 _E("FAIL: vconf_notify_key_changed()");
191
192         return 0;
193 }
194
195 static int ignore_vconf_keys(void)
196 {
197         int ret;
198
199         ret = vconf_ignore_key_changed(
200                         VCONFKEY_USB_SEL_MODE,
201                         client_mode_changed);
202         if (ret != 0) {
203                 _E("FAIL: vconf_ignore_key_changed()");
204                 return ret;
205         }
206
207         ret = vconf_ignore_key_changed(
208                         VCONFKEY_SETAPPL_USB_DEBUG_MODE_BOOL,
209                         debug_mode_changed);
210         if (ret != 0)
211                 _E("FAIL: vconf_ignore_key_changed()");
212
213         ret = vconf_ignore_key_changed(
214                         VCONFKEY_MOBILE_HOTSPOT_MODE,
215                         tethering_status_changed);
216         if (ret != 0)
217                 _E("FAIL: vconf_ignore_key_changed()");
218
219         return 0;
220 }
221
222
223 static int register_client_handlers(void)
224 {
225         int ret;
226
227         ret = notify_vconf_keys();
228         if (ret < 0)
229                 return ret;
230
231         /* TODO: register other handler (ex. dbus, ... ) */
232
233         return 0;
234 }
235
236 static int unregister_client_handlers(void)
237 {
238         int ret;
239
240         ret = ignore_vconf_keys();
241         if (ret < 0)
242                 return ret;
243
244         /* TODO: unregister other handler (ex. dbus, ... ) */
245
246         return 0;
247 }
248
249 static int init_client_values(void)
250 {
251         int ret;
252
253         ret = make_empty_configuration_list();
254         if (ret < 0)
255                 _E("Failed to get information of usb configurations");
256
257         ret = make_supported_confs_list();
258         if (ret < 0)
259                 _E("Failed to get information of usb configuration files");
260
261         return 0;
262 }
263
264 static void deinit_client_values(void)
265 {
266         int sel_mode;
267
268         sel_mode = get_selected_usb_mode();
269         switch (sel_mode) {
270         case SET_USB_RNDIS_TETHERING:
271         case SET_USB_RNDIS_DIAG:
272                 if (change_selected_usb_mode(get_default_mode()) != 0)
273                         _E("Failed to set selected usb mode");
274                 break;
275         default:
276                 break;
277         }
278
279         release_supported_confs_list();
280         release_configuration_list();
281 }
282
283 static int init_client(void)
284 {
285         int ret;
286
287         client_mode = true;
288
289         ret = register_client_handlers();
290         if (ret < 0)
291                 return ret;
292
293         ret = init_client_values();
294         if (ret < 0)
295                 return ret;
296
297         return 0;
298 }
299
300 static int deinit_client(void)
301 {
302         int ret;
303
304         client_mode = false;
305
306         ret = unregister_client_handlers();
307         if (ret < 0)
308                 _E("FAIL: unregister_client_handlers()");
309
310         deinit_client_values();
311
312         return 0;
313 }
314
315 #ifdef MICRO_DD
316 void act_usb_connected(void)
317 {
318         wait_configured = false;
319
320         if (vconf_set_int(VCONFKEY_USB_CONFIGURATION_ENABLED, USB_CONF_ENABLED) != 0)
321                 _E("Failed to set vconf key (%s)", VCONFKEY_USB_CONFIGURATION_ENABLED);
322
323         if (init_client() < 0)
324                 _E("FAIL: init_client()");
325
326         change_client_setting(SET_CONFIGURATION | SET_OPERATION | SET_NOTIFICATION);
327
328         pm_lock_internal(getpid(), LCD_OFF, STAY_CUR_STATE, 0);
329 }
330 #else
331 void act_usb_connected(void)
332 {
333         wait_configured = true;
334
335         if (vconf_set_int(VCONFKEY_USB_CONFIGURATION_ENABLED, USB_CONF_ENABLED) != 0)
336                 _E("Failed to set vconf key (%s)", VCONFKEY_USB_CONFIGURATION_ENABLED);
337
338         if (init_client() < 0)
339                 _E("FAIL: init_client()");
340
341         change_client_setting(SET_CONFIGURATION);
342
343         pm_lock_internal(getpid(), LCD_OFF, STAY_CUR_STATE, 0);
344 }
345 #endif
346
347 static void act_usb_disconnected(void)
348 {
349         int cur_mode;
350
351         wait_configured = false;
352
353         if (vconf_set_int(VCONFKEY_USB_CONFIGURATION_ENABLED, USB_CONF_DISABLED) != 0)
354                 _E("Failed to set vconf key (%s)", VCONFKEY_USB_CONFIGURATION_ENABLED);
355
356         pm_unlock_internal(getpid(), LCD_OFF, STAY_CUR_STATE);
357
358         cur_mode = get_current_usb_mode();
359         if (cur_mode > SET_USB_NONE)
360                 unset_client_mode(cur_mode, false);
361
362         if (deinit_client() < 0)
363                 _E("FAIL: deinit_client()");
364
365         if (update_usb_state(VCONFKEY_SYSMAN_USB_DISCONNECTED) < 0)
366                 _E("FAIL: update_usb_state(%d)", VCONFKEY_SYSMAN_USB_DISCONNECTED);
367 }
368
369 static void subsystem_switch_changed (struct udev_device *dev)
370 {
371         const char *name = NULL;
372         const char *state = NULL;
373         int ret;
374         int cur_mode;
375
376         name = udev_device_get_property_value(dev, UDEV_PROP_KEY_SWITCH_NAME);
377         if (!name)
378                 return;
379
380         if (strncmp(name, UDEV_PROP_VALUE_USB_CABLE, strlen(UDEV_PROP_VALUE_USB_CABLE)))
381                 return;
382
383         state = udev_device_get_property_value(dev, UDEV_PROP_KEY_SWITCH_STATE);
384         if (!state)
385                 return;
386
387         /* USB cable disconnected */
388         if (!strncmp(state, UDEV_PROP_VALUE_DISCON, strlen(UDEV_PROP_VALUE_DISCON))) {
389                 _I("USB cable is disconnected");
390                 act_usb_disconnected();
391                 return;
392         }
393
394         /* USB cable connected */
395         if (!strncmp(state, UDEV_PROP_VALUE_CON, strlen(UDEV_PROP_VALUE_CON))) {
396                 _I("USB cable is connected");
397                 act_usb_connected();
398                 return;
399         }
400 }
401
402 static void subsystem_platform_changed (struct udev_device *dev)
403 {
404         const char *chgdet = NULL;
405         int state;
406         int ret;
407
408         chgdet = udev_device_get_property_value(dev, UDEV_PROP_KEY_CHGDET);
409         if (!chgdet)
410                 return;
411
412         if (strncmp(chgdet, UDEV_PROP_VALUE_USB, strlen(UDEV_PROP_VALUE_USB)))
413                 return;
414
415         if (device_get_property(DEVICE_TYPE_EXTCON, PROP_EXTCON_USB_ONLINE, &state) != 0
416                         || (state != 0 && state != 1)) {
417                 _E("cannot get the usb cable connection status");
418                 state = get_usb_state_direct();
419         }
420
421         /* USB cable disconnected */
422         if (state == 0) {
423                 _I("USB cable is disconnected");
424                 act_usb_disconnected();
425                 return;
426         }
427
428         /* USB cable connected */
429         if (state == 1) {
430                 _I("USB cable is connected");
431                 act_usb_connected();
432                 return;
433         }
434
435         _E("USB state is unknown(%d)", state);
436 }
437
438 static void subsystem_usbmode_changed (struct udev_device *dev)
439 {
440         const char *state = NULL;
441
442         if (!wait_configured)
443                 return;
444
445         wait_configured = false;
446
447         state = udev_device_get_property_value(dev, UDEV_PROP_KEY_USB_STATE);
448         if (!state)
449                 return ;
450
451         if (strncmp(state, UDEV_PROP_VALUE_CONFIGURED, strlen(state)))
452                 return;
453
454         _I("Real USB cable is connected");
455         change_client_setting(SET_OPERATION | SET_NOTIFICATION);
456 }
457
458 const static struct uevent_handler uhs[] = {
459         { SWITCH_SUBSYSTEM     ,     subsystem_switch_changed     ,    NULL    },
460         { USBMODE_SUBSYSTEM    ,     subsystem_usbmode_changed    ,    NULL    },
461         { PLATFORM_SUBSYSTEM   ,     subsystem_platform_changed   ,    NULL    },
462 };
463
464 void usbclient_init_booting_done(void)
465 {
466         int ret, i;
467
468         for (i = 0 ; i < ARRAY_SIZE(uhs) ; i++) {
469                 ret = register_kernel_uevent_control(&uhs[i]);
470                 if (ret < 0)
471                         _E("FAIL: reg_uevent_control()");
472         }
473
474         if (register_usb_client_change_request() < 0)
475                 _E("Failed to register the request to change usb mode");
476 }
477
478 static void usbclient_init(void *data)
479 {
480         wait_until_booting_done();
481 }
482
483 static void usbclient_exit(void *data)
484 {
485         int i;
486
487         for (i = 0 ; i < ARRAY_SIZE(uhs) ; i++) {
488                 unregister_kernel_uevent_control(&uhs[i]);
489         }
490 }
491
492 static const struct device_ops usbclient_device_ops = {
493         .priority = DEVICE_PRIORITY_NORMAL,
494         .name     = "usbclient",
495         .init     = usbclient_init,
496         .exit     = usbclient_exit,
497         .start    = control_start,
498         .stop     = control_stop,
499         .status   = control_status,
500 };
501
502 DEVICE_OPS_REGISTER(&usbclient_device_ops)