예제 #1
0
int snd_bcm2835_new_spdif_pcm(struct bcm2835_chip *chip)
{
	struct snd_pcm *pcm;
	int err;

	audio_info(" .. IN\n");
	if (mutex_lock_interruptible(&chip->audio_mutex)) {
		audio_error("Interrupted whilst waiting for lock\n");
		return -EINTR;
	}
	err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
	if (err < 0)
		goto out;

	pcm->private_data = chip;
	strcpy(pcm->name, "bcm2835 IEC958/HDMI");
	chip->pcm_spdif = pcm;
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
			&snd_bcm2835_playback_spdif_ops);

	/* pre-allocation of buffers */
	/* NOTE: this may fail */
	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
		snd_dma_continuous_data(GFP_KERNEL),
		snd_bcm2835_playback_spdif_hw.buffer_bytes_max, snd_bcm2835_playback_spdif_hw.buffer_bytes_max);
out:
	mutex_unlock(&chip->audio_mutex);
	audio_info(" .. OUT\n");

	return 0;
}
예제 #2
0
/* create a pcm device */
int __devinit snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
{
	struct snd_pcm *pcm;
	int err;

	audio_info(" .. IN\n");
	err =
	    snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
	if (err < 0)
		return err;
	pcm->private_data = chip;
	strcpy(pcm->name, "bcm2835 ALSA");
	chip->pcm = pcm;
	chip->dest = AUDIO_DEST_AUTO;
	chip->volume = 100;
	/* set operators */
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
			&snd_bcm2835_playback_ops);

	/* pre-allocation of buffers */
	/* NOTE: this may fail */
	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
					      snd_dma_continuous_data
					      (GFP_KERNEL), 64 * 1024,
					      64 * 1024);

	audio_info(" .. OUT\n");

	return 0;
}
예제 #3
0
/* hw_params callback */
static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
				     struct snd_pcm_hw_params *params)
{
	int err;
	struct snd_pcm_runtime *runtime = substream->runtime;
	bcm2835_alsa_stream_t *alsa_stream =
	    (bcm2835_alsa_stream_t *) runtime->private_data;

	audio_info(" .. IN\n");

	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
	if (err < 0) {
		audio_error
		    (" pcm_lib_malloc failed to allocated pages for buffers\n");
		return err;
	}

	err = bcm2835_audio_set_params(alsa_stream, params_channels(params),
				       params_rate(params),
				       snd_pcm_format_width(params_format
							    (params)));
	if (err < 0) {
		audio_error(" error setting hw params\n");
	}

	bcm2835_audio_setup(alsa_stream);
	audio_info(" .. OUT\n");

