| b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | /*audio_if.c*/ |
| 2 | #include <fcntl.h> |
| 3 | #include <unistd.h> |
| 4 | #include <libubox/blobmsg_json.h> |
| 5 | #include "libubus.h" |
| 6 | #include <string.h> |
| 7 | #include "audio_if.h" |
| 8 | #include "audio_if_parameter.h" |
| 9 | #include "audio_if_types.h" |
| 10 | #include "audio_if_ubus.h" |
| 11 | #include "audio_if_api.h" |
| 12 | #include "audio_if_audio_hw_mrvl.h" |
| 13 | |
| 14 | #include "utlEventHandler.h" |
| 15 | #include "udev_monitor.h" |
| 16 | |
| 17 | /************************************************* |
| 18 | * Defines |
| 19 | **************************************************/ |
| 20 | |
| 21 | /************************************************* |
| 22 | * Prototype |
| 23 | **************************************************/ |
| 24 | extern void AudioIf_uBusFdAdd(int fd); |
| 25 | extern void AudioIf_uBusUloopRun(void); |
| 26 | extern int AudioIf_uBusSubscribeEvents(char isSubscribe); |
| 27 | |
| 28 | extern void* audio_hal_install(void); //returning ahw_dev handler |
| 29 | extern void audio_hal_uninstall(void); |
| 30 | extern int aud_hal_set_hw_device(int audio_device); |
| 31 | extern void aud_hal_select_output_device(void); |
| 32 | |
| 33 | extern int vcm_ctl_read(void *buffer, unsigned int bytes); |
| 34 | /************************************************** |
| 35 | * Global variables |
| 36 | **************************************************/ |
| 37 | AUDIO_IF_DATABASE audioIfDb; |
| 38 | struct uloop_timeout timeout; |
| 39 | audioIfReqDb_t audioIfReqDb; |
| 40 | audioIfUbusDb_t audioIfUbusDb; |
| 41 | |
| 42 | audio_hw_device_t *ahw_dev_ubus; |
| 43 | struct mrvl_audio_device *mrvl_ahw_dev_ubus; |
| 44 | pthread_mutex_t req_data_mutex; |
| 45 | pthread_mutex_t AudioIf_mutex; |
| 46 | pthread_mutex_t AudioIf_Ubus_mutex_play; |
| 47 | pthread_mutex_t AudioIf_Ubus_mutex_rec; |
| 48 | |
| 49 | /* Global variables for headset detection result */ |
| 50 | #if defined(CODEC_PM812) |
| 51 | //#define HS_STATUS_DEV "/sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hs_status" |
| 52 | //#define HK_STATUS_DEV "/sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hk_status" |
| 53 | #define HS_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hs_status" |
| 54 | #define HK_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hk_status" |
| 55 | |
| 56 | #elif defined(CODEC_ALC5616) |
| 57 | |
| 58 | #ifdef TARGET_mmp_asr1901_KSTR901 |
| 59 | #define HS_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-001b/alc5616-headset/hs_status" |
| 60 | #define HK_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-001b/alc5616-headset/hk_status" |
| 61 | #else |
| 62 | #define HS_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.0/i2c-0/0-001b/alc5616-headset/hs_status" |
| 63 | #define HK_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.0/i2c-0/0-001b/alc5616-headset/hk_status" |
| 64 | #endif |
| 65 | |
| 66 | #else |
| 67 | //#define HS_STATUS_DEV "/sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hs_status" |
| 68 | //#define HK_STATUS_DEV "/sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hk_status" |
| 69 | #define HS_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hs_status" |
| 70 | #define HK_STATUS_DEV "/sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hk_status" |
| 71 | |
| 72 | #endif |
| 73 | |
| 74 | #define IOCTL_DEV "/dev/audiostub_ctl" |
| 75 | |
| 76 | /* Global variables for UTL messages */ |
| 77 | #define AudioIf_UEVENT_BUFFER_SIZE 1024 |
| 78 | static pthread_t AudioIf_utid; |
| 79 | static int AudioIf_ueventfd = -1; |
| 80 | static utlEventHandlerId_T AudioIf_ueventHandler; |
| 81 | static char AudioIf_ueventBuffer[AudioIf_UEVENT_BUFFER_SIZE]; |
| 82 | |
| 83 | /* Global variables for DTMF Detection */ |
| 84 | #define DTMFCODEID "dtmfcode" |
| 85 | #define DTMFCODE_NOTIFICATION_NAME "audioif.dtmfcode" |
| 86 | |
| 87 | static struct blob_buf DTMFCodeNotify_blob; |
| 88 | static void AudioIf_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj) |
| 89 | { |
| 90 | UNUSEDPARAM(ctx); |
| 91 | UNUSEDPARAM(obj); |
| 92 | AUDIO_IF_LOGD("%s, Subscribers active: %s", __FUNCTION__, obj->has_subscribers?"true":"false"); |
| 93 | } |
| 94 | |
| 95 | static struct ubus_object_type DTMFCode_object_type; |
| 96 | static struct ubus_object DTMFCode_notify_obj = { |
| 97 | .name = DTMFCODE_NOTIFICATION_NAME, |
| 98 | .type = &DTMFCode_object_type, |
| 99 | .subscribe_cb = AudioIf_subscribe_cb, |
| 100 | }; |
| 101 | |
| 102 | /*----------------voice status----------------*/ |
| 103 | extern unsigned int voice_status;/* bit1:record; bit0:playback; */ |
| 104 | unsigned int old_voice_status = 0;/* bit1:record; bit0:playback; */ |
| 105 | |
| 106 | /* Global variables for voice status */ |
| 107 | #define VOICESTATUSID "voicestatus" |
| 108 | #define VOICESTATUS_NOTIFICATION_NAME "audioif.voicestatus" |
| 109 | |
| 110 | static struct blob_buf VoiceStatusNotify_blob; |
| 111 | static void AudioIf_VoiceStatus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj) |
| 112 | { |
| 113 | UNUSEDPARAM(ctx); |
| 114 | UNUSEDPARAM(obj); |
| 115 | AUDIO_IF_LOGD("%s, Subscribers active: %s", __FUNCTION__, obj->has_subscribers?"true":"false"); |
| 116 | } |
| 117 | |
| 118 | static struct ubus_object_type VoiceStatus_object_type; |
| 119 | static struct ubus_object VoiceStatus_notify_obj = { |
| 120 | .name = VOICESTATUS_NOTIFICATION_NAME, |
| 121 | .type = &VoiceStatus_object_type, |
| 122 | .subscribe_cb = AudioIf_VoiceStatus_subscribe_cb, |
| 123 | }; |
| 124 | |
| 125 | /*******************************************************************************\ |
| 126 | * Function: AudioIf_ReadFromDevice |
| 127 | * Description: This function handle events in ubus context that were sent |
| 128 | from audio-HAL through pipe audioIfDb.pipes_fd[1]. |
| 129 | * Returns: void |
| 130 | \*******************************************************************************/ |
| 131 | void AudioIf_ReadFromDevice(int fd) |
| 132 | { |
| 133 | |
| 134 | // here do: |
| 135 | // 1. read from audioHAL: (dataLen = read(fd, inbuff, maxControlTransfer) |
| 136 | // 2. chheck if dataLen!= 0 |
| 137 | // 3. handle the data and process the command |
| 138 | // see reference code for thi function in MBIM |
| 139 | int dataLen, i; |
| 140 | char inBuf[AUDIO_IF_AUDIO_STUB_CTRL_BUFF_MAX_LEN]; |
| 141 | |
| 142 | memset(inBuf, 0, sizeof(inBuf)); |
| 143 | //Read from audio_if internal pipe driver |
| 144 | if ( (dataLen = read(fd, inBuf, sizeof(inBuf))) < 0 ) |
| 145 | { |
| 146 | AUDIO_IF_LOGE("Error while reading from AUDIO_IF device return\n"); |
| 147 | return; |
| 148 | } |
| 149 | |
| 150 | AUDIO_IF_LOGD("%s: read %d bytes from socket %d", __FUNCTION__, dataLen, fd); |
| 151 | |
| 152 | if (dataLen == 0) |
| 153 | { |
| 154 | AUDIO_IF_LOGD("Read Zero\n"); |
| 155 | return; |
| 156 | } |
| 157 | |
| 158 | //Dump the data been read |
| 159 | for(i = 0; i < dataLen; i++) |
| 160 | { |
| 161 | AUDIO_IF_LOGD("%s: [%d]=0x%x\n", __FUNCTION__, i, inBuf[i]); |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | /*******************************************************************************\ |
| 166 | * Function: AudioIf_BroadcastDTMFCode |
| 167 | * Description: Broadcast DTMF code using uBus notification |
| 168 | * Returns: 0: success, -1: fail |
| 169 | \*******************************************************************************/ |
| 170 | int AudioIf_BroadcastDTMFCode(unsigned short Code) |
| 171 | { |
| 172 | int ret =0; |
| 173 | |
| 174 | blob_buf_init(&DTMFCodeNotify_blob, 0); |
| 175 | blobmsg_add_u32(&DTMFCodeNotify_blob, DTMFCODEID, Code); |
| 176 | |
| 177 | ret = ubus_notify(audioIfUbusDb.ctx, &DTMFCode_notify_obj, DTMFCode_notify_obj.name, DTMFCodeNotify_blob.head, -1); |
| 178 | |
| 179 | return ret; |
| 180 | } |
| 181 | |
| 182 | /*******************************************************************************\ |
| 183 | * Function: AudioIf_MainLoopTask |
| 184 | * Description: This function is a preparation for audio HAL usage in case |
| 185 | audio HAL wants to send indications/responses toward audio_if |
| 186 | ubus-clients. |
| 187 | the function that handle the input from audio HAL in ubus context is |
| 188 | AudioIf_ReadFromDevice() |
| 189 | * Returns: void |
| 190 | \*******************************************************************************/ |
| 191 | void *AudioIf_MainLoopTask(void *arg) |
| 192 | { |
| 193 | UNUSEDPARAM(arg); |
| 194 | |
| 195 | int dataLen, i; |
| 196 | int ret = 0; |
| 197 | int sock_fd; |
| 198 | char inBuf[AUDIO_IF_AUDIO_STUB_CTRL_BUFF_MAX_LEN]; |
| 199 | |
| 200 | struct ATCMsg *p_atc_msg = (struct ATCMsg *)inBuf; |
| 201 | unsigned short *p_ecall_msg; |
| 202 | char cmd_code, sub_cmd, cmd_type; |
| 203 | unsigned short DTMF_code; |
| 204 | unsigned short eCall_cmd; |
| 205 | |
| 206 | sock_fd = audioIfDb.pipes_fd[1]; |
| 207 | |
| 208 | memset(inBuf, 0, sizeof(inBuf)); |
| 209 | AUDIO_IF_LOGD("%s: returned socket fd = %d\n", __FUNCTION__, sock_fd); |
| 210 | /*This is a thread that listen to audioHAL input into audio_if*/ |
| 211 | while (TRUE) { |
| 212 | AUDIO_IF_LOGD("%s: thread alive\n", __FUNCTION__); |
| 213 | //reset received buffer |
| 214 | memset(inBuf, 0, sizeof(inBuf)); |
| 215 | |
| 216 | if ( (dataLen = vcm_ctl_read(inBuf, sizeof(inBuf))) < 0 ) { |
| 217 | AUDIO_IF_LOGE("%s Error while reading from audio control device return\n", __FUNCTION__); |
| 218 | sleep(2); |
| 219 | continue; |
| 220 | } |
| 221 | |
| 222 | if (dataLen == 0) { |
| 223 | AUDIO_IF_LOGD("%s Read Zero\n", __FUNCTION__); |
| 224 | sleep(2); |
| 225 | continue; |
| 226 | } |
| 227 | |
| 228 | //Dump the data been read |
| 229 | for(i = 0; i < dataLen; i++) |
| 230 | { |
| 231 | AUDIO_IF_LOGD("%s: [%d]=0x%x\n", __FUNCTION__, i, inBuf[i]); |
| 232 | } |
| 233 | |
| 234 | //Get header info |
| 235 | cmd_code = p_atc_msg->header.cmd_code; // audio is fixed as 9 |
| 236 | sub_cmd = p_atc_msg->header.sub_cmd; // 0xa: eCall, 0xc: DTMF detection |
| 237 | cmd_type = p_atc_msg->header.cmd_type; // 1: confirm, 2: indication |
| 238 | |
| 239 | //Check whether it is audio cmd |
| 240 | if(cmd_code != ATC_AUDIO_CMD) { |
| 241 | AUDIO_IF_LOGD("Warning: it is not audio command(%d), cmd_code=%d", ATC_AUDIO_CMD, cmd_code); |
| 242 | sleep(2); |
| 243 | continue; |
| 244 | } |
| 245 | |
| 246 | switch (sub_cmd) { |
| 247 | case ATC_ECALLCTL: |
| 248 | //Check whether it is eCall indication |
| 249 | if(cmd_type != CMD_TYPE_INDICATION) { |
| 250 | AUDIO_IF_LOGD("Warning: it is not eCall indication(%d), cmd_type=%d", CMD_TYPE_INDICATION, cmd_type); |
| 251 | sleep(2); |
| 252 | continue; |
| 253 | } |
| 254 | |
| 255 | p_ecall_msg = (unsigned short *) &(p_atc_msg->eCallPayload); |
| 256 | eCall_cmd = *(unsigned short *)p_ecall_msg; |
| 257 | switch(eCall_cmd){ |
| 258 | case ACIPC_CODE_AUDIO_VCM_ECALL_DATA_GET_CNF: |
| 259 | audio_if_ecall_data_status_response(p_ecall_msg); |
| 260 | break; |
| 261 | |
| 262 | case ACIPC_CODE_AUDIO_VCM_ECALL_VOICE_GET_CNF: |
| 263 | audio_if_ecall_voice_status_response(p_ecall_msg); |
| 264 | break; |
| 265 | |
| 266 | default: |
| 267 | AUDIO_IF_LOGD("Unsupport eCall_cmd: 0x%x", eCall_cmd); |
| 268 | break; |
| 269 | } |
| 270 | |
| 271 | break; |
| 272 | |
| 273 | case ATC_DTMFDETECTIONCTL: |
| 274 | DTMF_code = p_atc_msg->DTMF_code; |
| 275 | AUDIO_IF_LOGD("Got DTMF code: 0x%x", DTMF_code); |
| 276 | ret = AudioIf_BroadcastDTMFCode(DTMF_code); |
| 277 | if(ret != 0) |
| 278 | AUDIO_IF_LOGD("%s failed to broadcast DTMF code onto uBus, ret=0x%x", __FUNCTION__, ret); |
| 279 | break; |
| 280 | |
| 281 | default: |
| 282 | AUDIO_IF_LOGD("Unsupport sub_cmd: 0x%x", sub_cmd); |
| 283 | break; |
| 284 | } |
| 285 | |
| 286 | AUDIO_IF_LOGD("%s: wrote %d bytes to socket %d\n", __FUNCTION__, dataLen, sock_fd); |
| 287 | ret = write(sock_fd, inBuf, dataLen); |
| 288 | }; |
| 289 | } |
| 290 | |
| 291 | int AudioIf_BroadcastVoiceStatus(unsigned int status) |
| 292 | { |
| 293 | int ret =0; |
| 294 | |
| 295 | blob_buf_init(&VoiceStatusNotify_blob, 0); |
| 296 | blobmsg_add_u32(&VoiceStatusNotify_blob, VOICESTATUSID, status); |
| 297 | |
| 298 | ret = ubus_notify(audioIfUbusDb.ctx, &VoiceStatus_notify_obj, VoiceStatus_notify_obj.name, VoiceStatusNotify_blob.head, -1); |
| 299 | |
| 300 | return ret; |
| 301 | } |
| 302 | |
| 303 | void AudioIf_report_voice_status(void) |
| 304 | { |
| 305 | if (old_voice_status != voice_status) { |
| 306 | AUDIO_IF_LOGD("%s:Got Voice status: %d", __FUNCTION__, voice_status); |
| 307 | AudioIf_BroadcastVoiceStatus(voice_status); |
| 308 | old_voice_status = voice_status; |
| 309 | } |
| 310 | |
| 311 | return; |
| 312 | } |
| 313 | /***************************************************************************************\ |
| 314 | * Function: AudioIf_HanldeHeadsetEvent |
| 315 | * Description: This function handles headset driver reports: |
| 316 | * /sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hs_status |
| 317 | * /sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset/hk_status |
| 318 | * |
| 319 | * |
| 320 | * Jack types which can be reported.(Defined in Jack.h) |
| 321 | * enum snd_jack_types { |
| 322 | * SND_JACK_HEADPHONE = 0x0001, |
| 323 | * SND_JACK_MICROPHONE = 0x0002, |
| 324 | * SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE, |
| 325 | * SND_JACK_LINEOUT = 0x0004, |
| 326 | * SND_JACK_MECHANICAL = 0x0008, |
| 327 | * SND_JACK_VIDEOOUT = 0x0010, |
| 328 | * SND_JACK_AVOUT = SND_JACK_LINEOUT | SND_JACK_VIDEOOUT, |
| 329 | * SND_JACK_LINEIN = 0x0020, |
| 330 | * SND_JACK_BTN_0 = 0x4000, |
| 331 | * SND_JACK_BTN_1 = 0x2000, |
| 332 | * SND_JACK_BTN_2 = 0x1000, |
| 333 | * SND_JACK_BTN_3 = 0x0800, |
| 334 | * SND_JACK_BTN_4 = 0x0400, |
| 335 | * SND_JACK_BTN_5 = 0x0200, |
| 336 | * }; |
| 337 | * Returns: void |
| 338 | \***************************************************************************************/ |
| 339 | static void AudioIf_HanldeHeadsetEvent(void) |
| 340 | { |
| 341 | int mDev, hk_status, hs_status = 0; |
| 342 | char value[32]; //written as '%d' |
| 343 | |
| 344 | /************************************************************************************* |
| 345 | * Set correct audio device in boot up phase. |
| 346 | * ----------------------------------------------------------------------------------- |
| 347 | * |
| 348 | * In boot up phase, headset driver(88pm800-headset.c) will report headset status, using UEvent. |
| 349 | * But, audio_if is started later than headset driver, and miss this UEvent. |
| 350 | * |
| 351 | * So, audio_if should check the files(HK_STATUS_DEV & HS_STATUS_DEV) created by headset driver |
| 352 | * and set the correct audio device. |
| 353 | *************************************************************************************/ |
| 354 | |
| 355 | /* Open HK_STATUS_DEV */ |
| 356 | mDev = open(HK_STATUS_DEV, O_RDONLY); |
| 357 | if (mDev < 0) |
| 358 | { |
| 359 | AUDIO_IF_LOGE("%s: Failed to open %s!err=%s\n", __FUNCTION__, HK_STATUS_DEV,strerror(errno)); |
| 360 | } |
| 361 | else |
| 362 | { |
| 363 | read(mDev, &value, sizeof(value)); |
| 364 | close(mDev); |
| 365 | hk_status = atoi(value); |
| 366 | AUDIO_IF_LOGD("%s: Success to open %s, value=%s, hk_status=%d\n", __FUNCTION__, HK_STATUS_DEV, value, hk_status); |
| 367 | } |
| 368 | |
| 369 | /* Open HS_STATUS_DEV */ |
| 370 | mDev = open(HS_STATUS_DEV, O_RDONLY); |
| 371 | if (mDev < 0) |
| 372 | { |
| 373 | AUDIO_IF_LOGE("%s: Failed to open %s!err=%s\n", __FUNCTION__, HS_STATUS_DEV,strerror(errno)); |
| 374 | } |
| 375 | else |
| 376 | { |
| 377 | read(mDev, &value, sizeof(value)); |
| 378 | close(mDev); |
| 379 | hs_status = atoi(value); |
| 380 | AUDIO_IF_LOGD("%s: Success to open %s, value=%s, hs_status=%d\n", __FUNCTION__, HS_STATUS_DEV, value, hs_status); |
| 381 | } |
| 382 | |
| 383 | /************************************************************************************* |
| 384 | * Set correct audio device according to hs_status |
| 385 | * ----------------------------------------------------------------------------------- |
| 386 | * |
| 387 | * hs_status=0, hk_status=0 ==>no headset |
| 388 | * hs_status=1, hk_status=0 ==>headphone(without mic) |
| 389 | * hs_status=3, hk_status=0 ==>headset(with mic) |
| 390 | *************************************************************************************/ |
| 391 | switch (hs_status) |
| 392 | { |
| 393 | case 1: |
| 394 | #ifdef TARGET_mmp_asr1901_KSTR901 |
| 395 | //For test |
| 396 | aud_hal_set_hw_device((int)AUDIO_DEVICE_OUT_WIRED_HEADSET); |
| 397 | AUDIO_IF_LOGD("%s: Set audio device = AUDIO_DEVICE_OUT_WIRED_HEADSET \n", __FUNCTION__); |
| 398 | #else |
| 399 | aud_hal_set_hw_device((int)AUDIO_DEVICE_OUT_WIRED_HEADPHONE); |
| 400 | AUDIO_IF_LOGD("%s: Set audio device = AUDIO_DEVICE_OUT_WIRED_HEADPHONE \n", __FUNCTION__); |
| 401 | #endif |
| 402 | break; |
| 403 | |
| 404 | case 3: |
| 405 | aud_hal_set_hw_device((int)AUDIO_DEVICE_OUT_WIRED_HEADSET); |
| 406 | AUDIO_IF_LOGD("%s: Set audio device = AUDIO_DEVICE_OUT_WIRED_HEADSET \n", __FUNCTION__); |
| 407 | break; |
| 408 | |
| 409 | case 0: |
| 410 | default: |
| 411 | /* Align with default audio device in CP audio */ |
| 412 | aud_hal_set_hw_device((int)AUDIO_DEVICE_OUT_EARPIECE); |
| 413 | AUDIO_IF_LOGD("%s: Set audio device = AUDIO_DEVICE_OUT_EARPIECE \n", __FUNCTION__); |
| 414 | break; |
| 415 | } |
| 416 | } |
| 417 | |
| 418 | |
| 419 | /***************************************************************************************\ |
| 420 | * Function: AudioIf_HandleDataFromUevent |
| 421 | * Description: This function handles Uevent |
| 422 | * For PM812 |
| 423 | * len=430, online@/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset |
| 424 | * len=424, add@/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset |
| 425 | * len=430, remove@/devices/soc.0/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-0030/88pm800-headset |
| 426 | * For ALC5616 |
| 427 | * len=270, add@/devices/soc.0/d4000000.apb/pxa2xx-i2c.0/i2c-0/0-001b/alc5616-headset |
| 428 | * len=276, remove@/devices/soc.0/d4000000.apb/pxa2xx-i2c.0/i2c-0/0-001b/alc5616-headset |
| 429 | * Returns: void |
| 430 | \***************************************************************************************/ |
| 431 | static int AudioIf_HandleDataFromUevent(char * buf, int buflen) |
| 432 | { |
| 433 | const char * device; |
| 434 | const char * action; |
| 435 | |
| 436 | AUDIO_IF_LOGD("%s: len=%d, %s", __FUNCTION__, buflen, buf); |
| 437 | device = search_key("DRIVER", buf, buflen); |
| 438 | action = search_key("ACTION", buf, buflen); |
| 439 | |
| 440 | #if defined(CODEC_PM812) |
| 441 | if(device && (!strcmp(device, "88pm800-headset"))) |
| 442 | #elif defined(CODEC_ALC5616) |
| 443 | if(device && (!strcmp(device, "alc5616-headset"))) |
| 444 | #else |
| 445 | if(0) |
| 446 | #endif |
| 447 | { |
| 448 | AUDIO_IF_LOGD("%s: device=%s, action=%s!", __FUNCTION__, device, action); |
| 449 | |
| 450 | if(action && ( (!strcmp(action, "add"))||(!strcmp(action, "remove")))) |
| 451 | { //headset plugged or unplugged |
| 452 | AudioIf_HanldeHeadsetEvent(); |
| 453 | |
| 454 | //Make new audio device take effect, no matter it is in call or not |
| 455 | pthread_mutex_lock(&AudioIf_mutex); |
| 456 | aud_hal_select_output_device(); |
| 457 | pthread_mutex_unlock(&AudioIf_mutex); |
| 458 | } |
| 459 | } |
| 460 | |
| 461 | return 0; |
| 462 | } |
| 463 | |
| 464 | |
| 465 | static utlReturnCode_T AudioIf_ReceiveDataFromUevent(const utlEventHandlerType_T handler_type, |
| 466 | const utlEventHandlerType_T event_type, |
| 467 | const int fd, |
| 468 | const utlRelativeTime_P2c period_p, |
| 469 | void *arg_p) |
| 470 | { |
| 471 | UNUSEDPARAM(handler_type) |
| 472 | UNUSEDPARAM(event_type) |
| 473 | UNUSEDPARAM(period_p) |
| 474 | UNUSEDPARAM(arg_p) |
| 475 | |
| 476 | int ret; |
| 477 | |
| 478 | ret = read(fd, AudioIf_ueventBuffer, AudioIf_UEVENT_BUFFER_SIZE); |
| 479 | if(ret > 0) |
| 480 | AudioIf_HandleDataFromUevent(AudioIf_ueventBuffer, ret); |
| 481 | |
| 482 | return utlSUCCESS; |
| 483 | } |
| 484 | |
| 485 | |
| 486 | static int AudioIf_OpenEventLink(void) |
| 487 | { |
| 488 | while(AudioIf_ueventfd < 0) |
| 489 | { |
| 490 | AudioIf_ueventfd = open_uevent_socket(); |
| 491 | if(AudioIf_ueventfd < 0) |
| 492 | AUDIO_IF_LOGD("open EventLink error:%s\n", strerror(errno)); |
| 493 | } |
| 494 | |
| 495 | AudioIf_ueventHandler = utlSetFdEventHandler(utlEVENT_HANDLER_TYPE_READ, utlEVENT_HANDLER_PRIORITY_MEDIUM, AudioIf_ueventfd, AudioIf_ReceiveDataFromUevent, NULL); |
| 496 | |
| 497 | return AudioIf_ueventfd; |
| 498 | } |
| 499 | |
| 500 | |
| 501 | static void AudioIf_CloseEventLink(void) |
| 502 | { |
| 503 | utlDeleteEventHandler(AudioIf_ueventHandler); |
| 504 | close(AudioIf_ueventfd); |
| 505 | AudioIf_ueventfd = -1; |
| 506 | } |
| 507 | |
| 508 | |
| 509 | /*******************************************************************************\ |
| 510 | * Function: AudioIf_UTLTask |
| 511 | * Description: This function is the main task for UTL message. |
| 512 | * It will firstly set correct audio device; |
| 513 | * AudioIf_ReceiveDataFromUevent() will handle the input from UTL socket. |
| 514 | * Returns: void |
| 515 | \*******************************************************************************/ |
| 516 | static void AudioIf_UTLTask(void) |
| 517 | { |
| 518 | AudioIf_HanldeHeadsetEvent(); |
| 519 | |
| 520 | AudioIf_OpenEventLink(); |
| 521 | if (utlEventLoop(true) != utlSUCCESS) |
| 522 | { |
| 523 | AUDIO_IF_LOGE("Event loop reports failure!!!"); |
| 524 | AudioIf_CloseEventLink(); |
| 525 | return; |
| 526 | } |
| 527 | } |
| 528 | |
| 529 | |
| 530 | /*******************************************************************************\ |
| 531 | * Function: main |
| 532 | \*******************************************************************************/ |
| 533 | int main(int argc, char **argv) |
| 534 | { |
| 535 | UNUSEDPARAM(argc); |
| 536 | UNUSEDPARAM(argv); |
| 537 | |
| 538 | int ioctl_fd, err; |
| 539 | |
| 540 | /* Set log tag for logcat */ |
| 541 | set_service_log_tag("audio_if"); |
| 542 | |
| 543 | /* Wait until audiostub ready */ |
| 544 | while(1) |
| 545 | { |
| 546 | ioctl_fd = open(IOCTL_DEV, O_RDONLY); |
| 547 | if(ioctl_fd < 0) |
| 548 | { |
| 549 | err = errno; |
| 550 | AUDIO_IF_LOGE("Fail to open %s:%s\n", IOCTL_DEV, strerror(err)); |
| 551 | sleep(1); |
| 552 | continue; |
| 553 | } |
| 554 | else |
| 555 | { |
| 556 | AUDIO_IF_LOGD("Success to open %s\n", IOCTL_DEV); |
| 557 | close(ioctl_fd); |
| 558 | break; |
| 559 | } |
| 560 | } |
| 561 | |
| 562 | /* Create mutex for Ril and headset interrupt handlers */ |
| 563 | pthread_mutex_init(&AudioIf_mutex, NULL); |
| 564 | pthread_mutex_init(&AudioIf_Ubus_mutex_play, NULL); |
| 565 | pthread_mutex_init(&AudioIf_Ubus_mutex_rec, NULL); |
| 566 | |
| 567 | /* Init ubus server */ |
| 568 | if (AudioIf_uBusInit() != 0) { |
| 569 | AUDIO_IF_LOGE("%s: Init ubus server failed!", __FUNCTION__); |
| 570 | exit (-1); |
| 571 | } |
| 572 | |
| 573 | /* Init global variables */ |
| 574 | ahw_dev_ubus = audio_hal_install(); |
| 575 | if (ahw_dev_ubus == NULL) { |
| 576 | AUDIO_IF_LOGE("%s: audio_hal_install failed!", __FUNCTION__); |
| 577 | exit (-1); |
| 578 | } |
| 579 | |
| 580 | mrvl_ahw_dev_ubus = (struct mrvl_audio_device*)ahw_dev_ubus; |
| 581 | |
| 582 | /* Init ubus subscriber */ |
| 583 | AudioIf_uBusSubscribeEvents(TRUE); |
| 584 | |
| 585 | /* Create a pipe to communicate between (1)ubus thread and (2)audio HAL listner thread */ |
| 586 | if (pipe(audioIfDb.pipes_fd) != 0) { |
| 587 | AUDIO_IF_LOGE("%s: pipe failed with error %d [ %s ].", __FUNCTION__, errno, strerror(errno)); |
| 588 | exit (-1); |
| 589 | } |
| 590 | /* Create thread to listen on Audio HAL */ |
| 591 | pthread_create(&audioIfDb.tid, NULL, AudioIf_MainLoopTask, NULL); |
| 592 | /*add fd to the ubus contex. this fd is listen on audioHAL */ |
| 593 | AudioIf_uBusFdAdd(audioIfDb.pipes_fd[0]); |
| 594 | |
| 595 | /* Add notify object onto bus */ |
| 596 | ubus_add_object(audioIfUbusDb.ctx, &DTMFCode_notify_obj); |
| 597 | ubus_add_object(audioIfUbusDb.ctx, &VoiceStatus_notify_obj); |
| 598 | |
| 599 | /* Create thread to listen to UTL socket */ |
| 600 | pthread_create(&AudioIf_utid, NULL, (void *)AudioIf_UTLTask, NULL); |
| 601 | |
| 602 | /* Start uloop */ |
| 603 | AudioIf_uBusUloopRun(); |
| 604 | |
| 605 | /* Destroy mutex */ |
| 606 | pthread_mutex_destroy(&AudioIf_mutex); |
| 607 | pthread_mutex_destroy(&AudioIf_Ubus_mutex_play); |
| 608 | pthread_mutex_destroy(&AudioIf_Ubus_mutex_rec); |
| 609 | |
| 610 | /* Unregister uloop */ |
| 611 | /* Thread will get here only if uloop stopped */ |
| 612 | ubus_remove_object(audioIfUbusDb.ctx, &audioIfUbusDb.server_obj); |
| 613 | ubus_free(audioIfUbusDb.ctx); |
| 614 | uloop_done(); |
| 615 | |
| 616 | /* Unregister subscriber */ |
| 617 | AudioIf_uBusSubscribeEvents(FALSE); |
| 618 | |
| 619 | /* Unregister server */ |
| 620 | pthread_cancel(audioIfDb.tid); |
| 621 | |
| 622 | audio_hal_uninstall(); |
| 623 | exit(0); |
| 624 | } |