示例#1
0
int auddev_register_evt_listner(u32 evt_id, u32 clnt_type, u32 clnt_id,
		void (*listner)(u32 evt_id,
			union auddev_evt_data *evt_payload,
			void *private_data),
		void *private_data)
{
	int rc;
	struct msm_snd_evt_listner *callback = NULL;
	struct msm_snd_evt_listner *new_cb;

	new_cb = kzalloc(sizeof(struct msm_snd_evt_listner), GFP_KERNEL);
	if (!new_cb) {
		MM_AUD_ERR("No memory to add new listener node\n");
		return -ENOMEM;
	}

	mutex_lock(&session_lock);
	new_cb->cb_next = NULL;
	new_cb->auddev_evt_listener = listner;
	new_cb->evt_id = evt_id;
	new_cb->clnt_type = clnt_type;
	new_cb->clnt_id = clnt_id;
	new_cb->private_data = private_data;
	if (event.cb == NULL) {
		event.cb = new_cb;
		new_cb->cb_prev = NULL;
	} else {
		callback = event.cb;
		for (; ;) {
			if (callback->cb_next == NULL)
				break;
			else {
				callback = callback->cb_next;
				continue;
			}
		}
		callback->cb_next = new_cb;
		new_cb->cb_prev = callback;
	}
	event.num_listner++;
	mutex_unlock(&session_lock);
	rc = 0;
	return rc;
}
示例#2
0
int lpa_cmd_enable_codec(struct lpa_drv *lpa, bool enable)
{
	u32 val;
	struct lpa_mem_bank_select mem_bank;

	MM_AUD_INFO(" %s\n", (enable ? "enable" : "disable"));

	if (!lpa)
		return -EINVAL;

	val = LPA_REG_READL(lpa, LPA_OBUF_CODEC);

	if (enable) {
		if (val & LPA_OBUF_CODEC_CODEC_INTF_EN_BMSK)
			return -EBUSY;
		/* Power up all memory bank for now */
		mem_bank.b0 = 1;
		mem_bank.b1 = 1;
		mem_bank.b2 = 1;
		mem_bank.b3 = 1;
		mem_bank.b4 = 1;
		mem_bank.b5 = 1;
		mem_bank.b6 = 1;
		mem_bank.b7 = 1;
		mem_bank.b8 = 1;
		mem_bank.b9 = 1;
		mem_bank.b10 = 1;
		mem_bank.llb = 1;
		lpa_powerup_mem_bank(lpa, &mem_bank);

		/*clear LLB*/
		lpa_clear_llb(lpa);

		lpa_enable_codec(lpa, 1);
		MM_AUD_INFO("LPA codec is enabled\n");
	} else {
		if (val & LPA_OBUF_CODEC_CODEC_INTF_EN_BMSK) {
			lpa_enable_codec(lpa, 0);
			MM_AUD_INFO("LPA codec is disabled\n");
		} else
			MM_AUD_ERR("LPA codec is already disable\n");
	}
	return 0;
}
/* must be called with audio->lock held */
static int audio_enable(struct audio *audio)
{
	struct audmgr_config cfg;
	int rc;

	MM_AUD_INFO("audio_enable()\n");

	if (audio->enabled)
		return 0;	

	/* refuse to start if we're not ready */
	if (!audio->out[0].used || !audio->out[1].used)
		return -EIO;

	/* we start buffers 0 and 1, so buffer 0 will be the
	 * next one the dsp will want
	 */
	audio->out_tail = 0;
	audio->out_needed = 0;

	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
	cfg.def_method = RPC_AUD_DEF_METHOD_HOST_PCM;
	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
	cfg.snd_method = RPC_SND_METHOD_MIDI;

	audio_prevent_sleep(audio);	
	rc = audmgr_enable(&audio->audmgr, &cfg);
	if (rc < 0) {
		audio_allow_sleep(audio);
		return rc;
	}

	if (audpp_enable(-1, audio_dsp_event, audio)) {
		MM_AUD_ERR("audio: audpp_enable() failed\n");
		audmgr_disable(&audio->audmgr);
		audio_allow_sleep(audio);
		return -ENODEV;
	}

	audio->enabled = 1;
	htc_pwrsink_audio_set(PWRSINK_AUDIO_PCM, 100);
	return 0;
}
示例#4
0
static int32_t adsp_validate_queue(uint32_t mod_id, unsigned q_idx,
							uint32_t size)
{
	int32_t i;
	struct adsp_rtos_mp_mtoa_init_info_type	*sptr;

	sptr = adsp_info.init_info_ptr;
	for (i = 0; i < sptr->mod_to_q_entries; i++)
		if (mod_id == sptr->mod_to_q_tbl[i].module)
			if (q_idx == sptr->mod_to_q_tbl[i].q_type) {
				if (size <= sptr->mod_to_q_tbl[i].q_max_len)
					return 0;
				MM_AUD_ERR("q_idx: %d is not a valid queue \
					for module %x\n", q_idx, mod_id);
				return -EINVAL;
			}
	MM_AUD_ERR("cmd_buf size is more than allowed size\n");
	return -EINVAL;
}
示例#5
0
static int __init audpcm_in_init(void)
{
	the_audio_in.data = dma_alloc_coherent(NULL, DMASZ,
					       &the_audio_in.phys, GFP_KERNEL);
	MM_DBG("Memory addr = 0x%8x  phy addr = 0x%8x ---- \n", \
		(int) the_audio_in.data, (int) the_audio_in.phys);

	if (!the_audio_in.data) {
		MM_AUD_ERR("Unable to allocate DMA buffer\n");
		return -ENOMEM;
	}
	mutex_init(&the_audio_in.lock);
	mutex_init(&the_audio_in.read_lock);
	spin_lock_init(&the_audio_in.dsp_lock);
	spin_lock_init(&the_audio_in.dev_lock);
	init_waitqueue_head(&the_audio_in.wait);
	init_waitqueue_head(&the_audio_in.wait_enable);
	return misc_register(&audio_in_misc);
}
示例#6
0
static int rpc_adsp_rtos_app_to_modem(uint32_t cmd, uint32_t module,
				      struct msm_adsp_module *adsp_module)
{
	struct adsp_rtos_atom_cmd adspsvc_cmd;
	int err;

	adspsvc_cmd.cmd = cmd;
	adspsvc_cmd.proc_id = RPC_ADSP_RTOS_PROC_APPS;
	adspsvc_cmd.module = module;
	adspsvc_cmd.cb_handle = adsp_info.cb_handle;

	err = dalrpc_fcn_5(DALDEVICE_ADSP_CMD_IDX | 0x80000000,
					adsp_info.handle,
					&adspsvc_cmd, sizeof(adspsvc_cmd));
	if (err < 0)
		MM_AUD_ERR("ADSP command send Failed\n");

	return 0;
}
示例#7
0
int msm_snddev_enable_sidetone(u32 dev_id, u32 enable)
{
	int rc;
	struct msm_snddev_info *dev_info;

	MM_DBG("dev_id %d enable %d\n", dev_id, enable);

	dev_info = audio_dev_ctrl_find_dev(dev_id);

	if (IS_ERR(dev_info)) {
		MM_AUD_ERR("bad dev_id %d\n", dev_id);
		rc = -EINVAL;
	} else if (!dev_info->dev_ops.enable_sidetone) {
		MM_DBG("dev %d no sidetone support\n", dev_id);
		rc = -EPERM;
	} else
		rc = dev_info->dev_ops.enable_sidetone(dev_info, enable);

	return rc;
}
示例#8
0
static int msm_device_get(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	int rc = 0;
	struct msm_audio_route_config route_cfg;
	struct msm_snddev_info *dev_info;

	route_cfg.dev_id = ucontrol->id.numid - device_index;
	dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);

	if (IS_ERR(dev_info)) {
		MM_AUD_ERR("pass invalid dev_id\n");
		rc = PTR_ERR(dev_info);
		return rc;
	}

	ucontrol->value.integer.value[0] = dev_info->copp_id;
	ucontrol->value.integer.value[1] = dev_info->capability;

	return 0;
}
/* ------------------- dsp --------------------- */
static void audpre_dsp_event(void *data, unsigned id, size_t len,
			    void (*getevent)(void *ptr, size_t len))
{
	uint16_t msg[2];
	MM_AUD_INFO("%s %d\n", __func__, id);
	getevent(msg, sizeof(msg));

	switch (id) {
	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
		MM_AUD_INFO("audpre: type %d, status_flag %d\n", msg[0], msg[1]);
		break;
	case AUDPREPROC_MSG_ERROR_MSG_ID:
		MM_AUD_INFO("audpre: err_index %d\n", msg[0]);
		break;
	case ADSP_MESSAGE_ID:
		MM_AUD_INFO("audpre: module enabled\n");
		break;
	default:
		MM_AUD_ERR("audpre: unknown event %d\n", id);
	}
}
示例#10
0
int msm_adsp_get(const char *name, struct msm_adsp_module **out,
		 struct msm_adsp_ops *ops, void *driver_data)
{
	struct msm_adsp_module *module;
	int rc = 0;