	return err;
}
예제 #4
0
/* close callback */
static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
{
	/* the hardware-specific codes will be here */

	struct bcm2835_chip *chip;
	struct snd_pcm_runtime *runtime;
	struct bcm2835_alsa_stream *alsa_stream;

	audio_info(" .. IN\n");

	chip = snd_pcm_substream_chip(substream);
	if (mutex_lock_interruptible(&chip->audio_mutex)) {
		audio_error("Interrupted whilst waiting for lock\n");
		return -EINTR;
	}
	runtime = substream->runtime;
	alsa_stream = runtime->private_data;

	audio_info("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)
			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
	 */

	chip->opened &= ~(1 << substream->number);

	mutex_unlock(&chip->audio_mutex);
	audio_info(" .. OUT\n");

	return 0;
}
예제 #5
0
/* prepare callback */
static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
{
	struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
	int channels;
	int err;

	audio_info(" .. IN\n");

	if (mutex_lock_interruptible(&chip->audio_mutex))
		return -EINTR;

	/* notify the vchiq that it should enter spdif passthrough mode by
	 * setting channels=0 (see
	 * https://github.com/raspberrypi/linux/issues/528) */
	if (chip->spdif_status & IEC958_AES0_NONAUDIO)
		channels = 0;
	else
		channels = alsa_stream->channels;

	err = bcm2835_audio_set_params(alsa_stream, channels,
		alsa_stream->params_rate,
		alsa_stream->pcm_format_width);
	if (err < 0) {
		audio_error(" error setting hw params\n");
	}

	bcm2835_audio_setup(alsa_stream);

	/* in preparation of the stream, set the controls (volume level) of the stream */
	bcm2835_audio_set_ctls(alsa_stream->chip);


	memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));

	alsa_stream->pcm_indirect.hw_buffer_size =
		alsa_stream->pcm_indirect.sw_buffer_size =
		snd_pcm_lib_buffer_bytes(substream);

	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);

	mutex_unlock(&chip->audio_mutex);
	audio_info(" .. OUT\n");
	return 0;
}
예제 #6
0
/* trigger callback */
static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
	int err = 0;

	audio_info(" .. IN\n");

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
		audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
			alsa_stream->running);
		if (!alsa_stream->running) {
			err = bcm2835_audio_start(alsa_stream);
			if (!err) {
				alsa_stream->pcm_indirect.hw_io =
					alsa_stream->pcm_indirect.hw_data =
					bytes_to_frames(runtime,
					alsa_stream->pos);
				substream->ops->ack(substream);
				alsa_stream->running = 1;
				alsa_stream->draining = 1;
			} else {
				audio_error(" Failed to START alsa device (%d)\n", err);
			}
		}
		break;
	case SNDRV_PCM_TRIGGER_STOP:
		audio_debug
			("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
			alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
		if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
			audio_info("DRAINING\n");
			alsa_stream->draining = 1;
		} else {
			audio_info("DROPPING\n");
			alsa_stream->draining = 0;
		}
		if (alsa_stream->running) {
			err = bcm2835_audio_stop(alsa_stream);
			if (err != 0)
				audio_error(" Failed to STOP alsa device (%d)\n", err);
			alsa_stream->running = 0;
		}
		break;
	default:
		err = -EINVAL;
	}

	audio_info(" .. OUT\n");
	return err;
}
예제 #7
0
static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
{
	audio_info("Freeing up alsa stream here ..\n");
	if (runtime->private_data)
		kfree(runtime->private_data);
	runtime->private_data = NULL;
}
예제 #8
0
/* pointer callback */
static snd_pcm_uframes_t
snd_bcm2835_pcm_pointer(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");

	audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
		      frames_to_bytes(runtime, runtime->status->hw_ptr),
		      frames_to_bytes(runtime, runtime->control->appl_ptr),
		      alsa_stream->pos);

	audio_info(" .. OUT\n");
	return bytes_to_frames(runtime, alsa_stream->pos);
}
예제 #9
0
static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
				     unsigned int cmd, void *arg)
{
	int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
	audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
		    cmd, arg, arg ? *(unsigned *)arg : 0, ret);
	return ret;
}
예제 #10
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;
}
예제 #11
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;
}
예제 #12
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;
}
예제 #13
0
static int snd_bcm2835_pcm_copy(struct snd_pcm_substream *substream,
				int channel, snd_pcm_uframes_t pos, void *src,
				snd_pcm_uframes_t count)
{
	int ret;
	struct snd_pcm_runtime *runtime = substream->runtime;
	bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;

	audio_info(" .. IN\n");
	audio_debug("copy.......... (%d) hwptr=%d appl=%d pos=%d\n",
		      frames_to_bytes(runtime, count), frames_to_bytes(runtime,
								       runtime->
								       status->
								       hw_ptr),
		      frames_to_bytes(runtime, runtime->control->appl_ptr),
		      alsa_stream->pos);
	ret =
	    bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count),
				src);
	audio_info(" .. OUT\n");
	return ret;
}
예제 #14
0
/* toggles mute on or off depending on the value of nmute, and returns
 * 1 if the mute value was changed, otherwise 0
 */
static int toggle_mute(struct bcm2835_chip *chip, int nmute)
{
	/* if settings are ok, just return 0 */
	if(chip->mute == nmute)
		return 0;

	/* if the sound is muted then we need to unmute */
	if(chip->mute == CTRL_VOL_MUTE)
	{
		chip->volume = chip->old_volume; /* copy the old volume back */
		audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
	}
	else /* otherwise we mute */
	{
		chip->old_volume = chip->volume;
		chip->volume = 26214; /* set volume to minimum level AKA mute */
		audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
	}

	chip->mute = nmute;
	return 1;
}
예제 #15
0
static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
			       struct snd_ctl_elem_value *ucontrol)
{
	struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
	int changed = 0;

