static void audio_buffdone(void *data) { struct snd_pcm_substream *substream = data; struct runtime_data *prtd; pr_debug("Entered %s\n", __func__); if (!substream) return; prtd = substream->runtime->private_data; if (prtd->state & ST_RUNNING) { snd_pcm_period_elapsed(substream); if (!samsung_dma_has_circular()) { spin_lock(&prtd->lock); prtd->dma_loaded--; if (!samsung_dma_has_infiniteloop()) dma_enqueue(substream); spin_unlock(&prtd->lock); } } }
static int dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct runtime_data *prtd = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; unsigned long totbytes = params_buffer_bytes(params); struct s3c_dma_params *dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); struct samsung_dma_req req; struct samsung_dma_config config; pr_debug("Entered %s\n", __func__); /* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma) return 0; /* this may get called several times by oss emulation * with different params -HW */ if (prtd->params == NULL) { /* prepare DMA */ prtd->params = dma; pr_debug("params %p, client %p, channel %d\n", prtd->params, prtd->params->client, prtd->params->channel); prtd->params->ops = samsung_dma_get_ops(); req.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE); req.client = prtd->params->client; config.direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); config.width = prtd->params->dma_size; config.maxburst = 1; config.fifo = prtd->params->dma_addr; prtd->params->ch = prtd->params->ops->request( prtd->params->channel, &req); prtd->params->ops->config(prtd->params->ch, &config); } snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = totbytes; spin_lock_irq(&prtd->lock); prtd->dma_loaded = 0; prtd->dma_period = params_period_bytes(params); prtd->dma_start = runtime->dma_addr; prtd->dma_pos = prtd->dma_start; prtd->dma_end = prtd->dma_start + totbytes; spin_unlock_irq(&prtd->lock); return 0; }
static int dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct runtime_data *prtd = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; unsigned long totbytes = params_buffer_bytes(params); struct s3c_dma_params *dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); struct samsung_dma_info dma_info; pr_debug("Entered %s\n", __func__); /* */ if (!dma) return 0; /* */ if (prtd->params == NULL) { /* */ prtd->params = dma; pr_debug("params %p, client %p, channel %d\n", prtd->params, prtd->params->client, prtd->params->channel); prtd->params->ops = samsung_dma_get_ops(); dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE); dma_info.client = prtd->params->client; dma_info.direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); dma_info.width = prtd->params->dma_size; dma_info.fifo = prtd->params->dma_addr; prtd->params->ch = prtd->params->ops->request( prtd->params->channel, &dma_info); } snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = totbytes; spin_lock_irq(&prtd->lock); prtd->dma_loaded = 0; prtd->dma_period = params_period_bytes(params); prtd->dma_start = runtime->dma_addr; prtd->dma_pos = prtd->dma_start; prtd->dma_end = prtd->dma_start + totbytes; spin_unlock_irq(&prtd->lock); return 0; }
/* dma_enqueue * * place a dma buffer onto the queue for the dma system * to handle. */ static void dma_enqueue(struct snd_pcm_substream *substream) { struct runtime_data *prtd = substream->runtime->private_data; dma_addr_t pos = prtd->dma_pos; unsigned int limit; struct samsung_dma_prep dma_info; pr_debug("Entered %s\n", __func__); limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; pr_debug("%s: loaded %d, limit %d\n", __func__, prtd->dma_loaded, limit); dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE); dma_info.direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); dma_info.fp = audio_buffdone; dma_info.fp_param = substream; dma_info.period = prtd->dma_period; dma_info.len = prtd->dma_period*limit; if (dma_info.cap == DMA_CYCLIC) { dma_info.buf = pos; prtd->params->ops->prepare(prtd->params->ch, &dma_info); prtd->dma_loaded += limit; return; } while (prtd->dma_loaded < limit) { pr_debug("dma_loaded: %d\n", prtd->dma_loaded); if ((pos + dma_info.period) > prtd->dma_end) { dma_info.period = prtd->dma_end - pos; pr_debug("%s: corrected dma len %ld\n", __func__, dma_info.period); } dma_info.buf = pos; prtd->params->ops->prepare(prtd->params->ch, &dma_info); prtd->dma_loaded++; pos += prtd->dma_period; if (pos >= prtd->dma_end) pos = prtd->dma_start; } prtd->dma_pos = pos; }
static void audio_buffdone(void *data) { struct snd_pcm_substream *substream = data; struct runtime_data *prtd = substream->runtime->private_data; pr_debug("Entered %s\n", __func__); if (prtd->state & ST_RUNNING) { prtd->dma_pos += prtd->dma_period; if (prtd->dma_pos >= prtd->dma_end) prtd->dma_pos = prtd->dma_start; if (substream) snd_pcm_period_elapsed(substream); spin_lock(&prtd->lock); if (!samsung_dma_has_circular()) { prtd->dma_loaded--; dma_enqueue(substream); } spin_unlock(&prtd->lock); } }
//static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, // void *dev_id, int size, // enum s3c2410_dma_buffresult result) static void audio_buffdone(void *data) { //struct snd_pcm_substream *substream = dev_id; //struct s3c24xx_runtime_data *prtd; struct snd_pcm_substream *substream = data; struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; pr_debug("Entered %s\n", __func__); //if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) // return; // //prtd = substream->runtime->private_data; if (prtd->state & ST_RUNNING) { prtd->dma_pos += prtd->dma_period; if (prtd->dma_pos >= prtd->dma_end) prtd->dma_pos = prtd->dma_start; //if (substream) // snd_pcm_period_elapsed(substream); if (substream) snd_pcm_period_elapsed(substream); //spin_lock(&prtd->lock); //if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { // prtd->dma_loaded--; // s3c_dma_enqueue(substream); //} spin_lock(&prtd->lock); if (!samsung_dma_has_circular()) { prtd->dma_loaded--; s3c_dma_enqueue(substream); } spin_unlock(&prtd->lock); } //spin_unlock(&prtd->lock); }
/* s3c_dma_enqueue * * place a dma buffer onto the queue for the dma system * to handle. */ static void s3c_dma_enqueue(struct snd_pcm_substream *substream) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; dma_addr_t pos = prtd->dma_pos; unsigned int limit; //int ret; struct samsung_dma_prep_info dma_info; pr_debug("Entered %s\n", __func__); //if (s3c_dma_has_circular()) // limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; //else // limit = prtd->dma_limit; limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; pr_debug("%s: loaded %d, limit %d\n", __func__, prtd->dma_loaded, limit); //while (prtd->dma_loaded < limit) { // unsigned long len = prtd->dma_period; dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE); dma_info.direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_TO_DEVICE : DMA_FROM_DEVICE); dma_info.fp = audio_buffdone; dma_info.fp_param = substream; dma_info.period = prtd->dma_period; dma_info.len = prtd->dma_period*limit; while (prtd->dma_loaded < limit) { pr_debug("dma_loaded: %d\n", prtd->dma_loaded); //if ((pos + len) > prtd->dma_end) { // len = prtd->dma_end - pos; // pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n", // __func__, len); //} if ((pos + dma_info.period) > prtd->dma_end) { dma_info.period = prtd->dma_end - pos; pr_debug("%s: corrected dma len %ld\n", __func__, dma_info.period); } //ret = s3c2410_dma_enqueue(prtd->params->channel, // substream, pos, len); dma_info.buf = pos; prtd->params->ops->prepare(prtd->params->ch, &dma_info); //if (ret == 0) { // prtd->dma_loaded++; // pos += prtd->dma_period; // if (pos >= prtd->dma_end) // pos = prtd->dma_start; //} else // break; prtd->dma_loaded++; pos += prtd->dma_period; if (pos >= prtd->dma_end) pos = prtd->dma_start; } prtd->dma_pos = pos; }
static int s3c_dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct s3c24xx_runtime_data *prtd = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; unsigned long totbytes = params_buffer_bytes(params); struct s3c_dma_params *dma = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream); //int ret = 0; struct samsung_dma_info dma_info; pr_debug("Entered %s\n", __func__); /* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma) return 0; /* this may get called several times by oss emulation * with different params -HW */ if (prtd->params == NULL) { /* prepare DMA */ prtd->params = dma; pr_debug("params %p, client %p, channel %d\n", prtd->params, prtd->params->client, prtd->params->channel); //ret = s3c2410_dma_request(prtd->params->channel, // prtd->params->client, NULL); // //if (ret < 0) { // printk(KERN_ERR "failed to get dma channel\n"); // return ret; //} // ///* use the circular buffering if we have it available. */ //if (s3c_dma_has_circular()) // s3c2410_dma_setflags(prtd->params->channel, // S3C2410_DMAF_CIRCULAR); prtd->params->ops = samsung_dma_get_ops(); dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE); dma_info.client = prtd->params->client; dma_info.direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_TO_DEVICE : DMA_FROM_DEVICE); dma_info.width = prtd->params->dma_size; dma_info.fifo = prtd->params->dma_addr; prtd->params->ch = prtd->params->ops->request( prtd->params->channel, &dma_info); } //s3c2410_dma_set_buffdone_fn(prtd->params->channel, // s3c24xx_audio_buffdone); snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = totbytes; spin_lock_irq(&prtd->lock); prtd->dma_loaded = 0; //prtd->dma_limit = runtime->hw.periods_min; prtd->dma_period = params_period_bytes(params); prtd->dma_start = runtime->dma_addr; prtd->dma_pos = prtd->dma_start; prtd->dma_end = prtd->dma_start + totbytes; spin_unlock_irq(&prtd->lock); return 0; }