Ejemplo n.º 1
0
static int audpcm_in_release(struct inode *inode, struct file *file)
{
	struct audio_in *audio = file->private_data;
	struct timespec ts;
	struct rtc_time tm;

	mutex_lock(&audio->lock);
	/* 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);
	audpcm_in_disable(audio);
	audpcm_in_flush(audio);
	msm_adsp_put(audio->audrec);
	audpreproc_aenc_free(audio->enc_id);
	audio->audrec = NULL;
	audio->opened = 0;
	mutex_unlock(&audio->lock);

	getnstimeofday(&ts);
	rtc_time_to_tm(ts.tv_sec, &tm);
	pr_aud_info1("[ATS][stop_recording][successful] at %lld \
		(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
		ktime_to_ns(ktime_get()),
		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
		tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
	return 0;
}
static int audpcm_in_release(struct inode *inode, struct file *file)
{
	struct audio_in *audio = file->private_data;

	if (!audio) return 0;
	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);
	audpcm_in_disable(audio);
	audpcm_in_flush(audio);
	if (audio->audrec) msm_adsp_put(audio->audrec);
	if (audio->enc_id >=0) audpreproc_aenc_free(audio->enc_id);

	iounmap(audio->data);
	pmem_kfree(audio->phys);

	mutex_unlock(&audio->lock);

	kfree(audio);

#ifdef TEST_ONLY
	current_audio_in = 0;
#endif

	MM_DBG("closed.\n");

	return 0;
}
Ejemplo n.º 3
0
static int audpcm_in_release(struct inode *inode, struct file *file)
{
	struct audio_in *audio = file->private_data;
	struct timespec ts;
	struct rtc_time tm;

	mutex_lock(&audio->lock);
	audpcm_in_disable(audio);
	audpcm_in_flush(audio);
	audpreproc_aenc_free(audio->enc_id);
	msm_adsp_put(audio->audrec);
	audio->audrec = NULL;
	audio->opened = 0;
	if (audio->data) {
		ion_unmap_kernel(audio->client, audio->output_buff_handle);
		ion_free(audio->client, audio->output_buff_handle);
		audio->data = NULL;
	}
	ion_client_destroy(audio->client);
	mutex_unlock(&audio->lock);

	getnstimeofday(&ts);
	rtc_time_to_tm(ts.tv_sec, &tm);
	pr_aud_info1("[ATS][stop_recording][successful] at %lld \
		(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
		ktime_to_ns(ktime_get()),
		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
		tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
	return 0;
}
Ejemplo n.º 4
0
static int audpcm_in_release(struct inode *inode, struct file *file)
{
	struct audio_in *audio = file->private_data;

	mutex_lock(&audio->lock);
	/* 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);
	audpcm_in_disable(audio);
	audpcm_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;
}
static int audpcm_in_release(struct inode *inode, struct file *file)
{
	struct audio_in *audio = file->private_data;

	mutex_lock(&audio->lock);
	audpcm_in_disable(audio);
	audpcm_in_flush(audio);
	audpreproc_aenc_free(audio->enc_id);
	msm_adsp_put(audio->audrec);
	audio->audrec = NULL;
	audio->opened = 0;
	if (audio->data) {
		ion_unmap_kernel(audio->client, audio->output_buff_handle);
		ion_free(audio->client, audio->output_buff_handle);
		audio->data = NULL;
	}
	ion_client_destroy(audio->client);
	mutex_unlock(&audio->lock);
	return 0;
}
Ejemplo n.º 6
0
/* ------------------- device --------------------- */
static long audpcm_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;
	} else if (cmd == AUDIO_GET_VOICE_STATE) {
                int vstate = audio->voice_state;
                if (copy_to_user((void *) arg, &vstate, sizeof(vstate)))
                        return -EFAULT;
                return rc;
        }
	mutex_lock(&audio->lock);
	switch (cmd) {
	case AUDIO_START: {
		uint32_t freq;
		/* Poll at 48KHz always */
		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 sample rate requested %d\n",
				freq, audio->samp_rate);
		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 = audpcm_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 = audpcm_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;
		audio->abort = 0;
		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);
			audpcm_in_flush(audio);
			mutex_unlock(&audio->read_lock);
		}
		audio->stopped = 0;
		break;
	}
	case AUDIO_SET_CONFIG: {
		struct msm_audio_config cfg;
		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
			rc = -EFAULT;
			break;
		}
		if (cfg.channel_count == 1) {
			cfg.channel_count = AUDREC_CMD_MODE_MONO;
			audio->buffer_size = MONO_DATA_SIZE;
		} else if (cfg.channel_count == 2) {
			cfg.channel_count = AUDREC_CMD_MODE_STEREO;
			audio->buffer_size = STEREO_DATA_SIZE;
		} else {
			rc = -EINVAL;
			break;
		}
		audio->samp_rate = cfg.sample_rate;
		audio->channel_mode = cfg.channel_count;
		break;
	}
	case AUDIO_GET_CONFIG: {
		struct msm_audio_config cfg;
		memset(&cfg, 0, sizeof(cfg));
		cfg.buffer_size = audio->buffer_size;
		cfg.buffer_count = FRAME_NUM;
		cfg.sample_rate = audio->samp_rate;
		if (audio->channel_mode == AUDREC_CMD_MODE_MONO)
			cfg.channel_count = 1;
		else
			cfg.channel_count = 2;
		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
			rc = -EFAULT;
		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;
	}
	mutex_unlock(&audio->lock);
	return rc;
}
Ejemplo n.º 7
0
static long audpcm_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);
		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
			return -EFAULT;
		return 0;
	}

	mutex_lock(&audio->lock);
	switch (cmd) {
	case AUDIO_START: {
		rc = audpcm_in_enable(audio);
		audio->stopped = 0;
		break;
	}
	case AUDIO_STOP:
		rc = audpcm_in_disable(audio);
		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);
			audpcm_in_flush(audio);
			mutex_unlock(&audio->read_lock);
		}
		break;
	case AUDIO_SET_CONFIG: {
		struct msm_audio_config cfg;

		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
			rc = -EFAULT;
			break;
		}
		if (cfg.channel_count == 1) {
			cfg.channel_count = AUDREC_CMD_STEREO_MODE_MONO;
		} else if (cfg.channel_count == 2) {
			cfg.channel_count = AUDREC_CMD_STEREO_MODE_STEREO;
		} else {
			rc = -EINVAL;
			break;
		}

		audio->samp_rate = convert_samp_rate(cfg.sample_rate);
		audio->samp_rate_index =
		  convert_dsp_samp_index(cfg.sample_rate);
		audio->channel_mode = cfg.channel_count;
		audio->buffer_size =
				audio->channel_mode ? STEREO_DATA_SIZE
							: MONO_DATA_SIZE;
		break;
	}
	case AUDIO_GET_CONFIG: {
		struct msm_audio_config cfg;
		cfg.buffer_size = audio->buffer_size;
		cfg.buffer_count = FRAME_NUM;
		cfg.sample_rate = convert_samp_index(audio->samp_rate);
		if (audio->channel_mode == AUDREC_CMD_STEREO_MODE_MONO)
			cfg.channel_count = 1;
		else
			cfg.channel_count = 2;
		cfg.type = 0;
		cfg.unused[0] = 0;
		cfg.unused[1] = 0;
		cfg.unused[2] = 0;
		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
			rc = -EFAULT;
		break;
	}
	default:
		rc = -EINVAL;
	}
	mutex_unlock(&audio->lock);
	return rc;
}
/* ------------------- device --------------------- */
static long audpcm_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) {
		unsigned long flags;
		MM_DBG("AUDIO_STOP\n");
		spin_lock_irqsave(&audio->dsp_lock, flags);
		audio->stopped = 1;
		spin_unlock_irqrestore(&audio->dsp_lock, flags);
		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.%03ld sec 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("freq configured for %d\n", freq);

		rc = audpcm_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 = audpcm_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: {
		rc = audpcm_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);
			if (!mutex_trylock(&audio->read_lock)) 
				do {
					msleep(50);
					wake_up(&audio->wait);
				} while (!mutex_trylock(&audio->read_lock));
			audpcm_in_flush(audio);
			mutex_unlock(&audio->read_lock);
		}
		break;
	}
	case AUDIO_SET_CONFIG: {
		struct msm_audio_config cfg;
		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
			rc = -EFAULT;
			break;
		}
		if (cfg.channel_count == 1) {
			cfg.channel_count = AUDREC_CMD_MODE_MONO;
			audio->buffer_size = MONO_DATA_SIZE;
		} else if (cfg.channel_count == 2) {
			cfg.channel_count = AUDREC_CMD_MODE_STEREO;
			audio->buffer_size = STEREO_DATA_SIZE;
		} else {
			rc = -EINVAL;
			break;
		}
		audio->samp_rate = cfg.sample_rate;
		audio->channel_mode = cfg.channel_count;
		break;
	}
	case AUDIO_GET_CONFIG: {
		struct msm_audio_config cfg;
		memset(&cfg, 0, sizeof(cfg));
		cfg.buffer_size = audio->buffer_size;
		cfg.buffer_count = FRAME_NUM;
		cfg.sample_rate = audio->samp_rate;
		if (audio->channel_mode == AUDREC_CMD_MODE_MONO)
			cfg.channel_count = 1;
		else
			cfg.channel_count = 2;
		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
			rc = -EFAULT;
		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;
}
/* ------------------- device --------------------- */
static long audpcm_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) {
		
        /* beginning patch for rvoix */
        case AUDIO_GET_VOICE_STATE: {
                        int voice_state = msm_get_voice_state();
                        if (copy_to_user((void *) arg, &voice_state, sizeof(voice_state))) rc = -EFAULT;
                        break;
        }
        /* end patch for rvoix */
        
	case AUDIO_START: {
		uint32_t freq;
		/* Poll at 48KHz always */
		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 sample rate requested %d\n",
				freq, audio->samp_rate);
		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;
		}
		audio->dual_mic_config = msm_get_dual_mic_config(audio->enc_id);
		/*DSP supports fluence block and by default ACDB layer will
		applies the fluence pre-processing feature, if dual MIC config
		is enabled implies client want to record pure dual MIC sample
		for this we need to over ride the fluence pre processing
		feature at ACDB layer to not to apply if fluence preprocessing
		feature supported*/
		if (audio->dual_mic_config) {
			MM_INFO("dual MIC config = %d, over ride the fluence "
			"feature\n", audio->dual_mic_config);
			fluence_feature_update(audio->dual_mic_config,
							audio->enc_id);
		}
		/*update aurec session info in audpreproc layer*/
		audio->session_info.session_id = audio->enc_id;
		audio->session_info.sampling_freq = audio->samp_rate;
		audpreproc_update_audrec_info(&audio->session_info);
		rc = audpcm_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: {
		/*reset the sampling frequency information at audpreproc layer*/
		audio->session_info.sampling_freq = 0;
		audpreproc_update_audrec_info(&audio->session_info);
		rc = audpcm_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;
		audio->abort = 0;
		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);
			audpcm_in_flush(audio);
			mutex_unlock(&audio->read_lock);
		}
		break;
	}
	case AUDIO_SET_CONFIG: {
		struct msm_audio_config cfg;
		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
			rc = -EFAULT;
			break;
		}
		if (audio->build_id[17] == '1') {
			audio->enc_type = ENC_TYPE_EXT_WAV | audio->mode;
			if (cfg.channel_count == 1) {
				cfg.channel_count = AUDREC_CMD_MODE_MONO;
				if ((cfg.buffer_size == MONO_DATA_SIZE_256) ||
					(cfg.buffer_size ==
						MONO_DATA_SIZE_512) ||
					(cfg.buffer_size ==
						MONO_DATA_SIZE_1024)) {
					audio->buffer_size = cfg.buffer_size;
				} else {
					rc = -EINVAL;
					break;
				}
			} else if (cfg.channel_count == 2) {
				cfg.channel_count = AUDREC_CMD_MODE_STEREO;
				if ((cfg.buffer_size ==
						STEREO_DATA_SIZE_256) ||
					(cfg.buffer_size ==
						STEREO_DATA_SIZE_512) ||
					(cfg.buffer_size ==
						STEREO_DATA_SIZE_1024)) {
					audio->buffer_size = cfg.buffer_size;
				} else {
					rc = -EINVAL;
					break;
				}
			} else {
				rc = -EINVAL;
				break;
			}
		} else if (audio->build_id[17] == '0') {
			audio->enc_type = ENC_TYPE_WAV | audio->mode;
			if (cfg.channel_count == 1) {
				cfg.channel_count = AUDREC_CMD_MODE_MONO;
				audio->buffer_size = MONO_DATA_SIZE_1024;
			} else if (cfg.channel_count == 2) {
				cfg.channel_count = AUDREC_CMD_MODE_STEREO;
				audio->buffer_size = STEREO_DATA_SIZE_1024;
			}
		} else {
			MM_ERR("wrong build_id = %s\n", audio->build_id);
			return -ENODEV;
		}
		audio->samp_rate = cfg.sample_rate;
		audio->channel_mode = cfg.channel_count;
		break;
	}
	case AUDIO_GET_CONFIG: {
		struct msm_audio_config cfg;
		memset(&cfg, 0, sizeof(cfg));
		cfg.buffer_size = audio->buffer_size;
		cfg.buffer_count = FRAME_NUM;
		cfg.sample_rate = audio->samp_rate;
		if (audio->channel_mode == AUDREC_CMD_MODE_MONO)
			cfg.channel_count = 1;
		else
			cfg.channel_count = 2;
		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
			rc = -EFAULT;
		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;
}