	if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
		audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
		if (chip->mute == CTRL_VOL_MUTE) {
			/* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
			return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
		}
		if (changed
		    || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {

			chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
			changed = 1;
		}

	} else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
		/* Now implemented */
		audio_info(" Mute attempted\n");
		changed = toggle_mute(chip, ucontrol->value.integer.value[0]);

	} else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
		if (ucontrol->value.integer.value[0] != chip->dest) {
			chip->dest = ucontrol->value.integer.value[0];
			changed = 1;
		}
	}

	if (changed) {
		if (bcm2835_audio_set_ctls(chip))
			printk(KERN_ERR "Failed to set ALSA controls..\n");
	}

	return changed;
}
예제 #16
0
/* create a pcm device */
int snd_bcm2835_new_pcm(struct bcm2835_chip *chip)
{
	struct snd_pcm *pcm;
	int err;

	audio_info(" .. IN\n");
	mutex_init(&chip->audio_mutex);
	if (mutex_lock_interruptible(&chip->audio_mutex)) {
		audio_error("Interrupted whilst waiting for lock\n");
		return -EINTR;
	}
	err = snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
	if (err < 0)
		goto out;
	pcm->private_data = chip;
	strcpy(pcm->name, "bcm2835 ALSA");
	chip->pcm = pcm;
	chip->dest = AUDIO_DEST_AUTO;
	chip->volume = alsa2chip(0);
	chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
	/* set operators */
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
			&snd_bcm2835_playback_ops);

	/* pre-allocation of buffers */
	/* NOTE: this may fail */
	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
					      snd_dma_continuous_data(GFP_KERNEL),
					      snd_bcm2835_playback_hw.buffer_bytes_max,
					      snd_bcm2835_playback_hw.buffer_bytes_max);


out:
	mutex_unlock(&chip->audio_mutex);
	audio_info(" .. OUT\n");

	return 0;
}
예제 #17
0
static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_info *uinfo)
{
	audio_info(" ... IN\n");
	if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
		uinfo->count = 1;
		uinfo->value.integer.min = CTRL_VOL_MIN;
		uinfo->value.integer.max = CTRL_VOL_MAX;      /* 2303 */
	} else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
		uinfo->count = 1;
		uinfo->value.integer.min = 0;
		uinfo->value.integer.max = 1;
	} else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
		uinfo->count = 1;
		uinfo->value.integer.min = 0;
		uinfo->value.integer.max = AUDIO_DEST_MAX-1;
	}
	audio_info(" ... OUT\n");
	return 0;
}
예제 #18
0
/* hw_params callback */
static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
	struct snd_pcm_hw_params *params)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
	int err;

	audio_info(" .. IN\n");

	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
	if (err < 0) {
		audio_error
			(" pcm_lib_malloc failed to allocated pages for buffers\n");
		return err;
	}

	alsa_stream->channels = params_channels(params);
	alsa_stream->params_rate = params_rate(params);
	alsa_stream->pcm_format_width = snd_pcm_format_width(params_format(params));
	audio_info(" .. OUT\n");

	return err;
}
예제 #19
0
static void audio_loop(t_mdxmini *data, int freq, int len)
{
    
	int total;
	int sec;
	int sec_sample;

    if (len < 0)
        len = mdx_get_length(data);

	mdx_set_max_loop(data, 0);
    
	fade_init();
	
	total = sec = sec_sample = 0;

    // put title info
    audio_disp_title(data);
    
    // put time
    audio_info(data, sec, len);

	do
	{
		// waiting for next block
        while(pcm.count >=  (PCM_BUFFER_LEN - PCM_BLOCK_SIZE))
        {
            if (audio_poll_event() < 0)
            {
                SDL_PauseAudio(1);
                return;
            }
            SDL_Delay(1);
        }
		
        // calculate samples
		mdx_calc_sample(data, pcm.buffer + pcm.write_pos, PCM_BLOCK);
		if (is_fade_run())
			fade_stereo (pcm.buffer + pcm.write_pos, PCM_BLOCK);
		
		pcm.write_pos += PCM_BLOCK_SIZE;
		if (pcm.write_pos >= PCM_BUFFER_LEN)
				pcm.write_pos = 0;
        
        pcm.count += PCM_BLOCK_SIZE;
		
		total += PCM_BLOCK;
		sec_sample += PCM_BLOCK;
        
        // if sec_samples > 1sec
		while (sec_sample >= freq)
		{
			sec_sample -= freq;
			sec++;
            
            if (sec >= (len - 3))
			{
				if (!is_fade_run())
					fade_start(freq, 1);
			}
            if (!g_viewnote)
                audio_info(data, sec, len);
            
		}
        
		if (g_viewnote)
            audio_info(data, sec, len);

	}while(sec < len && !pcm.stop);
    
    printf("\n");
	
	SDL_PauseAudio(1);
}
예제 #20
0
static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
{
	static int dev;
	bcm2835_chip_t *chip;
	struct snd_card *card;
	int err;

	if (dev >= MAX_SUBSTREAMS)
		return -ENODEV;

	if (!enable[dev]) {
		dev++;
		return -ENOENT;
	}

	if (dev > 0)
		goto add_register_map;

	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &g_card);
	if (err < 0)
		goto out;

	snd_card_set_dev(g_card, &pdev->dev);
	strcpy(g_card->driver, "bcm2835");
	strcpy(g_card->shortname, "bcm2835 ALSA");
	sprintf(g_card->longname, "%s", g_card->shortname);

	err = snd_bcm2835_create(g_card, pdev, &chip);
	if (err < 0) {
		dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
		goto out_bcm2835_create;
	}

	g_chip = chip;
	err = snd_bcm2835_new_pcm(chip);
	if (err < 0) {
		dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
		goto out_bcm2835_new_pcm;
	}

	err = snd_bcm2835_new_spdif_pcm(chip);
	if (err < 0) {
		dev_err(&pdev->dev, "Failed to create new BCM2835 spdif pcm device\n");
		goto out_bcm2835_new_spdif;
	}

	err = snd_bcm2835_new_ctl(chip);
	if (err < 0) {
		dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
		goto out_bcm2835_new_ctl;
	}

