Card and device arguments are added to pcm open API
[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         static int modem_index = 0;
728         vbc_ctrl_pipe_para_t *para = &modem->vbc_ctrl_pipe_info[modem_index];
729
730         if (modem->vbc_ctrl_pipe_info) {
731             /* Obtain the modem name  \pipe\vbc   filed */
732             if (strcmp(attr[0], "name") != 0) {
733                 AUDIO_LOG_ERROR("Unnamed modem!");
734                 goto attr_err;
735             }
736             if (strcmp(attr[2], "pipe") != 0) {
737                 AUDIO_LOG_ERROR("'%s' No pipe filed!", attr[0]);
738                 goto attr_err;
739             }
740             if (strcmp(attr[4], "vbchannel") != 0) {
741                 AUDIO_LOG_ERROR("'%s' No vbc filed!", attr[0]);
742                 goto attr_err;
743             }
744             AUDIO_LOG_DEBUG("cp name is '%s', pipe is '%s',vbc is '%s'", attr[1], attr[3],attr[5]);
745             if(strcmp(attr[1], "w") == 0)
746             {
747                 para->cp_type = CP_W;
748             }
749             else if(strcmp(attr[1], "t") == 0)
750             {
751                 para->cp_type = CP_TG;
752             }
753             memcpy((void*)para->s_vbc_ctrl_pipe_name,(void*)attr[3],strlen((char *)attr[3]));
754             para->channel_id = atoi((char *)attr[5]);
755             modem_index++;
756
757         } else {
758             AUDIO_LOG_ERROR("error profile!");
759         }
760     } else if (strcmp(tag_name, "i2s_for_btcall") == 0) {
761         if (strcmp(attr[0], "index") == 0) {
762             AUDIO_LOG_DEBUG("The iis_for_btcall index is '%s'", attr[1]);
763             modem->i2s_bt.index = atoi((char *)attr[1]);
764         } else {
765             AUDIO_LOG_ERROR("no iis_ctl index for bt call!");
766         }
767
768         if (strcmp(attr[2], "switch") == 0) {
769             AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
770             if(strcmp(attr[3],"1") == 0)
771                 modem->i2s_bt.is_switch = true;
772             else if(strcmp(attr[3],"0") == 0)
773                 modem->i2s_bt.is_switch = false;
774         } else {
775             AUDIO_LOG_ERROR("no iis_ctl switch for bt call!");
776         }
777         if (strcmp(attr[4], "dst") == 0) {
778             AUDIO_LOG_DEBUG("The iis_for_btcall dst  is '%s'", attr[5]);
779             if (strcmp(attr[5], "internal") == 0)
780                 modem->i2s_bt.is_ext = 0;
781             else if (strcmp(attr[5], "external") == 0)
782                 modem->i2s_bt.is_ext = 1;
783         } else {
784             AUDIO_LOG_ERROR("no dst path for bt call!");
785         }
786     } else if (strcmp(tag_name, "i2s_for_extspeaker") == 0) {
787         if (strcmp(attr[0], "index") == 0) {
788             AUDIO_LOG_DEBUG("The i2s_for_extspeaker index is '%s'", attr[1]);
789             modem->i2s_extspk.index = atoi((char *)attr[1]);
790         } else {
791             AUDIO_LOG_ERROR("no iis_ctl index for extspk call!");
792         }
793         if (strcmp(attr[2], "switch") == 0) {
794             AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
795             if(strcmp(attr[3],"1") == 0)
796                 modem->i2s_extspk.is_switch = true;
797             else if(strcmp(attr[3],"0") == 0)
798                 modem->i2s_extspk.is_switch = false;
799         } else {
800             AUDIO_LOG_ERROR("no iis_ctl switch for extspk call!");
801         }
802         if (strcmp(attr[4], "dst") == 0) {
803             if (strcmp(attr[5], "external") == 0)
804                 modem->i2s_extspk.is_ext = 1;
805             else if(strcmp(attr[5], "internal") == 0)
806                 modem->i2s_extspk.is_ext = 0;
807
808             AUDIO_LOG_DEBUG("The i2s_for_extspeaker dst  is '%d'", modem->i2s_extspk.is_ext);
809
810         } else {
811             AUDIO_LOG_ERROR("no dst path for bt call!");
812         }
813     } else if (strcmp(tag_name, "debug") == 0) {  //parse debug info
814         if (strcmp(attr[0], "enable") == 0) {
815             if (strcmp(attr[1], "0") == 0) {
816                 modem->debug_info.enable = 0;
817             } else {
818                 modem->debug_info.enable = 1;
819             }
820         } else {
821             AUDIO_LOG_ERROR("no adaptable type for debug!");
822             goto attr_err;
823         }
824     } else if (strcmp(tag_name, "debuginfo") == 0) { //parse debug info
825         if (strcmp(attr[0], "sleepdeltatimegate") == 0) {
826             AUDIO_LOG_DEBUG("The sleepdeltatimegate is  '%s'", attr[1]);
827             modem->debug_info.sleeptime_gate=atoi((char *)attr[1]);
828         } else if (strcmp(attr[0], "pcmwritetimegate") == 0) {
829             AUDIO_LOG_DEBUG("The pcmwritetimegate is  '%s'", attr[1]);
830             modem->debug_info.pcmwritetime_gate=atoi((char *)attr[1]);
831         } else if (strcmp(attr[0], "lastthiswritetimegate") == 0) {
832             AUDIO_LOG_DEBUG("The lastthiswritetimegate is  '%s'", attr[1]);
833             modem->debug_info.lastthis_outwritetime_gate=atoi((char *)attr[1]);
834         } else {
835             AUDIO_LOG_ERROR("no adaptable info for debuginfo!");
836             goto attr_err;
837         }
838    }
839
840 attr_err:
841     return;
842 }
843 static void __audio_modem_end_tag(void *data, const XML_Char *tag_name)
844 {
845     return;
846 }
847
848 static audio_modem_t * __audio_modem_parse (void)
849 {
850     XML_Parser parser;
851     FILE *file;
852     int bytes_read;
853     void *buf;
854     audio_modem_t *modem = NULL;
855
856     modem = calloc(1, sizeof(audio_modem_t));
857
858     if(modem == NULL) {
859         goto err_alloc;
860     }
861     memset(modem, 0, sizeof(audio_modem_t));
862     modem->num = 0;
863     modem->vbc_ctrl_pipe_info = NULL;
864
865     file = fopen(AUDIO_XML_PATH, "r");
866     if (!file) {
867         AUDIO_LOG_ERROR("Failed to open %s", AUDIO_XML_PATH);
868         goto err_fopen;
869     }
870
871     parser = XML_ParserCreate(NULL);
872     if (!parser) {
873         AUDIO_LOG_ERROR("Failed to create XML parser");
874         goto err_parser_create;
875     }
876
877     XML_SetUserData(parser, modem);
878     XML_SetElementHandler(parser, __audio_modem_start_tag, __audio_modem_end_tag);
879
880     for (;;) {
881         buf = XML_GetBuffer(parser, BUF_SIZE);
882         if (buf == NULL)
883             goto err_parse;
884
885         bytes_read = fread(buf, 1, BUF_SIZE, file);
886         if (bytes_read < 0)
887             goto err_parse;
888
889         if (XML_ParseBuffer(parser, bytes_read, bytes_read == 0) == XML_STATUS_ERROR) {
890             AUDIO_LOG_ERROR("Error in codec PGA xml (%s)", AUDIO_XML_PATH);
891             goto err_parse;
892         }
893
894         if (bytes_read == 0)
895             break;
896     }
897     XML_ParserFree(parser);
898     fclose(file);
899     return modem;
900
901 err_parse:
902     XML_ParserFree(parser);
903 err_parser_create:
904     fclose(file);
905 err_fopen:
906     free(modem);
907 err_alloc:
908     modem = NULL;
909     return NULL;
910 }
911
912 audio_return_t _audio_modem_init(audio_hal_t *ah)
913 {
914     audio_return_t audio_ret = AUDIO_RET_OK;
915
916     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
917
918     ah->modem.vbc.vbpipe_count = 0;
919
920     /* Initialize vbc interface */
921     if ((audio_ret = __vbc_control_open(ah))) {
922         AUDIO_LOG_ERROR("__vbc_control_open failed");
923         goto exit;
924     }
925     ah->modem.vbc.voice_pcm_handle_p = NULL;
926     ah->modem.vbc.voice_pcm_handle_c = NULL;
927     ah->modem.samplerate = 0;
928     ah->modem.cp = __audio_modem_parse();
929     if (ah->modem.cp == NULL) {
930         AUDIO_LOG_ERROR("modem parse failed");
931         goto exit;
932     }
933
934     /* FIXME : Use cp type of first modem explicitly */
935     ah->modem.cp_type = ah->modem.cp->vbc_ctrl_pipe_info[0].cp_type;
936
937     /* This ctrl need to be set "0" always - SPRD */
938     _mixer_control_set_value(ah, PIN_SWITCH_BT_IIS_CON_SWITCH, 0);
939
940 exit:
941     return audio_ret;
942 }
943
944 audio_return_t _audio_modem_deinit(audio_hal_t *ah)
945 {
946     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
947
948     /* Close vbc interface */
949     __vbc_control_close(ah);
950
951     return AUDIO_RET_OK;
952 }