static int qsd_pcm_playback_copy(struct snd_pcm_substream *substream, int a, snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames) { int fbytes = 0; size_t xfer; int rc; struct snd_pcm_runtime *runtime = substream->runtime; struct qsd_audio *prtd = runtime->private_data; fbytes = frames_to_bytes(runtime, frames); prtd->cbs.buffer = (void *)buf; prtd->cbs.phys_addr = 0; prtd->cbs.max_size = fbytes; prtd->cbs.actual_size = fbytes; prtd->pcm_buf_pos += fbytes; mutex_lock(&the_locks.lock); xfer = cad_write(prtd->cad_w_handle, &prtd->cbs); mutex_unlock(&the_locks.lock); mutex_lock(&the_locks.mixer_lock); if (qsd_glb_ctl.update) { rc = qsd_audio_volume_update(prtd); qsd_glb_ctl.update = 0; } mutex_unlock(&the_locks.mixer_lock); return 0; }
static int snd_qsd_fake_playback_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 } // send buffer to DSP // ptr = runtime->dma_area + prtd->buf_curoff; rcopy = prtd->buf_chunk; if (rcopy > ab->size) rcopy = ab->size; memcpy(ab->data, ptr, rcopy); ab->used = rcopy; q6audio_write(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); // update stream settings if required // if (qsd_glb_ctl.update) { rc = qsd_audio_volume_update(prtd); qsd_glb_ctl.update = 0; } mutex_unlock(&prtd->mlock); fail: ; // CotullaTODO: handle this fault somehow. } DBG(" end handler"); } DBG(" exit"); return 0; }