add_register_map:
	card = g_card;
	chip = g_chip;

	BUG_ON(!(card && chip));

	chip->avail_substreams |= (1 << dev);
	chip->pdev[dev] = pdev;

	if (dev == 0) {
		err = snd_card_register(card);
		if (err < 0) {
			dev_err(&pdev->dev,
				"Failed to register bcm2835 ALSA card \n");
			goto out_card_register;
		}
		platform_set_drvdata(pdev, card);
		audio_info("bcm2835 ALSA card created!\n");
	} else {
		audio_info("bcm2835 ALSA chip created!\n");
		platform_set_drvdata(pdev, (void *)dev);
	}

	dev++;

	return 0;

out_card_register:
out_bcm2835_new_ctl:
out_bcm2835_new_spdif:
out_bcm2835_new_pcm:
out_bcm2835_create:
	BUG_ON(!g_card);
	if (snd_card_free(g_card))
		dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
	g_card = NULL;
out:
	dev = SNDRV_CARDS;	/* stop more avail_substreams from being probed */
	dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
	return err;
}
예제 #21
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;
}
예제 #22
0
static void audio_loop_file(
    t_mdxmini *data, const char *file, int freq , int len)
{
    FILE *fp = NULL;
    
    int sec;
    int last_sec;
    
    int frames;
    int total_frames;
    
    short pcm_buffer[PCM_BLOCK_SIZE];
    
    
    // put title info
    audio_disp_title(data);

    
    // get length
    
    if (len < 0)
        len = mdx_get_length(data);

    // len = 5;
    
    fade_init();
    
    
    sec =
    frames =
    total_frames = 0;
    
    
    if (file)
        fp = fopen(file, "wb");
    
    if (file && fp == NULL)
    {
        printf("Can't write a PCM file!\n");
        return;
    }
    
    audio_write_wav_header(fp, freq, 0);
    
    audio_info(data, sec, len);
    
    do
    {
        // calculate samples
        if (fp)
            mdx_calc_sample(data, pcm_buffer, PCM_BLOCK);
		else
            mdx_calc_log(data, pcm_buffer, PCM_BLOCK);
        
        if (is_fade_run())
			fade_stereo(pcm_buffer, PCM_BLOCK);
		      
        if (fp)
            fwrite(pcm_buffer, PCM_BLOCK_BYTES, 1, fp);
        
        // increase pointer
        frames += PCM_BLOCK;
        total_frames += PCM_BLOCK;
        
        /* increase seconds */
        while(frames >= freq)
        {
            frames -= freq;
            sec++;
            audio_info(data, sec, len);
            
            // start fader
            if (sec >= (len - 3))
            {
                if (!is_fade_run())
                    fade_start(freq, 1);
            }
        }

    }while(sec < len && !pcm.stop);
    
    audio_write_wav_header(
            fp, freq, (total_frames * PCM_CH * PCM_BYTE_PER_SAMPLE));
    
    printf("\n");
    
    if (fp)
        fclose(fp);
}
예제 #23
0
/* hw_free callback */
static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
{
	audio_info(" .. IN\n");
	return snd_pcm_lib_free_pages(substream);
}
예제 #24
0
static int snd_bcm2835_alsa_probe_dt(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct bcm2835_chip *chip;
	struct snd_card *card;
	u32 numchans;
	int err, i;

	err = of_property_read_u32(dev->of_node, "brcm,pwm-channels",
				   &numchans);
	if (err) {
		dev_err(dev, "Failed to get DT property 'brcm,pwm-channels'");
		return err;
	}

	if (numchans == 0 || numchans > MAX_SUBSTREAMS) {
		numchans = MAX_SUBSTREAMS;
		dev_warn(dev, "Illegal 'brcm,pwm-channels' value, will use %u\n",
			 numchans);
	}

	err = snd_card_new(&pdev->dev, -1, NULL, THIS_MODULE, 0, &card);
	if (err) {
		dev_err(dev, "Failed to create soundcard structure\n");
		return err;
	}

	snd_card_set_dev(card, dev);
	strcpy(card->driver, "bcm2835");
	strcpy(card->shortname, "bcm2835 ALSA");
	sprintf(card->longname, "%s", card->shortname);

	err = snd_bcm2835_create(card, pdev, &chip);
	if (err < 0) {
		dev_err(dev, "Failed to create bcm2835 chip\n");
		goto err_free;
	}

	err = snd_bcm2835_new_pcm(chip);
	if (err < 0) {
		dev_err(dev, "Failed to create new bcm2835 pcm device\n");
		goto err_free;
	}

	err = snd_bcm2835_new_spdif_pcm(chip);
	if (err < 0) {
		dev_err(dev, "Failed to create new bcm2835 spdif pcm device\n");
		goto err_free;
	}

	err = snd_bcm2835_new_ctl(chip);
	if (err < 0) {
		dev_err(dev, "Failed to create new bcm2835 ctl\n");
		goto err_free;
	}

	for (i = 0; i < numchans; i++) {
		chip->avail_substreams |= (1 << i);
		chip->pdev[i] = pdev;
	}

	err = snd_card_register(card);
	if (err) {
		dev_err(dev, "Failed to register bcm2835 ALSA card\n");
		goto err_free;
	}

	g_card = card;
	g_chip = chip;
	platform_set_drvdata(pdev, card);
	audio_info("bcm2835 ALSA card created with %u channels\n", numchans);

	return 0;

err_free:
	snd_card_free(card);

	return err;
}
예제 #25
0
/* open callback */
static int snd_bcm2835_playback_open_generic(
	struct snd_pcm_substream *substream, int spdif)
{
	struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct bcm2835_alsa_stream *alsa_stream;
	int idx;
	int err;

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

