64220d0e84b7356055ce93edd6009e07d134b8a1
[platform/core/telephony/tel-plugin-imc.git] / src / imc_call.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
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 <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <glib.h>
24
25 #include <tcore.h>
26 #include <server.h>
27 #include <plugin.h>
28 #include <core_object.h>
29 #include <hal.h>
30 #include <queue.h>
31 #include <storage.h>
32 #include <at.h>
33 #include <vconf.h>
34 #include <co_call.h>
35
36 #include "imc_call.h"
37 #include "imc_common.h"
38
39 #define COMMA   0X2c
40 #define STATUS_INCOMING    4
41 #define STATUS_WAITING     5
42 #define STATUS_CONNECTED   7
43
44 #define find_call_object(co, call_id, call_obj) \
45         do { \
46                 call_obj = tcore_call_object_find_by_id(co, call_id); \
47                 if (!call_obj) { \
48                         err("unable to find call object"); \
49                         return; \
50                 } \
51         } while (0)
52
53 struct imc_set_volume_info {
54         guint next_index;
55         guint volume;
56 };
57
58 static gchar *xdrv_set_volume[] = {
59         "AT+XDRV=40,7,3,88",
60         "AT+XDRV=40,7,0,88",
61         "AT+XDRV=40,8,0,88",
62         "AT+XDRV=40,8,2,",
63         NULL
64 };
65
66 /*Forward Declarations*/
67 static void on_response_imc_call_default(TcorePending *p,
68         guint data_len, const void *data, void *user_data);
69
70 static TelReturn __call_list_get(CoreObject *co, gboolean flag);
71
72 static void __on_response_imc_call_end_cause(TcorePending *p,
73         guint data_len, const void *data, void *user_data);
74
75 static TelCallType __call_type(int type)
76 {
77         dbg("Entry");
78
79         switch (type) {
80         case 0:
81                 return TEL_CALL_TYPE_VOICE;
82
83         case 1:
84                 return TEL_CALL_TYPE_VIDEO;
85
86         default:
87                 err("invalid call type, returning default call type as voice");
88                 return TEL_CALL_TYPE_VOICE;
89         }
90 }
91
92 static TelCallState __call_state(int state)
93 {
94         dbg("Entry");
95
96         switch (state) {
97         case 0:
98                 return TEL_CALL_STATE_ACTIVE;
99
100         case 1:
101                 return TEL_CALL_STATE_HELD;
102
103         case 2:
104                 return TEL_CALL_STATE_DIALING;
105
106         case 3:
107                 return TEL_CALL_STATE_ALERT;
108
109         case 4:
110         case 5:
111                 return TEL_CALL_STATE_INCOMING;
112
113         default:
114                 return TEL_CALL_STATE_IDLE;
115         }
116 }
117
118 static void __call_branch_by_status(CoreObject *co, CallObject *call_obj,
119         TelCallState call_state)
120 {
121         unsigned int call_id;
122         TelCallType call_type;
123         TelCallState state;
124         TcoreNotification command = TCORE_NOTIFICATION_UNKNOWN;
125         dbg("Call State[%d]", call_state);
126
127         if (tcore_call_object_get_state(call_obj, &state) == FALSE) {
128                 err("unable to get call status");
129                 return;
130         }
131
132         if (call_state == state) {
133                 dbg("current call state and existing call state are same");
134                 return;
135         }
136
137         if (tcore_call_object_get_call_type(call_obj, &call_type) == FALSE) {
138                 err("unable to get call type");
139                 return;
140         }
141
142         if (tcore_call_object_get_id(call_obj, &call_id) == FALSE) {
143                 err("unable to get call id");
144                 return;
145         }
146
147         /* Set Status */
148         tcore_call_object_set_state(call_obj, call_state);
149
150         if (call_type == TEL_CALL_TYPE_VOICE) {
151                 /* voice call notification */
152                 switch (call_state) {
153                 case TEL_CALL_STATE_ACTIVE:
154                         command = TCORE_NOTIFICATION_CALL_STATUS_ACTIVE;
155                 break;
156
157                 case TEL_CALL_STATE_HELD:
158                         command = TCORE_NOTIFICATION_CALL_STATUS_HELD;
159                 break;
160
161                 case TEL_CALL_STATE_DIALING:
162                         command = TCORE_NOTIFICATION_CALL_STATUS_DIALING;
163                 break;
164
165                 case TEL_CALL_STATE_ALERT:
166                         command = TCORE_NOTIFICATION_CALL_STATUS_ALERT;
167                 break;
168
169                 case TEL_CALL_STATE_INCOMING:
170                 case TEL_CALL_STATE_WAITING: {
171                         TelCallIncomingInfo incoming = {0,};
172
173                         incoming.call_id = call_id;
174                         tcore_call_object_get_cli_validity(call_obj, &incoming.cli_validity);
175                         tcore_call_object_get_number(call_obj, incoming.number);
176                         tcore_call_object_get_cni_validity(call_obj, &incoming.cni_validity);
177                         tcore_call_object_get_name(call_obj, incoming.name);
178                         tcore_call_object_get_mt_forward(call_obj, &incoming.forward);
179                         tcore_call_object_get_active_line(call_obj, &incoming.active_line);
180
181                         /* Send notification */
182                         tcore_object_send_notification(co,
183                                 TCORE_NOTIFICATION_CALL_STATUS_INCOMING,
184                                 sizeof(TelCallIncomingInfo), &incoming);
185                         return;
186                 }
187
188                 case TEL_CALL_STATE_IDLE: {
189                         /* Send AT+CEER command*/
190                         ImcRespCbData *resp_cb_data = NULL;
191                         TelReturn ret;
192
193                         /* Response callback data */
194                         resp_cb_data = imc_create_resp_cb_data(NULL, NULL, &call_id, sizeof(call_id));
195
196                         /* Send Request to modem */
197                         ret = tcore_at_prepare_and_send_request(co,
198                                 "AT+CEER", "+CEER:",
199                                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
200                                 NULL,
201                                 __on_response_imc_call_end_cause, resp_cb_data,
202                                 on_send_imc_request, NULL);
203                         if (ret != TEL_RETURN_SUCCESS) {
204                                 warn("Failed to send request");
205                                 TelCallStatusIdleNoti idle;
206
207                                 idle.call_id = call_id;
208                                 idle.cause = TEL_CALL_END_CAUSE_NONE;
209
210                                 /* Send notification */
211                                 tcore_object_send_notification(co,
212                                         TCORE_NOTIFICATION_CALL_STATUS_IDLE,
213                                         sizeof(TelCallStatusIdleNoti), &idle);
214
215                                 imc_destroy_resp_cb_data(resp_cb_data);
216                         }
217
218                         /* Free Call object */
219                         tcore_call_object_free(co, call_obj);
220                         return;
221                 }
222                 }
223
224         }
225         else if (call_type == TEL_CALL_TYPE_VIDEO) {
226                 /* video call notification */
227                 switch (call_state) {
228                 case TEL_CALL_STATE_ACTIVE:
229                         command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_ACTIVE;
230                 break;
231
232                 case TEL_CALL_STATE_HELD:
233                         err("invalid state");
234                 break;
235
236                 case TEL_CALL_STATE_DIALING:
237                         command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_DIALING;
238                 break;
239
240                 case TEL_CALL_STATE_ALERT:
241                         command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_ALERT;
242                 break;
243
244                 case TEL_CALL_STATE_INCOMING:
245                 case TEL_CALL_STATE_WAITING:
246                         command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_INCOMING;
247                 break;
248
249                 case TEL_CALL_STATE_IDLE: {
250                         TelCallStatusIdleNoti idle;
251
252                         idle.call_id = call_id;
253                         idle.cause = TEL_CALL_END_CAUSE_NONE;
254
255                         /* Send notification */
256                         tcore_object_send_notification(co,
257                                 TCORE_NOTIFICATION_VIDEO_CALL_STATUS_IDLE,
258                                 sizeof(TelCallStatusIdleNoti), &idle);
259
260                         /* Free Call object */
261                         tcore_call_object_free(co, call_obj);
262                         return;
263                 }
264                 }
265         } else {
266                 err("Unknown Call type: [%d]", call_type);
267         }
268
269         if (command != TCORE_NOTIFICATION_UNKNOWN)
270                 tcore_object_send_notification(co, command, sizeof(call_id), &call_id);
271 }
272
273 static void __handle_call_list_get(CoreObject *co, gboolean flag, void *data)
274 {
275         int call_id;
276         int direction;
277         int call_type;
278         int state;
279         int mpty;
280         int ton = -1;
281         GSList *tokens = NULL;
282         char *resp = NULL;
283         char *line;
284         char *num = NULL;
285         int num_type;
286         char number[TEL_CALL_CALLING_NUMBER_LEN_MAX +1] = {0,};
287         GSList *lines = data;
288         CallObject *call_obj = NULL;
289
290          while (lines != NULL) {
291                 line = (char *)lines->data;
292                 /* point to next node */
293                 lines = lines->next;
294                 /* free previous tokens*/
295                 tcore_at_tok_free(tokens);
296
297                 tokens = tcore_at_tok_new(line);
298
299                 /* <id1> */
300                 resp = g_slist_nth_data(tokens, 0);
301                 if (NULL == resp) {
302                         err("Invalid call_id");
303                         continue;
304                 }
305                 call_id = atoi(resp);
306
307                 /* <dir> */
308                 resp = g_slist_nth_data(tokens, 1);
309                 if (NULL == resp) {
310                         err("Invalid direction");
311                         continue;
312                 }
313                 direction = (atoi(resp) == 0) ? 1 : 0;
314
315                 /* <stat> */
316                 resp = g_slist_nth_data(tokens, 2);
317                 if (NULL == resp) {
318                         err("Invalid state");
319                         continue;
320                 }
321                 state = __call_state(atoi(resp));
322
323                 /* <mode> */
324                 resp = g_slist_nth_data(tokens, 3);
325                 if (NULL == resp) {
326                         err("Invalid call_type");
327                         continue;
328                 }
329                 call_type = __call_type(atoi(resp));
330
331                 /* <mpty> */
332                 resp = g_slist_nth_data(tokens, 4);
333                 if (NULL == resp) {
334                         err("Invalid mpty");
335                         continue;
336                 }
337                 mpty = atoi(resp);
338
339                 /* <number> */
340                 resp = g_slist_nth_data(tokens, 5);
341                 if (NULL == resp) {
342                         err("Number is NULL");
343                 } else {
344                         /* Strike off double quotes */
345                         num = tcore_at_tok_extract(resp);
346                         dbg("Number: [%s]", num);
347
348                         /* <type> */
349                         resp = g_slist_nth_data(tokens, 6);
350                         if (!resp) {
351                                 err("Invalid num type");
352                         } else {
353                                 num_type = atoi(resp);
354                                 /* check number is international or national. */
355                                 ton = ((num_type) >> 4) & 0x07;
356                                 if (ton == 1 && num[0] != '+') {
357                                         /* international number */
358                                         number[0] = '+';
359                                         memcpy(&number[1], num, strlen(num));
360                                 } else {
361                                         memcpy(number, num, strlen(num));
362                                 }
363                         }
364                         g_free(num);
365                 }
366
367                 dbg("Call ID: [%d] Direction: [%s] Call Type: [%d] Multi-party: [%s] "
368                         "Number: [%s] TON: [%d] State: [%d]",
369                         call_id, (direction ? "Outgoing" : "Incoming"), call_type,
370                         (mpty ? "YES" : "NO"), number, ton, state);
371
372                 call_obj = tcore_call_object_find_by_id(co, call_id);
373                 if (NULL == call_obj) {
374                         call_obj = tcore_call_object_new(co, call_id);
375                         if (NULL == call_obj) {
376                                 err("unable to create call object");
377                                 continue;
378                         }
379                 }
380
381                 /* Set Call parameters */
382                 tcore_call_object_set_type(call_obj, call_type);
383                 tcore_call_object_set_direction(call_obj, direction);
384                 tcore_call_object_set_multiparty_state(call_obj, mpty);
385                 tcore_call_object_set_cli_info(call_obj, TEL_CALL_CLI_VALIDITY_VALID, number);
386                 tcore_call_object_set_active_line(call_obj, TEL_CALL_ACTIVE_LINE1);
387                 if (flag == TRUE)
388                         __call_branch_by_status(co, call_obj, state);
389                 else
390                         tcore_call_object_set_state(call_obj, state);
391         }
392 }
393
394 /* internal notification operation */
395 static void __on_notification_imc_call_incoming(CoreObject *co, unsigned int call_id,
396         void *user_data)
397 {
398         GSList *list = NULL;
399         CallObject *call_obj = NULL;
400         dbg("entry");
401
402         /* check call with incoming status already exist */
403         list = tcore_call_object_find_by_status(co, TEL_CALL_STATE_INCOMING);
404         if (list != NULL) {
405                 err("Incoming call already exist! Skip...");
406                 g_slist_free(list);
407                 return;
408         }
409
410         call_obj = tcore_call_object_find_by_id(co, call_id);
411         if (call_obj != NULL) {
412                 err("Call object for Call ID [%d] already exist! Skip...", call_id);
413                 return;
414         }
415
416         /* Create new Call object */
417         call_obj = tcore_call_object_new(co, (unsigned int)call_id);
418         if (NULL == call_obj) {
419                 err("Failed to create Call object");
420                 return;
421         }
422
423         /* Make request to get current Call list */
424         __call_list_get(co, TRUE);
425 }
426
427 static void __on_notification_imc_call_status(CoreObject *co, unsigned int call_id,
428         unsigned int call_state, void *user_data)
429 {
430         CallObject *call_obj = NULL;
431         TelCallState state;
432
433         state = __call_state(call_state);
434         dbg("state [%d]", state);
435
436         switch (state) {
437         case TEL_CALL_STATE_ACTIVE: {
438                 find_call_object(co, call_id, call_obj);
439                 /* Send notification to application */
440                 __call_branch_by_status(co, call_obj, state);
441         }
442         break;
443
444         case TEL_CALL_STATE_HELD: {
445                 find_call_object(co, call_id, call_obj);
446                 /* Send notification to application */
447                 __call_branch_by_status(co, call_obj, state);
448         }
449         break;
450
451         case TEL_CALL_STATE_DIALING: {
452                 call_obj = tcore_call_object_find_by_id(co, call_id);
453                 if (!call_obj) {
454                         call_obj = tcore_call_object_new(co, call_id);
455                         if (!call_obj) {
456                                 err("unable to create call object");
457                                 return;
458                         }
459                 }
460                 /* Make request to get current call list.Update CallObject with <number>
461                  * and send notification to application */
462                 __call_list_get(co, TRUE);
463         }
464         break;
465
466         case TEL_CALL_STATE_ALERT: {
467                 find_call_object(co, call_id, call_obj);
468                 /* Send notification to application */
469                 __call_branch_by_status(co, call_obj, TEL_CALL_STATE_ALERT);
470         }
471         break;
472
473         case TEL_CALL_STATE_IDLE: {
474                 find_call_object(co, call_id, call_obj);
475                 /* Send notification to application */
476                 __call_branch_by_status(co, call_obj, state);
477         }
478         break;
479
480         default:
481                 err("invalid call status");
482                 break;
483         }
484 }
485
486 /*internal response operation */
487 static void __on_response_imc_call_list_get(TcorePending *p, guint data_len, const void *data,
488         void *user_data)
489 {
490         const TcoreAtResponse *at_resp = data;
491         CoreObject *co = tcore_pending_ref_core_object(p);
492         ImcRespCbData *resp_cb_data = user_data;
493         GSList *lines = NULL;
494         TelCallResult result = TEL_CALL_RESULT_FAILURE;
495         gboolean *flag = IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
496         int count;
497         dbg("entry");
498
499         tcore_check_return_assert(co != NULL);
500         tcore_check_return_assert(resp_cb_data != NULL);
501
502         if (at_resp && at_resp->success) {
503                 if (NULL == at_resp->lines) {
504                         err("invalid response received");
505                         return;
506                 }
507
508                 lines = (GSList *) at_resp->lines;
509                 count = g_slist_length(lines);
510                 dbg("Total records : %d", count);
511                 if (0 == count) {
512                         err("Call count is zero");
513                         return;
514                 }
515                 result = TEL_CALL_RESULT_SUCCESS;
516                 dbg("RESPONSE OK");
517
518                 /* parse +CLCC notification parameter */
519                 __handle_call_list_get(co, *flag, lines);
520
521         } else {
522                 err("RESPONSE NOK");
523         }
524 }
525
526 /*internal request operation */
527 static TelReturn __send_call_request(CoreObject *co, TcoreObjectResponseCallback cb,
528         void *cb_data, gchar *at_cmd, gchar *func_name)
529 {
530         ImcRespCbData *resp_cb_data;
531         TelReturn ret;
532
533         /* Response callback data */
534         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, func_name,
535                         strlen(func_name) + 1);
536
537         /* Send Request to modem */
538         ret = tcore_at_prepare_and_send_request(co,
539                 at_cmd, NULL,
540                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
541                 NULL,
542                 on_response_imc_call_default, resp_cb_data,
543                 on_send_imc_request, NULL);
544         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, func_name);
545
546         /* Free resources */
547         g_free(at_cmd);
548         return ret;
549 }
550
551  /*
552  * Operation -  Get current call list.
553  *
554  * Request -
555  * AT-Command: AT+CLCC
556  *
557  * Response -
558  * Success:
559  *[+CLCC: <id1>, <dir>, <stat>, <mode>,<mpty>[,<number>,<type>[,<alpha>[,<priority>]]]
560  *
561  * OK
562  * Failure:
563  * +CME ERROR: <error>
564  */
565 static TelReturn __call_list_get(CoreObject *co, gboolean flag)
566 {
567         ImcRespCbData *resp_cb_data;
568         TelReturn ret = TEL_RETURN_FAILURE;
569         dbg("Entry");
570
571         if (NULL == co) {
572                 err("Core Object is NULL");
573                 return ret;
574         }
575
576         /* Response callback data */
577         resp_cb_data = imc_create_resp_cb_data(NULL, NULL, &flag, sizeof(gboolean));
578
579         /* Send Request to modem */
580         ret = tcore_at_prepare_and_send_request(co,
581                 "AT+CLCC","+CLCC",
582                 TCORE_AT_COMMAND_TYPE_MULTILINE,
583                 NULL,
584                 __on_response_imc_call_list_get, resp_cb_data,
585                 on_send_imc_request, NULL);
586         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get current call list");
587
588         return ret;
589 }
590
591 static TelCallResult __convert_imc_extended_err_tel_call_result(gint error)
592 {
593         /*
594          * CEER error codes
595          * 1   - unassigned (unallocated) number.
596          * 28  - invalid number format (incomplete number).
597          * 96  - invalid mandatory information.
598          * 258 - Invalid parameters.
599          * 371 - Invalid mandatory info.
600          * 257 - Out of memory.
601          * 279 - FDN Failed.
602          * 42  - switching equipment congestion
603          * 287 - MM network failure unspecified.
604          * 380 - Congestion.
605          */
606         dbg("CEER Error: [%d]", error);
607
608         switch (error) {
609         case 1:
610         case 28:
611         case 96:
612         case 258:
613         case 371:
614                 return TEL_CALL_RESULT_INVALID_PARAMETER;
615         case 257:
616                 return TEL_CALL_RESULT_MEMORY_FAILURE;
617         case 279:
618                 return TEL_CALL_RESULT_FDN_RESTRICTED;
619         case 42:
620         case 287:
621         case 380:
622                 return TEL_CALL_RESULT_NETWORK_BUSY;
623         default:
624                 return TEL_CALL_RESULT_FAILURE;
625         }
626 }
627
628 static TelCallEndCause __convert_imc_extended_err_call_end_cause(gint error)
629 {
630         /*
631          * CEER error codes
632          * 1  - unassigned (unallocated) number.
633          * 3  -  No route to destination.
634          * 16 - operator determined barring.
635          * 17 - user busy.
636          * 18 - no user responding.
637          * 19 -  user alerting, no answer.
638          * 21 - call rejected.
639          * 22 - number changed
640          * 27 - destination out of order.
641          * 28 - invalid number format (incomplete number).
642          * 29 - facility rejected
643          * 34 - no circuit / channel available.
644          * 38 - network out of order
645          * 41 - temporary failure
646          * 44 - requested circuit / channel not available.
647          * 50 - requested facility not subscribed
648          * 68 - ACM equal to or greater than ACMmax
649          */
650         dbg("Call end-cause: [%d]", error);
651         switch (error) {
652         case 1:
653                 return TEL_CALL_END_CAUSE_UNASSIGNED_NUMBER;
654         case 3:
655                 return TEL_CALL_END_CAUSE_NO_ROUTE_TO_DEST;
656         case 8:
657                 return TEL_CALL_END_CAUSE_OPERATOR_DETERMINED_BARRING;
658         case 16:
659                 return TEL_CALL_END_CAUSE_NORMAL_CALL_CLEARING;
660         case 17:
661                 return TEL_CALL_END_CAUSE_USER_BUSY;
662         case 18:
663                 return TEL_CALL_END_CAUSE_NO_USER_RESPONDING;
664         case 19:
665                 return TEL_CALL_END_CAUSE_USER_ALERTING_NO_ANSWER;
666         case 21:
667                 return TEL_CALL_END_CAUSE_CALL_REJECTED;
668         case 22:
669                 return TEL_CALL_END_CAUSE_NUMBER_CHANGED;
670         case 27:
671                 return TEL_CALL_END_CAUSE_DESTINATION_OUT_OF_ORDER;
672         case 28:
673                 return TEL_CALL_END_CAUSE_INVALID_NUMBER_FORMAT;
674         case 29:
675                 return TEL_CALL_END_CAUSE_FACILITY_REJECTED;
676         case 34:
677                 return TEL_CALL_END_CAUSE_NO_CIRCUIT_CHANNEL_AVAILABLE;
678         case 38:
679                 return TEL_CALL_END_CAUSE_NETWORK_OUT_OF_ORDER;
680         case 41:
681                 return TEL_CALL_END_CAUSE_TEMPORARY_FAILURE;
682         case 42:
683                 return TEL_CALL_END_CAUSE_SWITCHING_EQUIPMENT_CONGESTION;
684         case 44:
685                 return TEL_CALL_END_CAUSE_REQUESTED_CIRCUIT_CHANNEL_NOT_AVAILABLE;
686         case 50:
687                 return TEL_CALL_END_CAUSE_REQUESTED_FACILITY_NOT_SUBSCRIBED;
688         case 68:
689                 return TEL_CALL_END_CAUSE_ACM_GEQ_ACMMAX;
690         case 63:
691         case 79:
692                 return TEL_CALL_END_CAUSE_SERVICE_OPTION_OUT_OF_ORDER;
693         default:
694                 return TEL_CALL_END_CAUSE_FAILED;
695         }
696 }
697
698 static TelCallResult __convert_imc_xdrv_result_tel_call_result(gint xdrv_err)
699 {
700          /*
701           * 0  - Command was executed without any error.
702           * 1  - One of the parameters is out of range.
703           * 2  - The function doesn’t exist for this driver.
704           * 3  - The group is not supported.
705           * 4  - The internal state of the driver is not allowing to process the command.
706           * 5  - The driver interface function for the command is not available.
707           * 6  - The corresponding driver for the command retuns an error.
708           * 7  - Timeout occured when expecting response from the corresponding driver.
709           * 8  - The driver is not supported for this product.
710           * 12 - No of parameteres passed for the command is mismatch with the rquirements.
711           * 13 - The given command to xdrv is invalid.
712           * 14 - Any internal error in xdrv like out of memory.
713           */
714
715         dbg("XDRV result: [%d]", xdrv_err);
716         switch (xdrv_err) {
717         case 1:
718         case 12:
719         case 13:
720                 return  TEL_CALL_RESULT_INVALID_PARAMETER;
721         case 14:
722                 return TEL_CALL_RESULT_MEMORY_FAILURE;
723         default:
724                 return TEL_CALL_RESULT_OPERATION_NOT_SUPPORTED;
725         }
726 }
727
728 /* Notification */
729
730 /*
731  * Operation -  call status notification from network.
732  * notification message format:
733  * +XCALLSTAT: <call_id><stat>
734  * where
735  * <call_id>
736  * indicates the call identification (GSM02.30 4.5.5.1)
737  * <stat>
738  * 0 active
739  * 1 hold
740  * 2 dialling (MO call)
741  * 3 alerting (MO call; ringing for the remote party)
742  * 4 ringing (MT call)
743  * 5 waiting (MT call)
744  * 6 disconnected
745  * 7 connected (indicates the completion of a call setup first time
746  *      for MT and MO calls this is reported in addition to state active)
747  */
748 static gboolean on_notification_imc_call_status(CoreObject *co, const void *data,
749         void *user_data)
750 {
751         GSList *tokens = NULL;
752         GSList *lines = NULL;
753         const char *line = NULL;
754         char *state = NULL, *call_handle = NULL;
755         unsigned int status, call_id;
756
757         dbg("Entry");
758
759         lines = (GSList *) data;
760         if (lines == NULL) {
761                 err("Invalid response received");
762                 return TRUE;
763         }
764         line = (char *) (lines->data);
765         tokens = tcore_at_tok_new(line);
766
767         call_handle = g_slist_nth_data(tokens, 0);
768         if (NULL == call_handle) {
769                 err("call id missing from %XCALLSTAT indication");
770                 goto OUT;
771         }
772         call_id = atoi(call_handle);
773         state = g_slist_nth_data(tokens, 1);
774         if (NULL == state) {
775                 err("call state is missing from %XCALLSTAT indication");
776                 goto OUT;
777         }
778         status = atoi(state);
779         dbg("call id[%d], status[%d]", call_id, status);
780
781         switch (status) {
782         case STATUS_INCOMING:
783         case STATUS_WAITING:
784                 __on_notification_imc_call_incoming(co, call_id, user_data);
785                 break;
786
787         case STATUS_CONNECTED:     /* ignore Connected state. */
788                 dbg("ignore connected state");
789                 break;
790
791         default:
792                 __on_notification_imc_call_status(co, call_id, status, user_data);
793                 break;
794         }
795 OUT:
796         // Free tokens
797         tcore_at_tok_free(tokens);
798         return TRUE;
799 }
800
801 /*
802  * Operation -  SS network initiated notification.
803  *
804  * notification message format:
805  * +CSSU: <code2>[<index> [,<number>,<type>]]
806  * <code2>
807  * (it is manufacturer specific, which of these codes are supported):
808  * 0 this is a forwarded call (MT call setup)
809  * 1 this is a CUG call (<index> present) (MT call setup)
810  * 2 call has been put on hold (during a voice call)
811  * 3 call has been retrieved (during a voice call)
812  * 4 multiparty call entered (during a voice call)
813  * 5 Call has been released - not a SS notification (during a voice call)
814  * 6 forward check SS message received (can be received whenever)
815  * 7 call is being connected (alerting) with the remote party in alerting state
816  *   in explicit call transfer operation
817  *   (during a voice call)
818  * 8 call has been connected with the other remote party in explicit call transfer
819  *   operation (during a voice call or MT call setup)
820  * 9 this is a deflected call (MT call setup)
821  * 10 additional incoming call forwarded
822  * <index>
823  * refer Closed user group +CCUG
824  * <number>
825  *  string type phone of format specified by <type>
826  * <type>
827  * type of address octet in integer format.
828  */
829 static gboolean on_notification_imc_call_ss_cssu_info(CoreObject *co, const void *event_data,
830         void *user_data)
831 {
832         GSList *tokens = NULL;
833         TcoreNotification command = TCORE_NOTIFICATION_UNKNOWN;
834         char *resp = NULL;
835         char *cmd = 0;
836         int index = 0;
837         int code2 = -1;
838         char *number = NULL;
839
840         dbg("entry");
841
842         if (1 != g_slist_length((GSList *) event_data)) {
843                 err("unsolicited msg but multiple line");
844                 return TRUE;
845         }
846
847         cmd = (char *) ((GSList *) event_data)->data;
848         dbg("ss notification message[%s]", cmd);
849
850         tokens = tcore_at_tok_new(cmd);
851
852         /* parse <code2> */
853         resp = g_slist_nth_data(tokens, 0);
854         if (NULL == resp) {
855                 err("Code2 is missing from +CSSU indication");
856                 tcore_at_tok_free(tokens);
857                 return TRUE;
858         }
859
860         code2 = atoi(resp);
861
862         /* parse [ <index>, <number> <type>] */
863         if ((resp = g_slist_nth_data(tokens, 1)))
864                 index = atoi(resp);
865
866         if ((resp = g_slist_nth_data(tokens, 2))) {
867                 /* Strike off double quotes */
868                 number = tcore_at_tok_extract(resp);
869         }
870
871         dbg("+CSSU: <code2> = %d <index> = %d <number> = %s ", code2, index, number);
872
873         /* <code2> - other values will be ignored */
874         switch (code2) {
875         case 0:
876                 command = TCORE_NOTIFICATION_CALL_INFO_MT_FORWARDED;
877                 break;
878         case 2:
879                 command = TCORE_NOTIFICATION_CALL_INFO_HELD;
880                 break;
881         case 3:
882                 command = TCORE_NOTIFICATION_CALL_INFO_ACTIVE;
883                 break;
884         case 4:
885                 command = TCORE_NOTIFICATION_CALL_INFO_JOINED;
886                 break;
887         case 7:
888         case 8:
889                 command = TCORE_NOTIFICATION_CALL_INFO_TRANSFERED;
890                 break;
891         case 9:
892                 command = TCORE_NOTIFICATION_CALL_INFO_MT_DEFLECTED;
893                 break;
894         default:
895                 dbg("Unsupported +CSSU notification : %d", code2);
896                 break;
897         }
898
899         if (command != TCORE_NOTIFICATION_UNKNOWN)
900                 tcore_object_send_notification(co, command, 0, NULL);
901         tcore_at_tok_free(tokens);
902         g_free(number);
903
904         return TRUE;
905 }
906
907 /*
908 * Operation -  SS network initiated notification.
909 * notification message format:
910 * +CSSI : <code1>[,<index>]
911 * where
912 * <code1>
913 * 0 unconditional call forwarding is active
914 * 1 some of the conditional call forwarding are active
915 * 2 call has been forwarded
916 * 3 call is waiting
917 * 4 this is a CUG call (also <index> present)
918 * 5 outgoing calls are barred
919 * 6 incoming calls are barred
920 * 7 CLIR suppression rejected
921 * 8 call has been deflected
922
923 * <index>
924 * refer Closed user group +CCUG.
925 */
926 static gboolean on_notification_imc_call_ss_cssi_info(CoreObject *co, const void *event_data,
927         void *user_data)
928 {
929         GSList *tokens = NULL;
930         TcoreNotification command = TCORE_NOTIFICATION_UNKNOWN;
931         char *resp = NULL;
932         char *cmd = 0;
933         int index = 0;
934         int code1 = -1;
935
936         dbg("entry");
937
938         if (1 != g_slist_length((GSList *) event_data)) {
939                 err("unsolicited msg but multiple line");
940                 return TRUE;
941         }
942         cmd = (char *) ((GSList *) event_data)->data;
943         dbg("ss notification message[%s]", cmd);
944
945         tokens = tcore_at_tok_new(cmd);
946         /* parse <code1> */
947         resp = g_slist_nth_data(tokens, 0);
948         if (NULL == resp) {
949                 err("<code1> is missing from %CSSI indication");
950                 tcore_at_tok_free(tokens);
951                 return TRUE;
952         }
953
954         code1 = atoi(resp);
955
956         /* parse [ <index>] */
957         if ((resp = g_slist_nth_data(tokens, 1)))
958                 index = atoi(resp);
959
960         dbg("+CSSI: <code1> = %d <index> = %d ", code1, index);
961
962         /* <code1> - other values will be ignored */
963         switch (code1) {
964         case 0:
965                 command = TCORE_NOTIFICATION_CALL_INFO_MO_FORWARD_UNCONDITIONAL;
966                 break;
967         case 1:
968                 command = TCORE_NOTIFICATION_CALL_INFO_MO_FORWARD_CONDITIONAL;
969                 break;
970         case 2:
971                 command = TCORE_NOTIFICATION_CALL_INFO_MO_FORWARDED;
972                 break;
973         case 3:
974                 command = TCORE_NOTIFICATION_CALL_INFO_MO_WAITING;
975                 break;
976         case 5:
977                 command = TCORE_NOTIFICATION_CALL_INFO_MO_BARRED_OUTGOING;
978                 break;
979         case 6:
980                 command = TCORE_NOTIFICATION_CALL_INFO_MO_BARRED_INCOMING;
981                 break;
982         case 8:
983                 command  = TCORE_NOTIFICATION_CALL_INFO_MO_DEFLECTED;
984                 break;
985         default:
986                 dbg("Unsupported +CSSI notification : %d", code1);
987                 break;
988         }
989
990         if (command != TCORE_NOTIFICATION_UNKNOWN)
991                 tcore_object_send_notification(co, command, 0, NULL);
992         tcore_at_tok_free(tokens);
993
994         return TRUE;
995 }
996
997 static gboolean on_notification_imc_call_clip_info(CoreObject *co, const void *data,
998         void *user_data)
999 {
1000         dbg("entry");
1001         /* TODO - handle +CLIP notification*/
1002         return TRUE;
1003 }
1004
1005 /* Response */
1006 static void __on_response_imc_call_handle_error_report(TcorePending *p,
1007         guint data_len, const void *data, void *user_data)
1008 {
1009         const TcoreAtResponse *at_resp = data;
1010         CoreObject *co = tcore_pending_ref_core_object(p);
1011         ImcRespCbData *resp_cb_data = user_data;
1012         TelCallResult result = TEL_CALL_RESULT_FAILURE;
1013         GSList *tokens = NULL;
1014         dbg("entry");
1015
1016         tcore_check_return_assert(co != NULL);
1017         tcore_check_return_assert(resp_cb_data != NULL);
1018
1019         if (at_resp && at_resp->success) {
1020                 GSList *resp_data = NULL;
1021                 gchar *resp_str;
1022                 gint error;
1023
1024                 resp_data = at_resp->lines;
1025                 if (!resp_data) {
1026                         err("invalid response data received");
1027                         goto OUT;
1028                 }
1029
1030                 tokens = tcore_at_tok_new(resp_data->data);
1031                 resp_str = g_slist_nth_data(tokens, 0);
1032                 if (!resp_str) {
1033                         err("In extended error report - <category> missing");
1034                         goto OUT;
1035                 }
1036                 dbg("category[%s]", resp_str);
1037
1038                 resp_str = g_slist_nth_data(tokens, 1);
1039                 if (!resp_str) {
1040                         err("In extended error report - <cause> missing");
1041                         goto OUT;
1042                 }
1043                 error = atoi(resp_str);
1044                 dbg("Cause: [%d] description: [%s]", error, g_slist_nth_data(tokens, 2));
1045
1046                 result = __convert_imc_extended_err_tel_call_result(error);
1047                 dbg("result: [%d]", result);
1048         } else {
1049                 err("Response - [NOK]");
1050         }
1051 OUT:
1052
1053         dbg("%s: [%s]", IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data),
1054                  (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1055
1056         /* Invoke callback */
1057         if (resp_cb_data->cb)
1058                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1059
1060         /* Free callback data */
1061         imc_destroy_resp_cb_data(resp_cb_data);
1062
1063         /* Free tokens*/
1064         tcore_at_tok_free(tokens);
1065 }
1066
1067 static void __on_response_imc_call_end_cause(TcorePending *p,
1068         guint data_len, const void *data, void *user_data)
1069 {
1070         const TcoreAtResponse *at_resp = data;
1071         CoreObject *co = tcore_pending_ref_core_object(p);
1072         ImcRespCbData *resp_cb_data = user_data;
1073         TelCallStatusIdleNoti idle;
1074         TcoreNotification command;
1075         TelCallEndCause cause = TEL_CALL_END_CAUSE_NONE;
1076         guint *call_id;
1077         GSList *tokens = NULL;
1078
1079         dbg("entry");
1080
1081         tcore_check_return_assert(co != NULL);
1082         tcore_check_return_assert(resp_cb_data != NULL);
1083         call_id = IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
1084
1085         if (at_resp && at_resp->success) {
1086                 GSList *resp_data = NULL;
1087                 gchar *resp_str;
1088                 gint error;
1089
1090                 resp_data = at_resp->lines;
1091                 if (!resp_data) {
1092                         err("invalid response data received");
1093                         goto OUT;
1094                 }
1095                 tokens = tcore_at_tok_new(resp_data->data);
1096                 resp_str = g_slist_nth_data(tokens, 0);
1097                 if (!resp_str) {
1098                         err("In extended error report - <category> missing");
1099                         goto OUT;
1100                 }
1101                 dbg("category[%s]", resp_str);
1102                 resp_str = g_slist_nth_data(tokens, 1);
1103                 if (!resp_str) {
1104                         err("In extended error report - <cause> missing");
1105                         goto OUT;
1106                 }
1107                 error = atoi(resp_str);
1108                 dbg("cause: [%d] description: [%s]", error, g_slist_nth_data(tokens, 2));
1109
1110                 cause = __convert_imc_extended_err_call_end_cause(error);
1111                 dbg("cause: [%d]", cause);
1112
1113         } else {
1114                 err("RESPONSE - [NOK]");
1115         }
1116 OUT:
1117         command = TCORE_NOTIFICATION_CALL_STATUS_IDLE;
1118         idle.call_id = *call_id;
1119
1120         idle.cause = cause;
1121
1122         /* Send notification */
1123         tcore_object_send_notification(co, command,
1124                 sizeof(TelCallStatusIdleNoti), &idle);
1125
1126         /* Free callback data */
1127         imc_destroy_resp_cb_data(resp_cb_data);
1128
1129         /* Free tokens*/
1130         tcore_at_tok_free(tokens);
1131 }
1132 static void on_response_imc_call_default(TcorePending *p,
1133         guint data_len, const void *data, void *user_data)
1134 {
1135         const TcoreAtResponse *at_resp = data;
1136         CoreObject *co = tcore_pending_ref_core_object(p);
1137         ImcRespCbData *resp_cb_data = user_data;
1138
1139         TelCallResult result = TEL_CALL_RESULT_FAILURE;
1140         dbg("entry");
1141
1142         tcore_check_return_assert(co != NULL);
1143         tcore_check_return_assert(resp_cb_data != NULL);
1144
1145         if (at_resp && at_resp->success) {
1146                 result = TEL_CALL_RESULT_SUCCESS;
1147         } else {
1148                 TelReturn ret;
1149                 if(at_resp){
1150                         err("ERROR[%s]", at_resp->final_response);
1151                 }
1152
1153                 /* Send Request to modem to get extended error report*/
1154                 ret = tcore_at_prepare_and_send_request(co,
1155                         "AT+CEER", "+CEER:",
1156                         TCORE_AT_COMMAND_TYPE_SINGLELINE,
1157                         NULL,
1158                         __on_response_imc_call_handle_error_report, resp_cb_data,
1159                         on_send_imc_request, NULL);
1160
1161
1162                 if (ret == TEL_RETURN_SUCCESS)
1163                         return;
1164         }
1165
1166         dbg("%s: [%s]", IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data),
1167                  (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1168
1169         /* Invoke callback */
1170         if (resp_cb_data->cb)
1171                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1172
1173         /* Free callback data */
1174         imc_destroy_resp_cb_data(resp_cb_data);
1175 }
1176
1177 static void on_response_imc_call_set_volume_info(TcorePending *p,
1178         guint data_len, const void *data, void *user_data)
1179 {
1180         const TcoreAtResponse *at_resp = data;
1181         CoreObject *co = tcore_pending_ref_core_object(p);
1182         ImcRespCbData *resp_cb_data = user_data;
1183         GSList *tokens = NULL;
1184         GSList *line = NULL;
1185         char *resp_str = NULL;
1186         gboolean error;
1187
1188         TelCallResult result = TEL_CALL_RESULT_FAILURE;
1189         dbg("Enter");
1190
1191         tcore_check_return_assert(co != NULL);
1192         tcore_check_return_assert(resp_cb_data != NULL);
1193
1194         if (at_resp && at_resp->success) {
1195                 line = at_resp->lines;
1196                 tokens = tcore_at_tok_new(line->data);
1197
1198                 if (!g_slist_nth_data(tokens, 0)) {
1199                         err("group_id  missing");
1200                         goto OUT;
1201                 }
1202
1203                 if (!g_slist_nth_data(tokens, 1)) {
1204                         err(" function_id  missing");
1205                         goto OUT;
1206                 }
1207
1208                 resp_str = g_slist_nth_data(tokens, 2);
1209                 if (!resp_str) {
1210                         err("xdrv result missing");
1211                         goto OUT;
1212                 } else {
1213                         struct imc_set_volume_info *volume_info;
1214                         gchar *vol = "";
1215                         gchar *at_cmd;
1216                         TelReturn ret;
1217
1218                         error = atoi(resp_str);
1219                         if (error) {
1220                                 err("RESPONSE NOK");
1221                                 result = __convert_imc_xdrv_result_tel_call_result(error);
1222                                 goto OUT;
1223                         }
1224
1225                         /* Fetch volume_info from resp_cb_data */
1226                         volume_info = (struct imc_set_volume_info *)
1227                                         IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
1228                         dbg("volume info index[%d]", volume_info->next_index);
1229
1230                         if (xdrv_set_volume[volume_info->next_index] == NULL) {
1231                                 /*Processing of xdrv commands  completed */
1232                                 dbg("RESPONSE OK");
1233                                 result = TEL_CALL_RESULT_SUCCESS;
1234                                 goto OUT;
1235                         } else if (volume_info->next_index == 3) {
1236                                 switch ((volume_info->volume) / 10) {
1237                                 case 0 :
1238                                         vol = "0";
1239                                 break;
1240                                 case 1 :
1241                                         vol = "40";
1242                                 break;
1243                                 case 2 :
1244                                         vol = "46";
1245                                 break;
1246                                 case 3 :
1247                                         vol = "52";
1248                                 break;
1249                                 case 4 :
1250                                         vol = "58";
1251                                 break;
1252                                 case 5 :
1253                                         vol = "64";
1254                                 break;
1255                                 case 6 :
1256                                         vol = "70";
1257                                 break;
1258                                 case 7 :
1259                                         vol = "76";
1260                                 break;
1261                                 case 8 :
1262                                         vol = "82";
1263                                 break;
1264                                 case 9 :
1265                                 default :
1266                                         vol = "88";
1267                                 }
1268                         }
1269
1270                         at_cmd = g_strdup_printf("%s%s",
1271                                         xdrv_set_volume[volume_info->next_index], vol);
1272
1273                         /* Increment index to point to next xdrv command */
1274                         volume_info->next_index += 1;
1275
1276                         /* Send Request to modem */
1277                         ret = tcore_at_prepare_and_send_request(co,
1278                                         at_cmd, "+XDRV",
1279                                         TCORE_AT_COMMAND_TYPE_SINGLELINE,
1280                                         NULL,
1281                                         on_response_imc_call_set_volume_info,
1282                                         resp_cb_data, on_send_imc_request, NULL);
1283                         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_volume_info");
1284                         g_free(at_cmd);
1285
1286                         return;
1287                 }
1288         }
1289
1290 OUT :
1291         dbg("Set Volume Info: [%s]",
1292                         (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1293
1294         /* Invoke callback */
1295         if (resp_cb_data->cb)
1296                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1297
1298         imc_destroy_resp_cb_data(resp_cb_data);
1299         tcore_at_tok_free(tokens);
1300 }
1301
1302 static void on_response_imc_call_set_sound_path(TcorePending *p,
1303         guint data_len, const void *data, void *user_data)
1304 {
1305         const TcoreAtResponse *at_resp = data;
1306         CoreObject *co = tcore_pending_ref_core_object(p);
1307         ImcRespCbData *resp_cb_data = user_data;
1308         GSList *tokens = NULL;
1309         GSList *line = NULL;
1310         char *resp_str = NULL;
1311         gboolean error;
1312         gint xdrv_func_id = -1;
1313
1314         TelCallResult result = TEL_CALL_RESULT_FAILURE;
1315         dbg("Enter");
1316
1317         tcore_check_return_assert(co != NULL);
1318         tcore_check_return_assert(resp_cb_data != NULL);
1319
1320         if (at_resp && at_resp->success) {
1321                 line = at_resp->lines;
1322                 tokens = tcore_at_tok_new(line->data);
1323                 if (!g_slist_nth_data(tokens, 0)) {
1324                         err("group_id  missing");
1325                         goto OUT;
1326                 }
1327
1328                 if (!(resp_str = g_slist_nth_data(tokens, 1))) {
1329                         err("function_id  missing");
1330                         goto OUT;
1331                 }
1332                 xdrv_func_id = atoi(resp_str);
1333
1334                 if (!(resp_str = g_slist_nth_data(tokens, 2))) {
1335                         err("RESPONSE NOK");
1336                         goto OUT;
1337                 }
1338                 error = atoi(resp_str);
1339                 if (error) {
1340                         err("RESPONSE NOK");
1341                         result = __convert_imc_xdrv_result_tel_call_result(error);
1342                         goto OUT;
1343                 }
1344
1345                 if (xdrv_func_id == 4) {
1346                         /* Send next command to configure destination device type */
1347                         gchar *at_cmd;
1348                         TelReturn ret;
1349                         gint *device_type = IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
1350
1351                         at_cmd = g_strdup_printf("AT+XDRV=40,5,2,0,0,0,0,0,1,0,1,0,%d",
1352                                                 *device_type);
1353
1354                         ret = tcore_at_prepare_and_send_request(co,
1355                                         at_cmd, "+XDRV",
1356                                         TCORE_AT_COMMAND_TYPE_SINGLELINE,
1357                                         NULL,
1358                                         on_response_imc_call_set_sound_path, resp_cb_data,
1359                                         on_send_imc_request, NULL);
1360                         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_sound_path");
1361                         g_free(at_cmd);
1362
1363                         return;
1364                 }
1365                 dbg("RESPONSE OK");
1366                 result = TEL_CALL_RESULT_SUCCESS;
1367         }
1368
1369 OUT :
1370         dbg("Set Sound Path: [%s]",
1371                         (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1372
1373         tcore_at_tok_free(tokens);
1374
1375         /* Invoke callback */
1376         if (resp_cb_data->cb)
1377                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1378
1379         imc_destroy_resp_cb_data(resp_cb_data);
1380 }
1381
1382 static void on_response_set_sound_path(TcorePending *p, guint data_len,
1383                                         const void *data, void *user_data)
1384 {
1385         const TcoreAtResponse *at_resp = data;
1386         ImcRespCbData *resp_cb_data = user_data;
1387         TelCallResult result = TEL_CALL_RESULT_FAILURE;
1388         CoreObject *co_call = tcore_pending_ref_core_object(p);
1389
1390         if (at_resp && at_resp->success)
1391                         result = TEL_CALL_RESULT_SUCCESS;
1392
1393         if(resp_cb_data->cb)
1394                 resp_cb_data->cb(co_call, (gint)result, NULL, resp_cb_data->cb_data);
1395
1396         imc_destroy_resp_cb_data(resp_cb_data);
1397 }
1398
1399 static void on_response_imc_call_set_mute(TcorePending *p, guint data_len,
1400         const void *data, void *user_data)
1401 {
1402         const TcoreAtResponse *at_resp = data;
1403         CoreObject *co = tcore_pending_ref_core_object(p);
1404         ImcRespCbData *resp_cb_data = user_data;
1405         GSList *tokens = NULL;
1406         const char *line = NULL;
1407         char *resp_str = NULL;
1408         gboolean error;
1409
1410         TelCallResult result = TEL_CALL_RESULT_FAILURE;
1411         dbg("Enter");
1412
1413         tcore_check_return_assert(co != NULL);
1414         tcore_check_return_assert(resp_cb_data != NULL);
1415
1416         if (at_resp && at_resp->success) {
1417                 line = (((GSList *)at_resp->lines)->data);
1418                 tokens = tcore_at_tok_new(line);
1419
1420                 if (!g_slist_nth_data(tokens, 0)) {
1421                         err("group_id  missing");
1422                         goto OUT;
1423                 }
1424
1425                 if (!g_slist_nth_data(tokens, 1)) {
1426                         err("function_id  missing");
1427                         goto OUT;
1428                 }
1429
1430                 if (!(resp_str = g_slist_nth_data(tokens, 2))) {
1431                         err("xdrv_result missing");
1432                         goto OUT;
1433                 }
1434
1435                 error = atoi(resp_str);
1436                 if (error) {
1437                         err(" RESPONSE NOK [%d]", error);
1438                         result = __convert_imc_xdrv_result_tel_call_result(error);
1439                         goto OUT;
1440                 }
1441                 result = TEL_CALL_RESULT_SUCCESS;
1442         }
1443
1444 OUT :
1445         dbg("Set Mute: [%s]",
1446                         (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1447         tcore_at_tok_free(tokens);
1448
1449         /* Invoke callback */
1450         if (resp_cb_data->cb)
1451                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1452
1453         imc_destroy_resp_cb_data(resp_cb_data);
1454 }
1455
1456
1457  /* Request */
1458  /*
1459  * Operation - dial
1460  *
1461  * Request -
1462  * AT-Command: ATD <num> [I] [G] [;]
1463  * <num> - dialed number
1464  * [I][i] - CLI presentation(supression or invocation)
1465  * [G] - control the CUG supplementary service information for this call.
1466  *
1467  * Response -
1468  * Success:
1469  * OK or CONNECT
1470  * Failure:
1471  * "ERROR"
1472  * "NO ANSWER"
1473  * "NO CARRIER"
1474  * "BUSY"
1475  * "NO DIALTONE"
1476  * +CME ERROR: <error>
1477  */
1478 static TelReturn imc_call_dial(CoreObject *co, const TelCallDial *dial_info,
1479                 TcoreObjectResponseCallback cb, void *cb_data)
1480 {
1481         gchar *at_cmd;
1482         const gchar *clir;
1483         gchar *num;
1484
1485         dbg("entry");
1486
1487         if (dial_info->call_type == TEL_CALL_TYPE_VIDEO) {
1488                 err("Video call is not supported in imc modem");
1489                  return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1490         }
1491
1492         if (!strncmp(dial_info->number, "*31#", 4)) {
1493                 dbg("clir suppression");
1494                 clir = "i";
1495                 num = (gchar *)&(dial_info->number[4]);
1496         } else if (!strncmp(dial_info->number, "#31#", 4)) {
1497                 dbg("clir invocation");
1498                 clir = "I";
1499                 num = (gchar *)&(dial_info->number[4]);
1500         } else {
1501                 int cli = 0;
1502
1503                 dbg("no clir string in number");
1504
1505                 /* it will be removed when setting application use tapi_ss_set_cli()
1506                  * instead of his own vconfkey. (0 : By network, 1 : Show, 2 : Hide)
1507                  */
1508                 vconf_get_int("db/ciss/show_my_number", &cli);
1509                 if (cli == 2){
1510                         dbg("clir invocation from setting application");
1511                         clir = "I";
1512                 } else {
1513                         dbg("set clir state to default");
1514                         clir = "";
1515                 }
1516                 num = (gchar *)dial_info->number;
1517         }
1518
1519         /* AT-Command */
1520         at_cmd = g_strdup_printf("ATD%s%s;", num, clir);
1521         dbg(" at command : %s", at_cmd);
1522
1523         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_dial");
1524 }
1525
1526 /*
1527  * Operation - Answer/Reject/Replace/hold(current call) & accept incoming call.
1528  *
1529  * Request -
1530  *
1531  * 1. AT-Command: ATA
1532  * Response -
1533  * Success:
1534  * OK
1535  * Failure:
1536  * +CME ERROR: <error>
1537  *
1538  * 2. AT-Command: AT+CHLD=[<n>]
1539  * <n>
1540  * 0 - (deafult)release all held calls or set User Determined User Busy for a waiting/incoming
1541  * call; if both exists then only the waiting call will be rejected.
1542  * 1 -  release all active calls and accepts the other (held or waiting)
1543  * Note: In the scenario: An active call, a waiting call and held call, when the active call is
1544  * terminated, we will make the Waiting call as active.
1545  * 2 -  place all active calls (if exist) on hold and accepts the other call (held or waiting/in-coming).
1546  * If only one call exists which is active, place it on hold and if only held call exists make it active call.
1547  * Response -
1548  * Success:
1549  * OK
1550  * Failure:
1551  * +CME ERROR: <error>
1552  * For more informatiion refer 3GPP TS 27.007.
1553  */
1554 static TelReturn imc_call_answer(CoreObject *co, TelCallAnswerType ans_type,
1555         TcoreObjectResponseCallback cb, void *cb_data)
1556 {
1557         gchar *at_cmd;
1558         dbg("entry");
1559
1560         if (ans_type == TEL_CALL_ANSWER_ACCEPT) {
1561                 /* AT-Command */
1562                 at_cmd = g_strdup_printf("%s", "ATA");
1563         }else if (ans_type == TEL_CALL_ANSWER_REJECT) {
1564                 /* AT-Command */
1565                 at_cmd = g_strdup_printf("%s", "AT+CHLD=0");
1566         } else if (ans_type == TEL_CALL_ANSWER_REPLACE) {
1567                 /* AT-Command */
1568                 at_cmd = g_strdup_printf("%s", "AT+CHLD=1");
1569         } else if (ans_type == TEL_CALL_ANSWER_HOLD_AND_ACCEPT) {
1570                 /* AT-Command */
1571                 at_cmd = g_strdup_printf("%s", "AT+CHLD=2");
1572         }else {
1573                 err("Unsupported call answer type");
1574                 return TEL_RETURN_FAILURE;
1575         }
1576
1577         dbg("at command : %s", at_cmd);
1578
1579         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_answer");
1580 }
1581
1582 /*
1583  * Operation - release all calls/release specific call/release all active
1584  * call/release all held calls.
1585  *
1586  * Request -
1587  * 1. AT-Command: AT+CHLD=[<n>]
1588  * <n>
1589  * 0  - (defualt)release all held calls or set User Determined User -
1590  *       Busy for a waiting/incoming.
1591  * call; if both exists then only the waiting call will be rejected.
1592  * 1  - release all active calls and accepts the other (held or waiting).
1593  * 1x - release a specific call (x specific call number as indicated by call id).
1594  * 8  - release all calls.
1595  * Response -
1596  * Success:
1597  * OK
1598  * Failure:
1599  * +CME ERROR: <error>
1600  */
1601 static TelReturn imc_call_end(CoreObject *co, const TelCallEnd *end_info,
1602         TcoreObjectResponseCallback cb, void *cb_data)
1603 {
1604         gchar *at_cmd;
1605         dbg("entry");
1606
1607         if (end_info->end_type == TEL_CALL_END_ALL) {
1608                 /* AT-Command */
1609                 at_cmd = g_strdup_printf("%s", "AT+CHLD=8");
1610         }else if (end_info->end_type == TEL_CALL_END) {
1611                 /* AT-Command */
1612                 at_cmd = g_strdup_printf("%s%d", "AT+CHLD=1",end_info->call_id);
1613         } else if (end_info->end_type == TEL_CALL_END_ACTIVE_ALL) {
1614                 /* AT-Command */
1615                 at_cmd = g_strdup_printf("%s", "AT+CHLD=1");
1616         } else if (end_info->end_type == TEL_CALL_END_HOLD_ALL) {
1617                 /* AT-Command */
1618                 at_cmd = g_strdup_printf("%s", "AT+CHLD=0");
1619         }else {
1620                 err("Unsupported call end type");
1621                 return TEL_RETURN_FAILURE;
1622         }
1623
1624         dbg("at command : %s", at_cmd);
1625
1626         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_end");
1627 }
1628
1629 /*
1630  * Operation - send dtmf.
1631  *
1632  * Request -
1633  * 1. AT-Command: AT+VTS=<DTMF>,{<DTMF>,<duration>}.
1634  * where
1635  * <DTMF>:
1636  * is a single ASCII character in the set 0-9, #, *, A-D. Even it will support string DTMF.
1637  * <duration>:
1638  * integer in range 0-255, meaning 1/10(10 millisec) seconds multiples. The string parameter
1639  * of the command consists of combinations of the following separated by commas:
1640  * NOTE : There is a limit of 50 dtmf tones can be requested through a single VTS command.
1641  * Response -
1642  * Success:
1643  * OK
1644  * Failure:
1645  * +CME ERROR: <error>
1646  */
1647 static TelReturn imc_call_send_dtmf(CoreObject *co, const char *dtmf_str,
1648         TcoreObjectResponseCallback cb,  void *cb_data)
1649 {
1650         gchar *at_cmd;
1651         char *tmp_dtmf = NULL, *dtmf;
1652         unsigned int count;
1653
1654         dbg("entry");
1655
1656         //(void) _set_dtmf_tone_duration(o, dup);
1657
1658         /* DTMF digits + comma for each dtmf digit */
1659         tmp_dtmf = tcore_malloc0((strlen(dtmf_str) * 2) + 1);
1660         tcore_check_return_value_assert(tmp_dtmf != NULL, TEL_RETURN_FAILURE);
1661         /* Save initial pointer */
1662         dtmf = tmp_dtmf;
1663
1664         for (count = 0; count < strlen(dtmf_str); count++) {
1665                 *tmp_dtmf = dtmf_str[count];
1666                 tmp_dtmf++;
1667
1668                 *tmp_dtmf = COMMA;
1669                 tmp_dtmf++;
1670         }
1671
1672         /* last digit is having COMMA , overwrite it with '\0'*/
1673         *(--tmp_dtmf) = '\0';
1674
1675         /* (AT+VTS = <d1>,<d2>,<d3>,<d4>,<d5>,<d6>, ..... <d32> */
1676         at_cmd = g_strdup_printf("AT+VTS=%s", dtmf);
1677         dbg("at command : %s", at_cmd);
1678
1679         tcore_free(dtmf);
1680
1681         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_send_dtmf");
1682 }
1683
1684 /*
1685  * Operation - call hold.
1686  *
1687  * Request -
1688  * 1. AT-Command: AT+CHLD=[<n>]
1689  * Where
1690  * <n>
1691  * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/incoming).
1692  * If only one call exists which is active, place it on hold and if only held call exists
1693  * make it active call
1694  * Response -
1695  * Success:
1696  * OK
1697  * Failure:
1698  * +CME ERROR: <error>
1699  */
1700 static TelReturn imc_call_hold(CoreObject *co, TcoreObjectResponseCallback cb,
1701         void *cb_data)
1702
1703 {
1704         gchar *at_cmd;
1705         dbg("entry");
1706
1707         at_cmd = g_strdup_printf("%s", "AT+CHLD=2");
1708         dbg("at command : %s", at_cmd);
1709
1710         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_hold");
1711 }
1712
1713 /*
1714  * Operation - call active.
1715  *
1716  * Request -
1717  * 1. AT-Command: AT+CHLD=[<n>]
1718  * Where
1719  * <n>
1720  * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/incoming).
1721  * If only one call exists which is active, place it on hold and if only held call exists
1722  * make it active call
1723  * Response -
1724  * Success:
1725  * OK
1726  * Failure:
1727  * +CME ERROR: <error>
1728  */
1729 static TelReturn imc_call_active(CoreObject *co, TcoreObjectResponseCallback cb,
1730         void *cb_data)
1731 {
1732         gchar *at_cmd;
1733         dbg("entry");
1734
1735         at_cmd = g_strdup_printf("%s", "AT+CHLD=2");
1736         dbg("at command : %s", at_cmd);
1737
1738         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_active");
1739 }
1740
1741 /*
1742  * Operation - call swap.
1743  *
1744  * Request -
1745  * 1. AT-Command: AT+CHLD=[<n>]
1746  * Where
1747  * <n>
1748  * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/incoming).
1749  * If only one call exists which is active, place it on hold and if only held call exists
1750  * make it active call
1751  * Response -
1752  * Success:
1753  * OK
1754  * Failure:
1755  * +CME ERROR: <error>
1756  */
1757 static TelReturn imc_call_swap(CoreObject *co, TcoreObjectResponseCallback cb,
1758         void *cb_data)
1759 {
1760         gchar *at_cmd;
1761         dbg("entry");
1762
1763         at_cmd = g_strdup_printf("%s", "AT+CHLD=2");
1764         dbg("at command : %s", at_cmd);
1765
1766         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_swap");
1767 }
1768
1769 /*
1770  * Operation - call join.
1771  *
1772  * Request -
1773  * 1. AT-Command: AT+CHLD=[<n>]
1774  * Where
1775  * <n>
1776  * 3 - adds a held call to the conversation
1777  * Response -
1778  * Success:
1779  * OK
1780  * Failure:
1781  * +CME ERROR: <error>
1782  */
1783 static TelReturn imc_call_join(CoreObject *co, TcoreObjectResponseCallback cb,
1784         void *cb_data)
1785 {
1786         gchar *at_cmd;
1787         dbg("entry");
1788
1789         at_cmd = g_strdup_printf("%s", "AT+CHLD=3");
1790         dbg("at command : %s", at_cmd);
1791
1792         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_join");
1793 }
1794
1795 /*
1796  * Operation - call split.
1797  *
1798  * Request -
1799  * 1. AT-Command: AT+CHLD=[<n>]
1800  * Where
1801  * <n>
1802  * 2x - place all active calls on hold except call x with which communication is supported
1803  * Response -
1804  * Success:
1805  * OK
1806  * Failure:
1807  * +CME ERROR: <error>
1808  */
1809 static TelReturn imc_call_split(CoreObject *co, unsigned int call_id,
1810         TcoreObjectResponseCallback cb, void *cb_data)
1811 {
1812         gchar *at_cmd;
1813         dbg("entry");
1814
1815         at_cmd = g_strdup_printf("%s%d", "AT+CHLD=2", call_id);
1816         dbg("at command : %s", at_cmd);
1817
1818         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_split");
1819 }
1820
1821 /*
1822  * Operation - call transfer.
1823  *
1824  * Request -
1825  * 1. AT-Command: AT+CHLD=[<n>]
1826  * Where
1827  * <n>
1828  * 4 connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer)
1829  * Response -
1830  * Success:
1831  * OK
1832  * Failure:
1833  * +CME ERROR: <error>
1834  */
1835 static TelReturn imc_call_transfer(CoreObject *co, TcoreObjectResponseCallback cb,
1836         void *cb_data)
1837 {
1838         gchar *at_cmd;
1839         dbg("entry");
1840
1841         at_cmd = g_strdup_printf("%s", "AT+CHLD=4");
1842         dbg("at command : %s", at_cmd);
1843
1844         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_transfer");
1845 }
1846
1847 /*
1848  * Operation - call deflect.
1849  *
1850  * Request -
1851  * 1. AT-Command: AT+CTFR= <number>[,<type>]
1852  * Where
1853  * number>
1854  * string type phone number
1855  * <type>
1856  * type of address octet in integer format. It is optional parameter.
1857  *
1858  * Response -
1859  * Success:
1860  * OK
1861  * Failure:
1862  * +CME ERROR: <error>
1863  */
1864 static TelReturn imc_call_deflect(CoreObject *co, const char *deflect_to,
1865         TcoreObjectResponseCallback cb, void *cb_data)
1866 {
1867         gchar *at_cmd;
1868         dbg("entry");
1869
1870         at_cmd = g_strdup_printf("AT+CTFR=%s", deflect_to);
1871         dbg("at command : %s", at_cmd);
1872
1873         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_deflect");
1874 }
1875
1876 static TelReturn imc_call_set_active_line(CoreObject *co, TelCallActiveLine active_line,
1877         TcoreObjectResponseCallback cb, void *cb_data)
1878 {
1879         dbg("entry");
1880
1881         dbg("exit");
1882         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1883 }
1884
1885 static TelReturn imc_call_get_active_line(CoreObject *co, TcoreObjectResponseCallback cb,
1886         void *cb_data)
1887 {
1888         dbg("entry");
1889
1890         dbg("exit");
1891         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1892 }
1893
1894 /*
1895  * Operation - Set voule info.
1896  *
1897  * Request -
1898  * AT-Command: AT+XDRV=<group_id>,<function_id>[,<param_n>]
1899  * The first command parameter defines the involved driver group.
1900  * The second command parameter defines a certain function in the selected driver group.
1901  * Other parameters are dependent on the first two parameters.
1902  * Nearly all parameters are integer values, also if they are represented by literals.
1903  * Only very few are strings or
1904  * hex data strings.
1905  *
1906  * Response -
1907  * +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>]
1908  * The first response parameter defines the involved driver group.
1909  * The second response parameter defines the current function in the selected driver group.
1910  * The third response parameter defines the xdrv_result of the operation.
1911  * Additional response parameters dependent on the first two parameters.
1912  */
1913 static TelReturn imc_call_set_volume_info(CoreObject *co, const TelCallVolumeInfo *volume_info,
1914         TcoreObjectResponseCallback cb, void *cb_data)
1915 {
1916         ImcRespCbData *resp_cb_data = NULL;
1917         gchar *at_cmd;
1918         TelReturn ret;
1919         struct imc_set_volume_info cb_volume_info;
1920
1921         dbg("entry");
1922
1923         cb_volume_info.next_index = 1;
1924         cb_volume_info.volume = volume_info->volume;
1925
1926         /* Response callback data */
1927         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
1928                                 &cb_volume_info, sizeof(struct imc_set_volume_info));
1929
1930         at_cmd = g_strdup_printf("%s", xdrv_set_volume[0]);
1931
1932         /* Send Request to modem */
1933         ret = tcore_at_prepare_and_send_request(co,
1934                         at_cmd, "+XDRV",
1935                         TCORE_AT_COMMAND_TYPE_SINGLELINE,
1936                         NULL,
1937                         on_response_imc_call_set_volume_info, resp_cb_data,
1938                         on_send_imc_request, NULL);
1939         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_volume_info");
1940
1941         g_free(at_cmd);
1942         return ret;
1943 }
1944
1945
1946 static TelReturn imc_call_get_volume_info(CoreObject *co, TelCallSoundDevice sound_device,
1947         TcoreObjectResponseCallback cb, void *cb_data)
1948 {
1949         dbg("Entry");
1950
1951         dbg("Exit");
1952         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1953 }
1954
1955 /*
1956  * Operation - Set sound path.
1957  *
1958  * Request -
1959  * AT-Command: AT+XDRV=<group_id>,<function_id>[,<param_n>]
1960  * The first command parameter defines the involved driver group.
1961  * The second command parameter defines a certain function in the selected driver group.
1962  * Other parameters are dependent on the first two parameters.
1963  * Nearly all parameters are integer values, also if they are represented by literals.
1964  * Only very few are strings or
1965  * hex data strings.
1966  *
1967  * Response -
1968  * +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>]
1969  * The first response parameter defines the involved driver group.
1970  * The second response parameter defines the current function in the selected driver group.
1971  * The third response parameter defines the xdrv_result of the operation.
1972  * Additional response parameters dependent on the first two parameters.
1973  */
1974
1975 static TelReturn imc_call_set_sound_path(CoreObject *co, const TelCallSoundPathInfo *sound_path_info,
1976         TcoreObjectResponseCallback cb, void *cb_data)
1977 {
1978         ImcRespCbData *resp_cb_data = NULL;
1979         TelReturn ret;
1980         gchar *at_cmd;
1981         gint device_type = -1;
1982         TcorePlugin *plugin = tcore_object_ref_plugin(co);
1983         const char *cp_name = tcore_server_get_cp_name_by_plugin(plugin);
1984
1985         dbg("audio device type - 0x%x", sound_path_info->path);
1986
1987         switch (sound_path_info->path) {
1988                 case TEL_SOUND_PATH_HANDSET:
1989                         device_type = 1;
1990                         break;
1991                 case TEL_SOUND_PATH_HEADSET:
1992                         device_type = 2;
1993                         break;
1994                 case TEL_SOUND_PATH_HEADSET_3_5PI:
1995                         device_type = 3;
1996                         break;
1997                 case TEL_SOUND_PATH_SPK_PHONE:
1998                         device_type = 4;
1999                         break;
2000                 case TEL_SOUND_PATH_HANDSFREE:
2001                         device_type = 5;
2002                         break;
2003                 case TEL_SOUND_PATH_HEADSET_HAC:
2004                         device_type = 6;
2005                         break;
2006                 case TEL_SOUND_PATH_BLUETOOTH:
2007                 case TEL_SOUND_PATH_STEREO_BLUETOOTH:
2008                         device_type = 7;
2009                         break;
2010                 case TEL_SOUND_PATH_BT_NSEC_OFF:
2011                 case TEL_SOUND_PATH_MIC1:
2012                 case TEL_SOUND_PATH_MIC2:
2013                 default:
2014                         dbg("unsupported device type");
2015                         return TEL_RETURN_INVALID_PARAMETER;
2016         }
2017
2018         if (g_str_has_prefix(cp_name, "imcmodem")) {
2019                 /* Response callback data */
2020                 resp_cb_data = imc_create_resp_cb_data(cb, cb_data, &device_type, sizeof(gint));
2021
2022                 at_cmd = g_strdup_printf("AT+XDRV=40,4,3,0,0,0,0,0,1,0,1,0,%d", device_type);
2023
2024                 ret = tcore_at_prepare_and_send_request(co,
2025                         at_cmd, "+XDRV",
2026                         TCORE_AT_COMMAND_TYPE_SINGLELINE,
2027                         NULL,
2028                         on_response_imc_call_set_sound_path, resp_cb_data,
2029                         on_send_imc_request, NULL);
2030                 IMC_CHECK_REQUEST_RET(ret, NULL, "imc_call_set_sound_path");
2031                 g_free(at_cmd);
2032         } else {
2033                 /* Response callback data */
2034                 resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
2035
2036                 /* Configure modem I2S1 to 8khz, mono, PCM if routing to bluetooth */
2037                 if (sound_path_info->path == TEL_SOUND_PATH_BLUETOOTH ||
2038                                 sound_path_info->path == TEL_SOUND_PATH_STEREO_BLUETOOTH) {
2039                         tcore_at_prepare_and_send_request(co,
2040                                         "AT+XDRV=40,4,3,0,1,0,0,0,0,0,0,0,21",
2041                                         NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2042                                         NULL, NULL, NULL, NULL, NULL);
2043
2044                         tcore_at_prepare_and_send_request(co,
2045                                         "AT+XDRV=40,5,2,0,1,0,0,0,0,0,0,0,22",
2046                                         NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2047                                         NULL, NULL, NULL, NULL, NULL);
2048                 } else {
2049                         tcore_at_prepare_and_send_request(co,
2050                                         "AT+XDRV=40,4,3,0,1,0,8,0,1,0,2,0,21",
2051                                         NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2052                                         NULL, NULL, NULL, NULL, NULL);
2053
2054                         tcore_at_prepare_and_send_request(co,
2055                                         "AT+XDRV=40,5,2,0,1,0,8,0,1,0,2,0,22",
2056                                         NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2057                                         NULL, NULL, NULL, NULL, NULL);
2058                 }
2059
2060                 /* Configure modem I2S2 and do the modem routing */
2061                 tcore_at_prepare_and_send_request(co,
2062                                 "AT+XDRV=40,4,4,0,0,0,8,0,1,0,2,0,21",
2063                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2064                                 NULL, NULL, NULL, NULL, NULL);
2065
2066                 tcore_at_prepare_and_send_request(co,
2067                                 "AT+XDRV=40,5,3,0,0,0,8,0,1,0,2,0,22",
2068                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2069                                 NULL, NULL, NULL, NULL, NULL);
2070
2071                 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,0,4",
2072                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2073                                 NULL, NULL, NULL, NULL, NULL);
2074
2075                 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,3,0",
2076                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2077                                 NULL, NULL, NULL, NULL, NULL);
2078
2079                 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,4,2",
2080                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2081                                 NULL, NULL, NULL, NULL, NULL);
2082
2083                 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,5,2",
2084                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2085                                 NULL, NULL, NULL, NULL, NULL);
2086
2087                 /* amc enable */
2088                 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,2,4",
2089                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2090                                 NULL, NULL, NULL, NULL, NULL);
2091
2092                 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,2,3",
2093                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
2094                                 NULL, NULL, NULL, NULL, NULL);
2095
2096                 /* amc route: AMC_RADIO_RX => AMC_I2S1_TX */
2097                 ret = tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,0,2",
2098                                 "+XDRV", TCORE_AT_COMMAND_TYPE_SINGLELINE, NULL,
2099                                 on_response_set_sound_path, resp_cb_data, NULL, NULL);
2100
2101                 IMC_CHECK_REQUEST_RET(ret, NULL, "imc_call_set_sound_path");
2102         }
2103
2104         return ret;
2105 }
2106
2107 /*
2108  * Operation - Set/Unset mute status.
2109  *
2110  * Request -
2111  * AT-Command: AT+XDRV=<group_id>,<function_id>[,<param_n>]
2112  * The first command parameter defines the involved driver group.
2113  * The second command parameter defines a certain function in the selected driver group.
2114  * Other parameters are dependent on the first two parameters.
2115  * Nearly all parameters are integer values, also if they are represented by literals.
2116  * Only very few are strings or
2117  * hex data strings.
2118  *
2119  * Response -
2120  * +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>]
2121  * The first response parameter defines the involved driver group.
2122  * The second response parameter defines the current function in the selected driver group.
2123  * The third response parameter defines the xdrv_result of the operation.
2124  * Additional response parameters dependent on the first two parameters.
2125  */
2126 static TelReturn imc_call_set_mute(CoreObject *co, gboolean mute, TcoreObjectResponseCallback cb,
2127         void *cb_data)
2128 {
2129         ImcRespCbData *resp_cb_data = NULL;
2130         gchar *at_cmd;
2131         TelReturn ret;
2132
2133         dbg("entry");
2134
2135         /* Response callback data */
2136         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
2137
2138         /* AT - Command */
2139         if (mute)
2140                 at_cmd = g_strdup_printf("%s", "AT+XDRV=40,8,0,0,0");  /*MUTE*/
2141         else
2142                 at_cmd = g_strdup_printf("%s", "AT+XDRV=40,8,0,0,88"); /*UNMUTE*/
2143
2144         /* Send Request to modem */
2145         ret = tcore_at_prepare_and_send_request(co,
2146                         at_cmd, "+XDRV",
2147                         TCORE_AT_COMMAND_TYPE_SINGLELINE,
2148                         NULL,
2149                         on_response_imc_call_set_mute, resp_cb_data,
2150                         on_send_imc_request, NULL);
2151         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_mute");
2152
2153         g_free(at_cmd);
2154
2155         return ret;
2156 }
2157
2158 static TelReturn imc_call_get_mute_status(CoreObject *co, TcoreObjectResponseCallback cb,
2159         void *cb_data)
2160 {
2161         dbg("entry");
2162
2163         dbg("exit");
2164         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
2165 }
2166
2167
2168 static TelReturn imc_call_set_sound_recording(CoreObject *co, TelCallSoundRecording sound_rec,
2169         TcoreObjectResponseCallback cb, void *cb_data)
2170 {
2171         dbg("entry");
2172
2173         dbg("exit");
2174         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
2175 }
2176
2177 static TelReturn imc_call_set_sound_equalization(CoreObject *co, const TelCallSoundEqualization *sound_eq,
2178         TcoreObjectResponseCallback cb, void *cb_data)
2179 {
2180         dbg("entry");
2181
2182         dbg("exit");
2183         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
2184 }
2185
2186 /* Call Operations */
2187 static TcoreCallOps imc_call_ops = {
2188         .dial = imc_call_dial,
2189         .answer = imc_call_answer,
2190         .end = imc_call_end,
2191         .send_dtmf = imc_call_send_dtmf,
2192         .hold = imc_call_hold,
2193         .active = imc_call_active,
2194         .swap = imc_call_swap,
2195         .join = imc_call_join,
2196         .split = imc_call_split,
2197         .transfer = imc_call_transfer,
2198         .deflect = imc_call_deflect,
2199         .set_active_line = imc_call_set_active_line,
2200         .get_active_line = imc_call_get_active_line,
2201         .set_volume_info = imc_call_set_volume_info,
2202         .get_volume_info = imc_call_get_volume_info,
2203         .set_sound_path = imc_call_set_sound_path,
2204         .set_mute = imc_call_set_mute,
2205         .get_mute_status = imc_call_get_mute_status,
2206         .set_sound_recording = imc_call_set_sound_recording,
2207         .set_sound_equalization = imc_call_set_sound_equalization,
2208 };
2209
2210 gboolean imc_call_init(TcorePlugin *p, CoreObject *co)
2211 {
2212         dbg("Entry");
2213
2214         /* Set operations */
2215         tcore_call_set_ops(co, &imc_call_ops);
2216
2217         /* Add Callbacks */
2218         tcore_object_add_callback(co, "+XCALLSTAT", on_notification_imc_call_status, NULL);
2219         tcore_object_add_callback(co, "+CLIP", on_notification_imc_call_clip_info, NULL);
2220         tcore_object_add_callback(co, "+CSSU", on_notification_imc_call_ss_cssu_info, NULL);
2221         tcore_object_add_callback(co, "+CSSI", on_notification_imc_call_ss_cssi_info, NULL);
2222
2223         return TRUE;
2224 }
2225
2226 void imc_call_exit(TcorePlugin *p, CoreObject *co)
2227 {
2228         dbg("Exit");
2229 }