Loading sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c +184 −23 Original line number Diff line number Diff line Loading @@ -195,18 +195,21 @@ static void pcm_afe_process_tx_pkt(uint32_t opcode, * Multiplication by 1000000 is done in two * steps to keep the accuracy of poll time. */ if (prtd->mmap_flag) { period_bytes = ((uint64_t)( (snd_pcm_lib_period_bytes( prtd->substream)) * 1000)); bytes_one_sec = (runtime->rate * runtime->channels * 2); bytes_one_sec = (runtime->rate * runtime->channels * 2); bytes_one_sec = div_u64(bytes_one_sec, 1000); prtd->poll_time = div_u64(period_bytes, bytes_one_sec); div_u64(period_bytes, bytes_one_sec); pr_debug("prtd->poll_time: %d", prtd->poll_time); } break; } case AFE_EVENT_RTPORT_STOP: Loading Loading @@ -255,6 +258,7 @@ static void pcm_afe_process_rx_pkt(uint32_t opcode, uint16_t event; uint64_t period_bytes; uint64_t bytes_one_sec; uint32_t mem_map_handle = 0; if (prtd == NULL) return; Loading @@ -276,14 +280,33 @@ static void pcm_afe_process_rx_pkt(uint32_t opcode, * Multiplication by 1000000 is done in two steps to * keep the accuracy of poll time. */ if (prtd->mmap_flag) { period_bytes = ((uint64_t)( (snd_pcm_lib_period_bytes(prtd->substream)) * 1000)); bytes_one_sec = (runtime->rate * runtime->channels * 2); (snd_pcm_lib_period_bytes( prtd->substream)) * 1000)); bytes_one_sec = (runtime->rate * runtime->channels * 2); bytes_one_sec = div_u64(bytes_one_sec , 1000); prtd->poll_time = div_u64(period_bytes, bytes_one_sec); pr_debug("prtd->poll_time : %d\n", prtd->poll_time); pr_debug("prtd->poll_time : %d\n", prtd->poll_time); } else { mem_map_handle = afe_req_mmap_handle(prtd->audio_client); if (!mem_map_handle) pr_err("%s:mem_map_handle is NULL\n", __func__); /* Do initial read to start transfer */ afe_rt_proxy_port_read((prtd->dma_addr + (prtd->dsp_cnt * snd_pcm_lib_period_bytes( prtd->substream))), mem_map_handle, snd_pcm_lib_period_bytes( prtd->substream)); prtd->dsp_cnt++; } break; } case AFE_EVENT_RTPORT_STOP: Loading @@ -305,9 +328,13 @@ static void pcm_afe_process_rx_pkt(uint32_t opcode, case APR_BASIC_RSP_RESULT: { switch (payload[0]) { case AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2: pr_debug("Read done\n"); pr_debug("%s :Read done\n", __func__); prtd->pcm_irq_pos += snd_pcm_lib_period_bytes (prtd->substream); if (!prtd->mmap_flag) { atomic_set(&prtd->rec_bytes_avail, 1); wake_up(&prtd->read_wait); } snd_pcm_period_elapsed(prtd->substream); break; default: Loading Loading @@ -410,6 +437,9 @@ static int msm_afe_open(struct snd_pcm_substream *substream) return -ENOMEM; } atomic_set(&prtd->rec_bytes_avail, 0); init_waitqueue_head(&prtd->read_wait); hrtimer_init(&prtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) prtd->hrt.function = afe_hrtimer_callback; Loading Loading @@ -443,6 +473,134 @@ static int msm_afe_open(struct snd_pcm_substream *substream) return 0; } static int msm_afe_playback_copy(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames) { int ret = 0; struct snd_pcm_runtime *runtime = substream->runtime; struct pcm_afe_info *prtd = runtime->private_data; char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); u32 mem_map_handle = 0; pr_debug("%s : appl_ptr 0x%lx hw_ptr 0x%lx dest_to_copy 0x%p\n", __func__, runtime->control->appl_ptr, runtime->status->hw_ptr, hwbuf); if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames))) { pr_err("%s :Failed to copy audio from user buffer\n", __func__); ret = -EFAULT; goto fail; } if (!prtd->mmap_flag) { mem_map_handle = afe_req_mmap_handle(prtd->audio_client); if (!mem_map_handle) { pr_err("%s: mem_map_handle is NULL\n", __func__); ret = -EFAULT; goto fail; } pr_debug("%s : prtd-> dma_addr 0x%lx dsp_cnt %d\n", __func__, prtd->dma_addr, prtd->dsp_cnt); if (prtd->dsp_cnt == runtime->periods) prtd->dsp_cnt = 0; ret = afe_rt_proxy_port_write( (prtd->dma_addr + (prtd->dsp_cnt * snd_pcm_lib_period_bytes(prtd->substream))), mem_map_handle, snd_pcm_lib_period_bytes(prtd->substream)); if (ret) { pr_err("%s: AFE proxy port write failed %d\n", __func__, ret); goto fail; } prtd->dsp_cnt++; } fail: return ret; } static int msm_afe_capture_copy(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames) { int ret = 0; struct snd_pcm_runtime *runtime = substream->runtime; struct pcm_afe_info *prtd = runtime->private_data; char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); u32 mem_map_handle = 0; if (!prtd->mmap_flag) { mem_map_handle = afe_req_mmap_handle(prtd->audio_client); if (!mem_map_handle) { pr_err("%s: mem_map_handle is NULL\n", __func__); ret = -EFAULT; goto fail; } if (prtd->dsp_cnt == runtime->periods) prtd->dsp_cnt = 0; ret = afe_rt_proxy_port_read((prtd->dma_addr + (prtd->dsp_cnt * snd_pcm_lib_period_bytes(prtd->substream))), mem_map_handle, snd_pcm_lib_period_bytes(prtd->substream)); if (ret) { pr_err("%s: AFE proxy port read failed %d\n", __func__, ret); goto fail; } prtd->dsp_cnt++; ret = wait_event_timeout(prtd->read_wait, atomic_read(&prtd->rec_bytes_avail), 5 * HZ); if (ret < 0) { pr_err("%s: wait_event_timeout failed\n", __func__); ret = -ETIMEDOUT; goto fail; } atomic_set(&prtd->rec_bytes_avail, 0); } pr_debug("%s:appl_ptr 0x%lx hw_ptr 0x%lx src_to_copy 0x%p\n", __func__, runtime->control->appl_ptr, runtime->status->hw_ptr, hwbuf); if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames))) { pr_err("%s: copy to user failed\n", __func__); goto fail; ret = -EFAULT; } fail: return ret; } static int msm_afe_copy(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames) { int ret = 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ret = msm_afe_playback_copy(substream, channel, hwoff, buf, frames); else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ret = msm_afe_capture_copy(substream, channel, hwoff, buf, frames); return ret; } static int msm_afe_close(struct snd_pcm_substream *substream) { int rc = 0; Loading Loading @@ -477,6 +635,7 @@ static int msm_afe_close(struct snd_pcm_substream *substream) if (ret < 0) pr_err("AFE unregister for events failed\n"); } if (prtd->mmap_flag) hrtimer_cancel(&prtd->hrt); rc = afe_cmd_memory_unmap(afe_req_mmap_handle(prtd->audio_client)); Loading Loading @@ -551,6 +710,7 @@ static int msm_afe_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: pr_debug("%s: SNDRV_PCM_TRIGGER_START\n", __func__); prtd->start = 1; if (prtd->mmap_flag) hrtimer_start(&prtd->hrt, ns_to_ktime(0), HRTIMER_MODE_REL); break; Loading Loading @@ -650,6 +810,7 @@ static snd_pcm_uframes_t msm_afe_pointer(struct snd_pcm_substream *substream) static struct snd_pcm_ops msm_afe_ops = { .open = msm_afe_open, .copy = msm_afe_copy, .hw_params = msm_afe_hw_params, .trigger = msm_afe_trigger, .close = msm_afe_close, Loading sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h +3 −1 Original line number Diff line number Diff line /* Copyright (c) 2012, The Linux Foundation. All rights reserved. /* Copyright (c) 2012,2015 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -31,6 +31,8 @@ struct pcm_afe_info { struct hrtimer hrt; int poll_time; struct afe_audio_client *audio_client; wait_queue_head_t read_wait; atomic_t rec_bytes_avail; }; Loading Loading
sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c +184 −23 Original line number Diff line number Diff line Loading @@ -195,18 +195,21 @@ static void pcm_afe_process_tx_pkt(uint32_t opcode, * Multiplication by 1000000 is done in two * steps to keep the accuracy of poll time. */ if (prtd->mmap_flag) { period_bytes = ((uint64_t)( (snd_pcm_lib_period_bytes( prtd->substream)) * 1000)); bytes_one_sec = (runtime->rate * runtime->channels * 2); bytes_one_sec = (runtime->rate * runtime->channels * 2); bytes_one_sec = div_u64(bytes_one_sec, 1000); prtd->poll_time = div_u64(period_bytes, bytes_one_sec); div_u64(period_bytes, bytes_one_sec); pr_debug("prtd->poll_time: %d", prtd->poll_time); } break; } case AFE_EVENT_RTPORT_STOP: Loading Loading @@ -255,6 +258,7 @@ static void pcm_afe_process_rx_pkt(uint32_t opcode, uint16_t event; uint64_t period_bytes; uint64_t bytes_one_sec; uint32_t mem_map_handle = 0; if (prtd == NULL) return; Loading @@ -276,14 +280,33 @@ static void pcm_afe_process_rx_pkt(uint32_t opcode, * Multiplication by 1000000 is done in two steps to * keep the accuracy of poll time. */ if (prtd->mmap_flag) { period_bytes = ((uint64_t)( (snd_pcm_lib_period_bytes(prtd->substream)) * 1000)); bytes_one_sec = (runtime->rate * runtime->channels * 2); (snd_pcm_lib_period_bytes( prtd->substream)) * 1000)); bytes_one_sec = (runtime->rate * runtime->channels * 2); bytes_one_sec = div_u64(bytes_one_sec , 1000); prtd->poll_time = div_u64(period_bytes, bytes_one_sec); pr_debug("prtd->poll_time : %d\n", prtd->poll_time); pr_debug("prtd->poll_time : %d\n", prtd->poll_time); } else { mem_map_handle = afe_req_mmap_handle(prtd->audio_client); if (!mem_map_handle) pr_err("%s:mem_map_handle is NULL\n", __func__); /* Do initial read to start transfer */ afe_rt_proxy_port_read((prtd->dma_addr + (prtd->dsp_cnt * snd_pcm_lib_period_bytes( prtd->substream))), mem_map_handle, snd_pcm_lib_period_bytes( prtd->substream)); prtd->dsp_cnt++; } break; } case AFE_EVENT_RTPORT_STOP: Loading @@ -305,9 +328,13 @@ static void pcm_afe_process_rx_pkt(uint32_t opcode, case APR_BASIC_RSP_RESULT: { switch (payload[0]) { case AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2: pr_debug("Read done\n"); pr_debug("%s :Read done\n", __func__); prtd->pcm_irq_pos += snd_pcm_lib_period_bytes (prtd->substream); if (!prtd->mmap_flag) { atomic_set(&prtd->rec_bytes_avail, 1); wake_up(&prtd->read_wait); } snd_pcm_period_elapsed(prtd->substream); break; default: Loading Loading @@ -410,6 +437,9 @@ static int msm_afe_open(struct snd_pcm_substream *substream) return -ENOMEM; } atomic_set(&prtd->rec_bytes_avail, 0); init_waitqueue_head(&prtd->read_wait); hrtimer_init(&prtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) prtd->hrt.function = afe_hrtimer_callback; Loading Loading @@ -443,6 +473,134 @@ static int msm_afe_open(struct snd_pcm_substream *substream) return 0; } static int msm_afe_playback_copy(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames) { int ret = 0; struct snd_pcm_runtime *runtime = substream->runtime; struct pcm_afe_info *prtd = runtime->private_data; char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); u32 mem_map_handle = 0; pr_debug("%s : appl_ptr 0x%lx hw_ptr 0x%lx dest_to_copy 0x%p\n", __func__, runtime->control->appl_ptr, runtime->status->hw_ptr, hwbuf); if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames))) { pr_err("%s :Failed to copy audio from user buffer\n", __func__); ret = -EFAULT; goto fail; } if (!prtd->mmap_flag) { mem_map_handle = afe_req_mmap_handle(prtd->audio_client); if (!mem_map_handle) { pr_err("%s: mem_map_handle is NULL\n", __func__); ret = -EFAULT; goto fail; } pr_debug("%s : prtd-> dma_addr 0x%lx dsp_cnt %d\n", __func__, prtd->dma_addr, prtd->dsp_cnt); if (prtd->dsp_cnt == runtime->periods) prtd->dsp_cnt = 0; ret = afe_rt_proxy_port_write( (prtd->dma_addr + (prtd->dsp_cnt * snd_pcm_lib_period_bytes(prtd->substream))), mem_map_handle, snd_pcm_lib_period_bytes(prtd->substream)); if (ret) { pr_err("%s: AFE proxy port write failed %d\n", __func__, ret); goto fail; } prtd->dsp_cnt++; } fail: return ret; } static int msm_afe_capture_copy(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames) { int ret = 0; struct snd_pcm_runtime *runtime = substream->runtime; struct pcm_afe_info *prtd = runtime->private_data; char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); u32 mem_map_handle = 0; if (!prtd->mmap_flag) { mem_map_handle = afe_req_mmap_handle(prtd->audio_client); if (!mem_map_handle) { pr_err("%s: mem_map_handle is NULL\n", __func__); ret = -EFAULT; goto fail; } if (prtd->dsp_cnt == runtime->periods) prtd->dsp_cnt = 0; ret = afe_rt_proxy_port_read((prtd->dma_addr + (prtd->dsp_cnt * snd_pcm_lib_period_bytes(prtd->substream))), mem_map_handle, snd_pcm_lib_period_bytes(prtd->substream)); if (ret) { pr_err("%s: AFE proxy port read failed %d\n", __func__, ret); goto fail; } prtd->dsp_cnt++; ret = wait_event_timeout(prtd->read_wait, atomic_read(&prtd->rec_bytes_avail), 5 * HZ); if (ret < 0) { pr_err("%s: wait_event_timeout failed\n", __func__); ret = -ETIMEDOUT; goto fail; } atomic_set(&prtd->rec_bytes_avail, 0); } pr_debug("%s:appl_ptr 0x%lx hw_ptr 0x%lx src_to_copy 0x%p\n", __func__, runtime->control->appl_ptr, runtime->status->hw_ptr, hwbuf); if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames))) { pr_err("%s: copy to user failed\n", __func__); goto fail; ret = -EFAULT; } fail: return ret; } static int msm_afe_copy(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames) { int ret = 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ret = msm_afe_playback_copy(substream, channel, hwoff, buf, frames); else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ret = msm_afe_capture_copy(substream, channel, hwoff, buf, frames); return ret; } static int msm_afe_close(struct snd_pcm_substream *substream) { int rc = 0; Loading Loading @@ -477,6 +635,7 @@ static int msm_afe_close(struct snd_pcm_substream *substream) if (ret < 0) pr_err("AFE unregister for events failed\n"); } if (prtd->mmap_flag) hrtimer_cancel(&prtd->hrt); rc = afe_cmd_memory_unmap(afe_req_mmap_handle(prtd->audio_client)); Loading Loading @@ -551,6 +710,7 @@ static int msm_afe_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: pr_debug("%s: SNDRV_PCM_TRIGGER_START\n", __func__); prtd->start = 1; if (prtd->mmap_flag) hrtimer_start(&prtd->hrt, ns_to_ktime(0), HRTIMER_MODE_REL); break; Loading Loading @@ -650,6 +810,7 @@ static snd_pcm_uframes_t msm_afe_pointer(struct snd_pcm_substream *substream) static struct snd_pcm_ops msm_afe_ops = { .open = msm_afe_open, .copy = msm_afe_copy, .hw_params = msm_afe_hw_params, .trigger = msm_afe_trigger, .close = msm_afe_close, Loading
sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h +3 −1 Original line number Diff line number Diff line /* Copyright (c) 2012, The Linux Foundation. All rights reserved. /* Copyright (c) 2012,2015 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -31,6 +31,8 @@ struct pcm_afe_info { struct hrtimer hrt; int poll_time; struct afe_audio_client *audio_client; wait_queue_head_t read_wait; atomic_t rec_bytes_avail; }; Loading