	if (mutex_lock_interruptible(&chip->audio_mutex)) {
		audio_error("Interrupted whilst waiting for lock\n");
		return -EINTR;
	}
	audio_info("Alsa open (%d)\n", substream->number);
	idx = substream->number;

	if (spdif && chip->opened) {
		err = -EBUSY;
		goto out;
	} else if (!spdif && (chip->opened & (1 << idx))) {
		err = -EBUSY;
		goto out;
	}
	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(*alsa_stream), GFP_KERNEL);
	if (!alsa_stream) {
		err = -ENOMEM;
		goto out;
	}

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

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

	err = bcm2835_audio_open(alsa_stream);
	if (err) {
		kfree(alsa_stream);
		goto out;
	}
	runtime->private_data = alsa_stream;
	runtime->private_free = snd_bcm2835_playback_free;
	if (spdif) {
		runtime->hw = snd_bcm2835_playback_spdif_hw;
	} else {
		/* clear spdif status, as we are not in spdif mode */
		chip->spdif_status = 0;
		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);

	chip->alsa_stream[idx] = alsa_stream;

	chip->opened |= (1 << idx);
	alsa_stream->open = 1;
	alsa_stream->draining = 1;

out:
	mutex_unlock(&chip->audio_mutex);

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

	return err;
}