	module = find_adsp_module_by_name(&adsp_info, name);
	if (!module)
		return -ENODEV;

	mutex_lock(&module->lock);
	MM_AUD_INFO("opening module %s\n", module->name);

	if (module->ops) {
		rc = -EBUSY;
		mutex_unlock(&module->lock);
		goto done;
	}

	module->ops = ops;
	module->driver_data = driver_data;
	*out = module;
	mutex_unlock(&module->lock);
	rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_REGISTER_APP,
					module->id, module);
	if (rc) {
		mutex_lock(&module->lock);
		module->ops = NULL;
		module->driver_data = NULL;
		*out = NULL;
		MM_AUD_ERR("REGISTER_APP failed\n");
		mutex_unlock(&module->lock);
		goto done;
	}

	MM_AUD_INFO("module %s has been registered\n", module->name);

done:
	return rc;
}
示例#11
0
int afe_config_aux_codec(int pcm_ctl_value, int aux_codec_intf_value,
				int data_format_pad)
{
	struct afe_cmd_aux_codec_config cmd;
	struct msm_afe_state *afe = &the_afe_state;
	int rc = 0;

	MM_AUD_INFO(" configure aux codec \n");
	mutex_lock(&afe->lock);
	if (!afe->in_use && !afe->aux_conf_flag) {
		/* enable afe */
		rc = msm_adsp_get("AFETASK", &afe->mod, &afe->adsp_ops, afe);
		if (rc < 0) {
			MM_AUD_ERR("%s: failed to get AFETASK module\n",
					__func__);
			goto error_adsp_get;
		}
		rc = msm_adsp_enable(afe->mod);
		if (rc < 0)
			goto error_adsp_enable;
	}
	afe->aux_conf_flag = 1;
	memset(&cmd, 0, sizeof(cmd));
	cmd.cmd_id = AFE_CMD_AUX_CODEC_CONFIG_CMD;
	cmd.dma_path_ctl = 0;
	cmd.pcm_ctl = pcm_ctl_value;
	cmd.eight_khz_int_mode = 0;
	cmd.aux_codec_intf_ctl = aux_codec_intf_value;
	cmd.data_format_padding_info = data_format_pad;

	afe_send_queue(afe, &cmd, sizeof(cmd));

	mutex_unlock(&afe->lock);
	return rc;
error_adsp_enable:
	msm_adsp_put(afe->mod);
error_adsp_get:
	mutex_unlock(&afe->lock);
	return rc;
}
示例#12
0
static void audpre_dsp_event(void *data, unsigned id,  void *event_data)
{

	uint16_t *msg = event_data;

	if (!msg)
		return;

	switch (id) {
	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
		MM_AUD_INFO("audpre: type %d, status_flag %d\n", msg[0], msg[1]);
		break;
	case AUDPREPROC_MSG_ERROR_MSG_ID:
		MM_AUD_INFO("audpre: err_index %d\n", msg[0]);
		break;
	case ADSP_MESSAGE_ID:
		MM_AUD_INFO("audpre: module enabled\n");
		break;
	default:
		MM_AUD_ERR("audpre: unknown event %d\n", id);
	}
}
示例#13
0
static void lpa_reset(struct lpa_drv *lpa)
{
	u32 status;
	struct clk *adsp_clk;
	/* Need to make sure not disable clock while other device is enabled */
	adsp_clk = clk_get(NULL, "adsp_clk");
	if (!adsp_clk) {
		MM_AUD_ERR("failed to get adsp clk\n");
		goto error;
	}
	clk_enable(adsp_clk);
	lpa_enable_codec(lpa, 0);
	LPA_REG_WRITEL(lpa, (LPA_OBUF_RESETS_MISR_RESET |
		LPA_OBUF_RESETS_OVERALL_RESET), LPA_OBUF_RESETS);
	do {
		status = LPA_REG_READL(lpa, LPA_OBUF_STATUS);
	} while (!(status & LPA_OBUF_STATUS_RESET_DONE));

	LPA_REG_WRITEL(lpa, LPA_OBUF_ACK_RESET_DONE_BMSK, LPA_OBUF_ACK);
	clk_disable(adsp_clk);
	clk_put(adsp_clk);
error:
	return;
}
static int audamrnb_in_open(struct inode *inode, struct file *file)
{
	struct audio_in *audio = &the_audio_amrnb_in;
	int rc;
	int encid;

	mutex_lock(&audio->lock);
	if (audio->opened) {
		rc = -EBUSY;
		goto done;
	}
	if ((file->f_mode & FMODE_WRITE) &&
			(file->f_mode & FMODE_READ)) {
		rc = -EACCES;
		MM_AUD_ERR("Non tunnel encoding is not supported\n");
		goto done;
	} else if (!(file->f_mode & FMODE_WRITE) &&
					(file->f_mode & FMODE_READ)) {
		audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
		MM_DBG("Opened for tunnel mode encoding\n");
	} else {
		rc = -EACCES;
		goto done;
	}


	/* Settings will be re-config at AUDIO_SET_CONFIG,
	 * but at least we need to have initial config
	 */
	audio->buffer_size = (FRAME_SIZE - 8);
	audio->enc_type = ENC_TYPE_AMRNB | audio->mode;
	audio->dtx_mode = -1;
	audio->frame_format = 0;
	audio->used_mode = 7; /* Bit Rate 12.2 kbps MR122 */

	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
			&audio->queue_ids);
	if (encid < 0) {
		MM_AUD_ERR("No free encoder available\n");
		rc = -ENODEV;
		goto done;
	}
	audio->enc_id = encid;

	rc = msm_adsp_get(audio->module_name, &audio->audrec,
			   &audrec_amrnb_adsp_ops, audio);

	if (rc) {
		audpreproc_aenc_free(audio->enc_id);
		goto done;
	}

	audio->stopped = 0;
	audio->source = 0;

	audamrnb_in_flush(audio);

	audio->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
				AUDDEV_EVT_VOICE_STATE_CHG;

	audio->voice_state = VOICE_STATE_INCALL;
	rc = auddev_register_evt_listner(audio->device_events,
					AUDDEV_CLNT_ENC, audio->enc_id,
					amrnb_in_listener, (void *) audio);
	if (rc) {
		MM_AUD_ERR("failed to register device event listener\n");
		goto evt_error;
	}
	file->private_data = audio;
	audio->opened = 1;
done:
	mutex_unlock(&audio->lock);
	return rc;
