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