static int lola_pcm_prepare(struct snd_pcm_substream *substream) { struct lola *chip = snd_pcm_substream_chip(substream); struct lola_pcm *pcm = lola_get_pcm(substream); struct lola_stream *str = lola_get_stream(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int bufsize, period_bytes, format_verb; int i, err; mutex_lock(&chip->open_mutex); lola_stream_reset(chip, str); lola_cleanup_slave_streams(pcm, str); if (str->index + runtime->channels > pcm->num_streams) { mutex_unlock(&chip->open_mutex); return -EINVAL; } for (i = 1; i < runtime->channels; i++) { str[i].master = str; str[i].opened = 1; } mutex_unlock(&chip->open_mutex); bufsize = snd_pcm_lib_buffer_bytes(substream); period_bytes = snd_pcm_lib_period_bytes(substream); format_verb = lola_get_format_verb(substream); str->bufsize = bufsize; str->period_bytes = period_bytes; str->format_verb = format_verb; err = lola_setup_periods(chip, pcm, substream, str); if (err < 0) return err; err = lola_set_sample_rate(chip, runtime->rate); if (err < 0) return err; chip->sample_rate = runtime->rate; /* sample rate gets locked */ err = lola_set_stream_config(chip, str, runtime->channels); if (err < 0) return err; err = lola_setup_controller(chip, pcm, str); if (err < 0) { lola_stream_reset(chip, str); return err; } return 0; }
static enum hrtimer_restart afe_hrtimer_rec_callback(struct hrtimer *hrt) { struct pcm_afe_info *prtd = container_of(hrt, struct pcm_afe_info, hrt); struct snd_pcm_substream *substream = prtd->substream; struct snd_pcm_runtime *runtime = substream->runtime; if (prtd->start) { if (prtd->dsp_cnt == runtime->periods) prtd->dsp_cnt = 0; afe_rt_proxy_port_read( (prtd->dma_addr + (prtd->dsp_cnt * snd_pcm_lib_period_bytes(prtd->substream))), snd_pcm_lib_period_bytes(prtd->substream)); prtd->dsp_cnt++; pr_debug("sending frame rec to DSP: poll_time: %d\n", prtd->poll_time); hrtimer_forward_now(hrt, ns_to_ktime(prtd->poll_time * 1000)); return HRTIMER_RESTART; } else return HRTIMER_NORESTART; }
static int snd_ad1889_playback_prepare(struct snd_pcm_substream *ss) { struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); struct snd_pcm_runtime *rt = ss->runtime; unsigned int size = snd_pcm_lib_buffer_bytes(ss); unsigned int count = snd_pcm_lib_period_bytes(ss); u16 reg; ad1889_channel_reset(chip, AD_CHAN_WAV); reg = ad1889_readw(chip, AD_DS_WSMC); /* Mask out 16-bit / Stereo */ reg &= ~(AD_DS_WSMC_WA16 | AD_DS_WSMC_WAST); if (snd_pcm_format_width(rt->format) == 16) reg |= AD_DS_WSMC_WA16; if (rt->channels > 1) reg |= AD_DS_WSMC_WAST; /* let's make sure we don't clobber ourselves */ spin_lock_irq(&chip->lock); chip->wave.size = size; chip->wave.reg = reg; chip->wave.addr = rt->dma_addr; ad1889_writew(chip, AD_DS_WSMC, chip->wave.reg); /* Set sample rates on the codec */ ad1889_writew(chip, AD_DS_WAS, rt->rate); /* Set up DMA */ ad1889_load_wave_buffer_address(chip, chip->wave.addr); ad1889_load_wave_buffer_count(chip, size); ad1889_load_wave_interrupt_count(chip, count); /* writes flush */ ad1889_readw(chip, AD_DS_WSMC); spin_unlock_irq(&chip->lock); ad1889_debug("prepare playback: addr = 0x%x, count = %u, " "size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr, count, size, reg, rt->rate); return 0; }
static enum hrtimer_restart afe_hrtimer_rec_callback(struct hrtimer *hrt) { struct pcm_afe_info *prtd = container_of(hrt, struct pcm_afe_info, hrt); struct snd_pcm_substream *substream = prtd->substream; struct snd_pcm_runtime *runtime = substream->runtime; u32 mem_map_handle = 0; int ret; mem_map_handle = afe_req_mmap_handle(prtd->audio_client); if (!mem_map_handle) pr_err("%s: mem_map_handle is NULL\n", __func__); if (prtd->start) { if (prtd->dsp_cnt == runtime->periods) prtd->dsp_cnt = 0; pr_debug("%s: mem_map_handle 0x%x\n", __func__, mem_map_handle); 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 < 0) { pr_err("%s: AFE port read fails: %d\n", __func__, ret); prtd->start = 0; return HRTIMER_NORESTART; } prtd->dsp_cnt++; pr_debug("sending frame rec to DSP: poll_time: %d\n", prtd->poll_time); hrtimer_forward_now(hrt, ns_to_ktime(prtd->poll_time * 1000)); return HRTIMER_RESTART; } else return HRTIMER_NORESTART; }
int msm_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { struct snd_pcm_runtime *runtime = substream->runtime; struct msm_audio *prtd = runtime->private_data; prtd->out_head = 0; /* point to First buffer on startup */ prtd->mmap_flag = 1; runtime->dma_bytes = snd_pcm_lib_period_bytes(substream)*2; dma_mmap_coherent(substream->pcm->card->dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); return 0; }
static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct msm_audio *prtd = runtime->private_data; struct audmgr_config cfg; int rc; prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream); prtd->pcm_count = snd_pcm_lib_period_bytes(substream); prtd->pcm_irq_pos = 0; prtd->pcm_buf_pos = 0; /* rate and channels are sent to audio driver */ prtd->samp_rate = convert_samp_rate(runtime->rate); prtd->samp_rate_index = convert_dsp_samp_index(runtime->rate); prtd->channel_mode = (runtime->channels - 1); prtd->buffer_size = prtd->channel_mode ? STEREO_DATA_SIZE : \ MONO_DATA_SIZE; if (prtd->enabled == 1) return 0; prtd->type = AUDREC_CMD_TYPE_0_INDEX_WAV; cfg.tx_rate = convert_samp_rate(runtime->rate); cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE; cfg.def_method = RPC_AUD_DEF_METHOD_RECORD; cfg.codec = RPC_AUD_DEF_CODEC_PCM; cfg.snd_method = RPC_SND_METHOD_MIDI; rc = audmgr_enable(&prtd->audmgr, &cfg); if (rc < 0) return rc; if (msm_adsp_enable(prtd->audpre)) { audmgr_disable(&prtd->audmgr); return -ENODEV; } if (msm_adsp_enable(prtd->audrec)) { msm_adsp_disable(prtd->audpre); audmgr_disable(&prtd->audmgr); return -ENODEV; } prtd->enabled = 1; alsa_rec_dsp_enable(prtd, 1); return 0; }
static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct msm_audio *prtd = runtime->private_data; prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream); prtd->pcm_count = snd_pcm_lib_period_bytes(substream); prtd->pcm_irq_pos = 0; prtd->pcm_buf_pos = 0; /* rate and channels are sent to audio driver */ prtd->out_sample_rate = runtime->rate; prtd->out_channel_mode = runtime->channels; return 0; }
static int snd_ad1889_capture_prepare(struct snd_pcm_substream *ss) { struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); struct snd_pcm_runtime *rt = ss->runtime; unsigned int size = snd_pcm_lib_buffer_bytes(ss); unsigned int count = snd_pcm_lib_period_bytes(ss); u16 reg; ad1889_channel_reset(chip, AD_CHAN_ADC); reg = ad1889_readw(chip, AD_DS_RAMC); /* Mask out 16-bit / Stereo */ reg &= ~(AD_DS_RAMC_AD16 | AD_DS_RAMC_ADST); if (snd_pcm_format_width(rt->format) == 16) reg |= AD_DS_RAMC_AD16; if (rt->channels > 1) reg |= AD_DS_RAMC_ADST; /* let's make sure we don't clobber ourselves */ spin_lock_irq(&chip->lock); chip->ramc.size = size; chip->ramc.reg = reg; chip->ramc.addr = rt->dma_addr; ad1889_writew(chip, AD_DS_RAMC, chip->ramc.reg); /* Set up DMA */ ad1889_load_adc_buffer_address(chip, chip->ramc.addr); ad1889_load_adc_buffer_count(chip, size); ad1889_load_adc_interrupt_count(chip, count); /* writes flush */ ad1889_readw(chip, AD_DS_RAMC); spin_unlock_irq(&chip->lock); dev_dbg(chip->card->dev, "prepare capture: addr = 0x%x, count = %u, size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr, count, size, reg, rt->rate); return 0; }
static void msm_pcm_enqueue_data(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct msm_audio *prtd = runtime->private_data; unsigned int period_size; pr_debug("prtd->out_tail =%d mmap_flag=%d\n", prtd->out_tail, prtd->mmap_flag); period_size = snd_pcm_lib_period_bytes(substream); alsa_dsp_send_buffer(prtd, prtd->out_tail, period_size); prtd->out_tail ^= 1; ++copy_count; prtd->period++; if (unlikely(prtd->period >= runtime->periods)) prtd->period = 0; }
static int snd_ad1889_capture_prepare(struct snd_pcm_substream *ss) { struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); struct snd_pcm_runtime *rt = ss->runtime; unsigned int size = snd_pcm_lib_buffer_bytes(ss); unsigned int count = snd_pcm_lib_period_bytes(ss); u16 reg; ad1889_channel_reset(chip, AD_CHAN_ADC); reg = ad1889_readw(chip, AD_DS_RAMC); reg &= ~(AD_DS_RAMC_AD16 | AD_DS_RAMC_ADST); if (snd_pcm_format_width(rt->format) == 16) reg |= AD_DS_RAMC_AD16; if (rt->channels > 1) reg |= AD_DS_RAMC_ADST; spin_lock_irq(&chip->lock); chip->ramc.size = size; chip->ramc.reg = reg; chip->ramc.addr = rt->dma_addr; ad1889_writew(chip, AD_DS_RAMC, chip->ramc.reg); ad1889_load_adc_buffer_address(chip, chip->ramc.addr); ad1889_load_adc_buffer_count(chip, size); ad1889_load_adc_interrupt_count(chip, count); ad1889_readw(chip, AD_DS_RAMC); spin_unlock_irq(&chip->lock); ad1889_debug("prepare capture: addr = 0x%x, count = %u, " "size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr, count, size, reg, rt->rate); return 0; }
static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) { struct davinci_runtime_data *prtd = substream->runtime->private_data; struct snd_pcm_runtime *runtime = substream->runtime; int lch = prtd->slave_lch; unsigned int period_size; unsigned int dma_offset; dma_addr_t dma_pos; dma_addr_t src, dst; unsigned short src_bidx, dst_bidx; unsigned int data_type; unsigned int count; period_size = snd_pcm_lib_period_bytes(substream); dma_offset = prtd->period * period_size; dma_pos = runtime->dma_addr + dma_offset; pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d " "dma_ptr = %x period_size=%x\n", lch, dma_pos, period_size); data_type = prtd->params->data_type; count = period_size / data_type; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { src = dma_pos; dst = prtd->params->dma_addr; src_bidx = data_type; dst_bidx = 0; } else { src = prtd->params->dma_addr; dst = dma_pos; src_bidx = 0; dst_bidx = data_type; } davinci_set_dma_src_params(lch, src, INCR, W8BIT); davinci_set_dma_dest_params(lch, dst, INCR, W8BIT); davinci_set_dma_src_index(lch, src_bidx, 0); davinci_set_dma_dest_index(lch, dst_bidx, 0); davinci_set_dma_transfer_params(lch, data_type, count, 1, 0, ASYNC); prtd->period++; if (unlikely(prtd->period >= runtime->periods)) prtd->period = 0; }
/* prepare callback */ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; audio_info(" .. IN\n"); alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream); alsa_stream->period_size = snd_pcm_lib_period_bytes(substream); alsa_stream->pos = 0; audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n", alsa_stream->buffer_size, alsa_stream->period_size, alsa_stream->pos, runtime->frame_bits); audio_info(" .. OUT\n"); return 0; }
static int omap_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct omap_runtime_data *prtd = runtime->private_data; struct omap_pcm_dma_data *dma_data = prtd->dma_data; struct omap_dma_channel_params dma_params; memset(&dma_params, 0, sizeof(dma_params)); /* * Note: Regardless of interface data formats supported by OMAP McBSP * or EAC blocks, internal representation is always fixed 16-bit/sample */ dma_params.data_type = OMAP_DMA_DATA_TYPE_S16; dma_params.trigger = dma_data->dma_req; dma_params.sync_mode = OMAP_DMA_SYNC_ELEMENT; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dma_params.src_amode = OMAP_DMA_AMODE_POST_INC; dma_params.dst_amode = OMAP_DMA_AMODE_CONSTANT; dma_params.src_or_dst_synch = OMAP_DMA_DST_SYNC; dma_params.src_start = runtime->dma_addr; dma_params.dst_start = dma_data->port_addr; dma_params.dst_port = OMAP_DMA_PORT_MPUI; } else { dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT; dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC; dma_params.src_or_dst_synch = OMAP_DMA_SRC_SYNC; dma_params.src_start = dma_data->port_addr; dma_params.dst_start = runtime->dma_addr; dma_params.src_port = OMAP_DMA_PORT_MPUI; } /* * Set DMA transfer frame size equal to ALSA period size and frame * count as no. of ALSA periods. Then with DMA frame interrupt enabled, * we can transfer the whole ALSA buffer with single DMA transfer but * still can get an interrupt at each period bounary */ dma_params.elem_count = snd_pcm_lib_period_bytes(substream) / 2; dma_params.frame_count = runtime->periods; omap_set_dma_params(prtd->dma_ch, &dma_params); omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); return 0; }
static int snd_card_dummy_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_dummy_pcm *dpcm = runtime->private_data; unsigned int bps; bps = runtime->rate * runtime->channels; bps *= snd_pcm_format_width(runtime->format); bps /= 8; if (bps <= 0) return -EINVAL; dpcm->pcm_bps = bps; dpcm->pcm_jiffie = bps / HZ; dpcm->pcm_size = snd_pcm_lib_buffer_bytes(substream); dpcm->pcm_count = snd_pcm_lib_period_bytes(substream); dpcm->pcm_irq_pos = 0; dpcm->pcm_buf_pos = 0; return 0; }
static int ipq_pcm_mi2s_prepare(struct snd_pcm_substream *substream) { int ret; struct snd_pcm_runtime *runtime = substream->runtime; struct dai_dma_params dma_params; struct ipq_lpass_runtime_data_t *prtd = (struct ipq_lpass_runtime_data_t *)runtime->private_data; if (!prtd) { pr_err("%s %d:Error in getting runtime data\n", __func__, __LINE__); return -EINVAL; } /* * This is the case for under\over-run, we have already * configured the DMA registers for this stream */ if (prtd->pcm_stream_info.pcm_prepare_start) return 0; ipq_lpaif_dma_stop(prtd->lpaif_info.dma_ch); prtd->pcm_stream_info.pcm_prepare_start = 1; prtd->lpaif_info.lpa_if_dma_start = 0; memset(&dma_params, 0, sizeof(dma_params)); dma_params.src_start = runtime->dma_addr; dma_params.buffer_size = snd_pcm_lib_buffer_bytes(substream); dma_params.period_size = snd_pcm_lib_period_bytes(substream); dma_params.channels = runtime->channels; ret = ipq_lpaif_cfg_dma(prtd->lpaif_info.dma_ch, &dma_params, prtd->pcm_stream_info.bit_width, 1 /*enable intr*/); if (ret) return -EINVAL; ipq_lpaif_register_dma_irq_handler(prtd->lpaif_info.dma_ch, ipq_mi2s_irq, (void *)substream); return 0; }
static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream) { struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); struct dma_chan *chan = prtd->dma_chan; struct dma_async_tx_descriptor *desc; enum dma_transfer_direction direction; unsigned long flags = DMA_CTRL_ACK; direction = snd_pcm_substream_to_dma_direction(substream); if (!substream->runtime->no_period_wakeup) flags |= DMA_PREP_INTERRUPT; prtd->pos = 0; desc = dmaengine_prep_dma_cyclic(chan, substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream), direction, flags); if (!desc) return -ENOMEM; desc->callback = dmaengine_pcm_dma_complete; desc->callback_param = substream; prtd->cookie = dmaengine_submit(desc); #ifdef CONFIG_SND_PXA_SSP_DUMP if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && ssp_playback_enable) { prtd->playback_totsize = snd_pcm_lib_buffer_bytes(substream); prtd->playback_transfer_addr = substream->runtime->dma_addr; prtd->playback_dump_addr = substream->runtime->dma_addr; } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && ssp_capture_enable) { prtd->capture_totsize = snd_pcm_lib_buffer_bytes(substream); prtd->capture_transfer_addr = substream->runtime->dma_addr; prtd->capture_dump_addr = substream->runtime->dma_addr; } #endif return 0; }
static int snd_card_dummy_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_dummy_pcm *dpcm = runtime->private_data; int bps; bps = snd_pcm_format_width(runtime->format) * runtime->rate * runtime->channels / 8; if (bps <= 0) return -EINVAL; dpcm->pcm_bps = bps; dpcm->pcm_hz = HZ; dpcm->pcm_buffer_size = snd_pcm_lib_buffer_bytes(substream); dpcm->pcm_period_size = snd_pcm_lib_period_bytes(substream); dpcm->pcm_irq_pos = 0; dpcm->pcm_buf_pos = 0; snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes)); return 0; }
static void pcsp_pointer_update(struct snd_pcsp *chip) { struct snd_pcm_substream *substream; size_t period_bytes, buffer_bytes; int periods_elapsed; unsigned long flags; /* update the playback position */ substream = chip->playback_substream; if (!substream) return; period_bytes = snd_pcm_lib_period_bytes(substream); buffer_bytes = snd_pcm_lib_buffer_bytes(substream); spin_lock_irqsave(&chip->substream_lock, flags); chip->playback_ptr += PCSP_INDEX_INC() * chip->fmt_size; periods_elapsed = chip->playback_ptr - chip->period_ptr; if (periods_elapsed < 0) { #if PCSP_DEBUG printk(KERN_INFO "PCSP: buffer_bytes mod period_bytes != 0 ? " "(%zi %zi %zi)\n", chip->playback_ptr, period_bytes, buffer_bytes); #endif periods_elapsed += buffer_bytes; } periods_elapsed /= period_bytes; /* wrap the pointer _before_ calling snd_pcm_period_elapsed(), * or ALSA will BUG on us. */ chip->playback_ptr %= buffer_bytes; if (periods_elapsed) { chip->period_ptr += periods_elapsed * period_bytes; chip->period_ptr %= buffer_bytes; } spin_unlock_irqrestore(&chip->substream_lock, flags); if (periods_elapsed) tasklet_schedule(&pcsp_pcm_tasklet); }
static void check_for_elapsed_periods(struct snd_usb_caiaqdev *dev, struct snd_pcm_substream **subs) { int stream, pb, *cnt; struct snd_pcm_substream *sub; for (stream = 0; stream < dev->n_streams; stream++) { sub = subs[stream]; if (!sub) continue; pb = snd_pcm_lib_period_bytes(sub); cnt = (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) ? &dev->period_out_count[stream] : &dev->period_in_count[stream]; if (*cnt >= pb) { snd_pcm_period_elapsed(sub); *cnt %= pb; } } }
/* Lock me. */ static inline char *bcm947xx_from_linear(struct snd_pcm_substream *substream, snd_pcm_uframes_t pos) { struct snd_pcm_runtime *runtime = substream->runtime; struct bcm947xx_runtime_data *brtd = runtime->private_data; unsigned int slot; unsigned int extrabytes; char *hwbuf; /* Current slot (0-index). */ slot = pos / runtime->period_size; /* Extra bytes in descriptor (header + unused). */ extrabytes = BCM947XX_DMA_DATA_BYTES_MAX - snd_pcm_lib_period_bytes(substream); /* Calculate DMA buffer position by adding the unused * and header offset bytes. */ hwbuf = runtime->dma_area + /* base offset */ slot * extrabytes + /* all per slot extra up before current slot */ frames_to_bytes(runtime, pos) + /* position in slot */ brtd->dma_ofs; /* header offset in current slot */ return hwbuf; }
static snd_pcm_uframes_t snd_als300_pointer(struct snd_pcm_substream *substream) { u16 current_ptr; struct snd_als300 *chip = snd_pcm_substream_chip(substream); struct snd_als300_substream_data *data; unsigned short period_bytes; data = substream->runtime->private_data; period_bytes = snd_pcm_lib_period_bytes(substream); spin_lock(&chip->reg_lock); current_ptr = (u16) snd_als300_gcr_read(chip->port, data->block_counter_register) + 4; spin_unlock(&chip->reg_lock); if (current_ptr > period_bytes) current_ptr = 0; else current_ptr = period_bytes - current_ptr; if (data->period_flipflop == 0) current_ptr += period_bytes; snd_als300_dbgplay("Pointer (bytes): %d\n", current_ptr); return bytes_to_frames(substream->runtime, current_ptr); }
static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct msm_audio *prtd = runtime->private_data; prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream); prtd->pcm_count = snd_pcm_lib_period_bytes(substream); prtd->pcm_irq_pos = 0; prtd->pcm_buf_pos = 0; /* rate and channels are sent to audio driver */ prtd->out_sample_rate = runtime->rate; prtd->out_channel_mode = runtime->channels; if (prtd->enabled | !(prtd->mmap_flag)) return 0; prtd->data = substream->dma_buffer.area; prtd->phys = substream->dma_buffer.addr; prtd->out[0].data = prtd->data + 0; prtd->out[0].addr = prtd->phys + 0; prtd->out[0].size = BUFSZ; prtd->out[1].data = prtd->data + BUFSZ; prtd->out[1].addr = prtd->phys + BUFSZ; prtd->out[1].size = BUFSZ; prtd->out[0].used = prtd->pcm_count; prtd->out[1].used = prtd->pcm_count; mutex_lock(&the_locks.lock); alsa_audio_configure(prtd); mutex_unlock(&the_locks.lock); return 0; }
static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream) { struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); struct dma_chan *chan = prtd->dma_chan; struct dma_async_tx_descriptor *desc; enum dma_transfer_direction direction; direction = snd_pcm_substream_to_dma_direction(substream); prtd->pos = 0; desc = dmaengine_prep_dma_cyclic(chan, substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream), direction); if (!desc) return -ENOMEM; desc->callback = dmaengine_pcm_dma_complete; desc->callback_param = substream; prtd->cookie = dmaengine_submit(desc); return 0; }
static void dmaengine_pcm_dma_complete(void *arg) { struct snd_pcm_substream *substream = NULL; struct dmaengine_pcm_runtime_data *prtd = NULL; unsigned long flags; substream = arg; if (!substream) { return; } snd_pcm_stream_lock_irqsave(substream, flags); if (!substream->runtime) { snd_pcm_stream_unlock_irqrestore(substream, flags); return; } prtd = substream_to_prtd(substream); prtd->pos += snd_pcm_lib_period_bytes(substream); if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream)) prtd->pos = 0; snd_pcm_stream_unlock_irqrestore(substream, flags); snd_pcm_period_elapsed(substream); }
if (rate > 23000) { chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; break; } /* fallthru */ case SB_HW_20: chip->playback_format = SB_DSP_LO_OUTPUT_AUTO; break; case SB_HW_10: chip->playback_format = SB_DSP_OUTPUT; break; default: return -EINVAL; } size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); count = chip->p_period_size = snd_pcm_lib_period_bytes(substream); spin_lock_irqsave(&chip->reg_lock, flags); snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); if (runtime->channels > 1) { /* set playback stereo mode */ spin_lock(&chip->mixer_lock); mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW); snd_sbmixer_write(chip, SB_DSP_STEREO_SW, mixreg | 0x02); spin_unlock(&chip->mixer_lock); /* Soundblaster hardware programming reference guide, 3-23 */ snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT); runtime->dma_area[0] = 0x80; snd_dma_program(chip->dma8, runtime->dma_addr, 1, DMA_MODE_WRITE); /* force interrupt */ chip->mode = SB_MODE_HALT;
static void pcm_afe_process_rx_pkt(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv) { struct pcm_afe_info *prtd = priv; unsigned long dsp_flags; struct snd_pcm_substream *substream = NULL; struct snd_pcm_runtime *runtime = NULL; uint16_t event; uint64_t period_bytes; uint64_t bytes_one_sec; if (prtd == NULL) return; substream = prtd->substream; runtime = substream->runtime; pr_debug("%s\n", __func__); spin_lock_irqsave(&prtd->dsp_lock, dsp_flags); switch (opcode) { case AFE_EVENT_RT_PROXY_PORT_STATUS: { event = (uint16_t)((0xFFFF0000 & payload[0]) >> 0x10); switch (event) { case AFE_EVENT_RTPORT_START: { prtd->dsp_cnt = 0; /* Calculate poll time. Split steps to avoid overflow. * Poll time-time corresponding to one period in bytes. * (Samplerate * channelcount * format)=bytes in 1 sec. * Poll time = (period bytes / bytes in one sec) * * 1000000 micro seconds. * Multiplication by 1000000 is done in two steps to * keep the accuracy of poll time. */ period_bytes = ((uint64_t)( (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); break; } case AFE_EVENT_RTPORT_STOP: pr_debug("%s: event!=0\n", __func__); prtd->start = 0; snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); break; case AFE_EVENT_RTPORT_LOW_WM: pr_debug("%s: Underrun\n", __func__); break; case AFE_EVENT_RTPORT_HI_WM: pr_debug("%s: Overrun\n", __func__); break; default: break; } break; } case APR_BASIC_RSP_RESULT: { switch (payload[0]) { case AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2: pr_debug("Read done\n"); prtd->pcm_irq_pos += snd_pcm_lib_period_bytes (prtd->substream); snd_pcm_period_elapsed(prtd->substream); break; default: break; } break; } default: break; } spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags); }
static void pcm_afe_process_rx_pkt(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv) { struct pcm_afe_info *prtd = priv; unsigned long dsp_flags; struct snd_pcm_substream *substream = NULL; struct snd_pcm_runtime *runtime = NULL; uint16_t event; if (prtd == NULL) return; substream = prtd->substream; runtime = substream->runtime; pr_debug("%s\n", __func__); spin_lock_irqsave(&prtd->dsp_lock, dsp_flags); switch (opcode) { case AFE_EVENT_RT_PROXY_PORT_STATUS: { event = (uint16_t)((0xFFFF0000 & payload[0]) >> 0x10); switch (event) { case AFE_EVENT_RTPORT_START: { prtd->dsp_cnt = 0; prtd->poll_time = ((unsigned long)(( snd_pcm_lib_period_bytes(prtd->substream) * 1000 * 1000)/(runtime->rate * runtime->channels * 2))); pr_debug("prtd->poll_time : %d", prtd->poll_time); break; } case AFE_EVENT_RTPORT_STOP: pr_debug("%s: event!=0\n", __func__); prtd->start = 0; snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); break; case AFE_EVENT_RTPORT_LOW_WM: pr_debug("%s: Underrun\n", __func__); break; case AFE_EVENT_RTPORT_HI_WM: pr_debug("%s: Overrun\n", __func__); break; default: break; } break; } case APR_BASIC_RSP_RESULT: { switch (payload[0]) { case AFE_SERVICE_CMD_RTPORT_RD: pr_debug("Read done\n"); prtd->pcm_irq_pos += snd_pcm_lib_period_bytes (prtd->substream); snd_pcm_period_elapsed(prtd->substream); break; default: break; } break; } default: break; } spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags); }
static int omap_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct omap_runtime_data *prtd = runtime->private_data; struct omap_pcm_dma_data *dma_data = prtd->dma_data; struct omap_dma_channel_params dma_params; int bytes; /* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!prtd->dma_data) return 0; memset(&dma_params, 0, sizeof(dma_params)); dma_params.data_type = dma_data->data_type; dma_params.trigger = dma_data->dma_req; dma_params.sync_mode = dma_data->sync_mode; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dma_params.src_amode = OMAP_DMA_AMODE_POST_INC; dma_params.dst_amode = OMAP_DMA_AMODE_CONSTANT; dma_params.src_or_dst_synch = OMAP_DMA_DST_SYNC; dma_params.src_start = runtime->dma_addr; dma_params.dst_start = dma_data->port_addr; dma_params.dst_port = OMAP_DMA_PORT_MPUI; dma_params.dst_fi = dma_data->packet_size; } else { dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT; dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC; dma_params.src_or_dst_synch = OMAP_DMA_SRC_SYNC; dma_params.src_start = dma_data->port_addr; dma_params.dst_start = runtime->dma_addr; dma_params.src_port = OMAP_DMA_PORT_MPUI; dma_params.src_fi = dma_data->packet_size; } /* * Set DMA transfer frame size equal to ALSA period size and frame * count as no. of ALSA periods. Then with DMA frame interrupt enabled, * we can transfer the whole ALSA buffer with single DMA transfer but * still can get an interrupt at each period bounary */ bytes = snd_pcm_lib_period_bytes(substream); dma_params.elem_count = bytes >> dma_data->data_type; dma_params.frame_count = runtime->periods; omap_set_dma_params(prtd->dma_ch, &dma_params); if ((cpu_is_omap1510())) omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ | OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ); else if (!substream->runtime->no_period_wakeup) omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); else { /* * No period wakeup: * we need to disable BLOCK_IRQ, which is enabled by the omap * dma core at request dma time. */ omap_disable_dma_irq(prtd->dma_ch, OMAP_DMA_BLOCK_IRQ); } if (!(cpu_class_is_omap1())) { omap_set_dma_src_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); omap_set_dma_dest_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); } return 0; }
/* * Not used with ping/pong */ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) { struct davinci_runtime_data *prtd = substream->runtime->private_data; struct snd_pcm_runtime *runtime = substream->runtime; int link = prtd->asp_link[0]; unsigned int period_size; unsigned int dma_offset; dma_addr_t dma_pos; dma_addr_t src, dst; unsigned short src_bidx, dst_bidx; unsigned short src_cidx, dst_cidx; unsigned int data_type; unsigned short acnt; unsigned int count; unsigned int fifo_level; period_size = snd_pcm_lib_period_bytes(substream); dma_offset = prtd->period * period_size; dma_pos = runtime->dma_addr + dma_offset; fifo_level = prtd->params->fifo_level; pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d " "dma_ptr = %x period_size=%x\n", link, dma_pos, period_size); data_type = prtd->params->data_type; count = period_size / data_type; if (fifo_level) count /= fifo_level; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { src = dma_pos; dst = prtd->params->dma_addr; src_bidx = data_type; dst_bidx = 0; src_cidx = data_type * fifo_level; dst_cidx = 0; } else { src = prtd->params->dma_addr; dst = dma_pos; src_bidx = 0; dst_bidx = data_type; src_cidx = 0; dst_cidx = data_type * fifo_level; } acnt = prtd->params->acnt; edma_set_src(link, src, INCR, W8BIT); edma_set_dest(link, dst, INCR, W8BIT); edma_set_src_index(link, src_bidx, src_cidx); edma_set_dest_index(link, dst_bidx, dst_cidx); if (!fifo_level) edma_set_transfer_params(link, acnt, count, 1, 0, ASYNC); else edma_set_transfer_params(link, acnt, fifo_level, count, fifo_level, ABSYNC); prtd->period++; if (unlikely(prtd->period >= runtime->periods)) prtd->period = 0; }
static irqreturn_t socle_snd_isr(int irq_no, struct snd_soc_dai *soc_dai) { u32 int_stat; u32 *buf; struct snd_dma_buffer *dma_buffer; int_stat = socle_i2s_reg_read(SOCLE_I2S_ISR); //printk("Entered %s int_stat 0x%08X\n", __func__, int_stat); /* Check wether is is the rx fifo overrun interrupt*/ if (int_stat & SOCLE_I2S_RX_FIFO_OVR_INT) { printk("rx overrun\n"); /* Clear the rx fifo */ socle_i2s_reg_write( socle_i2s_reg_read(SOCLE_I2S_RXCTL) | SOCLE_I2S_RX_FIFO_CLR,SOCLE_I2S_RXCTL); /* Disable the interrupt */ socle_i2s_reg_write( socle_i2s_reg_read(SOCLE_I2S_IER) & ~(SOCLE_I2S_RX_FIFO_TRIG_INT_EN | SOCLE_I2S_RX_FIFO_OVR_INT_EN),SOCLE_I2S_IER); /* Stop the rx transmission */ socle_i2s_reg_write( socle_i2s_conf | (socle_i2s_reg_read(SOCLE_I2S_OPR) & SOCLE_I2S_TX_OP_STR),SOCLE_I2S_OPR); goto out; } /* Check whether it is the tx fifo data trigger interrupt */ if (int_stat & SOCLE_I2S_TX_FIFO_TRIG_INT) { //printk("%s: playback_substream %x\n", __func__, (u32)playback_substream); dma_buffer = &(playback_substream->dma_buffer); #if 0 while ((socle_i2s_reg_read(SOCLE_I2S_FIFOSTS) & SOCLE_I2S_TX_FIFO_FULL) != SOCLE_I2S_TX_FIFO_FULL) { buf = (u32 *) &(dma_buffer->area[playback_buf_pos]); socle_i2s_reg_write( *buf, SOCLE_I2S_TXR); playback_buf_pos += 4; playback_buf_period_pos +=4; } playback_buf_pos %= dma_buffer->bytes; if( playback_buf_period_pos > playback_substream->runtime->period_size) { //printk("period_size 0x%08X, buf_size 0x%08X\n",(u32) playback_substream->runtime->period_size, dma_buffer->bytes); playback_buf_period_pos %= playback_substream->runtime->period_size; snd_pcm_period_elapsed(playback_substream); } #else //printk("dma_buffer->area %x\n", (u32)dma_buffer->area); while ((socle_i2s_reg_read(SOCLE_I2S_FIFOSTS) & SOCLE_I2S_TX_FIFO_FULL) != SOCLE_I2S_TX_FIFO_FULL) { buf = (u32 *) &(dma_buffer->area[playback_buf_pos]); socle_i2s_reg_write( *buf, SOCLE_I2S_TXR); playback_buf_pos += 4; playback_buf_pos %= dma_buffer->bytes; if( playback_buf_pos % snd_pcm_lib_period_bytes(playback_substream) == 0) { //printk("%s: playback_buf_pos 0x%08X\n", __func__, playback_buf_pos); snd_pcm_period_elapsed(playback_substream); } } #endif } /* Check whether it is the rx fifo data trigger interrupt */ if (int_stat & SOCLE_I2S_RX_FIFO_TRIG_INT) { dma_buffer = &(capture_substream->dma_buffer); while ((socle_i2s_reg_read(SOCLE_I2S_FIFOSTS) & SOCLE_I2S_RX_FIFO_EMPTY) != SOCLE_I2S_RX_FIFO_EMPTY) { buf = (u32 *) &(dma_buffer->area[capture_buf_pos]); *buf = socle_i2s_reg_read(SOCLE_I2S_RXR); capture_buf_pos += 4; capture_buf_pos %= dma_buffer->bytes; if( capture_buf_pos % snd_pcm_lib_period_bytes(capture_substream) == 0) { snd_pcm_period_elapsed(capture_substream); } } } out: //printk("Exit %s\n", __func__); return IRQ_HANDLED; }