evt_error:
	msm_adsp_put(audio->audrec);
	audpreproc_aenc_free(audio->enc_id);
	mutex_unlock(&audio->lock);
	return rc;
}
static ssize_t audamrnb_in_read(struct file *file,
				char __user *buf,
				size_t count, loff_t *pos)
{
	struct audio_in *audio = file->private_data;
	unsigned long flags;
	const char __user *start = buf;
	void *data;
	uint32_t index;
	uint32_t size;
	int rc = 0;

	mutex_lock(&audio->read_lock);
	while (count > 0) {
		rc = wait_event_interruptible(
			audio->wait, (audio->in_count > 0) || audio->stopped
			|| (audio->in_call && audio->running &&
				(audio->voice_state == VOICE_STATE_OFFCALL)));
		if (rc < 0)
			break;

		if (!audio->in_count) {
			if (audio->stopped)  {
				rc = 0;/* End of File */
				break;
			} else if (audio->in_call && audio->running &&
				(audio->voice_state == VOICE_STATE_OFFCALL)) {
				MM_DBG("Not Permitted Voice Terminated\n");
				rc = -EPERM; /* Voice Call stopped */
				break;
			}
		}

		index = audio->in_tail;
		data = (uint8_t *) audio->in[index].data;
		size = audio->in[index].size;
		if (count >= size) {
			if (copy_to_user(buf, data, size)) {
				rc = -EFAULT;
				break;
			}
			spin_lock_irqsave(&audio->dsp_lock, flags);
			if (index != audio->in_tail) {
				/* overrun -- data is
				 * invalid and we need to retry */
				spin_unlock_irqrestore(&audio->dsp_lock, flags);
				continue;
			}
			audio->in[index].size = 0;
			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
			audio->in_count--;
			spin_unlock_irqrestore(&audio->dsp_lock, flags);
			count -= size;
			buf += size;
		} else {
			MM_AUD_ERR("short read\n");
			break;
		}
	}
	mutex_unlock(&audio->read_lock);

	if (buf > start)
		return buf - start;

	return rc;
}
示例#16
0
static int msm_voice_put(struct snd_kcontrol *kcontrol,
			struct snd_ctl_elem_value *ucontrol)
{
	int rc = 0;
	uint32_t rx_dev_id;
	uint32_t tx_dev_id;
	struct msm_snddev_info *rx_dev_info;
	struct msm_snddev_info *tx_dev_info;
	int set = ucontrol->value.integer.value[2];
	u32 session_mask;

	int i = 0, j = 0;
	struct snddev_icodec_state *icodec;
	struct adie_codec_hwsetting_entry *rx_entry;
	struct adie_codec_hwsetting_entry *tx_entry;
	struct timespec ts;
	struct rtc_time tm;

	/* if (!set)
		return -EPERM; */

	pr_aud_info("[ALSA] msm_route_voice: "
		"tx %d, rx %d, set %d\n",
		(int) ucontrol->value.integer.value[1],
		(int) ucontrol->value.integer.value[0],
		set);

	if (set) {
		getnstimeofday(&ts);
		rtc_time_to_tm(ts.tv_sec, &tm);
		pr_aud_info1("[ATS][phonecall_start][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);
	} else {
		getnstimeofday(&ts);
		rtc_time_to_tm(ts.tv_sec, &tm);
		pr_aud_info1("[ATS][phonecall_end][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);
	}

	/* Rx Device Routing */
	rx_dev_id = ucontrol->value.integer.value[0];
	rx_dev_info = audio_dev_ctrl_find_dev(rx_dev_id);

	if (IS_ERR(rx_dev_info)) {
		MM_AUD_ERR("pass invalid dev_id\n");
		rc = PTR_ERR(rx_dev_info);
		return rc;
	}

	if (!(rx_dev_info->capability & SNDDEV_CAP_RX)) {
		MM_AUD_ERR("First Dev is supposed to be RX\n");
		return -EFAULT;
	}

	MM_DBG("route cfg %d STREAM_VOICE_RX type\n",
		rx_dev_id);

	/* replace with Rx voice/media setting for adie */
	if (rx_dev_info->acdb_id != 10 &&
	    (rx_dev_info->acdb_id < 1000)) {
	    icodec = (struct snddev_icodec_state *)rx_dev_info->private_data;
	    rx_entry = icodec->data->profile->settings;
	    j = icodec->data->profile->setting_sz;
	    if (set) {
		for (i = 0; i < j; i++)
		    if (rx_entry[i].voc_action != NULL) {
			rx_entry[i].actions = rx_entry[i].voc_action;
			rx_entry[i].action_sz = rx_entry[i].voc_action_sz;
		    }
	    } else {
		for (i = 0; i < j; i++)
		    if (rx_entry[i].midi_action != NULL) {
			rx_entry[i].actions = rx_entry[i].midi_action;
			rx_entry[i].action_sz = rx_entry[i].midi_action_sz;
		    }
	    }
	}

	msm_set_voc_route(rx_dev_info, AUDIO_ROUTE_STREAM_VOICE_RX,
				rx_dev_id);

	session_mask =	0x1 << (8 * ((int)AUDDEV_CLNT_VOC-1));

	/* Tx Device Routing */
	tx_dev_id = ucontrol->value.integer.value[1];
	tx_dev_info = audio_dev_ctrl_find_dev(tx_dev_id);

	if (IS_ERR(tx_dev_info)) {
		MM_AUD_ERR("pass invalid dev_id\n");
		rc = PTR_ERR(tx_dev_info);
		return rc;
	}

	if (!(tx_dev_info->capability & SNDDEV_CAP_TX)) {
		MM_AUD_ERR("Second Dev is supposed to be Tx\n");
		return -EFAULT;
	}

	MM_DBG("route cfg %d %d type\n",
		tx_dev_id, AUDIO_ROUTE_STREAM_VOICE_TX);
	/* replace with Tx voice/media setting for adie */
	if (tx_dev_info->acdb_id != 9 &&
	    (tx_dev_info->acdb_id < 1000)) {
	    icodec = (struct snddev_icodec_state *)tx_dev_info->private_data;
	    tx_entry = icodec->data->profile->settings;
	    j = icodec->data->profile->setting_sz;
	    if (set) {
		for (i = 0; i < j; i++)
		    if (tx_entry[i].voc_action != NULL) {
			tx_entry[i].actions = tx_entry[i].voc_action;
			tx_entry[i].action_sz = tx_entry[i].voc_action_sz;
		    }
	    } else {
		for (i = 0; i < j; i++)
		    if (tx_entry[i].midi_action != NULL) {
			tx_entry[i].actions = tx_entry[i].midi_action;
			tx_entry[i].action_sz = tx_entry[i].midi_action_sz;
		    }
	    }
	}
	msm_set_voc_route(tx_dev_info, AUDIO_ROUTE_STREAM_VOICE_TX,
				tx_dev_id);

	broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, tx_dev_id, session_mask);

	if (set) {
	if (rx_dev_info->opened)
		broadcast_event(AUDDEV_EVT_DEV_RDY, rx_dev_id,	session_mask);

	if (tx_dev_info->opened)
		broadcast_event(AUDDEV_EVT_DEV_RDY, tx_dev_id, session_mask);
	}

	return rc;
}
示例#17
0
static ssize_t audpcm_in_read(struct file *file,
				char __user *buf,
				size_t count, loff_t *pos)
{
	struct audio_in *audio = file->private_data;
	unsigned long flags;
	const char __user *start = buf;
	void *data;
	uint32_t index;
	uint32_t size;
	int rc = 0;

	mutex_lock(&audio->read_lock);
	while (count > 0) {
		rc = wait_event_interruptible(
			audio->wait, (audio->in_count > 0) || audio->stopped ||
			audio->abort);

		if (rc < 0)
			break;

		if (audio->stopped && !audio->in_count) {
			MM_DBG("Driver in stop state, No more buffer to read");
			rc = 0;/* End of File */
			break;
		}

		if (audio->abort) {
			rc = -EPERM; /* Not permitted due to abort */
			break;
		}

		index = audio->in_tail;
		data = (uint8_t *) audio->in[index].data;
		size = audio->in[index].size;
		if (count >= size) {
			if (copy_to_user(buf, data, size)) {
				rc = -EFAULT;
				break;
			}
			spin_lock_irqsave(&audio->dsp_lock, flags);
			if (index != audio->in_tail) {
				/* overrun -- data is
				 * invalid and we need to retry */
				spin_unlock_irqrestore(&audio->dsp_lock, flags);
				continue;
			}
			audio->in[index].size = 0;
			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
			audio->in_count--;
			spin_unlock_irqrestore(&audio->dsp_lock, flags);
			count -= size;
			buf += size;
		} else {
			MM_AUD_ERR("short read\n");
			break;
		}
	}
	mutex_unlock(&audio->read_lock);

	if (buf > start)
		return buf - start;

	return rc;
}
示例#18
0
static long audio_dev_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	int rc = 0;
	struct audio_dev_ctrl_state *dev_ctrl = file->private_data;

