Fix SVACE defects (DEREF_OF_NULL.RET.ALLOC)
[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     int ret;
673     /* TODO. Make sure we always receive CLOSE command from modem and then close pcm device */
674     ah->modem.vbc.exit_vbc_thread = 1;
675     close(ah->modem.vbc.vbpipe_fd);
676
677     ret = pthread_cancel(ah->modem.vbc.voice_thread_handle);
678     AUDIO_LOG_INFO("cancel voice thread : %d", ret);
679     ret = pthread_cancel(ah->modem.vbc.voip_thread_handle);
680     AUDIO_LOG_INFO("cancel voip thread : %d", ret);
681
682     ret = pthread_join(ah->modem.vbc.voice_thread_handle, NULL);
683     AUDIO_LOG_INFO("join voice thread : %d", ret);
684     ret = pthread_join(ah->modem.vbc.voip_thread_handle, NULL);
685     AUDIO_LOG_INFO("join voip thread : %d", ret);
686
687     return;
688 }
689
690 static void __audio_modem_create(audio_modem_t *modem, const char *num)
691 {
692     if (!atoi((char *)num)) {
693         AUDIO_LOG_ERROR("Unnormal modem num!");
694         return;
695     }
696
697     modem->num = atoi((char *)num);
698     /* check if we need to allocate  space for modem profile */
699     if (!modem->vbc_ctrl_pipe_info) {
700         modem->vbc_ctrl_pipe_info = malloc(modem->num * sizeof(vbc_ctrl_pipe_para_t));
701         if (modem->vbc_ctrl_pipe_info == NULL) {
702             AUDIO_LOG_ERROR("Unable to allocate modem profiles");
703             return;
704         }
705
706         /* initialise the new profile */
707         memset((void*)modem->vbc_ctrl_pipe_info, 0x00, modem->num * sizeof(vbc_ctrl_pipe_para_t));
708     }
709
710     AUDIO_LOG_DEBUG("peter: modem num is %d", modem->num);
711 }
712
713
714 static void __audio_modem_start_tag(void *data, const XML_Char *tag_name,
715         const XML_Char **attr)
716 {
717     audio_modem_t *modem = (audio_modem_t *)data;
718
719     /* Look at tags */
720     if (strcmp(tag_name, "audio") == 0) {
721         if (strcmp(attr[0], "device") == 0) {
722             AUDIO_LOG_INFO("The device name is %s", attr[1]);
723         } else {
724             AUDIO_LOG_ERROR("Unnamed audio!");
725         }
726     } else if (strcmp(tag_name, "modem") == 0) {
727         /* Obtain the modem num */
728         if (strcmp(attr[0], "num") == 0) {
729             AUDIO_LOG_DEBUG("The modem num is '%s'", attr[1]);
730             __audio_modem_create(modem, attr[1]);
731         } else {
732             AUDIO_LOG_ERROR("no modem num!");
733         }
734     } else if (strcmp(tag_name, "cp") == 0) {
735         static int modem_index = 0;
736         vbc_ctrl_pipe_para_t *para = &modem->vbc_ctrl_pipe_info[modem_index];
737
738         if (modem->vbc_ctrl_pipe_info) {
739             /* Obtain the modem name  \pipe\vbc   filed */
740             if (strcmp(attr[0], "name") != 0) {
741                 AUDIO_LOG_ERROR("Unnamed modem!");
742                 goto attr_err;
743             }
744             if (strcmp(attr[2], "pipe") != 0) {
745                 AUDIO_LOG_ERROR("'%s' No pipe filed!", attr[0]);
746                 goto attr_err;
747             }
748             if (strcmp(attr[4], "vbchannel") != 0) {
749                 AUDIO_LOG_ERROR("'%s' No vbc filed!", attr[0]);
750                 goto attr_err;
751             }
752             AUDIO_LOG_DEBUG("cp name is '%s', pipe is '%s',vbc is '%s'", attr[1], attr[3],attr[5]);
753             if(strcmp(attr[1], "w") == 0)
754             {
755                 para->cp_type = CP_W;
756             }
757             else if(strcmp(attr[1], "t") == 0)
758             {
759                 para->cp_type = CP_TG;
760             }
761             memcpy((void*)para->s_vbc_ctrl_pipe_name,(void*)attr[3],strlen((char *)attr[3]));
762             para->channel_id = atoi((char *)attr[5]);
763             modem_index++;
764
765         } else {
766             AUDIO_LOG_ERROR("error profile!");
767         }
768     } else if (strcmp(tag_name, "i2s_for_btcall") == 0) {
769         if (strcmp(attr[0], "index") == 0) {
770             AUDIO_LOG_DEBUG("The iis_for_btcall index is '%s'", attr[1]);
771             modem->i2s_bt.index = atoi((char *)attr[1]);
772         } else {
773             AUDIO_LOG_ERROR("no iis_ctl index for bt call!");
774         }
775
776         if (strcmp(attr[2], "switch") == 0) {
777             AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
778             if(strcmp(attr[3],"1") == 0)
779                 modem->i2s_bt.is_switch = true;
780             else if(strcmp(attr[3],"0") == 0)
781                 modem->i2s_bt.is_switch = false;
782         } else {
783             AUDIO_LOG_ERROR("no iis_ctl switch for bt call!");
784         }
785         if (strcmp(attr[4], "dst") == 0) {
786             AUDIO_LOG_DEBUG("The iis_for_btcall dst  is '%s'", attr[5]);
787             if (strcmp(attr[5], "internal") == 0)
788                 modem->i2s_bt.is_ext = 0;
789             else if (strcmp(attr[5], "external") == 0)
790                 modem->i2s_bt.is_ext = 1;
791         } else {
792             AUDIO_LOG_ERROR("no dst path for bt call!");
793         }
794     } else if (strcmp(tag_name, "i2s_for_extspeaker") == 0) {
795         if (strcmp(attr[0], "index") == 0) {
796             AUDIO_LOG_DEBUG("The i2s_for_extspeaker index is '%s'", attr[1]);
797             modem->i2s_extspk.index = atoi((char *)attr[1]);
798         } else {
799             AUDIO_LOG_ERROR("no iis_ctl index for extspk call!");
800         }
801         if (strcmp(attr[2], "switch") == 0) {
802             AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
803             if(strcmp(attr[3],"1") == 0)
804                 modem->i2s_extspk.is_switch = true;
805             else if(strcmp(attr[3],"0") == 0)
806                 modem->i2s_extspk.is_switch = false;
807         } else {
808             AUDIO_LOG_ERROR("no iis_ctl switch for extspk call!");
809         }
810         if (strcmp(attr[4], "dst") == 0) {
811             if (strcmp(attr[5], "external") == 0)
812                 modem->i2s_extspk.is_ext = 1;
813             else if(strcmp(attr[5], "internal") == 0)
814                 modem->i2s_extspk.is_ext = 0;
815
816             AUDIO_LOG_DEBUG("The i2s_for_extspeaker dst  is '%d'", modem->i2s_extspk.is_ext);
817
818         } else {
819             AUDIO_LOG_ERROR("no dst path for bt call!");
820         }
821     } else if (strcmp(tag_name, "debug") == 0) {  //parse debug info
822         if (strcmp(attr[0], "enable") == 0) {
823             if (strcmp(attr[1], "0") == 0) {
824                 modem->debug_info.enable = 0;
825             } else {
826                 modem->debug_info.enable = 1;
827             }
828         } else {
829             AUDIO_LOG_ERROR("no adaptable type for debug!");
830             goto attr_err;
831         }
832     } else if (strcmp(tag_name, "debuginfo") == 0) { //parse debug info
833         if (strcmp(attr[0], "sleepdeltatimegate") == 0) {
834             AUDIO_LOG_DEBUG("The sleepdeltatimegate is  '%s'", attr[1]);
835             modem->debug_info.sleeptime_gate=atoi((char *)attr[1]);
836         } else if (strcmp(attr[0], "pcmwritetimegate") == 0) {
837             AUDIO_LOG_DEBUG("The pcmwritetimegate is  '%s'", attr[1]);
838             modem->debug_info.pcmwritetime_gate=atoi((char *)attr[1]);
839         } else if (strcmp(attr[0], "lastthiswritetimegate") == 0) {
840             AUDIO_LOG_DEBUG("The lastthiswritetimegate is  '%s'", attr[1]);
841             modem->debug_info.lastthis_outwritetime_gate=atoi((char *)attr[1]);
842         } else {
843             AUDIO_LOG_ERROR("no adaptable info for debuginfo!");
844             goto attr_err;
845         }
846    }
847
848 attr_err:
849     return;
850 }
851 static void __audio_modem_end_tag(void *data, const XML_Char *tag_name)
852 {
853     return;
854 }
855
856 static audio_modem_t * __audio_modem_parse (void)
857 {
858     XML_Parser parser;
859     FILE *file;
860     int bytes_read;
861     void *buf;
862     audio_modem_t *modem = NULL;
863
864     modem = calloc(1, sizeof(audio_modem_t));
865
866     if(modem == NULL) {
867         goto err_alloc;
868     }
869     memset(modem, 0, sizeof(audio_modem_t));
870     modem->num = 0;
871     modem->vbc_ctrl_pipe_info = NULL;
872
873     file = fopen(AUDIO_XML_PATH, "r");
874     if (!file) {
875         AUDIO_LOG_ERROR("Failed to open %s", AUDIO_XML_PATH);
876         goto err_fopen;
877     }
878
879     parser = XML_ParserCreate(NULL);
880     if (!parser) {
881         AUDIO_LOG_ERROR("Failed to create XML parser");
882         goto err_parser_create;
883     }
884
885     XML_SetUserData(parser, modem);
886     XML_SetElementHandler(parser, __audio_modem_start_tag, __audio_modem_end_tag);
887
888     for (;;) {
889         buf = XML_GetBuffer(parser, BUF_SIZE);
890         if (buf == NULL)
891             goto err_parse;
892
893         bytes_read = fread(buf, 1, BUF_SIZE, file);
894         if (bytes_read < 0)
895             goto err_parse;
896
897         if (XML_ParseBuffer(parser, bytes_read, bytes_read == 0) == XML_STATUS_ERROR) {
898             AUDIO_LOG_ERROR("Error in codec PGA xml (%s)", AUDIO_XML_PATH);
899             goto err_parse;
900         }
901
902         if (bytes_read == 0)
903             break;
904     }
905     XML_ParserFree(parser);
906     fclose(file);
907     return modem;
908
909 err_parse:
910     XML_ParserFree(parser);
911 err_parser_create:
912     fclose(file);
913 err_fopen:
914     free(modem);
915 err_alloc:
916     modem = NULL;
917     return NULL;
918 }
919
920 audio_return_t _audio_modem_init(audio_hal_t *ah)
921 {
922     audio_return_t audio_ret = AUDIO_RET_OK;
923
924     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
925
926     ah->modem.vbc.vbpipe_count = 0;
927
928     /* Initialize vbc interface */
929     if ((audio_ret = __vbc_control_open(ah))) {
930         AUDIO_LOG_ERROR("__vbc_control_open failed");
931         goto exit;
932     }
933     ah->modem.vbc.voice_pcm_handle_p = NULL;
934     ah->modem.vbc.voice_pcm_handle_c = NULL;
935     ah->modem.samplerate = 0;
936     ah->modem.cp = __audio_modem_parse();
937     if (ah->modem.cp == NULL) {
938         AUDIO_LOG_ERROR("modem parse failed");
939         goto exit;
940     }
941
942     /* FIXME : Use cp type of first modem explicitly */
943     ah->modem.cp_type = ah->modem.cp->vbc_ctrl_pipe_info[0].cp_type;
944
945     /* This ctrl need to be set "0" always - SPRD */
946     _mixer_control_set_value(ah, PIN_SWITCH_BT_IIS_CON_SWITCH, 0);
947
948 exit:
949     return audio_ret;
950 }
951
952 audio_return_t _audio_modem_deinit(audio_hal_t *ah)
953 {
954     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
955
956     /* Close vbc interface */
957     __vbc_control_close(ah);
958
959     return AUDIO_RET_OK;
960 }