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; }
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; }
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; }
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); }
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; }
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; }
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); } }
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; }
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; }
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); } }
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; }
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; }
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; }
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; }
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; }
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; }
/* 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)
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; }
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; }
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); }
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; }
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; } }
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; }