	mutex_lock(&session_lock);
	switch (cmd) {
	case AUDIO_GET_NUM_SND_DEVICE:
		rc = put_user(dev_ctrl->num_dev, (uint32_t __user *) arg);
		break;
	case AUDIO_GET_SND_DEVICES:
		rc = audio_dev_ctrl_get_devices(dev_ctrl, (void __user *) arg);
		break;
	case AUDIO_ENABLE_SND_DEVICE: {
		struct msm_snddev_info *dev_info;
		u32 dev_id;

		if (get_user(dev_id, (u32 __user *) arg)) {
			rc = -EFAULT;
			break;
		}
		dev_info = audio_dev_ctrl_find_dev(dev_id);
		if (IS_ERR(dev_info))
			rc = PTR_ERR(dev_info);
		else {
			rc = dev_info->dev_ops.open(dev_info);
			if (!rc)
				dev_info->opened = 1;
			wake_up(&audio_dev_ctrl.wait);
		}
		break;

	}

	case AUDIO_DISABLE_SND_DEVICE: {
		struct msm_snddev_info *dev_info;
		u32 dev_id;

		if (get_user(dev_id, (u32 __user *) arg)) {
			rc = -EFAULT;
			break;
		}
		dev_info = audio_dev_ctrl_find_dev(dev_id);
		if (IS_ERR(dev_info))
			rc = PTR_ERR(dev_info);
		else {
			rc = dev_info->dev_ops.close(dev_info);
			dev_info->opened = 0;
		}
		break;
	}

	case AUDIO_ROUTE_STREAM: {
		struct msm_audio_route_config route_cfg;
		struct msm_snddev_info *dev_info;

		if (copy_from_user(&route_cfg, (void __user *) arg,
			sizeof(struct msm_audio_route_config))) {
			rc = -EFAULT;
			break;
		}
		MM_DBG("%s: route cfg %d %d type\n", __func__,
		route_cfg.dev_id, route_cfg.stream_type);
		dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
		if (IS_ERR(dev_info)) {
			MM_AUD_ERR("%s: pass invalid dev_id\n", __func__);
			rc = PTR_ERR(dev_info);
			break;
		}

		switch (route_cfg.stream_type) {

		case AUDIO_ROUTE_STREAM_VOICE_RX:
			if (!(dev_info->capability & SNDDEV_CAP_RX) |
			    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
				rc = -EINVAL;
				break;
			}
			dev_ctrl->voice_rx_dev = dev_info;
			break;
		case AUDIO_ROUTE_STREAM_VOICE_TX:
			if (!(dev_info->capability & SNDDEV_CAP_TX) |
			    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
				rc = -EINVAL;
				break;
			}
			dev_ctrl->voice_tx_dev = dev_info;
			break;
		}
		break;
	}

	default:
		rc = -EINVAL;
	}
	mutex_unlock(&session_lock);
	return rc;
}
示例#19
0
static int audpcm_in_open(struct inode *inode, struct file *file)
{
	struct audio_in *audio = &the_audio_in;
	int rc;
	int len = 0;
	unsigned long ionflag = 0;
	ion_phys_addr_t addr = 0;
	struct ion_handle *handle = NULL;
	struct ion_client *client = NULL;

	int encid;
	struct timespec ts;
	struct rtc_time tm;

	mutex_lock(&audio->lock);
	if (audio->opened) {
		rc = -EBUSY;
		goto done;
	}

	audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
	audio->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_11025;
	audio->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_11025;
	audio->channel_mode = AUDREC_CMD_STEREO_MODE_MONO;
	audio->buffer_size = MONO_DATA_SIZE;
	audio->enc_type = AUDREC_CMD_TYPE_0_INDEX_WAV | audio->mode;

	rc = audmgr_open(&audio->audmgr);
	if (rc)
		goto done;
	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
			&audio->queue_ids);
	if (encid < 0) {
		MM_AUD_ERR("No free encoder available\n");
		rc = -ENODEV;
		goto done;
	}
	audio->enc_id = encid;

	rc = msm_adsp_get(audio->module_name, &audio->audrec,
			   &audrec_adsp_ops, audio);
	if (rc) {
		audpreproc_aenc_free(audio->enc_id);
		goto done;
	}

	audio->dsp_cnt = 0;
	audio->stopped = 0;

	audpcm_in_flush(audio);

	client = msm_ion_client_create(UINT_MAX, "Audio_PCM_in_client");
	if (IS_ERR_OR_NULL(client)) {
		MM_ERR("Unable to create ION client\n");
		rc = -ENOMEM;
		goto client_create_error;
	}
	audio->client = client;

	MM_DBG("allocating mem sz = %d\n", DMASZ);
	handle = ion_alloc(client, DMASZ, SZ_4K,
		ION_HEAP(ION_AUDIO_HEAP_ID));
	if (IS_ERR_OR_NULL(handle)) {
		MM_ERR("Unable to create allocate O/P buffers\n");
		rc = -ENOMEM;
		goto output_buff_alloc_error;
	}

	audio->output_buff_handle = handle;

	rc = ion_phys(client , handle, &addr, &len);
	if (rc) {
		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
			(unsigned int) addr, (unsigned int) len);
		rc = -ENOMEM;
		goto output_buff_get_phys_error;
	} else {
		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
			(unsigned int) addr, (unsigned int) len);
	}
	audio->phys = (int32_t)addr;

	rc = ion_handle_get_flags(client, handle, &ionflag);
	if (rc) {
		MM_ERR("could not get flags for the handle\n");
		rc = -ENOMEM;
		goto output_buff_get_flags_error;
	}

	audio->data = ion_map_kernel(client, handle, ionflag);
	if (IS_ERR(audio->data)) {
		MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
				(int)audio);
		rc = -ENOMEM;
		goto output_buff_map_error;
	}
	MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
		audio->phys, (int)audio->data);

	file->private_data = audio;
	audio->opened = 1;
	rc = 0;
done:
	mutex_unlock(&audio->lock);
	getnstimeofday(&ts);
	rtc_time_to_tm(ts.tv_sec, &tm);
	pr_aud_info1("[ATS][start_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 rc;
output_buff_map_error:
output_buff_get_phys_error:
output_buff_get_flags_error:
	ion_free(client, audio->output_buff_handle);
output_buff_alloc_error:
	ion_client_destroy(client);
client_create_error:
	msm_adsp_put(audio->audrec);
	audpreproc_aenc_free(audio->enc_id);
	mutex_unlock(&audio->lock);
	return rc;
}
示例#20
0
static ssize_t audpcm_in_read(struct file *file,
				char __user *buf,
				size_t count, loff_t *pos)
{
	struct audio_in *audio = file->private_data;
	unsigned long flags;
	const char __user *start = buf;
	void *data;
	uint32_t index;
	uint32_t size;
	int rc = 0;

	mutex_lock(&audio->read_lock);
	while (count > 0) {
		rc = wait_event_interruptible_timeout(
			audio->wait, (audio->in_count > 0) || audio->stopped,
			msecs_to_jiffies(MSM_AUD_BUFFER_UPDATE_WAIT_MS));
		if (rc == 0) {
			rc = -ETIMEDOUT;
			break;
		} else if (rc < 0) {
			break;
		}

		if (audio->stopped && !audio->in_count) {
			rc = 0;
			break;
		}

		index = audio->in_tail;
		data = (uint8_t *) audio->in[index].data;
		size = audio->in[index].size;
		if (count >= size) {
			
			dma_coherent_post_ops();
			if (copy_to_user(buf, data, size)) {
				rc = -EFAULT;
				break;
			}
			spin_lock_irqsave(&audio->dsp_lock, flags);
			if (index != audio->in_tail) {
				spin_unlock_irqrestore(&audio->dsp_lock, flags);
				continue;
			}
			audio->in[index].size = 0;
			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
			audio->in_count--;
			spin_unlock_irqrestore(&audio->dsp_lock, flags);
			count -= size;
			buf += size;
		} else {
			MM_AUD_ERR("audio_in: short read... count %d, size %d\n", count, size);
			break;
		}
	}
	mutex_unlock(&audio->read_lock);

	if (buf > start)
		return buf - start;

	return rc;
}
示例#21
0
/* session id is 32 bit routing mask per device
 * 0-7 for voice clients
 * 8-15 for Decoder clients
 * 16-23 for Encoder clients
 * 24-31 Do not care
 */
