Пример #1
0
static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
{
	bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id;
	uint32_t consumed = 0;
	int new_period = 0;

	audio_info(" .. IN\n");

	audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
		   alsa_stream ? alsa_stream->substream : 0);

	if (alsa_stream->open)
		consumed = bcm2835_audio_retrieve_buffers(alsa_stream);

	/* We get called only if playback was triggered, So, the number of buffers we retrieve in
	 * each iteration are the buffers that have been played out already
	 */

	if (alsa_stream->period_size) {
		if ((alsa_stream->pos / alsa_stream->period_size) !=
		    ((alsa_stream->pos + consumed) / alsa_stream->period_size))
			new_period = 1;
	}
	audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
		      alsa_stream->pos,
		      consumed,
		      alsa_stream->buffer_size,
			  (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods),
			  frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
			  new_period);
	if (alsa_stream->buffer_size) {
		alsa_stream->pos += consumed &~ (1<<30);
		alsa_stream->pos %= alsa_stream->buffer_size;
	}

	if (alsa_stream->substream) {
		if (new_period)
			snd_pcm_period_elapsed(alsa_stream->substream);
	} else {
		audio_warning(" unexpected NULL substream\n");
	}
	audio_info(" .. OUT\n");

	return IRQ_HANDLED;
}
Пример #2
0
/* close callback */
static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
{
	/* the hardware-specific codes will be here */

	struct snd_pcm_runtime *runtime = substream->runtime;
	bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;

	audio_info(" .. IN\n");
	audio_warning("Alsa close\n");

	/*
	 * Call stop if it's still running. This happens when app
	 * is force killed and we don't get a stop trigger.
	 */
	if (alsa_stream->running) {
		int err;
		err = bcm2835_audio_stop(alsa_stream);
		alsa_stream->running = 0;
		if (err != 0)
			audio_error(" Failed to STOP alsa device\n");
	}

	alsa_stream->period_size = 0;
	alsa_stream->buffer_size = 0;

	if (alsa_stream->open) {
		alsa_stream->open = 0;
		bcm2835_audio_close(alsa_stream);
	}
	if (alsa_stream->chip)
		alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
	/*
	 * Do not free up alsa_stream here, it will be freed up by
	 * runtime->private_free callback we registered in *_open above
	 */

	audio_info(" .. OUT\n");

	return 0;
}
Пример #3
0
/* open callback */
static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
{
	bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
	struct snd_pcm_runtime *runtime = substream->runtime;
	bcm2835_alsa_stream_t *alsa_stream;
	int idx;
	int err;

	audio_info(" .. IN (%d)\n", substream->number);

	audio_warning("Alsa open (%d)\n", substream->number);
	idx = substream->number;

	if (idx > MAX_SUBSTREAMS) {
		audio_error
		    ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
		     idx, MAX_SUBSTREAMS);
		err = -ENODEV;
		goto out;
	}

	/* Check if we are ready */
	if (!(chip->avail_substreams & (1 << idx))) {
		/* We are not ready yet */
		audio_error("substream(%d) device is not ready yet\n", idx);
		err = -EAGAIN;
		goto out;
	}

	alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL);
	if (alsa_stream == NULL) {
		return -ENOMEM;
	}

	/* Initialise alsa_stream */
	alsa_stream->chip = chip;
	alsa_stream->substream = substream;
	alsa_stream->idx = idx;
	chip->alsa_stream[idx] = alsa_stream;

	sema_init(&alsa_stream->buffers_update_sem, 0);
	sema_init(&alsa_stream->control_sem, 0);
	spin_lock_init(&alsa_stream->lock);

	/* Enabled in start trigger, called on each "fifo irq" after that */
	alsa_stream->enable_fifo_irq = 0;
	alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq;

	runtime->private_data = alsa_stream;
	runtime->private_free = snd_bcm2835_playback_free;
	runtime->hw = snd_bcm2835_playback_hw;

	/* minimum 16 bytes alignment (for vchiq bulk transfers) */
	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
				   16);

	err = bcm2835_audio_open(alsa_stream);
	if (err != 0) {
		kfree(alsa_stream);
		return err;
	}

	alsa_stream->open = 1;
	alsa_stream->draining = 1;

out:
	audio_info(" .. OUT =%d\n", err);

	return err;
}