static int q6_aac_flowcontrol(void *data) { struct audio_client *ac; struct audio_buffer *ab; struct aac *aac = data; int buff_index = 0; int xfer = 0; struct aac_fc *fc; ac = aac->audio_client; fc = aac->aac_fc; if (!ac) { pr_err("[%s:%s] audio_client is NULL\n", __MM_FILE__, __func__); return 0; } while (!kthread_should_stop()) { ab = ac->buf + ac->cpu_buf; if (ab->used) wait_event(ac->wait, (ab->used == 0)); pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d\n", __MM_FILE__, __func__, ab->data, ac->cpu_buf); xfer = ab->actual_size; mutex_lock(&(fc->fc_buff[buff_index].lock)); if (!fc->fc_buff[buff_index].empty) { pr_err("[%s:%s] flow control buffer[%d] not read!\n", __MM_FILE__, __func__, buff_index); } if (fc->fc_buff[buff_index].size < xfer) { pr_err("[%s:%s] buffer %d too small\n", __MM_FILE__, __func__, buff_index); memcpy(fc->fc_buff[buff_index].data, ab->data, fc->fc_buff[buff_index].size); fc->fc_buff[buff_index].empty = 0; fc->fc_buff[buff_index].actual_size = fc->fc_buff[buff_index].size; } else { memcpy(fc->fc_buff[buff_index].data, ab->data, xfer); fc->fc_buff[buff_index].empty = 0; fc->fc_buff[buff_index].actual_size = xfer; } mutex_unlock(&(fc->fc_buff[buff_index].lock)); /*wake up client, if any*/ wake_up(&fc->fc_wq); buff_index++; if (buff_index >= AAC_FC_BUFF_CNT) buff_index = 0; ab->used = 1; q6audio_read(ac, ab); ac->cpu_buf ^= 1; } return 0; }
static ssize_t q6_in_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct pcm *pcm = file->private_data; struct audio_client *ac; struct audio_buffer *ab; const char __user *start = buf; int xfer; int res; ac = pcm->ac; if (!ac) { res = -ENODEV; goto fail; } while (count > 0) { ab = ac->buf + ac->cpu_buf; if (ab->used) if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) { #ifdef CONFIG_EF12_BOARD printk("[SKY AUDIO] Dal timeout! maybe timeout or dsp dead.\n"); #else audio_client_dump(ac); pr_err("[%s:%s] timeout. dsp dead?\n", __MM_FILE__, __func__); q6audio_dsp_not_responding(); #endif } xfer = count; if (xfer > ab->size) xfer = ab->size; if (copy_to_user(buf, ab->data, xfer)) { res = -EFAULT; goto fail; } buf += xfer; count -= xfer; ab->used = 1; q6audio_read(ac, ab); ac->cpu_buf ^= 1; } fail: res = buf - start; return res; }
static ssize_t q6_aac_in_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct audio_client *ac; struct audio_buffer *ab; const char __user *start = buf; struct aac *aac = file->private_data; int xfer = 0; int res; mutex_lock(&aac->lock); ac = aac->audio_client; if (!ac) { res = -ENODEV; goto fail; } ab = ac->buf + ac->cpu_buf; if (ab->used) wait_event(ac->wait, (ab->used == 0)); xfer = ab->actual_size; if (xfer > count) { pr_err("[%s:%s] read failed! byte count too small\n", __MM_FILE__, __func__); res = -EINVAL; goto fail; } if (copy_to_user(buf, ab->data, xfer)) { res = -EFAULT; goto fail; } buf += xfer; ab->used = 1; q6audio_read(ac, ab); ac->cpu_buf ^= 1; res = buf - start; fail: mutex_unlock(&aac->lock); return res; }
static ssize_t q6_amrnb_in_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct audio_client *ac; struct audio_buffer *ab; const char __user *start = buf; struct amrnb *amrnb = file->private_data; int xfer = 0; int res; pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count); mutex_lock(&amrnb->lock); ac = amrnb->audio_client; if (!ac) { res = -ENODEV; goto fail; } while (count > xfer) { ab = ac->buf + ac->cpu_buf; if (ab->used) wait_event(ac->wait, (ab->used == 0)); pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d\n", __MM_FILE__, __func__, ab->data, ac->cpu_buf); xfer = ab->actual_size; if (copy_to_user(buf, ab->data, xfer)) { pr_err("[%s:%s] copy_to_user failed\n", __MM_FILE__, __func__); res = -EFAULT; goto fail; } buf += xfer; count -= xfer; ab->used = 1; q6audio_read(ac, ab); ac->cpu_buf ^= 1; } res = buf - start; fail: mutex_unlock(&amrnb->lock); return res; }
static ssize_t q6_in_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct pcm *pcm = file->private_data; struct audio_client *ac; struct audio_buffer *ab; const char __user *start = buf; int xfer; int res; ac = pcm->ac; if (!ac) { res = -ENODEV; goto fail; } while (count > 0) { ab = ac->buf + ac->cpu_buf; if (ab->used) if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) { audio_client_dump(ac); pr_err("pcm_read: timeout. dsp dead?\n"); BUG(); } xfer = count; if (xfer > ab->size) xfer = ab->size; if (copy_to_user(buf, ab->data, xfer)) { res = -EFAULT; goto fail; } buf += xfer; count -= xfer; ab->used = 1; q6audio_read(ac, ab); ac->cpu_buf ^= 1; } fail: res = buf - start; return res; }
static ssize_t qcelp_in_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct audio_client *ac; struct audio_buffer *ab; const char __user *start = buf; int xfer, res = 0; mutex_lock(&qcelp_in_lock); ac = file->private_data; if (!ac) { res = -ENODEV; pr_err("qcelp_in_read ac NULL\n"); goto fail; } while (count > 0) { ab = ac->buf + ac->cpu_buf; TRACE("qcelp_in_read wait count=%d ab=%d ac->buf=%d cpu_buf=%d ac->buf[1]=%d\n", count, ab, ac->buf, ac->cpu_buf, &(ac->buf[1])); if (ab->used) wait_event(ac->wait, (ab->used == 0)); TRACE(" qcelp_in_read event arrive ab->size=%d\n", ab->size); xfer = count; if (xfer > ab->size) xfer = ab->size; if (copy_to_user(buf, ab->data, xfer)) { res = -EFAULT; pr_err("Tomdbg copy to user failed \n"); goto fail; } TRACE("qcelp_in read buf = %d,xfer = %d,cnt = %d\n", buf, xfer, count); buf += xfer; count -= xfer; ab->used = 1; q6audio_read(ac, ab); ac->cpu_buf ^= 1; } fail: res = buf - start; mutex_unlock(&qcelp_in_lock); return res; }
static ssize_t q6_evrc_in_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct audio_client *ac; struct audio_buffer *ab; const char __user *start = buf; struct evrc *evrc = file->private_data; int xfer = 0; int res; mutex_lock(&evrc->lock); ac = evrc->audio_client; if (!ac) { res = -ENODEV; goto fail; } while (count > xfer) { ab = ac->buf + ac->cpu_buf; if (ab->used) wait_event(ac->wait, (ab->used == 0)); xfer = ab->actual_size; if (copy_to_user(buf, ab->data, xfer)) { res = -EFAULT; goto fail; } buf += xfer; count -= xfer; ab->used = 1; q6audio_read(ac, ab); ac->cpu_buf ^= 1; } res = buf - start; fail: mutex_unlock(&evrc->lock); return res; }
struct audio_client *q6audio_open_pcm(uint32_t bufsz, uint32_t rate, uint32_t channels, uint32_t flags, uint32_t acdb_id) { int rc, retry = 5; struct audio_client *ac; if (q6audio_init()) return 0; ac = audio_client_alloc(bufsz); if (!ac) return 0; ac->flags = flags; mutex_lock(&audio_path_lock); if (ac->flags & AUDIO_FLAG_WRITE) { audio_rx_path_refcount++; if (audio_rx_path_refcount == 1) { _audio_rx_clk_enable(); #ifdef CONFIG_MSM_QDSP6_CALLREC q6_rx_path_enable(0, acdb_id); adie_rx_path_enable(acdb_id); #else audio_update_acdb(audio_rx_device_id, acdb_id); qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, audio_rx_device_id); qdsp6_standby(ac_control); qdsp6_start(ac_control); #endif } } else { /* TODO: consider concurrency with voice call */ #ifdef CONFIG_MSM_QDSP6_CALLREC if (audio_tx_path_refcount > 0) { tx_clk_freq = 8000; } else { tx_clk_freq = rate; } #else tx_clk_freq = rate; #endif audio_tx_path_refcount++; if (audio_tx_path_refcount == 1) { #ifdef CONFIG_MSM_QDSP6_CALLREC tx_clk_freq = rate; #endif _audio_tx_clk_enable(); _audio_tx_path_enable(0, acdb_id); } } for (retry = 5;; retry--) { if (ac->flags & AUDIO_FLAG_WRITE) rc = audio_out_open(ac, bufsz, rate, channels); else #ifdef CONFIG_MSM_QDSP6_CALLREC rc = audio_in_open(ac, bufsz, flags, rate, channels); #else rc = audio_in_open(ac, bufsz, rate, channels); #endif if (rc == 0) break; if (retry == 0) q6audio_dsp_not_responding(); pr_err("q6audio: open pcm error %d, retrying\n", rc); msleep(1); } if (ac->flags & AUDIO_FLAG_WRITE) { if (audio_rx_path_refcount == 1) { #ifndef CONFIG_MSM_QDSP6_CALLREC adie_enable(); adie_set_path(adie, audio_rx_path_id, ADIE_PATH_RX); adie_set_path_freq_plan(adie, ADIE_PATH_RX, 48000); adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_READY); adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_ANALOG_READY); #endif audio_rx_analog_enable(1); } } mutex_unlock(&audio_path_lock); for (retry = 5;; retry--) { rc = audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START); if (rc == 0) break; if (retry == 0) q6audio_dsp_not_responding(); pr_err("q6audio: stream start error %d, retrying\n", rc); } if (!(ac->flags & AUDIO_FLAG_WRITE)) { ac->buf[0].used = 1; ac->buf[1].used = 1; q6audio_read(ac, &ac->buf[0]); q6audio_read(ac, &ac->buf[1]); } audio_prevent_sleep(); return ac; }
static int snd_qsd_fake_capture_dma_thread(void *data) { int rc = 0; int rcopy; struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; struct snd_pcm_runtime *runtime = substream->runtime; struct qsd_audio *prtd = runtime->private_data; struct audio_buffer *ab; struct audio_client *ac; unsigned char *ptr; while (prtd->thread_exit == 0) { DBG(" start handler"); // wait until state is changed // at this point this thread waits until SNDRV_PCM_TRIGGER_START comes // SNDRV_PCM_TRIGGER_STOP // wait_event_interruptible(prtd->fake_wait, (prtd->start == 1 || prtd->thread_exit == 1)); DBG(" wake up %d %d", prtd->start, prtd->thread_exit); if (prtd->thread_exit) break; ac = prtd->ac; while (prtd->start == 1) { // wait until new buffer appear // // DBG(" ac = %X, prtd = %X, substream = %X", ac, prtd, substream); ab = ac->buf + ac->cpu_buf; if (ab->used) { DBG("wait a buffer %d", ac->cpu_buf); if (!wait_event_timeout(ac->wait, (ab->used == 0), 5 * HZ)) { DBG("timeout. dsp dead?\n"); rc = -EFAULT; goto fail; } // some buffer become free, report about state change now // snd_pcm_period_elapsed(prtd->substream); } mutex_lock(&prtd->mlock); if (prtd->start == 0) { DBG("flag is set - exit thread"); mutex_unlock(&prtd->mlock); break; // EXIT FROM LOOP } // this buffer must contains recorded data // copy it to dma buffer // ptr = runtime->dma_area + prtd->buf_curoff; rcopy = prtd->buf_chunk; if (rcopy > ab->size) rcopy = ab->size; memcpy(ptr, ab->data, rcopy); // send this buffer to DSP queue again // ab->used = rcopy; q6audio_read(ac, ab); ac->cpu_buf ^= 1; // move fake dma pointer forward // spin_lock(&prtd->lock); prtd->buf_curoff += prtd->buf_chunk; if (prtd->buf_curoff >= prtd->buf_maxoff) prtd->buf_curoff = 0; spin_unlock(&prtd->lock); mutex_unlock(&prtd->mlock); fail: ; // CotullaTODO: handle this fault somehow. } DBG(" end handler"); } DBG(" exit"); return 0; }
static ssize_t q6_amrnb_in_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct audio_client *ac; struct audio_buffer *ab; const char __user *start = buf; struct amrnb *amrnb = file->private_data; int xfer = 0; int res; mutex_lock(&amrnb->lock); ac = amrnb->audio_client; if (!ac) { res = -ENODEV; goto fail; } #if 1 while (count > xfer) { ab = ac->buf + ac->cpu_buf; if (ab->used) wait_event(ac->wait, (ab->used == 0)); xfer = ab->actual_size; if (copy_to_user(buf, ab->data, xfer)) { res = -EFAULT; goto fail; } buf += xfer; count -= xfer; ab->used = 1; q6audio_read(ac, ab); ac->cpu_buf ^= 1; } #else while (count > 0) { ab = ac->buf + ac->cpu_buf; if (ab->used) wait_event(ac->wait, (ab->used == 0)); #if 0 if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) { audio_client_dump(ac); pr_err("pcm_read: timeout. dsp dead?\n"); q6audio_dsp_not_responding(); } #endif xfer = count; if (xfer > ab->size) xfer = ab->size; if (copy_to_user(buf, ab->data, xfer)) { res = -EFAULT; goto fail; } buf += xfer; count -= xfer; ab->used = 1; q6audio_read(ac, ab); ac->cpu_buf ^= 1; } #endif res = buf - start; fail: mutex_unlock(&amrnb->lock); return res; }