void broadcast_event(u32 evt_id, u32 dev_id, u32 session_id)
{
	int clnt_id = 0;
	union auddev_evt_data *evt_payload;
	struct msm_snd_evt_listner *callback;
	struct msm_snddev_info *dev_info = NULL;
	u32 session_mask = 0;
	static int pending_sent;

	MM_DBG(": evt_id = %d\n", evt_id);

	if ((evt_id != AUDDEV_EVT_START_VOICE)
		&& (evt_id != AUDDEV_EVT_END_VOICE)
                && (evt_id != AUDDEV_EVT_STREAM_VOL_CHG)
                && (evt_id != AUDDEV_EVT_VOICE_STATE_CHG)) {
		dev_info = audio_dev_ctrl_find_dev(dev_id);
                if (IS_ERR(dev_info)) {
                        MM_ERR("pass invalid dev_id\n");
			return;
	}
        }

	if (event.cb != NULL)
		callback = event.cb;
	else
		return;
	mutex_lock(&session_lock);

        if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
                routing_info.voice_state = dev_id;

	evt_payload = kzalloc(sizeof(union auddev_evt_data),
			GFP_KERNEL);

	if (!evt_payload) {
		MM_AUD_ERR("%s: fail to allocate memory\n", __func__);
		return;
	}

	for (; ;) {
		if (!(evt_id & callback->evt_id)) {
			if (callback->cb_next == NULL)
				break;
			else {
				callback = callback->cb_next;
				continue;
			}
		}
		clnt_id = callback->clnt_id;
		memset(evt_payload, 0, sizeof(union auddev_evt_data));

		if ((evt_id == AUDDEV_EVT_START_VOICE)
			|| (evt_id == AUDDEV_EVT_END_VOICE))
			goto skip_check;
		if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL)
			goto aud_cal;

		session_mask = (0x1 << (clnt_id))
				<< (8 * ((int)callback->clnt_type-1));

                if ((evt_id == AUDDEV_EVT_STREAM_VOL_CHG) || 
                        (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)) {
			MM_DBG("AUDDEV_EVT_STREAM_VOL_CHG or\
                                AUDDEV_EVT_VOICE_STATE_CHG\n");
			goto volume_strm;
		}

		MM_DBG("dev_info->sessions = %08x\n", dev_info->sessions);

		if ((!session_id && !(dev_info->sessions & session_mask)) ||
			(session_id && ((dev_info->sessions & session_mask) !=
						session_id))) {
			if (callback->cb_next == NULL)
				break;
			else {
				callback = callback->cb_next;
				continue;
			}
		}
		if (evt_id == AUDDEV_EVT_DEV_CHG_VOICE)
			goto voc_events;

volume_strm:
		if (callback->clnt_type == AUDDEV_CLNT_DEC) {
			MM_DBG("AUDDEV_CLNT_DEC\n");
			if (evt_id == AUDDEV_EVT_STREAM_VOL_CHG) {
				MM_DBG("clnt_id = %d, session_id = 0x%8x\n",
					clnt_id, session_id);
				if (session_mask != session_id)
					goto sent_dec;
				else
					evt_payload->session_vol =
						msm_vol_ctl.volume;
			} else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
				if (routing_info.dec_freq[clnt_id].evt) {
					routing_info.dec_freq[clnt_id].evt
							= 0;
					goto sent_dec;
				} else if (routing_info.dec_freq[clnt_id].freq
					== dev_info->set_sample_rate)
					goto sent_dec;
				else {
					evt_payload->freq_info.sample_rate
						= dev_info->set_sample_rate;
					evt_payload->freq_info.dev_type
						= dev_info->capability;
					evt_payload->freq_info.acdb_dev_id
						= dev_info->acdb_id;
				}
			} else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
                                evt_payload->voice_state =
                                        routing_info.voice_state;
                        else if (dev_info != NULL)
				evt_payload->routing_id = dev_info->copp_id;
			callback->auddev_evt_listener(
					evt_id,
					evt_payload,
					callback->private_data);
sent_dec:
                        if ((evt_id != AUDDEV_EVT_STREAM_VOL_CHG) &&
                                (evt_id != AUDDEV_EVT_VOICE_STATE_CHG))
				routing_info.dec_freq[clnt_id].freq
						= dev_info->set_sample_rate;

			if (callback->cb_next == NULL)
				break;
			else {
				callback = callback->cb_next;
				continue;
			}
		}
		if (callback->clnt_type == AUDDEV_CLNT_ENC) {
			MM_DBG("AUDDEV_CLNT_ENC\n");
			if (evt_id == AUDDEV_EVT_FREQ_CHG) {
				if (routing_info.enc_freq[clnt_id].evt) {
					routing_info.enc_freq[clnt_id].evt
							= 0;
					goto sent_enc;
				 } else {
					evt_payload->freq_info.sample_rate
						= dev_info->set_sample_rate;
					evt_payload->freq_info.dev_type
						= dev_info->capability;
					evt_payload->freq_info.acdb_dev_id
						= dev_info->acdb_id;
				}
			} else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
                                evt_payload->voice_state =
                                        routing_info.voice_state;
                        else
				evt_payload->routing_id = dev_info->copp_id;
			callback->auddev_evt_listener(
					evt_id,
					evt_payload,
					callback->private_data);
sent_enc:
			if (callback->cb_next == NULL)
					break;
			else {
				callback = callback->cb_next;
				continue;
			}
		}
