Fix SVACE defects
[platform/adaptation/spreadtrum/audio-hal-sc7727.git] / tizen-audio-modem.c
1 /*
2  * audio-hal
3  *
4  * Copyright (c) 2014 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <expat.h>
30 #include <stdbool.h>
31 #include <vconf.h>
32
33 #include "tizen-audio-internal.h"
34 #include "tizen-audio-impl.h"
35
36 #define vbc_thread_new pthread_create
37 #define VBPIPE_DEVICE           "/dev/spipe_w6"
38 #define VBPIPE_VOIP_DEVICE      "/dev/spipe_w4"
39 #define VBC_CMD_TAG             "VBC"
40
41 /* Voice */
42 typedef enum {
43     VBC_CMD_NONE = 0,
44     /* current mode and volume gain parameters.*/
45     VBC_CMD_SET_MODE = 1,
46     VBC_CMD_RESP_MODE = 2,
47
48     VBC_CMD_SET_GAIN = 3,
49     VBC_CMD_RESP_GAIN = 4,
50
51     /* whether switch vb control to dsp parameters.*/
52     VBC_CMD_SWITCH_CTRL = 5,
53     VBC_CMD_RESP_SWITCH = 6,
54
55     /* whether mute or not.*/
56     VBC_CMD_SET_MUTE = 7,
57     VBC_CMD_RESP_MUTE = 8,
58
59     /* open/close device parameters.*/
60     VBC_CMD_DEVICE_CTRL = 9,
61     VBC_CMD_RESP_DEVICE = 10,
62
63     VBC_CMD_PCM_OPEN = 11,
64     VBC_CMD_RESP_OPEN  =12,
65
66     VBC_CMD_PCM_CLOSE = 13,
67     VBC_CMD_RESP_CLOSE = 14,
68
69     VBC_CMD_SET_SAMPLERATE = 15,
70     VBC_CMD_RESP_SAMPLERATE = 16,
71
72     VBC_CMD_MAX
73 } vbc_command;
74
75 const static char* vbc_cmd_str_arry[VBC_CMD_MAX] = {"NONE", "SET_MODE", "RESP_MODE", "SET_GAIN", "RESP_GAIN", "SWITCH_CTL", "RESP_SWITCH",
76 "SET_MUTE", "RESP_MUTE", "DEVICE_CTL", "RESP_DEVICE", "PCM_OPEN", "RESP_OPEN", "PCM_CLOSE", "RESP_CLOSE", "SET_SAMPL", "RESP_SAMPL"};
77
78 typedef struct {
79     unsigned int  sim_card;   /*sim card number*/
80 } open_pcm_t;
81
82 typedef struct _vbc_parameters_head {
83     char            tag[4];
84     unsigned int    cmd_type;
85     unsigned int    paras_size;
86 } vbc_parameters_head;
87
88 typedef struct vbc_control_params {
89     int vbchannel_id;
90     audio_hal_t *ah;
91 } vbc_control_params_t;
92
93 typedef struct {
94     unsigned short      is_open; /* if is_open is true, open device; else close device.*/
95     unsigned short      is_headphone;
96     unsigned int        is_downlink_mute;
97     unsigned int        is_uplink_mute;
98 } device_ctrl_t;
99
100 typedef struct samplerate_ctrl {
101     unsigned int samplerate; /* change samplerate.*/
102 } set_samplerate_t;
103
104 typedef struct {
105     unsigned int  is_switch; /* switch vbc contrl to dsp.*/
106 } switch_ctrl_t;
107
108 static int __read_nonblock(int fd, void *buf, int bytes)
109 {
110     int ret = 0;
111     int bytes_to_read = bytes;
112
113     if ((fd > 0) && (buf != NULL)) {
114         do {
115             ret = read(fd, buf, bytes);
116             if ( ret > 0) {
117                 if (ret <= bytes) {
118                     bytes -= ret;
119                 }
120             } else if ((!((errno == EAGAIN) || (errno == EINTR))) || (0 == ret)) {
121                 break;
122             }
123         } while(bytes);
124     }
125
126     if (bytes == bytes_to_read)
127         return ret ;
128     else
129         return (bytes_to_read - bytes);
130 }
131
132 static int __write_nonblock(int fd, void *buf, int bytes)
133 {
134     int ret = -1;
135     int bytes_to_write = bytes;
136
137     if ((fd > 0) && (buf != NULL)) {
138         do {
139             ret = write(fd, buf, bytes);
140             if ( ret > 0) {
141                 if (ret <= bytes) {
142                     bytes -= ret;
143                 }
144             } else if ((!((errno == EAGAIN) || (errno == EINTR))) || (0 == ret)) {
145                 break;
146             }
147         } while(bytes);
148     }
149
150     if (bytes == bytes_to_write)
151         return ret ;
152     else
153         return (bytes_to_write - bytes);
154
155 }
156
157 static int __vbc_write_response(int fd, unsigned int cmd, uint32_t paras_size)
158 {
159     int ret = 0;
160     vbc_parameters_head write_head;
161
162     memset(&write_head, 0, sizeof(vbc_parameters_head));
163     memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
164     write_head.cmd_type = cmd + 1;
165     write_head.paras_size = paras_size;
166
167     ret = __write_nonblock(fd, (void*)&write_head, sizeof(vbc_parameters_head));
168     if (ret < 0)
169         AUDIO_LOG_ERROR("write failed");
170     else
171         AUDIO_LOG_DEBUG("write success for VBC_CMD_[%s]", vbc_cmd_str_arry[cmd]);
172
173     return 0;
174 }
175
176 int _audio_modem_is_call_connected(audio_hal_t *ah)
177 {
178     int val = -1; /* Mixer values 0 - cp [3g] ,1 - cp [2g] ,2 - ap */
179
180     _mixer_control_get_value(ah, MIXER_VBC_SWITCH, &val);
181     AUDIO_LOG_INFO("modem is connected for call = %d", (val == VBC_TD_CHANNELID));
182
183     return (val == VBC_TD_CHANNELID) ? 1 : 0;
184 }
185
186 static void __i2s_pin_mux_sel(audio_hal_t *ah, int type)
187 {
188     audio_return_t ret = AUDIO_RET_OK;
189     audio_modem_t *modem;
190
191     if (!ah) {
192         AUDIO_LOG_ERROR("ah is null");
193         return;
194     }
195
196     AUDIO_LOG_INFO("type is %d",type);
197     modem = ah->modem.cp;
198
199     if (type == 0) {
200        if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
201             if(modem->i2s_bt.is_ext) {
202                 if(modem->i2s_bt.is_switch) {
203                     ret = _mixer_control_set_value(ah,
204                             PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP0_ID);
205                 }
206             } else {
207                 if(modem->i2s_bt.is_switch) {
208                     int value = 0;
209                     _mixer_control_get_value (ah, PIN_SWITCH_IIS0_SYS_SEL, &value);
210                     if(value == PIN_SWITCH_IIS0_CP0_ID) {
211                         ret = _mixer_control_set_value(ah,
212                                 PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_AP_ID);
213                     }
214                 }
215                 if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
216                     if(modem->i2s_bt.is_switch) {
217                         ret = _mixer_control_set_value(ah,
218                                 PIN_SWITCH_BT_IIS_SYS_SEL, PIN_SWITCH_BT_IIS_CP0_IIS0_ID);
219                     }
220                 }
221             }
222         }
223     } else if (type == 1) {
224         if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
225             if(modem->i2s_bt.is_ext) {
226                 if(modem->i2s_bt.is_switch) {
227                     ret = _mixer_control_set_value(ah,
228                             PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP1_ID);
229                 }
230             } else {
231                 if(modem->i2s_bt.is_switch) {
232                     int value = 0;
233                     _mixer_control_get_value (ah, PIN_SWITCH_IIS0_SYS_SEL, &value);
234                     if(value == PIN_SWITCH_IIS0_CP1_ID) {
235                         ret = _mixer_control_set_value(ah,
236                                 PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP2_ID);
237                     }
238                 }
239                 if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
240                     if(modem->i2s_bt.is_switch) {
241                         ret = _mixer_control_set_value(ah,
242                                 PIN_SWITCH_BT_IIS_SYS_SEL, PIN_SWITCH_BT_IIS_CP1_IIS0_ID);
243                     }
244                 }
245             }
246         }
247     } else {
248         AUDIO_LOG_ERROR("invalid type");
249         return;
250     }
251     if (ret)
252         AUDIO_LOG_ERROR("error(0x%x)", ret);
253
254     return;
255 }
256
257 static void *__vbc_control_voice_thread_run(void *args)
258 {
259     audio_return_t audio_ret = AUDIO_RET_OK;
260     vbc_parameters_head read_head;
261     vbc_parameters_head write_head;
262     int exit_thread = 0; /* make exit variable global if required to gracefully exit */
263     int vbpipe_fd;
264     vbc_control_params_t *params = (vbc_control_params_t*)args;
265     if (params == NULL) {
266         return (void*)AUDIO_ERR_PARAMETER;
267     }
268     audio_hal_t *ah = params->ah;
269     fd_set fds_read;
270     struct timeval timeout = {5,0};
271
272     memset(&read_head, 0, sizeof(vbc_parameters_head));
273     memset(&write_head, 0, sizeof(vbc_parameters_head));
274
275     memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
276     write_head.cmd_type = VBC_CMD_NONE;
277     write_head.paras_size = 0;
278
279     AUDIO_LOG_INFO("[voice] vbc control VOICE thread run");
280
281 again:
282     /* open vbpipe device for vb parameter interface between ap and cp */
283     vbpipe_fd = open(VBPIPE_DEVICE, O_RDWR);
284     if (vbpipe_fd < 0) {
285         if (errno == EINTR)
286             goto again;
287         AUDIO_LOG_ERROR("[voice] vbpipe open failed: %s", strerror(errno));
288         return (void*)AUDIO_ERR_IOCTL;
289     }
290     ah->modem.vbc.vbpipe_fd = vbpipe_fd;
291
292     if (fcntl(vbpipe_fd, F_SETFL, O_NONBLOCK) < 0) {
293         AUDIO_LOG_DEBUG("[voice] vbpipe_fd(%d) fcntl error.", vbpipe_fd);
294     }
295
296     AUDIO_LOG_INFO("[voice] %s opened. vbc start loop", VBPIPE_DEVICE);
297
298     /* start loop */
299     while (!exit_thread) {
300         int ret;
301         timeout.tv_sec = 10;
302         timeout.tv_usec = 0;
303
304         /* read command received from cp */
305         FD_ZERO(&fds_read);
306         FD_SET(vbpipe_fd, &fds_read);
307
308         ret = select(vbpipe_fd+1, &fds_read, NULL, NULL, &timeout);
309         if (ret < 0) {
310             ALOGE("voice:select error %d", errno);
311
312             continue;
313         }
314
315         ret = __read_nonblock(vbpipe_fd, &read_head, sizeof(vbc_parameters_head));
316         if (ret < 0) {
317
318             continue;
319         }
320
321         AUDIO_LOG_DEBUG("[voice] Received %d bytes. data: %s, cmd_type: %d", ret, read_head.tag, read_head.cmd_type);
322
323         if (!memcmp(&read_head.tag[0], VBC_CMD_TAG, 3)) {
324             switch (read_head.cmd_type) {
325                 case VBC_CMD_PCM_OPEN: {
326                     open_pcm_t open_pcm_params;
327                     uint32_t paras_size = ((ah->modem.cp->i2s_bt.is_switch << 8) | (ah->modem.cp->i2s_bt.index << 0)
328                                         | (ah->modem.cp->i2s_extspk.is_switch << 9) | (ah->modem.cp->i2s_extspk.index << 4));
329
330                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_PCM_OPEN");
331
332                     ah->modem.is_connected = 1;
333                     if ((audio_ret = _audio_update_route_voicecall(ah, ah->device.init_call_devices, ah->device.num_of_call_devices))) {
334                         AUDIO_LOG_WARN("set voicecall route return 0x%x", audio_ret);
335                         if (audio_ret == AUDIO_ERR_INVALID_STATE) {
336                             /* send signal and wait for the ucm setting,
337                              * it might an incoming call scenario */
338                             _audio_comm_send_message(ah, SIGNAL_ROUTING_FOR_VOICE_CALL, 1);
339                             COND_TIMEDWAIT(ah->device.device_cond, ah->device.device_lock, "device_cond", TIMEOUT_SEC);
340                             MUTEX_UNLOCK(ah->device.device_lock, "device_lock");
341                         }
342                     }
343
344                     memset(&open_pcm_params, 0, sizeof(open_pcm_t));
345                     ret = __read_nonblock(vbpipe_fd, &open_pcm_params, sizeof(open_pcm_t));
346                     if (ret < 0)
347                         AUDIO_LOG_ERROR("read failed");
348                     else
349                         ah->modem.sim_id = open_pcm_params.sim_card;
350
351                     if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
352                         if (ah->modem.cp_type == CP_TG)
353                             __i2s_pin_mux_sel(ah, 1);
354                         else if(ah->modem.cp_type == CP_W)
355                             __i2s_pin_mux_sel(ah, 0);
356                     }
357
358                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_PCM_OPEN");
359                     __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_OPEN, paras_size);
360                     break;
361                 }
362
363                 case VBC_CMD_PCM_CLOSE: {
364                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_PCM_CLOSE");
365
366                     ah->modem.samplerate = 0;
367                     ah->modem.is_connected = 0;
368
369                     /* send signal and wait for the reset ucm */
370                     _audio_comm_send_message(ah, SIGNAL_ROUTING_FOR_VOICE_CALL, 0);
371                     COND_TIMEDWAIT(ah->device.device_cond, ah->device.device_lock, "device_cond", TIMEOUT_SEC);
372                     MUTEX_UNLOCK(ah->device.device_lock, "device_lock");
373
374                     _mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_ARM_CHANNELID);
375
376                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_PCM_CLOSE");
377                     __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
378                     break;
379                 }
380
381                 case VBC_CMD_RESP_CLOSE: {
382                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_RESP_CLOSE & send response");
383                     ret = __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
384                     break;
385                 }
386
387                 case VBC_CMD_SET_MODE: {
388                     char dummy[52];
389                     memset(dummy, 0, sizeof(dummy));
390                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_MODE");
391
392                     if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
393                         if (ah->modem.cp_type == CP_TG)
394                             __i2s_pin_mux_sel(ah, 1);
395                         else if(ah->modem.cp_type == CP_W)
396                             __i2s_pin_mux_sel(ah, 0);
397                     }
398                     /* To do: set mode params : __vbc_set_mode_params(ah, vbpipe_fd); */
399
400                     __read_nonblock(vbpipe_fd, dummy, sizeof(dummy));
401                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_MODE");
402                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MODE, 0);
403                     break;
404                 }
405                 case VBC_CMD_SET_GAIN: {
406                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_GAIN");
407
408                     /* To do: set gain params : __vbc_set_gain_params(ah, vbpipe_fd); */
409
410                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_GAIN");
411                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_GAIN, 0);
412                     break;
413                 }
414                 case VBC_CMD_SWITCH_CTRL: {
415                     switch_ctrl_t switch_ctrl_params;
416
417                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_SWITCH_CTRL");
418
419                     memset(&switch_ctrl_params,0,sizeof(switch_ctrl_t));
420                     ret = __read_nonblock(vbpipe_fd, &switch_ctrl_params, sizeof(switch_ctrl_t));
421                     if (ret < 0)
422                         AUDIO_LOG_ERROR("read failed");
423                     else
424                         AUDIO_LOG_INFO("is_switch:%d", switch_ctrl_params.is_switch);
425
426                     _mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_TD_CHANNELID);
427
428                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_GAIN");
429                     __vbc_write_response(vbpipe_fd, VBC_CMD_SWITCH_CTRL, 0);
430                    break;
431                 }
432                 case VBC_CMD_SET_MUTE: {
433                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_MUTE");
434                     break;
435                 }
436                 case VBC_CMD_DEVICE_CTRL: {
437                     char dummy[64];
438                     memset(dummy, 0, sizeof(dummy));
439                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_DEVICE_CTRL");
440
441                     /* To do: set device ctrl params :__vbc_set_device_ctrl_params(ah, vbpipe_fd); */
442                     __read_nonblock(vbpipe_fd, dummy, sizeof(dummy));
443
444                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_DEVICE_CTRL");
445                     __vbc_write_response(vbpipe_fd, VBC_CMD_DEVICE_CTRL, 0);
446
447                     break;
448                 }
449                 case VBC_CMD_SET_SAMPLERATE: {
450                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_SAMPLERATE");
451
452                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_SAMPLERATE");
453                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_SAMPLERATE, 0);
454                     break;
455                 }
456                 default:
457                     AUDIO_LOG_WARN("[voice] Unknown command received : %d", read_head.cmd_type);
458                     break;
459             }
460         }
461     }
462     if (params)
463         free(params);
464
465     close(vbpipe_fd);
466
467     AUDIO_LOG_INFO("Exit vbc VOICE thread");
468
469     return (void*)0;
470 }
471
472 static void *__vbc_control_voip_thread_run(void *args)
473 {
474     open_pcm_t open_pcm_params;
475     vbc_parameters_head read_head;
476     vbc_parameters_head write_head;
477     int exit_thread = 0; /* make exit variable global if required to gracefully exit */
478     int vbpipe_fd;
479     vbc_control_params_t *params = (vbc_control_params_t*)args;
480     if (params == NULL) {
481         return (void*)AUDIO_ERR_PARAMETER;
482     }
483     audio_hal_t *ah = params->ah;
484     fd_set fds_read;
485
486     struct timeval timeout = {5,0};
487
488     memset(&read_head, 0, sizeof(vbc_parameters_head));
489     memset(&write_head, 0, sizeof(vbc_parameters_head));
490
491     memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
492     write_head.cmd_type = VBC_CMD_NONE;
493     write_head.paras_size = 0;
494
495     AUDIO_LOG_INFO("[voip] vbc control VOIP thread run");
496
497 again:
498     /* open vbpipe device for vb parameter interface between ap and cp */
499     vbpipe_fd = open(VBPIPE_VOIP_DEVICE, O_RDWR);
500     if (vbpipe_fd < 0) {
501         if (errno == EINTR)
502             goto again;
503         AUDIO_LOG_ERROR("[voip] vbpipe open failed: %s", strerror(errno));
504         return (void*)0;
505     }
506     ah->modem.vbc.vbpipe_voip_fd = vbpipe_fd;
507
508     if (fcntl(vbpipe_fd, F_SETFL, O_NONBLOCK) < 0) {
509         AUDIO_LOG_DEBUG("[voip] vbpipe_fd(%d) fcntl error.", vbpipe_fd);
510     }
511
512     AUDIO_LOG_INFO("[voip] %s opened. vbc start loop", VBPIPE_VOIP_DEVICE);
513
514     /* start loop */
515     while (!exit_thread) {
516         int ret;
517         timeout.tv_sec = 5;;
518         timeout.tv_usec = 0;
519
520         /* read command received from cp */
521
522         FD_ZERO(&fds_read);
523         FD_SET(vbpipe_fd, &fds_read);
524
525         ret = select(vbpipe_fd+1, &fds_read, NULL, NULL, &timeout);
526         if (ret < 0) {
527             ALOGE("[voip] select error %d", errno);
528             continue;
529         }
530
531         ret = __read_nonblock(vbpipe_fd, &read_head, sizeof(vbc_parameters_head));
532         if (ret < 0) {
533             continue;
534         }
535
536         AUDIO_LOG_DEBUG("[voip] Received %d bytes. data: %s, cmd_type: %d", ret, read_head.tag, read_head.cmd_type);
537
538         if (!memcmp(&read_head.tag[0], VBC_CMD_TAG, 3)) {
539             switch (read_head.cmd_type) {
540                 case VBC_CMD_PCM_OPEN: {
541                     uint32_t paras_size = ((ah->modem.cp->i2s_bt.is_switch << 8) | (ah->modem.cp->i2s_bt.index << 0)
542                                         | (ah->modem.cp->i2s_extspk.is_switch << 9) | (ah->modem.cp->i2s_extspk.index << 4));
543
544                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_PCM_OPEN");
545
546                     memset(&open_pcm_params, 0, sizeof(open_pcm_t));
547                     ret = __read_nonblock(vbpipe_fd, &open_pcm_params, sizeof(open_pcm_t));
548                     if (ret < 0)
549                         AUDIO_LOG_ERROR("read failed");
550
551                     AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_PCM_OPEN");
552                     __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_OPEN, paras_size);
553                     break;
554                 }
555                 case VBC_CMD_PCM_CLOSE: {
556                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_PCM_CLOSE & send response");
557
558                     __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
559
560                     break;
561                 }
562                 case VBC_CMD_RESP_CLOSE: {
563                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_RESP_CLOSE & send response");
564
565                     ret = __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
566                     break;
567                 }
568                 case VBC_CMD_SET_MODE: {
569                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_MODE");
570
571                     if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
572                         if (ah->modem.cp_type == CP_TG)
573                             __i2s_pin_mux_sel(ah, 1);
574                         else if(ah->modem.cp_type == CP_W)
575                             __i2s_pin_mux_sel(ah, 0);
576                     }
577                     /* To do: set mode params : __vbc_set_mode_params(ah, vbpipe_fd); */
578                     AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_MODE");
579                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MODE, 0);
580                     break;
581                 }
582                 case VBC_CMD_SET_GAIN: {
583                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_GAIN");
584
585                     /* To do: set gain params : __vbc_set_gain_params(ah, vbpipe_fd); */
586                     AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_GAIN");
587                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_GAIN, 0);
588                     break;
589                 }
590                 case VBC_CMD_SWITCH_CTRL: {
591                     switch_ctrl_t switch_ctrl_params;
592
593                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_SWITCH_CTRL");
594
595                     memset(&switch_ctrl_params, 0, sizeof(switch_ctrl_t));
596                     ret = __read_nonblock(vbpipe_fd, &switch_ctrl_params, sizeof(switch_ctrl_t));
597                     if (ret < 0)
598                         AUDIO_LOG_ERROR("read failed");
599                     else
600                         AUDIO_LOG_INFO("is_switch:%d", switch_ctrl_params.is_switch);
601
602                     _mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_TD_CHANNELID);
603
604                     AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SWITCH_CTRL");
605                     __vbc_write_response(vbpipe_fd, VBC_CMD_SWITCH_CTRL, 0);
606                     break;
607                 }
608                 case VBC_CMD_SET_MUTE: {
609                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_MUTE & send response");
610                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MUTE, 0);
611                     break;
612                 }
613                 case VBC_CMD_DEVICE_CTRL: {
614                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_DEVICE_CTRL");
615                     __vbc_write_response(vbpipe_fd, VBC_CMD_DEVICE_CTRL, 0);
616                     break;
617                 }
618                 case VBC_CMD_SET_SAMPLERATE: {
619                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_SAMPLERATE");
620
621                     AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_SAMPLERATE");
622                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_SAMPLERATE, 0);
623                     break;
624                 }
625                 default:
626                     AUDIO_LOG_WARN("Unknown command received : %d", read_head.cmd_type);
627                     break;
628             }
629         }
630     }
631     close(vbpipe_fd);
632     if (params)
633         free(params);
634
635     AUDIO_LOG_INFO("Exit vbc VOIP thread");
636
637     return (void*)0;
638 }
639
640 static audio_return_t __vbc_control_open(audio_hal_t *ah)
641 {
642     vbc_control_params_t *params = (vbc_control_params_t*)malloc(sizeof(vbc_control_params_t));
643     audio_return_t ret = AUDIO_RET_OK;
644     audio_return_t ret2 = AUDIO_RET_OK;
645
646     if (params == NULL) {
647          AUDIO_LOG_ERROR("vbc control param allocation failed");
648          return AUDIO_ERR_RESOURCE;
649     }
650
651     params->ah = ah;
652     AUDIO_LOG_INFO("vbc control thread create");
653     ret = vbc_thread_new(&ah->modem.vbc.voice_thread_handle, NULL, __vbc_control_voice_thread_run, (void*)params);
654     if (ret < 0) {
655         AUDIO_LOG_ERROR("vbc control thread create failed");
656         ret = AUDIO_ERR_RESOURCE;
657         return ret;
658     }
659
660     ret2 = vbc_thread_new(&ah->modem.vbc.voip_thread_handle, NULL, __vbc_control_voip_thread_run, (void*)params);
661     if (ret2 < 0) {
662         AUDIO_LOG_ERROR("vbc control VOIP thread create failed");
663         ret2 = AUDIO_ERR_RESOURCE;
664         return ret2;
665     }
666
667     return AUDIO_RET_OK;
668 }
669
670 void __vbc_control_close(audio_hal_t *ah)
671 {
672     /* TODO. Make sure we always receive CLOSE command from modem and then close pcm device */
673     ah->modem.vbc.exit_vbc_thread = 1;
674     close(ah->modem.vbc.vbpipe_fd);
675
676     pthread_cancel(ah->modem.vbc.voice_thread_handle);
677     pthread_cancel(ah->modem.vbc.voip_thread_handle);
678
679     return;
680 }
681
682 static void __audio_modem_create(audio_modem_t *modem, const char *num)
683 {
684     if (!atoi((char *)num)) {
685         AUDIO_LOG_ERROR("Unnormal modem num!");
686         return;
687     }
688
689     modem->num = atoi((char *)num);
690     /* check if we need to allocate  space for modem profile */
691     if (!modem->vbc_ctrl_pipe_info) {
692         modem->vbc_ctrl_pipe_info = malloc(modem->num * sizeof(vbc_ctrl_pipe_para_t));
693         if (modem->vbc_ctrl_pipe_info == NULL) {
694             AUDIO_LOG_ERROR("Unable to allocate modem profiles");
695             return;
696         }
697
698         /* initialise the new profile */
699         memset((void*)modem->vbc_ctrl_pipe_info, 0x00, modem->num * sizeof(vbc_ctrl_pipe_para_t));
700     }
701
702     AUDIO_LOG_DEBUG("peter: modem num is %d", modem->num);
703 }
704
705
706 static void __audio_modem_start_tag(void *data, const XML_Char *tag_name,
707         const XML_Char **attr)
708 {
709     audio_modem_t *modem = (audio_modem_t *)data;
710
711     /* Look at tags */
712     if (strcmp(tag_name, "audio") == 0) {
713         if (strcmp(attr[0], "device") == 0) {
714             AUDIO_LOG_INFO("The device name is %s", attr[1]);
715         } else {
716             AUDIO_LOG_ERROR("Unnamed audio!");
717         }
718     } else if (strcmp(tag_name, "modem") == 0) {
719         /* Obtain the modem num */
720         if (strcmp(attr[0], "num") == 0) {
721             AUDIO_LOG_DEBUG("The modem num is '%s'", attr[1]);
722             __audio_modem_create(modem, attr[1]);
723         } else {
724             AUDIO_LOG_ERROR("no modem num!");
725         }
726     } else if (strcmp(tag_name, "cp") == 0) {
727         if (modem->vbc_ctrl_pipe_info) {
728             /* Obtain the modem name  \pipe\vbc   filed */
729             if (strcmp(attr[0], "name") != 0) {
730                 AUDIO_LOG_ERROR("Unnamed modem!");
731                 goto attr_err;
732             }
733             if (strcmp(attr[2], "pipe") != 0) {
734                 AUDIO_LOG_ERROR("'%s' No pipe filed!", attr[0]);
735                 goto attr_err;
736             }
737             if (strcmp(attr[4], "vbchannel") != 0) {
738                 AUDIO_LOG_ERROR("'%s' No vbc filed!", attr[0]);
739                 goto attr_err;
740             }
741             AUDIO_LOG_DEBUG("cp name is '%s', pipe is '%s',vbc is '%s'", attr[1], attr[3],attr[5]);
742             if(strcmp(attr[1], "w") == 0)
743             {
744                 modem->vbc_ctrl_pipe_info->cp_type = CP_W;
745             }
746             else if(strcmp(attr[1], "t") == 0)
747             {
748                 modem->vbc_ctrl_pipe_info->cp_type = CP_TG;
749             }
750             memcpy((void*)modem->vbc_ctrl_pipe_info->s_vbc_ctrl_pipe_name,(void*)attr[3],strlen((char *)attr[3]));
751             modem->vbc_ctrl_pipe_info->channel_id = atoi((char *)attr[5]);
752             modem->vbc_ctrl_pipe_info++;
753
754         } else {
755             AUDIO_LOG_ERROR("error profile!");
756         }
757     } else if (strcmp(tag_name, "i2s_for_btcall") == 0) {
758         if (strcmp(attr[0], "index") == 0) {
759             AUDIO_LOG_DEBUG("The iis_for_btcall index is '%s'", attr[1]);
760             modem->i2s_bt.index = atoi((char *)attr[1]);
761         } else {
762             AUDIO_LOG_ERROR("no iis_ctl index for bt call!");
763         }
764
765         if (strcmp(attr[2], "switch") == 0) {
766             AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
767             if(strcmp(attr[3],"1") == 0)
768                 modem->i2s_bt.is_switch = true;
769             else if(strcmp(attr[3],"0") == 0)
770                 modem->i2s_bt.is_switch = false;
771         } else {
772             AUDIO_LOG_ERROR("no iis_ctl switch for bt call!");
773         }
774         if (strcmp(attr[4], "dst") == 0) {
775             AUDIO_LOG_DEBUG("The iis_for_btcall dst  is '%s'", attr[5]);
776             if (strcmp(attr[5], "internal") == 0)
777                 modem->i2s_bt.is_ext = 0;
778             else if (strcmp(attr[5], "external") == 0)
779                 modem->i2s_bt.is_ext = 1;
780         } else {
781             AUDIO_LOG_ERROR("no dst path for bt call!");
782         }
783     } else if (strcmp(tag_name, "i2s_for_extspeaker") == 0) {
784         if (strcmp(attr[0], "index") == 0) {
785             AUDIO_LOG_DEBUG("The i2s_for_extspeaker index is '%s'", attr[1]);
786             modem->i2s_extspk.index = atoi((char *)attr[1]);
787         } else {
788             AUDIO_LOG_ERROR("no iis_ctl index for extspk call!");
789         }
790         if (strcmp(attr[2], "switch") == 0) {
791             AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
792             if(strcmp(attr[3],"1") == 0)
793                 modem->i2s_extspk.is_switch = true;
794             else if(strcmp(attr[3],"0") == 0)
795                 modem->i2s_extspk.is_switch = false;
796         } else {
797             AUDIO_LOG_ERROR("no iis_ctl switch for extspk call!");
798         }
799         if (strcmp(attr[4], "dst") == 0) {
800             if (strcmp(attr[5], "external") == 0)
801                 modem->i2s_extspk.is_ext = 1;
802             else if(strcmp(attr[5], "internal") == 0)
803                 modem->i2s_extspk.is_ext = 0;
804
805             AUDIO_LOG_DEBUG("The i2s_for_extspeaker dst  is '%d'", modem->i2s_extspk.is_ext);
806
807         } else {
808             AUDIO_LOG_ERROR("no dst path for bt call!");
809         }
810     } else if (strcmp(tag_name, "debug") == 0) {  //parse debug info
811         if (strcmp(attr[0], "enable") == 0) {
812             if (strcmp(attr[1], "0") == 0) {
813                 modem->debug_info.enable = 0;
814             } else {
815                 modem->debug_info.enable = 1;
816             }
817         } else {
818             AUDIO_LOG_ERROR("no adaptable type for debug!");
819             goto attr_err;
820         }
821     } else if (strcmp(tag_name, "debuginfo") == 0) { //parse debug info
822         if (strcmp(attr[0], "sleepdeltatimegate") == 0) {
823             AUDIO_LOG_DEBUG("The sleepdeltatimegate is  '%s'", attr[1]);
824             modem->debug_info.sleeptime_gate=atoi((char *)attr[1]);
825         } else if (strcmp(attr[0], "pcmwritetimegate") == 0) {
826             AUDIO_LOG_DEBUG("The pcmwritetimegate is  '%s'", attr[1]);
827             modem->debug_info.pcmwritetime_gate=atoi((char *)attr[1]);
828         } else if (strcmp(attr[0], "lastthiswritetimegate") == 0) {
829             AUDIO_LOG_DEBUG("The lastthiswritetimegate is  '%s'", attr[1]);
830             modem->debug_info.lastthis_outwritetime_gate=atoi((char *)attr[1]);
831         } else {
832             AUDIO_LOG_ERROR("no adaptable info for debuginfo!");
833             goto attr_err;
834         }
835    }
836
837 attr_err:
838     return;
839 }
840 static void __audio_modem_end_tag(void *data, const XML_Char *tag_name)
841 {
842     return;
843 }
844
845 static audio_modem_t * __audio_modem_parse (void)
846 {
847     XML_Parser parser;
848     FILE *file;
849     int bytes_read;
850     void *buf;
851     audio_modem_t *modem = NULL;
852
853     modem = calloc(1, sizeof(audio_modem_t));
854
855     if(modem == NULL) {
856         goto err_alloc;
857     }
858     memset(modem, 0, sizeof(audio_modem_t));
859     modem->num = 0;
860     modem->vbc_ctrl_pipe_info = NULL;
861
862     file = fopen(AUDIO_XML_PATH, "r");
863     if (!file) {
864         AUDIO_LOG_ERROR("Failed to open %s", AUDIO_XML_PATH);
865         goto err_fopen;
866     }
867
868     parser = XML_ParserCreate(NULL);
869     if (!parser) {
870         AUDIO_LOG_ERROR("Failed to create XML parser");
871         goto err_parser_create;
872     }
873
874     XML_SetUserData(parser, modem);
875     XML_SetElementHandler(parser, __audio_modem_start_tag, __audio_modem_end_tag);
876
877     for (;;) {
878         buf = XML_GetBuffer(parser, BUF_SIZE);
879         if (buf == NULL)
880             goto err_parse;
881
882         bytes_read = fread(buf, 1, BUF_SIZE, file);
883         if (bytes_read < 0)
884             goto err_parse;
885
886         if (XML_ParseBuffer(parser, bytes_read, bytes_read == 0) == XML_STATUS_ERROR) {
887             AUDIO_LOG_ERROR("Error in codec PGA xml (%s)", AUDIO_XML_PATH);
888             goto err_parse;
889         }
890
891         if (bytes_read == 0)
892             break;
893     }
894     XML_ParserFree(parser);
895     fclose(file);
896     return modem;
897
898 err_parse:
899     XML_ParserFree(parser);
900 err_parser_create:
901     fclose(file);
902 err_fopen:
903     free(modem);
904 err_alloc:
905     modem = NULL;
906     return NULL;
907 }
908
909 audio_return_t _audio_modem_init(audio_hal_t *ah)
910 {
911     audio_return_t audio_ret = AUDIO_RET_OK;
912
913     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
914
915     ah->modem.vbc.vbpipe_count = 0;
916
917     /* Initialize vbc interface */
918     if ((audio_ret = __vbc_control_open(ah))) {
919         AUDIO_LOG_ERROR("__vbc_control_open failed");
920         goto exit;
921     }
922     ah->modem.vbc.voice_pcm_handle_p = NULL;
923     ah->modem.vbc.voice_pcm_handle_c = NULL;
924     ah->modem.samplerate = 0;
925     ah->modem.cp = __audio_modem_parse();
926     if (ah->modem.cp == NULL) {
927         AUDIO_LOG_ERROR("modem parse failed");
928         goto exit;
929     }
930     ah->modem.cp_type = ah->modem.cp->vbc_ctrl_pipe_info->cp_type;
931
932     /* This ctrl need to be set "0" always - SPRD */
933     _mixer_control_set_value(ah, PIN_SWITCH_BT_IIS_CON_SWITCH, 0);
934
935 exit:
936     return audio_ret;
937 }
938
939 audio_return_t _audio_modem_deinit(audio_hal_t *ah)
940 {
941     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
942
943     /* Close vbc interface */
944     __vbc_control_close(ah);
945
946     return AUDIO_RET_OK;
947 }
948