static int reconfig_record(struct audio_in *audio) { MM_DBG("\n"); mutex_lock(&audio->lock); atomic_set(&audio->rec_conf,0); if (audamrnb_in_record_config(audio, 0) != 0) { mutex_unlock(&audio->lock); return -EFAULT; } wait_event_interruptible_timeout(audio->wait_rec_cfg, atomic_read(&audio->rec_conf) == 1, 1*HZ); if (atomic_read(&audio->rec_conf) != 1) { mutex_unlock(&audio->lock); return -ENODEV; } atomic_set(&audio->rec_conf,0); if (audamrnb_in_record_config(audio, 1) != 0) { mutex_unlock(&audio->lock); return -EFAULT; } wait_event_interruptible_timeout(audio->wait_rec_cfg, atomic_read(&audio->rec_conf) == 1, 1*HZ); if (atomic_read(&audio->rec_conf) != 1) { mutex_unlock(&audio->lock); return -ENODEV; } mutex_unlock(&audio->lock); return 0; }
/* ------------------- dsp preproc event handler--------------------- */ static void amrnb_in_dsp_event(void *data, unsigned id, void *msg) { struct audio_in *audio = data; switch (id) { case AUDPREPROC_ERROR_MSG: { struct audpreproc_err_msg *err_msg = msg; MM_ERR("ERROR_MSG: stream id %d err idx %d\n", err_msg->stream_id, err_msg->aud_preproc_err_idx); /* Error case */ wake_up(&audio->wait_enable); break; } case AUDPREPROC_CMD_CFG_DONE_MSG: { MM_DBG("CMD_CFG_DONE_MSG \n"); break; } case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: { struct audpreproc_cmd_enc_cfg_done_msg *enc_cfg_msg = msg; MM_DBG("CMD_ENC_CFG_DONE_MSG: stream id %d enc type 0x%x\n", enc_cfg_msg->stream_id, enc_cfg_msg->rec_enc_type); /* Encoder enable success */ if (enc_cfg_msg->rec_enc_type & ENCODE_ENABLE) audamrnb_in_param_config(audio); else { /* Encoder disable success */ audio->running = 0; audamrnb_in_record_config(audio, 0); } break; } case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: { MM_DBG("CMD_ENC_PARAM_CFG_DONE_MSG \n"); audamrnb_in_mem_config(audio); break; } case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: { MM_DBG("AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG \n"); atomic_set(&audio->rec_conf,1); wake_up(&audio->wait_rec_cfg); break; } case ADSP_MESSAGE_ID: pr_aud_info("audpre: enable/disable done\n"); break; default: MM_ERR("Unknown Event id %d\n", id); } }
/* ------------------- dsp audrec event handler--------------------- */ static void audrec_dsp_event(void *data, unsigned id, size_t len, void (*getevent)(void *ptr, size_t len)) { struct audio_in *audio = data; switch (id) { case AUDREC_CMD_MEM_CFG_DONE_MSG: { MM_DBG("CMD_MEM_CFG_DONE MSG DONE\n"); audio->running = 1; if ((!audio->in_call && (audio->dev_cnt > 0)) || (audio->in_call && (audio->voice_state == VOICE_STATE_INCALL))) audamrnb_in_record_config(audio, 1); break; } case AUDREC_FATAL_ERR_MSG: { struct audrec_fatal_err_msg fatal_err_msg; getevent(&fatal_err_msg, AUDREC_FATAL_ERR_MSG_LEN); MM_ERR("FATAL_ERR_MSG: err id %d\n", fatal_err_msg.audrec_err_id); /* Error stop the encoder */ audio->stopped = 1; wake_up(&audio->wait); break; } case AUDREC_UP_PACKET_READY_MSG: { struct audrec_up_pkt_ready_msg pkt_ready_msg; getevent(&pkt_ready_msg, AUDREC_UP_PACKET_READY_MSG_LEN); MM_DBG("UP_PACKET_READY_MSG: write cnt lsw %d \ write cnt msw %d read cnt lsw %d read cnt msw %d \n",\ pkt_ready_msg.audrec_packet_write_cnt_lsw, \ pkt_ready_msg.audrec_packet_write_cnt_msw, \ pkt_ready_msg.audrec_up_prev_read_cnt_lsw, \ pkt_ready_msg.audrec_up_prev_read_cnt_msw); audamrnb_in_get_dsp_frames(audio); break; } case ADSP_MESSAGE_ID: { MM_DBG("Received ADSP event:module audrectask\n"); break; } default: MM_ERR("Unknown Event id %d\n", id); } }
static void audpreproc_dsp_event(void *data, unsigned id, void *msg) { struct audio_in *audio = data; switch (id) { case AUDPREPROC_ERROR_MSG: { struct audpreproc_err_msg *err_msg = msg; MM_ERR("ERROR_MSG: stream id %d err idx %d\n", err_msg->stream_id, err_msg->aud_preproc_err_idx); wake_up(&audio->wait_enable); break; } case AUDPREPROC_CMD_CFG_DONE_MSG: { MM_DBG("CMD_CFG_DONE_MSG \n"); break; } case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: { struct audpreproc_cmd_enc_cfg_done_msg *enc_cfg_msg = msg; MM_DBG("CMD_ENC_CFG_DONE_MSG: stream id %d enc type \ 0x%8x\n", enc_cfg_msg->stream_id, enc_cfg_msg->rec_enc_type); if (enc_cfg_msg->rec_enc_type & ENCODE_ENABLE) audamrnb_in_param_config(audio); else { audio->running = 0; audamrnb_in_record_config(audio, 0); } break; } case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: { MM_DBG("CMD_ENC_PARAM_CFG_DONE_MSG \n"); audamrnb_in_mem_config(audio); break; } case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: { MM_DBG("AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG \n"); wake_up(&audio->wait_enable); break; } default: MM_ERR("Unknown Event id %d\n", id); } }
/* ------------------- dsp audrec event handler--------------------- */ static void audrec_dsp_event(void *data, unsigned id, size_t len, void (*getevent)(void *ptr, size_t len)) { struct audio_in *audio = data; switch (id) { case AUDREC_CMD_MEM_CFG_DONE_MSG: { MM_DBG("CMD_MEM_CFG_DONE\n"); audio->running = 1; if (!audio->in_call && (audio->dev_cnt > 0)) audamrnb_in_record_config(audio, 1); wake_up(&audio->wait_enable); break; } case AUDREC_FATAL_ERR_MSG: { struct audrec_fatal_err_msg fatal_err_msg; getevent(&fatal_err_msg, AUDREC_FATAL_ERR_MSG_LEN); MM_ERR("FATAL_ERR_MSG: err id %d\n", fatal_err_msg.audrec_err_id); /* Error stop the encoder */ audio->stopped = 1; wake_up(&audio->wait_voice_incall); wake_up(&audio->wait); break; } case AUDREC_UP_PACKET_READY_MSG: { struct audrec_up_pkt_ready_msg pkt_ready_msg; getevent(&pkt_ready_msg, AUDREC_UP_PACKET_READY_MSG_LEN); MM_DBG("UP_PACKET_READY_MSG: write lsw %d write msw %d read lsw %d read msw %d\n", pkt_ready_msg.audrec_packet_write_cnt_lsw, pkt_ready_msg.audrec_packet_write_cnt_msw, pkt_ready_msg.audrec_up_prev_read_cnt_lsw, pkt_ready_msg.audrec_up_prev_read_cnt_msw); audamrnb_in_get_dsp_frames(audio); break; } case ADSP_MESSAGE_ID: MM_DBG("audrec: enable/disable done\n"); break; default: MM_ERR("Unknown Event id %d\n", id); } }
static void amrnb_in_listener(u32 evt_id, union auddev_evt_data *evt_payload, void *private_data) { struct audio_in *audio = (struct audio_in *) private_data; unsigned long flags; MM_DBG("evt_id = 0x%8x\n", evt_id); switch (evt_id) { case AUDDEV_EVT_DEV_RDY: { MM_DBG("AUDDEV_EVT_DEV_RDY\n"); spin_lock_irqsave(&audio->dev_lock, flags); audio->dev_cnt++; if (!audio->in_call) audio->source |= (0x1 << evt_payload->routing_id); spin_unlock_irqrestore(&audio->dev_lock, flags); if ((audio->running == 1) && (audio->enabled == 1)) audamrnb_in_record_config(audio, 1); break; } case AUDDEV_EVT_DEV_RLS: { MM_DBG("AUDDEV_EVT_DEV_RLS\n"); spin_lock_irqsave(&audio->dev_lock, flags); audio->dev_cnt--; if (!audio->in_call) audio->source &= ~(0x1 << evt_payload->routing_id); spin_unlock_irqrestore(&audio->dev_lock, flags); if ((!audio->running) || (!audio->enabled)) break; /* Turn of as per source */ if (audio->source) audamrnb_in_record_config(audio, 1); else /* Turn off all */ audamrnb_in_record_config(audio, 0); break; } case AUDDEV_EVT_VOICE_STATE_CHG: { MM_DBG("AUDDEV_EVT_VOICE_STATE_CHG, state = %d\n", evt_payload->voice_state); audio->voice_state = evt_payload->voice_state; if (audio->in_call && audio->running) { if (audio->voice_state == VOICE_STATE_INCALL) audamrnb_in_record_config(audio, 1); else if (audio->voice_state == VOICE_STATE_OFFCALL) { audamrnb_in_record_config(audio, 0); wake_up(&audio->wait); } } break; } default: MM_ERR("wrong event %d\n", evt_id); break; } }
/* ------------------- device --------------------- */ static long audamrnb_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct audio_in *audio = file->private_data; int rc = 0; if (cmd == AUDIO_STOP) { audio->stopped = 1; wake_up(&audio->wait_voice_incall); } mutex_lock(&audio->lock); switch (cmd) { case AUDIO_GET_STATS: { struct msm_audio_stats stats; stats.byte_count = atomic_read(&audio->in_bytes); stats.sample_count = atomic_read(&audio->in_samples); if (copy_to_user((void *) arg, &stats, sizeof(stats))) rc = -EFAULT; break; } case AUDIO_GET_VOICE_STATE: { int vstate = audio->voice_state; if (copy_to_user((void *) arg, &vstate, sizeof(vstate))) rc = -EFAULT; break; } case AUDIO_GET_DEV_DRV_VER: { unsigned int vers = DEV_DRV_VER; if (copy_to_user((void *) arg, &vers, sizeof(vers))) rc = -EFAULT; break; } case AUDIO_START: { uint32_t freq; struct timespec ts; /* Poll at 48KHz always */ freq = 48000; MM_DBG("AUDIO_START\n"); if (audio->in_call && (audio->voice_state != VOICE_STATE_INCALL)) { ts = CURRENT_TIME; rc = wait_event_interruptible(audio->wait_voice_incall, audio->voice_state == VOICE_STATE_INCALL || audio->stopped); if(rc < 0 || audio->voice_state != VOICE_STATE_INCALL || audio->stopped) { MM_DBG("valid incall state unreacheable\n"); return -EPERM; } ts = timespec_sub(CURRENT_TIME,ts); MM_DBG("waited %ld.%ldms for voice incall state\n", ts.tv_sec, ts.tv_nsec/NSEC_PER_MSEC); } rc = msm_snddev_request_freq(&freq, audio->enc_id,SNDDEV_CAP_TX, AUDDEV_CLNT_ENC); if (rc < 0) { MM_DBG("sample rate can not be set, return code %d\n",rc); msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX, AUDDEV_CLNT_ENC); MM_DBG("msm_snddev_withdraw_freq\n"); break; } MM_DBG("sample rate configured %d\n", freq); rc = audamrnb_in_enable(audio); if (rc == 0) { ts = CURRENT_TIME; rc = wait_event_interruptible_timeout(audio->wait_enable, audio->running != 0, 3*HZ); ts = timespec_sub(CURRENT_TIME,ts); MM_DBG("state = %d, rc = %d after %ld.%03ld sec\n", audio->running, rc, ts.tv_sec, ts.tv_nsec/NSEC_PER_MSEC); rc = (audio->running == 0) ? -ENODEV : 0; } else MM_DBG("failed to enable audpcm\n"); if (rc == 0 && audio->in_call) { rc = audamrnb_in_record_config(audio, 1); if (rc != 0) MM_ERR("failed to send record config cmd\n"); else { ts = CURRENT_TIME; atomic_set(&audio->rec_conf,0); wait_event_interruptible_timeout(audio->wait_rec_cfg, atomic_read(&audio->rec_conf) != 0, 3*HZ); if (atomic_read(&audio->rec_conf) == 0) { MM_DBG("failed to config recording\n"); rc = -EFAULT; } else { ts = timespec_sub(CURRENT_TIME,ts); MM_DBG("record config success after %ld.%03ld sec\n", ts.tv_sec, ts.tv_nsec/NSEC_PER_MSEC); } } } audio->stopped = 0; break; } case AUDIO_STOP: { MM_DBG("AUDIO_STOP\n"); rc = audamrnb_in_disable(audio); if (rc != 0) MM_DBG("failed to stop audio\n"); rc = msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX, AUDDEV_CLNT_ENC); break; } case AUDIO_FLUSH: { MM_DBG("AUDIO_FLUSH\n"); if (audio->stopped) { /* Make sure we're stopped and we wake any threads * that might be blocked holding the read_lock. * While audio->stopped read threads will always * exit immediately. */ wake_up(&audio->wait); mutex_lock(&audio->read_lock); audamrnb_in_flush(audio); mutex_unlock(&audio->read_lock); } break; } case AUDIO_SET_STREAM_CONFIG: { break; } case AUDIO_GET_STREAM_CONFIG: { struct msm_audio_stream_config cfg; memset(&cfg, 0, sizeof(cfg)); cfg.buffer_size = audio->buffer_size; cfg.buffer_count = FRAME_NUM; if (copy_to_user((void *) arg, &cfg, sizeof(cfg))) rc = -EFAULT; break; } case AUDIO_GET_AMRNB_ENC_CONFIG_V2: { struct msm_audio_amrnb_enc_config_v2 cfg; memset(&cfg, 0, sizeof(cfg)); cfg.dtx_enable = ((audio->dtx_mode == AMRNB_DTX_MODE_ENABLE) ? 1 : 0); cfg.band_mode = audio->used_mode; if (copy_to_user((void *) arg, &cfg, sizeof(cfg))) rc = -EFAULT; break; } case AUDIO_SET_AMRNB_ENC_CONFIG_V2: { struct msm_audio_amrnb_enc_config_v2 cfg; if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) { rc = -EFAULT; break; } audio->dtx_mode = cfg.dtx_enable ? AMRNB_DTX_MODE_ENABLE : AMRNB_DTX_MODE_DISABLE; audio->used_mode = cfg.band_mode; break; } case AUDIO_SET_INCALL: { struct msm_voicerec_mode cfg; unsigned long flags; MM_DBG("AUDIO_SET_INCALL\n"); if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) { rc = -EFAULT; break; } if (cfg.rec_mode != VOC_REC_BOTH && cfg.rec_mode != VOC_REC_UPLINK && cfg.rec_mode != VOC_REC_DOWNLINK) { MM_ERR("invalid rec_mode\n"); rc = -EINVAL; break; } else { spin_lock_irqsave(&audio->dev_lock, flags); if (cfg.rec_mode == VOC_REC_UPLINK) audio->source = VOICE_UL_SOURCE_MIX_MASK; else if (cfg.rec_mode == VOC_REC_DOWNLINK) audio->source = VOICE_DL_SOURCE_MIX_MASK; else audio->source = VOICE_DL_SOURCE_MIX_MASK | VOICE_UL_SOURCE_MIX_MASK ; audio->in_call = 1; spin_unlock_irqrestore(&audio->dev_lock, flags); } break; } case AUDIO_GET_SESSION_ID: { if (copy_to_user((void *) arg, &audio->enc_id, sizeof(unsigned short))) { rc = -EFAULT; } break; } default: rc = -EINVAL; } if(rc != 0) MM_DBG("returning error %d\n",rc); mutex_unlock(&audio->lock); return rc; }