aud_cal:
		if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL) {
                        int temp_sessions;
			MM_DBG("AUDDEV_CLNT_AUDIOCAL\n");
			if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
                                evt_payload->voice_state =
                                        routing_info.voice_state;
                        else if (!dev_info->sessions)
				goto sent_aud_cal;
			else {
                                evt_payload->audcal_info.dev_id =
                                                dev_info->copp_id;
			evt_payload->audcal_info.acdb_id =
				dev_info->acdb_id;
			evt_payload->audcal_info.dev_type =
				(dev_info->capability & SNDDEV_CAP_TX) ?
				SNDDEV_CAP_TX : SNDDEV_CAP_RX;
			evt_payload->audcal_info.sample_rate =
				dev_info->set_sample_rate ?
				dev_info->set_sample_rate :
				dev_info->sample_rate;
                        }
                        if (evt_payload->audcal_info.dev_type ==
                                                SNDDEV_CAP_TX) {
                                if (session_id == SESSION_IGNORE)
                                        temp_sessions = dev_info->sessions;
                                else
                                        temp_sessions = session_id;
                                evt_payload->audcal_info.sessions =
                                        (temp_sessions >>
                                                ((AUDDEV_CLNT_ENC-1) * 8));
                        } else {
                                if (session_id == SESSION_IGNORE)
示例#22
0
int __msm_adsp_write(struct msm_adsp_module *module, unsigned dsp_queue_addr,
		   void *cmd_buf, size_t cmd_size)
{
	uint32_t ctrl_word;
	uint32_t dsp_q_addr;
	uint32_t dsp_addr;
	uint32_t cmd_id = 0;
	int cnt = 0;
	int ret_status = 0;
	unsigned long flags;
	struct adsp_info *info;

	if (!module || !cmd_buf) {
		MM_AUD_ERR("Called with NULL parameters\n");
		return -EINVAL;
	}
	info = module->info;
	spin_lock_irqsave(&adsp_write_lock, flags);

	if (module->state != ADSP_STATE_ENABLED) {
		spin_unlock_irqrestore(&adsp_write_lock, flags);
		MM_AUD_ERR("module %s not enabled before write\n",
				module->name);
		return -ENODEV;
	}
	if (adsp_validate_module(module->id)) {
		spin_unlock_irqrestore(&adsp_write_lock, flags);
		MM_AUD_INFO("module id validation failed %s  %d\n",
				module->name, module->id);
		return -ENXIO;
	}
	if (dsp_queue_addr >= QDSP_MAX_NUM_QUEUES) {
		spin_unlock_irqrestore(&adsp_write_lock, flags);
		MM_AUD_INFO("Invalid Queue Index: %d\n", dsp_queue_addr);
		return -ENXIO;
	}
	if (adsp_validate_queue(module->id, dsp_queue_addr, cmd_size)) {
		spin_unlock_irqrestore(&adsp_write_lock, flags);
		return -EINVAL;
	}
	dsp_q_addr = adsp_get_queue_offset(info, dsp_queue_addr);
	dsp_q_addr &= ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M;

	/* Poll until the ADSP is ready to accept a command.
	 * Wait for 100us, return error if it's not responding.
	 * If this returns an error, we need to disable ALL modules and
	 * then retry.
	 */
	while (((ctrl_word = readl(info->write_ctrl)) &
		ADSP_RTOS_WRITE_CTRL_WORD_READY_M) !=
		ADSP_RTOS_WRITE_CTRL_WORD_READY_V) {
		if (cnt > 50) {
			MM_AUD_ERR("timeout waiting for DSP write ready\n");
			ret_status = -EIO;
			goto fail;
		}
		MM_DBG("waiting for DSP write ready\n");
		udelay(2);
		cnt++;
	}

	/* Set the mutex bits */
	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M);
	ctrl_word |=  ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V;

	/* Clear the command bits */
	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M);

	/* Set the queue address bits */
	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M);
	ctrl_word |= dsp_q_addr;

	writel(ctrl_word, info->write_ctrl);

	/* Generate an interrupt to the DSP.  This notifies the DSP that
	 * we are about to send a command on this particular queue.  The
	 * DSP will in response change its state.
	 */
	writel(1, info->send_irq);

	/* Poll until the adsp responds to the interrupt; this does not
	 * generate an interrupt from the adsp.  This should happen within
	 * 5ms.
	 */
	cnt = 0;
	while ((readl(info->write_ctrl) &
		ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M) ==
		ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V) {
		if (cnt > 2500) {
			MM_AUD_ERR("timeout waiting for adsp ack\n");
			ret_status = -EIO;
			goto fail;
		}
		udelay(2);
		cnt++;
	}

	/* Read the ctrl word */
	ctrl_word = readl(info->write_ctrl);

	if ((ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_STATUS_M) !=
	    ADSP_RTOS_WRITE_CTRL_WORD_NO_ERR_V) {
		ret_status = -EAGAIN;
		goto fail;
	} else {
		/* No error */
		/* Get the DSP buffer address */
		dsp_addr = (ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M) +
			   (uint32_t)MSM_AD5_BASE;

		if (dsp_addr < (uint32_t)(MSM_AD5_BASE + QDSP_RAMC_OFFSET)) {
			uint16_t *buf_ptr = (uint16_t *) cmd_buf;
			uint16_t *dsp_addr16 = (uint16_t *)dsp_addr;
			cmd_size /= sizeof(uint16_t);

			/* Save the command ID */
			cmd_id = (uint32_t) buf_ptr[0];

			/* Copy the command to DSP memory */
			cmd_size++;
			while (--cmd_size)
				*dsp_addr16++ = *buf_ptr++;
		} else {
			uint32_t *buf_ptr = (uint32_t *) cmd_buf;
			uint32_t *dsp_addr32 = (uint32_t *)dsp_addr;
			cmd_size /= sizeof(uint32_t);

			/* Save the command ID */
			cmd_id = buf_ptr[0];

			cmd_size++;
			while (--cmd_size)
				*dsp_addr32++ = *buf_ptr++;
		}

		/* Set the mutex bits */
		ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M);
		ctrl_word |=  ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V;

		/* Set the command bits to write done */
		ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M);
		ctrl_word |= ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_DONE_V;

		/* Set the queue address bits */
		ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M);
		ctrl_word |= dsp_q_addr;

		writel(ctrl_word, info->write_ctrl);

		/* Generate an interrupt to the DSP.  It does not respond with
		 * an interrupt, and we do not need to wait for it to
		 * acknowledge, because it will hold the mutex lock until it's
		 * ready to receive more commands again.
		 */
		writel(1, info->send_irq);

		module->num_commands++;
	} /* Ctrl word status bits were 00, no error in the ctrl word */

fail:
	spin_unlock_irqrestore(&adsp_write_lock, flags);
	return ret_status;
}
示例#23
0
static int audpcm_in_open(struct inode *inode, struct file *file)
{
	struct audio_in *audio = &the_audio_in;
	int rc;
	int encid;
	struct timespec ts;
	struct rtc_time tm;

	mutex_lock(&audio->lock);
	if (audio->opened) {
		rc = -EBUSY;
		goto done;
	}
	/* Settings will be re-config at AUDIO_SET_CONFIG,
	 * but at least we need to have initial config
	 */
	audio->channel_mode = AUDREC_CMD_MODE_MONO;
	audio->buffer_size = MONO_DATA_SIZE;
	audio->samp_rate = 8000;
	audio->enc_type = ENC_TYPE_WAV | audio->mode;
	audio->source = INTERNAL_CODEC_TX_SOURCE_MIX_MASK;

	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
			&audio->queue_ids);
	if (encid < 0) {
		MM_AUD_ERR("No free encoder available\n");
		rc = -ENODEV;
		goto done;
	}
	audio->enc_id = encid;

	rc = msm_adsp_get(audio->module_name, &audio->audrec,
			   &audrec_adsp_ops, audio);

	if (rc) {
		audpreproc_aenc_free(audio->enc_id);
		goto done;
	}

	audio->stopped = 0;
	audio->source = 0;
	audio->abort = 0;
	audpcm_in_flush(audio);
	audio->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
				AUDDEV_EVT_FREQ_CHG;

	rc = auddev_register_evt_listner(audio->device_events,
					AUDDEV_CLNT_ENC, audio->enc_id,
					pcm_in_listener, (void *) audio);
	if (rc) {
		MM_AUD_ERR("failed to register device event listener\n");
		goto evt_error;
	}
	file->private_data = audio;
	audio->opened = 1;
	rc = 0;
