0154e26044b909cf740bbe311a6c2bdad03652f3
[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 __voice_read_samplerate(int fd, set_samplerate_t *paras_ptr)
186 {
187     int ret = 0;
188     if (fd > 0 && paras_ptr != NULL) {
189     ret = __read_nonblock(fd, paras_ptr, sizeof(set_samplerate_t));
190         if (ret != sizeof(set_samplerate_t))
191             ret = -1;
192     }
193     AUDIO_LOG_INFO("Return value of read sample rate = %d", ret);
194     return ret;
195
196 }
197
198 static int __voice_get_samplerate(audio_hal_t *ah, int fd)
199 {
200     set_samplerate_t samplerate_paras;
201
202     memset(&samplerate_paras, 0, sizeof(set_samplerate_t));
203     __voice_read_samplerate(fd, &samplerate_paras);
204
205     if (samplerate_paras.samplerate <= 0)
206         ah->modem.samplerate = 8000;
207     else
208         ah->modem.samplerate = samplerate_paras.samplerate;
209
210     return 0;
211 }
212
213 static int __vbc_write_response(int fd, unsigned int cmd, uint32_t paras_size)
214 {
215     int ret = 0;
216     vbc_parameters_head write_head;
217
218     memset(&write_head, 0, sizeof(vbc_parameters_head));
219     memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
220     write_head.cmd_type = cmd + 1;
221     write_head.paras_size = paras_size;
222
223     ret = __write_nonblock(fd, (void*)&write_head, sizeof(vbc_parameters_head));
224     if (ret < 0)
225         AUDIO_LOG_ERROR("write failed");
226     else
227         AUDIO_LOG_DEBUG("write success for VBC_CMD_[%s]", vbc_cmd_str_arry[cmd]);
228
229     return 0;
230 }
231
232 #define FM_IIS                                      0x10
233 static void i2s_pin_mux_sel(audio_hal_t *ah, int type)
234 {
235     audio_return_t ret = AUDIO_RET_OK;
236     audio_modem_t *modem;
237
238     if (!ah) {
239         AUDIO_LOG_ERROR("ah is null");
240         return;
241     }
242
243     AUDIO_LOG_INFO("type is %d",type);
244     modem = ah->modem.cp;
245
246     if (type == FM_IIS) {
247         _audio_mixer_control_set_value(ah,
248                     PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_VBC_ID);
249         return;
250     }
251     if (type == 0) {
252        if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
253             if(modem->i2s_bt.is_ext) {
254                 if(modem->i2s_bt.is_switch) {
255                     ret = _audio_mixer_control_set_value(ah,
256                             PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP0_ID);
257                 }
258             } else {
259                 if(modem->i2s_bt.is_switch) {
260                     int value = 0;
261                     _audio_mixer_control_get_value (ah, PIN_SWITCH_IIS0_SYS_SEL, &value);
262                     if(value == PIN_SWITCH_IIS0_CP0_ID) {
263                         ret = _audio_mixer_control_set_value(ah,
264                                 PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_AP_ID);
265                     }
266                 }
267                 if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
268                     if(modem->i2s_bt.is_switch) {
269                         ret = _audio_mixer_control_set_value(ah,
270                                 PIN_SWITCH_BT_IIS_SYS_SEL, PIN_SWITCH_BT_IIS_CP0_IIS0_ID);
271                     }
272                 }
273             }
274         }
275     } else if (type == 1) {
276         if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
277             if(modem->i2s_bt.is_ext) {
278                 if(modem->i2s_bt.is_switch) {
279                     ret = _audio_mixer_control_set_value(ah,
280                             PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP1_ID);
281                 }
282             } else {
283                 if(modem->i2s_bt.is_switch) {
284                     int value = 0;
285                     _audio_mixer_control_get_value (ah, PIN_SWITCH_IIS0_SYS_SEL, &value);
286                     if(value == PIN_SWITCH_IIS0_CP1_ID) {
287                         ret = _audio_mixer_control_set_value(ah,
288                                 PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP2_ID);
289                     }
290                 }
291                 if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
292                     if(modem->i2s_bt.is_switch) {
293                         ret = _audio_mixer_control_set_value(ah,
294                                 PIN_SWITCH_BT_IIS_SYS_SEL, PIN_SWITCH_BT_IIS_CP1_IIS0_ID);
295                     }
296                 }
297             }
298         }
299     } else {
300         AUDIO_LOG_ERROR("invalid type");
301         return;
302     }
303     if (ret)
304         AUDIO_LOG_ERROR("error(0x%x)", ret);
305
306     return;
307 }
308
309 static void *__vbc_control_voice_thread_run(void *args)
310 {
311     audio_return_t audio_ret = AUDIO_RET_OK;
312     vbc_parameters_head read_head;
313     vbc_parameters_head write_head;
314     int exit_thread = 0; /* make exit variable global if required to gracefully exit */
315     int vbpipe_fd;
316     vbc_control_params_t *params = (vbc_control_params_t*)args;
317     if (params == NULL) {
318         return (void*)AUDIO_ERR_PARAMETER;
319     }
320     audio_hal_t *ah = params->ah;
321     fd_set fds_read;
322     struct timeval timeout = {5,0};
323
324     memset(&read_head, 0, sizeof(vbc_parameters_head));
325     memset(&write_head, 0, sizeof(vbc_parameters_head));
326
327     memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
328     write_head.cmd_type = VBC_CMD_NONE;
329     write_head.paras_size = 0;
330
331     AUDIO_LOG_INFO("[voice] vbc control VOICE thread run");
332
333 again:
334     /* open vbpipe device for vb parameter interface between ap and cp */
335     vbpipe_fd = open(VBPIPE_DEVICE, O_RDWR);
336     if (vbpipe_fd < 0) {
337         if (errno == EINTR)
338             goto again;
339         AUDIO_LOG_ERROR("[voice] vbpipe open failed: %s", strerror(errno));
340         return (void*)AUDIO_ERR_IOCTL;
341     }
342     ah->modem.vbc.vbpipe_fd = vbpipe_fd;
343
344     if (fcntl(vbpipe_fd, F_SETFL, O_NONBLOCK) < 0) {
345         AUDIO_LOG_DEBUG("[voice] vbpipe_fd(%d) fcntl error.", vbpipe_fd);
346     }
347
348     AUDIO_LOG_INFO("[voice] %s opened. vbc start loop", VBPIPE_DEVICE);
349
350     /* start loop */
351     while (!exit_thread) {
352         int ret;
353         timeout.tv_sec = 10;
354         timeout.tv_usec = 0;
355
356         /* read command received from cp */
357         FD_ZERO(&fds_read);
358         FD_SET(vbpipe_fd, &fds_read);
359
360         ret = select(vbpipe_fd+1, &fds_read, NULL, NULL, &timeout);
361         if (ret < 0) {
362             ALOGE("voice:select error %d", errno);
363
364             continue;
365         }
366
367         ret = __read_nonblock(vbpipe_fd, &read_head, sizeof(vbc_parameters_head));
368         if (ret < 0) {
369
370             continue;
371         }
372
373         AUDIO_LOG_DEBUG("[voice] Received %d bytes. data: %s, cmd_type: %d", ret, read_head.tag, read_head.cmd_type);
374
375         if (!memcmp(&read_head.tag[0], VBC_CMD_TAG, 3)) {
376             switch (read_head.cmd_type) {
377                 case VBC_CMD_PCM_OPEN: {
378                     open_pcm_t open_pcm_params;
379                     uint32_t paras_size = ((ah->modem.cp->i2s_bt.is_switch << 8) | (ah->modem.cp->i2s_bt.index << 0)
380                                         | (ah->modem.cp->i2s_extspk.is_switch << 9) | (ah->modem.cp->i2s_extspk.index << 4));
381
382                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_PCM_OPEN");
383
384                     ah->modem.is_connected = 1;
385                     audio_ret = _audio_do_route_voicecall(ah, ah->device.init_call_devices, ah->device.num_of_call_devices);
386                     if (AUDIO_IS_ERROR(audio_ret)) {
387                         AUDIO_LOG_WARN("set voicecall route return 0x%x", audio_ret);
388                         if (audio_ret == AUDIO_ERR_INVALID_STATE) {
389                             /* send signal and wait for the ucm setting,
390                              * it might an incoming call scenario */
391                             _audio_comm_send_message(ah, SIGNAL_ROUTING_FOR_VOICE_CALL, 1);
392                             COND_TIMEDWAIT(ah->device.device_cond, ah->device.device_lock, "device_cond", TIMEOUT_SEC);
393                             MUTEX_UNLOCK(ah->device.device_lock, "device_lock");
394                         }
395                     }
396
397                     memset(&open_pcm_params, 0, sizeof(open_pcm_t));
398                     ret = __read_nonblock(vbpipe_fd, &open_pcm_params, sizeof(open_pcm_t));
399                     if (ret < 0)
400                         AUDIO_LOG_ERROR("read failed");
401                     else
402                         ah->modem.sim_id = open_pcm_params.sim_card;
403
404                     if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
405                         if (ah->modem.cp_type == CP_TG)
406                             i2s_pin_mux_sel(ah, 1);
407                         else if(ah->modem.cp_type == CP_W)
408                             i2s_pin_mux_sel(ah, 0);
409                     }
410
411                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_PCM_OPEN");
412                     __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_OPEN, paras_size);
413                     break;
414                 }
415
416                 case VBC_CMD_PCM_CLOSE: {
417                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_PCM_CLOSE");
418
419                     ah->modem.samplerate = 0;
420                     ah->modem.is_connected = 0;
421
422                     /* send signal and wait for the reset ucm */
423                     _audio_comm_send_message(ah, SIGNAL_ROUTING_FOR_VOICE_CALL, 0);
424                     COND_TIMEDWAIT(ah->device.device_cond, ah->device.device_lock, "device_cond", TIMEOUT_SEC);
425                     MUTEX_UNLOCK(ah->device.device_lock, "device_lock");
426
427                     _audio_mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_ARM_CHANNELID);
428
429                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_PCM_CLOSE");
430                     __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
431                     break;
432                 }
433
434                 case VBC_CMD_RESP_CLOSE: {
435                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_RESP_CLOSE & send response");
436                     ret = __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
437                     break;
438                 }
439
440                 case VBC_CMD_SET_MODE: {
441                     char dummy[52];
442                     memset(dummy, 0, sizeof(dummy));
443                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_MODE");
444
445                     if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
446                         if (ah->modem.cp_type == CP_TG)
447                             i2s_pin_mux_sel(ah, 1);
448                         else if(ah->modem.cp_type == CP_W)
449                             i2s_pin_mux_sel(ah, 0);
450                     }
451                     /* To do: set mode params : __vbc_set_mode_params(ah, vbpipe_fd); */
452
453                     __read_nonblock(vbpipe_fd, dummy, sizeof(dummy));
454                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_MODE");
455                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MODE, 0);
456                     break;
457                 }
458                 case VBC_CMD_SET_GAIN: {
459                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_GAIN");
460
461                     /* To do: set gain params : __vbc_set_gain_params(ah, vbpipe_fd); */
462
463                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_GAIN");
464                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_GAIN, 0);
465                     break;
466                 }
467                 case VBC_CMD_SWITCH_CTRL: {
468                     switch_ctrl_t switch_ctrl_params;
469
470                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_SWITCH_CTRL");
471
472                     memset(&switch_ctrl_params,0,sizeof(switch_ctrl_t));
473                     ret = __read_nonblock(vbpipe_fd, &switch_ctrl_params, sizeof(switch_ctrl_t));
474                     if (ret < 0)
475                         AUDIO_LOG_ERROR("read failed");
476                     else
477                         AUDIO_LOG_INFO("is_switch:%d", switch_ctrl_params.is_switch);
478
479                     _audio_mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_TD_CHANNELID);
480
481                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_GAIN");
482                     __vbc_write_response(vbpipe_fd, VBC_CMD_SWITCH_CTRL, 0);
483                    break;
484                 }
485                 case VBC_CMD_SET_MUTE: {
486                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_MUTE");
487                     break;
488                 }
489                 case VBC_CMD_DEVICE_CTRL: {
490                     char dummy[64];
491                     memset(dummy, 0, sizeof(dummy));
492                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_DEVICE_CTRL");
493
494                     /* To do: set device ctrl params :__vbc_set_device_ctrl_params(ah, vbpipe_fd); */
495                     __read_nonblock(vbpipe_fd, dummy, sizeof(dummy));
496
497                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_DEVICE_CTRL");
498                     __vbc_write_response(vbpipe_fd, VBC_CMD_DEVICE_CTRL, 0);
499
500                     break;
501                 }
502                 case VBC_CMD_SET_SAMPLERATE: {
503                     AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_SAMPLERATE");
504
505 //                    _voice_pcm_close(ah, 0);
506 //
507 //                    __voice_get_samplerate(ah, vbpipe_fd);
508 //
509 //                    ret = _voice_pcm_open(ah);
510 //                    if (ret < 0) {
511 //                        _voice_pcm_close(ah, 1);
512 //                        break;
513 //                    }
514
515                     AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_SAMPLERATE");
516                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_SAMPLERATE, 0);
517                     break;
518                 }
519                 default:
520                     AUDIO_LOG_WARN("[voice] Unknown command received : %d", read_head.cmd_type);
521                     break;
522             }
523         }
524     }
525     if (params)
526         free(params);
527
528     close(vbpipe_fd);
529
530     AUDIO_LOG_INFO("Exit vbc VOICE thread");
531
532     return (void*)0;
533 }
534
535 static void *__vbc_control_voip_thread_run(void *args)
536 {
537     open_pcm_t open_pcm_params;
538     vbc_parameters_head read_head;
539     vbc_parameters_head write_head;
540     int exit_thread = 0; /* make exit variable global if required to gracefully exit */
541     int vbpipe_fd;
542     vbc_control_params_t *params = (vbc_control_params_t*)args;
543     if (params == NULL) {
544         return (void*)AUDIO_ERR_PARAMETER;
545     }
546     audio_hal_t *ah = params->ah;
547     fd_set fds_read;
548
549     struct timeval timeout = {5,0};
550
551     memset(&read_head, 0, sizeof(vbc_parameters_head));
552     memset(&write_head, 0, sizeof(vbc_parameters_head));
553
554     memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
555     write_head.cmd_type = VBC_CMD_NONE;
556     write_head.paras_size = 0;
557
558     AUDIO_LOG_INFO("[voip] vbc control VOIP thread run");
559
560 again:
561     /* open vbpipe device for vb parameter interface between ap and cp */
562     vbpipe_fd = open(VBPIPE_VOIP_DEVICE, O_RDWR);
563     if (vbpipe_fd < 0) {
564         if (errno == EINTR)
565             goto again;
566         AUDIO_LOG_ERROR("[voip] vbpipe open failed: %s", strerror(errno));
567         return (void*)0;
568     }
569     ah->modem.vbc.vbpipe_voip_fd = vbpipe_fd;
570
571     if (fcntl(vbpipe_fd, F_SETFL, O_NONBLOCK) < 0) {
572         AUDIO_LOG_DEBUG("[voip] vbpipe_fd(%d) fcntl error.", vbpipe_fd);
573     }
574
575     AUDIO_LOG_INFO("[voip] %s opened. vbc start loop", VBPIPE_VOIP_DEVICE);
576
577     /* start loop */
578     while (!exit_thread) {
579         int ret;
580         timeout.tv_sec = 5;;
581         timeout.tv_usec = 0;
582
583         /* read command received from cp */
584
585         FD_ZERO(&fds_read);
586         FD_SET(vbpipe_fd, &fds_read);
587
588         ret = select(vbpipe_fd+1, &fds_read, NULL, NULL, &timeout);
589         if (ret < 0) {
590             ALOGE("[voip] select error %d", errno);
591             continue;
592         }
593
594         ret = __read_nonblock(vbpipe_fd, &read_head, sizeof(vbc_parameters_head));
595         if (ret < 0) {
596             continue;
597         }
598
599         AUDIO_LOG_DEBUG("[voip] Received %d bytes. data: %s, cmd_type: %d", ret, read_head.tag, read_head.cmd_type);
600
601         if (!memcmp(&read_head.tag[0], VBC_CMD_TAG, 3)) {
602             switch (read_head.cmd_type) {
603                 case VBC_CMD_PCM_OPEN: {
604                     uint32_t paras_size = ((ah->modem.cp->i2s_bt.is_switch << 8) | (ah->modem.cp->i2s_bt.index << 0)
605                                         | (ah->modem.cp->i2s_extspk.is_switch << 9) | (ah->modem.cp->i2s_extspk.index << 4));
606
607                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_PCM_OPEN");
608
609                     memset(&open_pcm_params, 0, sizeof(open_pcm_t));
610                     ret = __read_nonblock(vbpipe_fd, &open_pcm_params, sizeof(open_pcm_t));
611                     if (ret < 0)
612                         AUDIO_LOG_ERROR("read failed");
613
614                     AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_PCM_OPEN");
615                     __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_OPEN, paras_size);
616                     break;
617                 }
618                 case VBC_CMD_PCM_CLOSE: {
619                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_PCM_CLOSE & send response");
620
621                     __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
622
623                     break;
624                 }
625                 case VBC_CMD_RESP_CLOSE: {
626                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_RESP_CLOSE & send response");
627
628                     ret = __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
629                     break;
630                 }
631                 case VBC_CMD_SET_MODE: {
632                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_MODE");
633
634                     if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
635                         if (ah->modem.cp_type == CP_TG)
636                             i2s_pin_mux_sel(ah, 1);
637                         else if(ah->modem.cp_type == CP_W)
638                             i2s_pin_mux_sel(ah, 0);
639                     }
640                     /* To do: set mode params : __vbc_set_mode_params(ah, vbpipe_fd); */
641                     AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_MODE");
642                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MODE, 0);
643                     break;
644                 }
645                 case VBC_CMD_SET_GAIN: {
646                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_GAIN");
647
648                     /* To do: set gain params : __vbc_set_gain_params(ah, vbpipe_fd); */
649                     AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_GAIN");
650                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_GAIN, 0);
651                     break;
652                 }
653                 case VBC_CMD_SWITCH_CTRL: {
654                     switch_ctrl_t switch_ctrl_params;
655
656                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_SWITCH_CTRL");
657
658                     memset(&switch_ctrl_params, 0, sizeof(switch_ctrl_t));
659                     ret = __read_nonblock(vbpipe_fd, &switch_ctrl_params, sizeof(switch_ctrl_t));
660                     if (ret < 0)
661                         AUDIO_LOG_ERROR("read failed");
662                     else
663                         AUDIO_LOG_INFO("is_switch:%d", switch_ctrl_params.is_switch);
664
665                     _audio_mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_TD_CHANNELID);
666
667                     AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SWITCH_CTRL");
668                     __vbc_write_response(vbpipe_fd, VBC_CMD_SWITCH_CTRL, 0);
669                     break;
670                 }
671                 case VBC_CMD_SET_MUTE: {
672                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_MUTE & send response");
673                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MUTE, 0);
674                     break;
675                 }
676                 case VBC_CMD_DEVICE_CTRL: {
677                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_DEVICE_CTRL");
678                     __vbc_write_response(vbpipe_fd, VBC_CMD_DEVICE_CTRL, 0);
679                     break;
680                 }
681                 case VBC_CMD_SET_SAMPLERATE: {
682                     AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_SAMPLERATE");
683
684 //                    _voice_pcm_close(ah, 0);
685 //                    __voice_get_samplerate(ah, vbpipe_fd);
686 //
687 //                    ret = _voice_pcm_open(ah);
688 //                    if (ret < 0) {
689 //                        _voice_pcm_close(ah, 1);
690 //                        break;
691 //                    }
692                     AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_SAMPLERATE");
693                     __vbc_write_response(vbpipe_fd, VBC_CMD_SET_SAMPLERATE, 0);
694                     break;
695                 }
696                 default:
697                     AUDIO_LOG_WARN("Unknown command received : %d", read_head.cmd_type);
698                     break;
699             }
700         }
701     }
702     close(vbpipe_fd);
703     if (params)
704         free(params);
705
706     AUDIO_LOG_INFO("Exit vbc VOIP thread");
707
708     return (void*)0;
709 }
710
711 static audio_return_t __vbc_control_open(audio_hal_t *ah)
712 {
713     vbc_control_params_t *params = (vbc_control_params_t*)malloc(sizeof(vbc_control_params_t));
714     audio_return_t ret = AUDIO_RET_OK;
715     audio_return_t ret2 = AUDIO_RET_OK;
716
717     if (params == NULL) {
718          AUDIO_LOG_ERROR("vbc control param allocation failed");
719          return AUDIO_ERR_RESOURCE;
720     }
721
722     params->ah = ah;
723     AUDIO_LOG_INFO("vbc control thread create");
724     ret = vbc_thread_new(&ah->modem.vbc.voice_thread_handle, NULL, __vbc_control_voice_thread_run, (void*)params);
725     if (ret < 0) {
726         AUDIO_LOG_ERROR("vbc control thread create failed");
727         ret = AUDIO_ERR_RESOURCE;
728         return ret;
729     }
730
731     ret2 = vbc_thread_new(&ah->modem.vbc.voip_thread_handle, NULL, __vbc_control_voip_thread_run, (void*)params);
732     if (ret2 < 0) {
733         AUDIO_LOG_ERROR("vbc control VOIP thread create failed");
734         ret2 = AUDIO_ERR_RESOURCE;
735         return ret2;
736     }
737
738     return AUDIO_RET_OK;
739 }
740
741 static audio_return_t __vbc_control_close(audio_hal_t *ah)
742 {
743     /* TODO. Make sure we always receive CLOSE command from modem and then close pcm device */
744     ah->modem.vbc.exit_vbc_thread = 1;
745     close(ah->modem.vbc.vbpipe_fd);
746
747     pthread_cancel(ah->modem.vbc.voice_thread_handle);
748     pthread_cancel(ah->modem.vbc.voip_thread_handle);
749
750     return AUDIO_RET_OK;
751 }
752
753 static vbc_ctrl_pipe_para_t *__audio_modem_create(audio_modem_t  *modem, const char *num)
754 {
755     if (!atoi((char *)num)) {
756         AUDIO_LOG_ERROR("Unnormal modem num!");
757         return NULL;
758     }
759
760     modem->num = atoi((char *)num);
761     /* check if we need to allocate  space for modem profile */
762     if(!modem->vbc_ctrl_pipe_info) {
763         modem->vbc_ctrl_pipe_info = malloc(modem->num * sizeof(vbc_ctrl_pipe_para_t));
764
765         if (modem->vbc_ctrl_pipe_info == NULL) {
766             AUDIO_LOG_ERROR("Unable to allocate modem profiles");
767             return NULL;
768         } else {
769             /* initialise the new profile */
770             memset((void*)modem->vbc_ctrl_pipe_info, 0x00, modem->num * sizeof(vbc_ctrl_pipe_para_t));
771         }
772     }
773
774     AUDIO_LOG_DEBUG("peter: modem num is %d",modem->num);
775     /* return the profile just added */
776     return modem->vbc_ctrl_pipe_info;
777 }
778
779
780 static void __audio_modem_start_tag(void *data, const XML_Char *tag_name,
781         const XML_Char **attr)
782 {
783     struct modem_config_parse_state *state = data;
784     audio_modem_t *modem = state->modem_info;
785
786     /* Look at tags */
787     if (strcmp(tag_name, "audio") == 0) {
788         if (strcmp(attr[0], "device") == 0) {
789             AUDIO_LOG_INFO("The device name is %s", attr[1]);
790         } else {
791             AUDIO_LOG_ERROR("Unnamed audio!");
792         }
793     } else if (strcmp(tag_name, "modem") == 0) {
794         /* Obtain the modem num */
795         if (strcmp(attr[0], "num") == 0) {
796             AUDIO_LOG_DEBUG("The modem num is '%s'", attr[1]);
797             state->vbc_ctrl_pipe_info = __audio_modem_create(modem, attr[1]);
798         } else {
799             AUDIO_LOG_ERROR("no modem num!");
800         }
801     } else if (strcmp(tag_name, "cp") == 0) {
802         if (state->vbc_ctrl_pipe_info) {
803             /* Obtain the modem name  \pipe\vbc   filed */
804             if (strcmp(attr[0], "name") != 0) {
805                 AUDIO_LOG_ERROR("Unnamed modem!");
806                 goto attr_err;
807             }
808             if (strcmp(attr[2], "pipe") != 0) {
809                 AUDIO_LOG_ERROR("'%s' No pipe filed!", attr[0]);
810                 goto attr_err;
811             }
812             if (strcmp(attr[4], "vbchannel") != 0) {
813                 AUDIO_LOG_ERROR("'%s' No vbc filed!", attr[0]);
814                 goto attr_err;
815             }
816             AUDIO_LOG_DEBUG("cp name is '%s', pipe is '%s',vbc is '%s'", attr[1], attr[3],attr[5]);
817             if(strcmp(attr[1], "w") == 0)
818             {
819                 state->vbc_ctrl_pipe_info->cp_type = CP_W;
820             }
821             else if(strcmp(attr[1], "t") == 0)
822             {
823                 state->vbc_ctrl_pipe_info->cp_type = CP_TG;
824             }
825             memcpy((void*)state->vbc_ctrl_pipe_info->s_vbc_ctrl_pipe_name,(void*)attr[3],strlen((char *)attr[3]));
826             state->vbc_ctrl_pipe_info->channel_id = atoi((char *)attr[5]);
827             state->vbc_ctrl_pipe_info++;
828
829         } else {
830             AUDIO_LOG_ERROR("error profile!");
831         }
832     } else if (strcmp(tag_name, "i2s_for_btcall") == 0) {
833         if (strcmp(attr[0], "index") == 0) {
834             AUDIO_LOG_DEBUG("The iis_for_btcall index is '%s'", attr[1]);
835             modem->i2s_bt.index = atoi((char *)attr[1]);
836         } else {
837             AUDIO_LOG_ERROR("no iis_ctl index for bt call!");
838         }
839
840         if (strcmp(attr[2], "switch") == 0) {
841             AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
842             if(strcmp(attr[3],"1") == 0)
843                 modem->i2s_bt.is_switch = true;
844             else if(strcmp(attr[3],"0") == 0)
845                 modem->i2s_bt.is_switch = false;
846         } else {
847             AUDIO_LOG_ERROR("no iis_ctl switch for bt call!");
848         }
849         if (strcmp(attr[4], "dst") == 0) {
850             AUDIO_LOG_DEBUG("The iis_for_btcall dst  is '%s'", attr[5]);
851             if (strcmp(attr[5], "internal") == 0)
852                 modem->i2s_bt.is_ext = 0;
853             else if (strcmp(attr[5], "external") == 0)
854                 modem->i2s_bt.is_ext = 1;
855         } else {
856             AUDIO_LOG_ERROR("no dst path for bt call!");
857         }
858     } else if (strcmp(tag_name, "i2s_for_extspeaker") == 0) {
859         if (strcmp(attr[0], "index") == 0) {
860             AUDIO_LOG_DEBUG("The i2s_for_extspeaker index is '%s'", attr[1]);
861             modem->i2s_extspk.index = atoi((char *)attr[1]);
862         } else {
863             AUDIO_LOG_ERROR("no iis_ctl index for extspk call!");
864         }
865         if (strcmp(attr[2], "switch") == 0) {
866             AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
867             if(strcmp(attr[3],"1") == 0)
868                 modem->i2s_extspk.is_switch = true;
869             else if(strcmp(attr[3],"0") == 0)
870                 modem->i2s_extspk.is_switch = false;
871         } else {
872             AUDIO_LOG_ERROR("no iis_ctl switch for extspk call!");
873         }
874         if (strcmp(attr[4], "dst") == 0) {
875             if (strcmp(attr[5], "external") == 0)
876                 modem->i2s_extspk.is_ext = 1;
877             else if(strcmp(attr[5], "internal") == 0)
878                 modem->i2s_extspk.is_ext = 0;
879
880             AUDIO_LOG_DEBUG("The i2s_for_extspeaker dst  is '%d'", modem->i2s_extspk.is_ext);
881
882         } else {
883             AUDIO_LOG_ERROR("no dst path for bt call!");
884         }
885     } else if (strcmp(tag_name, "debug") == 0) {  //parse debug info
886         if (strcmp(attr[0], "enable") == 0) {
887             if (strcmp(attr[1], "0") == 0) {
888                 modem->debug_info.enable = 0;
889             } else {
890                 modem->debug_info.enable = 1;
891             }
892         } else {
893             AUDIO_LOG_ERROR("no adaptable type for debug!");
894             goto attr_err;
895         }
896     } else if (strcmp(tag_name, "debuginfo") == 0) { //parse debug info
897         if (strcmp(attr[0], "sleepdeltatimegate") == 0) {
898             AUDIO_LOG_DEBUG("The sleepdeltatimegate is  '%s'", attr[1]);
899             modem->debug_info.sleeptime_gate=atoi((char *)attr[1]);
900         } else if (strcmp(attr[0], "pcmwritetimegate") == 0) {
901             AUDIO_LOG_DEBUG("The pcmwritetimegate is  '%s'", attr[1]);
902             modem->debug_info.pcmwritetime_gate=atoi((char *)attr[1]);
903         } else if (strcmp(attr[0], "lastthiswritetimegate") == 0) {
904             AUDIO_LOG_DEBUG("The lastthiswritetimegate is  '%s'", attr[1]);
905             modem->debug_info.lastthis_outwritetime_gate=atoi((char *)attr[1]);
906         } else {
907             AUDIO_LOG_ERROR("no adaptable info for debuginfo!");
908             goto attr_err;
909         }
910    }
911
912 attr_err:
913     return;
914 }
915 static void __audio_modem_end_tag(void *data, const XML_Char *tag_name)
916 {
917     return;
918 }
919
920 struct config_parse_state {
921     audio_modem_t *modem_info;
922  /* To do : pga control setting*/
923  /* struct audio_pga *pga; */
924  /* struct pga_profile *profile; */
925  /* struct pga_attribute_item *attribute_item; */
926 };
927 static audio_modem_t * __audio_modem_parse (void)
928 {
929     struct config_parse_state state;
930     XML_Parser parser;
931     FILE *file;
932     int bytes_read;
933     void *buf;
934     audio_modem_t *modem = NULL;
935
936     modem = calloc(1, sizeof(audio_modem_t));
937
938     if(modem == NULL) {
939         goto err_alloc;
940     }
941     memset(modem, 0, sizeof(audio_modem_t));
942     modem->num = 0;
943     modem->vbc_ctrl_pipe_info = NULL;
944
945     file = fopen(AUDIO_XML_PATH, "r");
946     if (!file) {
947         AUDIO_LOG_ERROR("Failed to open %s", AUDIO_XML_PATH);
948         goto err_fopen;
949     }
950
951     parser = XML_ParserCreate(NULL);
952     if (!parser) {
953         AUDIO_LOG_ERROR("Failed to create XML parser");
954         goto err_parser_create;
955     }
956
957     memset(&state, 0, sizeof(state));
958     state.modem_info = modem;
959     XML_SetUserData(parser, &state);
960     XML_SetElementHandler(parser, __audio_modem_start_tag, __audio_modem_end_tag);
961
962     for (;;) {
963         buf = XML_GetBuffer(parser, BUF_SIZE);
964         if (buf == NULL)
965             goto err_parse;
966
967         bytes_read = fread(buf, 1, BUF_SIZE, file);
968         if (bytes_read < 0)
969             goto err_parse;
970
971         if (XML_ParseBuffer(parser, bytes_read, bytes_read == 0) == XML_STATUS_ERROR) {
972             AUDIO_LOG_ERROR("Error in codec PGA xml (%s)", AUDIO_XML_PATH);
973             goto err_parse;
974         }
975
976         if (bytes_read == 0)
977             break;
978     }
979     XML_ParserFree(parser);
980     fclose(file);
981     return modem;
982
983 err_parse:
984     XML_ParserFree(parser);
985 err_parser_create:
986     fclose(file);
987 err_fopen:
988     free(modem);
989 err_alloc:
990     modem = NULL;
991     return NULL;
992 }
993
994 audio_return_t _audio_modem_init(audio_hal_t *ah)
995 {
996     audio_return_t audio_ret = AUDIO_RET_OK;
997
998     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
999
1000     ah->modem.vbc.vbpipe_count = 0;
1001
1002     /* Initialize vbc interface */
1003     audio_ret = __vbc_control_open(ah);
1004     if (AUDIO_IS_ERROR(audio_ret)) {
1005         AUDIO_LOG_ERROR("__vbc_control_open failed");
1006         goto exit;
1007     }
1008     ah->modem.vbc.voice_pcm_handle_p = NULL;
1009     ah->modem.vbc.voice_pcm_handle_c = NULL;
1010     ah->modem.samplerate = 0;
1011     ah->modem.cp = __audio_modem_parse();
1012     if (ah->modem.cp == NULL) {
1013         AUDIO_LOG_ERROR("modem parse failed");
1014         goto exit;
1015     }
1016     ah->modem.cp_type = ah->modem.cp->vbc_ctrl_pipe_info->cp_type;
1017
1018     /* This ctrl need to be set "0" always - SPRD */
1019     _audio_mixer_control_set_value(ah, PIN_SWITCH_BT_IIS_CON_SWITCH, 0);
1020
1021 exit:
1022     return audio_ret;
1023 }
1024
1025 audio_return_t _audio_modem_deinit(audio_hal_t *ah)
1026 {
1027     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
1028
1029     /* Close vbc interface */
1030     __vbc_control_close(ah);
1031
1032     return AUDIO_RET_OK;
1033 }
1034