2 * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <sys/types.h>
21 #include <vconf-keys.h>
23 #include "mtp_event_handler.h"
24 #include "mtp_cmd_handler.h"
26 #include "mtp_thread.h"
28 #include "mtp_usb_driver.h"
29 #include "mtp_transport.h"
30 #include "mtp_media_info.h"
33 * GLOBAL AND EXTERN VARIABLES
35 extern mtp_mgr_t g_mtp_mgr;
36 pthread_t g_eh_thrd; /* event handler thread */
37 mtp_int32 g_pipefd[2];
42 static mtp_mgr_t *g_mgr = &g_mtp_mgr;
47 static mtp_bool __process_event_request(mtp_event_t *evt);
48 static void *__thread_event_handler(void *arg);
49 static mtp_bool __send_events_from_device_to_pc(mtp_dword store_id,
50 mtp_uint16 ptp_event, mtp_uint32 param1, mtp_uint32 param2);
51 static void __handle_usb_notification(keynode_t *key, void *data);
52 static void __handle_usb_mode_notification(keynode_t *key, void *data);
53 static mtp_bool __send_start_event_to_eh_thread(void);
59 mtp_bool _eh_register_notification_callbacks(void)
62 phone_status_t val = 0;
64 /* For FFS transport we rely on ep0 events */
65 if (_transport_get_type() == MTP_TRANSPORT_FFS) {
66 DBG("Using FFS transport, assuming established connection");
67 _util_set_local_usb_status(MTP_PHONE_USB_DISCONNECTED);
68 _util_set_local_usbmode_status(1);
70 DBG("Using legacy transport, registering vconf notifier");
71 _util_get_usb_status(&val);
72 _util_set_local_usb_status(val);
73 ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_USB_STATUS,
74 __handle_usb_notification, NULL);
76 ERR("vconf_notify_key_changed(%s) Fail", VCONFKEY_SYSMAN_USB_STATUS);
80 _util_get_usbmode_status(&val);
81 _util_set_local_usbmode_status(val);
82 ret = vconf_notify_key_changed(VCONFKEY_USB_CUR_MODE,
83 __handle_usb_mode_notification, NULL);
85 ERR("vconf_notify_key_changed(%s) Fail", VCONFKEY_USB_CUR_MODE);
90 _util_get_lock_status(&val);
91 _util_set_local_lock_status(val);
92 _util_get_mmc_status(&val);
93 _util_set_local_mmc_status(val);
95 DBG("Phone status: USB = [%d] MMC = [%d] USB_MODE = [%d] LOCK_STATUS = [%d]\n",
96 _util_get_local_usb_status(), _util_get_local_mmc_status(),
97 _util_get_local_usbmode_status(), _util_get_local_lock_status());
101 mtp_bool _eh_handle_usb_events(mtp_uint32 type)
103 mtp_state_t state = MTP_STATE_STOPPED;
105 /* Prevent repeated USB insert/remove mal-function */
106 static mtp_int32 is_usb_inserted = 0;
107 static mtp_int32 is_usb_removed = 0;
109 state = _transport_get_mtp_operation_state();
113 if (is_usb_inserted == 1) {
114 ERR("USB is already connected");
118 /* check USB connection state */
119 if (_transport_get_type() != MTP_TRANSPORT_FFS &&
120 MTP_PHONE_USB_DISCONNECTED == _util_get_local_usb_status()) {
121 ERR("USB is disconnected. So just return.");
126 _transport_set_usb_discon_state(FALSE);
127 _transport_set_cancel_initialization(FALSE);
129 if (state == MTP_STATE_INITIALIZING) {
130 ERR("MTP is already being initialized");
134 res = pipe(g_pipefd);
141 res = _util_thread_create(&g_eh_thrd,
142 "Mtp Event Request Handler", PTHREAD_CREATE_JOINABLE,
143 __thread_event_handler, NULL);
145 ERR("_util_thread_create() Fail");
149 __send_start_event_to_eh_thread();
154 if (is_usb_removed == 1) {
155 ERR("USB is already removed");
160 DBG("USB is disconnected");
162 _transport_set_usb_discon_state(TRUE);
163 _transport_set_cancel_initialization(TRUE);
165 /* cancel all transaction */
166 _transport_set_control_event(PTP_EVENTCODE_CANCELTRANSACTION);
168 _transport_usb_finalize();
169 _transport_set_mtp_operation_state(MTP_STATE_STOPPED);
172 * Temp file should be deleted after usb usb read/write threads
173 * are terminated. Because data receive thread tries to
174 * write the temp file until sink thread is terminated.
176 if (g_mgr->ftemp_st.filepath != NULL &&
177 (access(g_mgr->ftemp_st.filepath, F_OK) == 0)) {
178 DBG("USB disconnected but temp file is remaind.\
179 It will be deleted.");
181 if (g_mgr->ftemp_st.fhandle != NULL) {
182 DBG("handle is found. At first close file");
183 _util_file_close(g_mgr->ftemp_st.fhandle);
184 g_mgr->ftemp_st.fhandle = NULL;
186 if (remove(g_mgr->ftemp_st.filepath) < 0) {
187 ERR_SECURE("remove(%s) Fail", g_mgr->ftemp_st.filepath);
190 g_free(g_mgr->ftemp_st.filepath);
191 g_mgr->ftemp_st.filepath = NULL;
195 _device_uninstall_storage(MTP_ADDREM_AUTO);
196 _eh_send_event_req_to_eh_thread(EVENT_CLOSE, 1, 0, NULL);
200 ERR("can be ignored notify [0x%x]\n", type);
206 static mtp_bool __process_event_request(mtp_event_t *evt)
208 retv_if(evt == NULL, FALSE);
210 switch (evt->action) {
211 case EVENT_CANCEL_INITIALIZATION:
212 DBG("EVENT_CANCEL_INITIALIZATION entered.");
213 _device_uninstall_storage(MTP_ADDREM_AUTO);
216 case EVENT_START_MAIN_OP:
217 DBG("EVENT_START_MAIN_OP entered.");
220 _transport_set_cancel_initialization(FALSE);
221 _transport_set_mtp_operation_state(MTP_STATE_INITIALIZING);
223 _mtp_init(evt->param1);
224 _transport_set_mtp_operation_state(MTP_STATE_READY_SERVICE);
225 if (FALSE == _transport_init_interfaces(_receive_mq_data_cb)) {
226 ERR("USB init fail");
227 kill(getpid(), SIGTERM);
230 _transport_set_mtp_operation_state(MTP_STATE_ONSERVICE);
233 case EVENT_USB_REMOVED:
235 _eh_handle_usb_events(USB_REMOVED);
238 case EVENT_OBJECT_ADDED:
239 __send_events_from_device_to_pc(0, PTP_EVENTCODE_OBJECTADDED,
243 case EVENT_OBJECT_REMOVED:
244 __send_events_from_device_to_pc(0,
245 PTP_EVENTCODE_OBJECTREMOVED, evt->param1, 0);
248 case EVENT_OBJECT_PROP_CHANGED:
249 __send_events_from_device_to_pc(0,
250 MTP_EVENTCODE_OBJECTPROPCHANGED, evt->param1,
258 ERR("Unknown action");
264 static void *__thread_event_handler(void *arg)
266 DBG("__thread_event_handler is started ");
272 mtp_int32 status = 0;
273 status = read(g_pipefd[0], &evt, sizeof(mtp_event_t));
274 if ((status == -1) && errno == EINTR) {
279 __process_event_request(&evt);
281 if (evt.action == EVENT_CLOSE) {
282 /* USB removed, terminate the thread */
287 DBG("Event handler terminated");
292 _util_thread_exit("__thread_event_handler thread is over.");
296 static mtp_bool __send_events_from_device_to_pc(mtp_dword store_id,
297 mtp_uint16 ptp_event, mtp_uint32 param1, mtp_uint32 param2)
299 cmd_container_t event = { 0, };
301 memset(&event, 0, sizeof(cmd_container_t));
304 case PTP_EVENTCODE_STOREADDED:
305 DBG("case PTP_EVENTCODE_STOREADDED:");
306 DBG("store_id [0x%lu]\n", store_id);
307 _hdlr_init_event_container(&event, PTP_EVENTCODE_STOREADDED, 0,
311 case PTP_EVENTCODE_STOREREMOVED:
312 DBG("case PTP_EVENTCODE_STOREREMOVED");
313 DBG("store_id [0x%lu]\n", store_id);
314 _hdlr_init_event_container(&event,
315 PTP_EVENTCODE_STOREREMOVED, 0, store_id, 0);
318 case PTP_EVENTCODE_OBJECTADDED:
319 DBG("case PTP_EVENTCODE_OBJECTADDED");
320 DBG("param1 : [0x%x]\n", param1);
321 _hdlr_init_event_container(&event, PTP_EVENTCODE_OBJECTADDED,
325 case PTP_EVENTCODE_OBJECTREMOVED:
326 DBG("case PTP_EVENTCODE_OBJECTREMOVED");
327 DBG("param1 [0x%x]\n", param1);
328 _hdlr_init_event_container(&event, PTP_EVENTCODE_OBJECTREMOVED,
332 case MTP_EVENTCODE_OBJECTPROPCHANGED:
333 DBG("case MTP_EVENTCODE_OBJECTPROPCHANGED");
334 DBG("param1 [0x%x]\n", param1);
335 DBG("param2 [0x%x]\n", param2);
336 _hdlr_init_event_container_with_param(&event,
337 MTP_EVENTCODE_OBJECTPROPCHANGED, 0, param1 , param2);
341 DBG("Event not supported");
345 return _hdlr_send_event_container(&event);
348 static void __handle_usb_notification(keynode_t *key, void *data)
350 phone_status_t val = MTP_PHONE_USB_DISCONNECTED;
351 mtp_int32 intval = VCONFKEY_SYSMAN_USB_DISCONNECTED;
355 intval = vconf_keynode_get_int(key);
357 ERR("vconf_keynode_get_int() Fail");
361 if (VCONFKEY_SYSMAN_USB_DISCONNECTED == intval) {
362 DBG("USB Disconnected");
363 _util_set_local_usb_status(val);
368 val = MTP_PHONE_USB_CONNECTED;
369 _util_set_local_usb_status(val);
370 DBG("USB Connected. Just return.");
374 static void __handle_usb_mode_notification(keynode_t *key, void *data)
376 phone_status_t val = MTP_PHONE_USB_MODE_OTHER;
380 val = vconf_keynode_get_int(key);
382 _util_set_local_usbmode_status(val);
386 void _handle_lock_status_notification(keynode_t *key, void *data)
388 phone_status_t previous_val = MTP_PHONE_LOCK_ON;
389 phone_status_t current_val = MTP_PHONE_LOCK_ON;
391 previous_val = _util_get_local_lock_status();
392 _util_get_lock_status(¤t_val);
394 if (previous_val == current_val)
397 _util_set_local_lock_status(current_val);
399 if (MTP_PHONE_LOCK_OFF == current_val) {
400 _device_install_storage(MTP_ADDREM_INTERNAL);
401 __send_events_from_device_to_pc(MTP_INTERNAL_STORE_ID,
402 PTP_EVENTCODE_STOREADDED, 0, 0);
404 _util_media_content_connect();
405 } else if (MTP_PHONE_LOCK_ON == current_val) {
406 _device_uninstall_storage(MTP_ADDREM_INTERNAL);
408 __send_events_from_device_to_pc(MTP_INTERNAL_STORE_ID,
409 PTP_EVENTCODE_STOREREMOVED, 0, 0);
411 _util_media_content_disconnect();
417 void _handle_mmc_notification(keynode_t *key, void *data)
419 phone_status_t val = MTP_PHONE_MMC_NONE;
421 _util_get_mmc_status(&val);
422 _util_set_local_mmc_status(val);
424 if (MTP_PHONE_MMC_INSERTED == val) {
425 _device_install_storage(MTP_ADDREM_EXTERNAL);
426 __send_events_from_device_to_pc(MTP_EXTERNAL_STORE_ID,
427 PTP_EVENTCODE_STOREADDED, 0, 0);
429 } else if (MTP_PHONE_MMC_NONE == val) {
430 _device_uninstall_storage(MTP_ADDREM_EXTERNAL);
432 __send_events_from_device_to_pc(MTP_EXTERNAL_STORE_ID,
433 PTP_EVENTCODE_STOREREMOVED, 0, 0);
439 void _eh_deregister_notification_callbacks(void)
441 vconf_ignore_key_changed(VCONFKEY_SYSMAN_USB_STATUS,
442 __handle_usb_notification);
443 vconf_ignore_key_changed(VCONFKEY_USB_CUR_MODE,
444 __handle_usb_mode_notification);
449 void _eh_send_event_req_to_eh_thread(event_code_t action, mtp_ulong param1,
450 mtp_ulong param2, void *param3)
452 mtp_event_t event = { 0 };
455 event.action = action;
456 event.param1 = param1;
457 event.param2 = param2;
458 event.param3 = (mtp_ulong)param3;
460 DBG("action[%d], param1[%ld], param2[%ld]\n", action, param1, param2);
462 status = write(g_pipefd[1], &event, sizeof(mtp_event_t));
463 if (status == -1 || errno == EINTR) {
464 ERR("Event write over pipe Fail, status = [%d], pipefd = [%d], errno [%d]\n",
465 status, g_pipefd[1], errno);
470 static mtp_bool __send_start_event_to_eh_thread(void)
475 event.action = EVENT_START_MAIN_OP;
476 event.param1 = (mtp_ulong) MTP_ADDREM_AUTO;
480 DBG("Action : START MTP OPERATION");
482 status = write(g_pipefd[1], &event, sizeof(mtp_event_t));
483 if (status == -1 || errno == EINTR) {
484 ERR("Event write over pipe Fail, status= [%d],pipefd = [%d], errno [%d]\n",
485 status, g_pipefd[1], errno);