done:
	mutex_unlock(&audio->lock);
	getnstimeofday(&ts);
	rtc_time_to_tm(ts.tv_sec, &tm);
	pr_aud_info1("[ATS][start_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 rc;
evt_error:
	msm_adsp_put(audio->audrec);
	audpreproc_aenc_free(audio->enc_id);
	mutex_unlock(&audio->lock);
	return rc;
}
示例#24
0
static void adsp_rtos_mtoa_cb(void *context, uint32_t param,
					void *evt_buf, uint32_t len)
{
	struct adsp_rtos_mp_mtoa_s_type *args = NULL;
	uint32_t event = 0;
	uint32_t proc_id = 0;
	uint32_t module_id;
	uint32_t image;
	struct msm_adsp_module *module;
	struct adsp_rtos_mp_mtoa_type	*pkt_ptr;
	struct queue_to_offset_type	*qptr;
	struct queue_to_offset_type	*qtbl;
	struct mod_to_queue_offsets	*mqptr;
	struct mod_to_queue_offsets	*mqtbl;
	uint32_t	*mptr;
	uint32_t	*mtbl;
	uint32_t	q_idx;
	uint32_t	num_entries;
	uint32_t	entries_per_image;
	struct adsp_rtos_mp_mtoa_init_info_type *iptr;
	struct adsp_rtos_mp_mtoa_init_info_type	*sptr;
	int32_t		i_no, e_idx;
	static uint32_t	init_info_completed;
	static uint32_t init_info_len =
				sizeof(struct adsp_rtos_mp_mtoa_header_type);
	static uint32_t	next_init_info_byte;
	static uint32_t expected_byte = 1;
	uint32_t hdr_len = sizeof(struct adsp_rtos_mp_mtoa_header_type);

	if (len) {
		args = (struct adsp_rtos_mp_mtoa_s_type *) evt_buf;
		event = args->mp_mtoa_header.event;
		proc_id = args->mp_mtoa_header.proc_id;
	}

	if (!init_info_completed && event == RPC_ADSP_RTOS_INIT_INFO) {
		memcpy(((char *)adsp_info.raw_event) + init_info_len,
						(char *)evt_buf + hdr_len + 4,
							len - ((hdr_len + 4)));
		init_info_len += (len - (hdr_len + 4));
		evt_buf += hdr_len;
		next_init_info_byte = *(uint32_t *) evt_buf;
		expected_byte += len;
		if (next_init_info_byte &&
				(expected_byte != next_init_info_byte)) {
			MM_AUD_ERR("INIT_INFO - expecting next byte to be %d\n"
				"\tbut ADSPSVC indicated next byte to be %d\n",
				expected_byte, next_init_info_byte);
			return;
		}
		if (!next_init_info_byte) {
			args = adsp_info.raw_event;
			args->mp_mtoa_header.event = event;
			args->mp_mtoa_header.proc_id = proc_id;
			init_info_completed = 1;
		} else
			return;
	}

	if (event == RPC_ADSP_RTOS_INIT_INFO) {
		MM_AUD_INFO("INIT_INFO Event\n");
		sptr = &args->adsp_rtos_mp_mtoa_data.mp_mtoa_init_packet;

		iptr = adsp_info.init_info_ptr;
		iptr->image_count = sptr->image_count;
		if (iptr->image_count > IMG_MAX)
			iptr->image_count = IMG_MAX;
		iptr->num_queue_offsets = sptr->num_queue_offsets;
		num_entries = iptr->num_queue_offsets;
		if (num_entries > ENTRIES_MAX) {
			num_entries = ENTRIES_MAX;
			iptr->num_queue_offsets = ENTRIES_MAX;
		}
		qptr = &sptr->queue_offsets_tbl[0][0];
		for (i_no = 0; i_no < iptr->image_count; i_no++) {
			qtbl = &iptr->queue_offsets_tbl[i_no][0];
			for (e_idx = 0; e_idx < num_entries; e_idx++) {
				qtbl[e_idx].offset = qptr->offset;
				qtbl[e_idx].queue = qptr->queue;
				q_idx = qptr->queue;
				iptr->queue_offsets[i_no][q_idx] =
							qtbl[e_idx].offset;
				qptr++;
			}
		}

		num_entries = sptr->num_task_module_entries;
		if (num_entries > ENTRIES_MAX)
			num_entries = ENTRIES_MAX;
		iptr->num_task_module_entries = num_entries;
		entries_per_image = num_entries / iptr->image_count;
		mptr = &sptr->task_to_module_tbl[0][0];
		for (i_no = 0; i_no < iptr->image_count; i_no++) {
			mtbl = &iptr->task_to_module_tbl[i_no][0];
			for (e_idx = 0; e_idx < entries_per_image; e_idx++) {
				mtbl[e_idx] = *mptr;
				mptr++;
			}
		}

		iptr->module_table_size = sptr->module_table_size;
		if (iptr->module_table_size > MODULES_MAX)
			iptr->module_table_size = MODULES_MAX;
		mptr = &sptr->module_entries[0];
		for (i_no = 0; i_no < iptr->module_table_size; i_no++)
			iptr->module_entries[i_no] = mptr[i_no];

		mqptr = &sptr->mod_to_q_tbl[0];
		mqtbl = &iptr->mod_to_q_tbl[0];
		iptr->mod_to_q_entries = sptr->mod_to_q_entries;
		if (iptr->mod_to_q_entries > ENTRIES_MAX)
			iptr->mod_to_q_entries = ENTRIES_MAX;
		for (e_idx = 0; e_idx < iptr->mod_to_q_entries; e_idx++) {
			mqtbl[e_idx].module = mqptr->module;
			mqtbl[e_idx].q_type = mqptr->q_type;
			mqtbl[e_idx].q_max_len = mqptr->q_max_len;
			mqptr++;
		}

		adsp_info.init_info_state = ADSP_STATE_INIT_INFO;
		kfree(adsp_info.raw_event);
		wake_up(&adsp_info.init_info_wait);
		return;
	}

	if (args != NULL) {
		pkt_ptr = &args->adsp_rtos_mp_mtoa_data.mp_mtoa_packet;
		module_id = pkt_ptr->module;
		image     = pkt_ptr->image;

		MM_AUD_INFO("rpc event=%d, proc_id=%d, module=%d, image=%d\n",
			event, proc_id, module_id, image);

		module = find_adsp_module_by_id(&adsp_info, module_id);
		if (!module) {
			MM_AUD_ERR("module %d is not supported!\n", module_id);
			return;
		}
	} else {
		MM_AUD_ERR("NULL args\n");
		return;
	}

	mutex_lock(&module->lock);
	switch (event) {
	case RPC_ADSP_RTOS_MOD_READY:
		MM_AUD_INFO("module %s: READY\n", module->name);
		module->state = ADSP_STATE_ENABLED;
		wake_up(&module->state_wait);
		adsp_set_image(module->info, image);
		break;
	case RPC_ADSP_RTOS_MOD_DISABLE:
		MM_AUD_INFO("module %s: DISABLED\n", module->name);
		module->state = ADSP_STATE_DISABLED;
		wake_up(&module->state_wait);
		break;
	case RPC_ADSP_RTOS_SERVICE_RESET:
		MM_AUD_INFO("module %s: SERVICE_RESET\n", module->name);
		module->state = ADSP_STATE_DISABLED;
		wake_up(&module->state_wait);
		break;
	case RPC_ADSP_RTOS_CMD_SUCCESS:
		MM_AUD_INFO("module %s: CMD_SUCCESS\n", module->name);
		break;
	case RPC_ADSP_RTOS_CMD_FAIL:
		MM_AUD_INFO("module %s: CMD_FAIL\n", module->name);
		break;
	case RPC_ADSP_RTOS_DISABLE_FAIL:
		MM_AUD_INFO("module %s: DISABLE_FAIL\n", module->name);
		break;
	default:
		MM_AUD_ERR("unknown event %d\n", event);
		mutex_unlock(&module->lock);
		return;
	}
#ifdef CONFIG_MSM_ADSP_REPORT_EVENTS
	event_addr = (uint32_t *)evt_buf;
	if (module->ops)
		module->ops->event(module->driver_data,
					EVENT_MSG_ID,
					EVENT_LEN,
					read_event);
#endif
	mutex_unlock(&module->lock);
}
示例#25
0
static void pcm_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))
			audpcm_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)
			audpcm_in_record_config(audio, 1);
		else
			/* Turn off all */
			audpcm_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)
                                audpcm_in_record_config(audio, 1);
                        else if (audio->voice_state == VOICE_STATE_OFFCALL) {
                                audpcm_in_record_config(audio, 0);
                                wake_up(&audio->wait);
                        }
                }
                break;
        }
	case AUDDEV_EVT_FREQ_CHG: {
		MM_DBG("Encoder Driver got sample rate change event\n");
		MM_DBG("sample rate %d\n", evt_payload->freq_info.sample_rate);
		MM_DBG("dev_type %d\n", evt_payload->freq_info.dev_type);
		MM_DBG("acdb_dev_id %d\n", evt_payload->freq_info.acdb_dev_id);
		if (audio->running == 1) {
			/* Stop Recording sample rate does not match
			   with device sample rate */
			if (evt_payload->freq_info.sample_rate !=
				audio->samp_rate) {
				audpcm_in_record_config(audio, 0);
				audio->abort = 1;
				wake_up(&audio->wait);
			}
		}
		break;
	}
	default:
		MM_AUD_ERR("wrong event %d\n", evt_id);
		break;
	}
}
static int audpcm_in_open(struct inode *inode, struct file *file)
{
	struct audio_in *audio;
	const char *modname;	
	int rc;


	audio = kzalloc(sizeof(struct audio_in), GFP_KERNEL);

	if (!audio) return -ENOMEM;

#ifdef TEST_ONLY
	current_audio_in = audio;
#endif

        audio->phys = pmem_kalloc(DMASZ, PMEM_MEMTYPE_EBI1 | PMEM_ALIGNMENT_4K);
        if (!IS_ERR((void *) audio->phys)) {
		audio->data = ioremap(audio->phys, DMASZ);
                if (!audio->data) {
       	                MM_AUD_ERR("Could not remap DMA buffers\n");
               	        pmem_kfree(audio->phys);
			kfree(audio);
                       	return -ENOMEM;
	}
	} else {
       	        MM_AUD_ERR("Could not allocate DMA buffers\n");
		kfree(audio);
               	return -ENOMEM;
	}

	audio->enc_id = audpreproc_aenc_alloc(ENC_TYPE_WAV | MSM_AUD_ENC_MODE_TUNNEL, 
					&modname, &audio->queue_ids);
	if (audio->enc_id < 0) {
		MM_AUD_ERR("No free encoder available\n");
		rc = -ENODEV;
		goto no_aenc;
	}

	MM_DBG("allocated encoder %d, module %s\n", audio->enc_id, modname);

	rc = auddev_register_evt_listner(AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
					AUDDEV_EVT_FREQ_CHG | AUDDEV_EVT_VOICE_STATE_CHG,
					AUDDEV_CLNT_ENC, audio->enc_id,
					audpcm_in_listener, audio);
	if (rc) {
		MM_AUD_ERR("failed to register device event listener\n");
		goto evt_error;
	}

	rc = msm_adsp_get(modname, &audio->audrec, &audrec_adsp_ops, audio);

	if (rc) {
		MM_AUD_ERR("Failed to get AUDREC task\n");
		goto no_audrec;
	}

	if(!audio->audrec) {
		MM_AUD_ERR("Null AUDREC task returned by ADSP\n");
		rc = -EFAULT;
		goto no_audrec;
	}

	audio->source  = INTERNAL_CODEC_TX_SOURCE_MIX_MASK;
	audio->channel_mode = AUDREC_CMD_MODE_MONO;
	audio->buffer_size = MONO_DATA_SIZE;
	audio->samp_rate = 8000;
	audio->stopped = 0;
	audio->running = 0;
	audio->enabled = 0;
	audpcm_in_flush(audio);

	mutex_init(&audio->lock);
	mutex_init(&audio->read_lock);
	spin_lock_init(&audio->dsp_lock);
	spin_lock_init(&audio->dev_lock);
	init_waitqueue_head(&audio->wait);
	init_waitqueue_head(&audio->wait_enable);
	init_waitqueue_head(&audio->wait_voice_incall);
	init_waitqueue_head(&audio->wait_rec_cfg);

        audio->voice_state = msm_get_voice_state();

	file->private_data = audio;

	return rc;

no_audrec:
	auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, audio->enc_id);
