static int audamrnb_in_release(struct inode *inode, struct file *file) { struct audio_in *audio = file->private_data; MM_DBG("\n"); mutex_lock(&audio->lock); audio->in_call = 0; /* with draw frequency for session incase not stopped the driver */ msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX, AUDDEV_CLNT_ENC); auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, audio->enc_id); audamrnb_in_disable(audio); audamrnb_in_flush(audio); msm_adsp_put(audio->audrec); audpreproc_aenc_free(audio->enc_id); audio->audrec = NULL; audio->opened = 0; if (audio->data) { iounmap(audio->data); pmem_kfree(audio->phys); audio->data = NULL; } mutex_unlock(&audio->lock); return 0; }
static int audamrnb_in_release(struct inode *inode, struct file *file) { struct audio_in *audio = file->private_data; MM_DBG("\n"); mutex_lock(&audio->lock); audio->in_call = 0; /* with draw frequency for session incase not stopped the driver */ msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX, AUDDEV_CLNT_ENC); auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, audio->enc_id); /*reset the sampling frequency information at audpreproc layer*/ audio->session_info.sampling_freq = 0; audpreproc_update_audrec_info(&audio->session_info); audamrnb_in_disable(audio); audamrnb_in_flush(audio); msm_adsp_put(audio->audrec); audpreproc_aenc_free(audio->enc_id); audio->audrec = NULL; audio->opened = 0; if (audio->data) { ion_unmap_kernel(audio->client, audio->buff_handle); ion_free(audio->client, audio->buff_handle); ion_client_destroy(audio->client); audio->data = NULL; } mutex_unlock(&audio->lock); return 0; }
static int audamrnb_in_release(struct inode *inode, struct file *file) { struct audio_in *audio = file->private_data; MM_DBG("\n"); mutex_lock(&audio->lock); audio->in_call = 0; msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX, AUDDEV_CLNT_ENC); auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, audio->enc_id); audamrnb_in_disable(audio); audamrnb_in_flush(audio); msm_adsp_put(audio->audrec); audpreproc_aenc_free(audio->enc_id); audio->audrec = NULL; audio->opened = 0; mutex_unlock(&audio->lock); return 0; }
/* ------------------- 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_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))) return -EFAULT; return rc; } mutex_lock(&audio->lock); switch (cmd) { case AUDIO_START: { uint32_t freq; freq = 48000; MM_DBG("AUDIO_START\n"); if (audio->in_call && (audio->voice_state != VOICE_STATE_INCALL)) { rc = -EPERM; break; } rc = msm_snddev_request_freq(&freq, audio->enc_id, SNDDEV_CAP_TX, AUDDEV_CLNT_ENC); MM_DBG("sample rate configured %d\n", freq); 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; } rc = audamrnb_in_enable(audio); if (!rc) { rc = wait_event_interruptible_timeout(audio->wait_enable, audio->running != 0, 1*HZ); MM_DBG("state %d rc = %d\n", audio->running, rc); if (audio->running == 0) rc = -ENODEV; else rc = 0; } audio->stopped = 0; break; } case AUDIO_STOP: { rc = audamrnb_in_disable(audio); rc = msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX, AUDDEV_CLNT_ENC); MM_DBG("msm_snddev_withdraw_freq\n"); audio->stopped = 1; break; } case AUDIO_FLUSH: { 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: { struct msm_audio_stream_config cfg; if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) { rc = -EFAULT; break; } /* Allow only single frame */ if (cfg.buffer_size != (FRAME_SIZE - 8)) rc = -EINVAL; else audio->buffer_size = cfg.buffer_size; 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 == -1) ? 1 : 0); cfg.band_mode = audio->used_mode; cfg.frame_format = audio->frame_format; 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; } /* DSP does not support any other than default format */ if (audio->frame_format != cfg.frame_format) { rc = -EINVAL; break; } if (cfg.dtx_enable == 0) audio->dtx_mode = 0; else if (cfg.dtx_enable == 1) audio->dtx_mode = -1; else { rc = -EINVAL; break; } audio->used_mode = cfg.band_mode; break; } case AUDIO_SET_INCALL: { struct msm_voicerec_mode cfg; unsigned long flags; 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; } mutex_unlock(&audio->lock); return rc; }
/* ------------------- 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; }