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