evt_error:
	audpreproc_aenc_free(audio->enc_id);

no_aenc:
        iounmap(audio->data);
	pmem_kfree(audio->phys);
	kfree(audio);	

	return rc;
}
示例#27
0
static int msm_device_put(struct snd_kcontrol *kcontrol,
			struct snd_ctl_elem_value *ucontrol)
{
	int rc = 0;
	int set = 0;
	struct msm_audio_route_config route_cfg;
	struct msm_snddev_info *dev_info;
	int tx_freq = 0;
	int rx_freq = 0;
	u32 set_freq = 0;
	int retry = 3;

	set = ucontrol->value.integer.value[0];
	route_cfg.dev_id = ucontrol->id.numid - device_index;
	dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
	if (IS_ERR(dev_info)) {
		MM_AUD_ERR("pass invalid dev_id\n");
		rc = PTR_ERR(dev_info);
		return rc;
	}
	MM_AUD_INFO("device %s set %d\n", dev_info->name, set);
	pr_aud_info("[ALSA] msm_en_device (dev %s, id %d, enable %d, opened %d)\n",
		dev_info->name, route_cfg.dev_id, set, dev_info->opened);
	if (set) {
		if (!dev_info->opened) {
			set_freq = dev_info->sample_rate;
			if (!msm_device_is_voice(route_cfg.dev_id)) {
				msm_get_voc_freq(&tx_freq, &rx_freq);
				if (dev_info->capability & SNDDEV_CAP_TX)
					set_freq = tx_freq;

				if (set_freq == 0)
					set_freq = dev_info->sample_rate;
			} else
				set_freq = dev_info->sample_rate;


			MM_AUD_INFO("device freq =%d\n", set_freq);
			rc = dev_info->dev_ops.set_freq(dev_info, set_freq);
			if (rc < 0) {
				MM_AUD_ERR("device freq failed!\n");
				return rc;
			}
			dev_info->set_sample_rate = rc;
			rc = 0;
			do{
				rc = dev_info->dev_ops.open(dev_info);
				retry--;
			} while (rc < 0 && retry);

			if (rc < 0) {
				MM_AUD_ERR("Enabling %s failed, rc=%d\n", dev_info->name, rc);
				return rc;
			}
			dev_info->opened = 1;
			pr_aud_info("set device %s opened as %d\n",
				dev_info->name, dev_info->opened);
			broadcast_event(AUDDEV_EVT_DEV_RDY, route_cfg.dev_id,
							SESSION_IGNORE);
		}
	} else {
		if (dev_info->opened) {
			broadcast_event(AUDDEV_EVT_REL_PENDING,
						route_cfg.dev_id,
						SESSION_IGNORE);
			rc = dev_info->dev_ops.close(dev_info);
			if (rc < 0) {
				MM_AUD_ERR("Snd device failed close!\n");
				return rc;
			} else {
				dev_info->opened = 0;
				pr_aud_info("set device %s opened as %d\n",
					dev_info->name, dev_info->opened);
				broadcast_event(AUDDEV_EVT_DEV_RLS,
					route_cfg.dev_id,
					SESSION_IGNORE);
			}
		}

	}
	return rc;
}
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_AUD_ERR("wrong event %d\n", evt_id);
		break;
	}
}
示例#29
0
static int msm_route_put(struct snd_kcontrol *kcontrol,
			struct snd_ctl_elem_value *ucontrol)
{
	int rc = 0;
	int enc_freq = 0;
	int requested_freq = 0;
	struct msm_audio_route_config route_cfg;
	struct msm_snddev_info *dev_info;
	int session_id = ucontrol->value.integer.value[0];
	int set = ucontrol->value.integer.value[2];
	u32 session_mask = 0;
	route_cfg.dev_id = ucontrol->value.integer.value[1];

	pr_aud_info("[ALSA] msm_route_stream: session %d, dev %d, enable %d\n",
		session_id, route_cfg.dev_id, set);
	if (ucontrol->id.numid == 2)
		route_cfg.stream_type =	AUDIO_ROUTE_STREAM_PLAYBACK;
	else
		route_cfg.stream_type =	AUDIO_ROUTE_STREAM_REC;

	MM_DBG("route cfg %d %d type for popp %d\n",
		route_cfg.dev_id, route_cfg.stream_type, session_id);
	dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);

	if (IS_ERR(dev_info)) {
		MM_AUD_ERR("pass invalid dev_id\n");
		rc = PTR_ERR(dev_info);
		return rc;
	}
	if (route_cfg.stream_type == AUDIO_ROUTE_STREAM_PLAYBACK) {
		rc = msm_snddev_set_dec(session_id, dev_info->copp_id, set);
		session_mask =
			(0x1 << (session_id) << (8 * ((int)AUDDEV_CLNT_DEC-1)));
		if (!set) {
			if (dev_info->opened)
				broadcast_event(AUDDEV_EVT_DEV_RLS,
							route_cfg.dev_id,
							session_mask);
			dev_info->sessions &= ~(session_mask);
		} else {
			dev_info->sessions = dev_info->sessions | session_mask;
			if (dev_info->opened)
				broadcast_event(AUDDEV_EVT_DEV_RDY,
							route_cfg.dev_id,
							session_mask);
		}
	} else {
		rc = msm_snddev_set_enc(session_id, dev_info->copp_id, set);
		session_mask =
			(0x1 << (session_id)) << (8 * ((int)AUDDEV_CLNT_ENC-1));
		if (!set) {
			if (dev_info->opened)
				broadcast_event(AUDDEV_EVT_DEV_RLS,
							route_cfg.dev_id,
							session_mask);
			dev_info->sessions &= ~(session_mask);
		} else {
			dev_info->sessions = dev_info->sessions | session_mask;
			enc_freq = msm_snddev_get_enc_freq(session_id);
			requested_freq = enc_freq;
			if (enc_freq > 0) {
				rc = msm_snddev_request_freq(&enc_freq,
						session_id,
						SNDDEV_CAP_TX,
						AUDDEV_CLNT_ENC);
				MM_DBG("sample rate configured %d"
					"sample rate requested %d \n",
					enc_freq, requested_freq);
				if ((rc <= 0) || (enc_freq != requested_freq)) {
					MM_DBG("msm_snddev_withdraw_freq\n");
					rc = msm_snddev_withdraw_freq
						(session_id,
						SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
					broadcast_event(AUDDEV_EVT_FREQ_CHG,
							route_cfg.dev_id,
							SESSION_IGNORE);
				}
			}
			if (dev_info->opened)
				broadcast_event(AUDDEV_EVT_DEV_RDY,
							route_cfg.dev_id,
							session_mask);
		}
	}

	if (rc < 0) {
		MM_AUD_ERR("device could not be assigned!\n");
		return -EFAULT;
	}

	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_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_AUD_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;
}