Beispiel #1
0
static void
bcm2835_audio_start(struct bcm2835_audio_chinfo *ch)
{
	VC_AUDIO_MSG_T m;
	int ret;
	struct bcm2835_audio_info *sc = ch->parent;

	VCHIQ_VCHI_LOCK(sc);
	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
		vchi_service_use(sc->vchi_handle);

		bcm2835_audio_reset_channel(ch);

		m.type = VC_AUDIO_MSG_TYPE_START;
		ret = vchi_msg_queue(sc->vchi_handle,
		    &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);

		if (ret != 0)
			printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);

		vchi_service_release(sc->vchi_handle);
	}
	VCHIQ_VCHI_UNLOCK(sc);

}
Beispiel #2
0
static void
bcm2835_audio_worker(void *data)
{
	struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)data;
	struct bcm2835_audio_chinfo *ch = &sc->pch;
	mtx_lock(&sc->data_lock);
	while(1) {

		if (sc->unloading)
			break;

		if ((ch->playback_state == PLAYBACK_PLAYING) &&
		    (vchiq_unbuffered_bytes(ch) >= VCHIQ_AUDIO_PACKET_SIZE)
		    && (ch->free_buffer >= VCHIQ_AUDIO_PACKET_SIZE)) {
			bcm2835_audio_write_samples(ch);
		} else {
			if (ch->playback_state == PLAYBACK_STOPPING) {
				bcm2835_audio_reset_channel(&sc->pch);
				ch->playback_state = PLAYBACK_IDLE;
			}

			cv_wait_sig(&sc->data_cv, &sc->data_lock);

			if (ch->playback_state == PLAYBACK_STARTING) {
				/* Give it initial kick */
				chn_intr(sc->pch.channel);
				ch->playback_state = PLAYBACK_PLAYING;
			}
		}
	}
	mtx_unlock(&sc->data_lock);

	kproc_exit(0);
}
Beispiel #3
0
static void
bcm2835_audio_delayed_init(void *xsc)
{
    	struct bcm2835_audio_info *sc;
    	char status[SND_STATUSLEN];

	sc = xsc;

	config_intrhook_disestablish(&sc->intr_hook);

	bcm2835_audio_init(sc);
	bcm2835_audio_open(sc);
	sc->volume = 75;
	sc->dest = DEST_AUTO;

    	if (mixer_init(sc->dev, &bcmmixer_class, sc)) {
		device_printf(sc->dev, "mixer_init failed\n");
		goto no;
	}

    	if (pcm_register(sc->dev, sc, 1, 1)) {
		device_printf(sc->dev, "pcm_register failed\n");
		goto no;
	}

	pcm_addchan(sc->dev, PCMDIR_PLAY, &bcmchan_class, sc);
    	snprintf(status, SND_STATUSLEN, "at VCHIQ");
	pcm_setstatus(sc->dev, status);

	bcm2835_audio_reset_channel(&sc->pch);
	bcm2835_audio_create_worker(sc);

	vchi_audio_sysctl_init(sc);

no:
	;
}
Beispiel #4
0
static void
bcm2835_audio_worker(void *data)
{
	struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)data;
	struct bcm2835_audio_chinfo *ch = &sc->pch;
	uint32_t speed, format;
	uint32_t volume, dest;
	uint32_t flags;
	uint32_t count, size, readyptr;
	uint8_t *buf;

	ch->playback_state = PLAYBACK_IDLE;

	while (1) {
		if (sc->worker_state != WORKER_RUNNING)
			break;

		BCM2835_AUDIO_LOCK(sc);
		/*
		 * wait until there are flags set or buffer is ready
		 * to consume more samples
		 */
		while ((sc->flags_pending == 0) &&
		    bcm2835_audio_buffer_should_sleep(ch)) {
			cv_wait_sig(&sc->worker_cv, &sc->lock);
		}
		flags = sc->flags_pending;
		/* Clear pending flags */
		sc->flags_pending = 0;
		BCM2835_AUDIO_UNLOCK(sc);

		/* Requested to change parameters */
		if (flags & AUDIO_PARAMS) {
			BCM2835_AUDIO_LOCK(sc);
			speed = ch->spd;
			format = ch->fmt;
			volume = sc->volume;
			dest = sc->dest;
			BCM2835_AUDIO_UNLOCK(sc);
			if (ch->playback_state == PLAYBACK_IDLE)
				bcm2835_audio_update_params(sc, format, speed);
			bcm2835_audio_update_controls(sc, volume, dest);
		}

		/* Requested to stop playback */
		if ((flags & AUDIO_STOP) &&
		    (ch->playback_state == PLAYBACK_PLAYING)) {
			bcm2835_audio_stop(ch);
			BCM2835_AUDIO_LOCK(sc);
			bcm2835_audio_reset_channel(&sc->pch);
			ch->playback_state = PLAYBACK_IDLE;
			BCM2835_AUDIO_UNLOCK(sc);
			continue;
		}

		/* Requested to start playback */
		if ((flags & AUDIO_PLAY) &&
		    (ch->playback_state == PLAYBACK_IDLE)) {
			BCM2835_AUDIO_LOCK(sc);
			ch->playback_state = PLAYBACK_PLAYING;
			BCM2835_AUDIO_UNLOCK(sc);
			bcm2835_audio_start(ch);
		}

		if (ch->playback_state == PLAYBACK_IDLE)
			continue;

		if (sndbuf_getready(ch->buffer) == 0)
			continue;

		count = sndbuf_getready(ch->buffer);
		size = sndbuf_getsize(ch->buffer);
		readyptr = sndbuf_getreadyptr(ch->buffer);

		BCM2835_AUDIO_LOCK(sc);
		if (readyptr + count > size)
			count = size - readyptr;
		count = min(count, ch->available_space);
		count -= (count % VCHIQ_AUDIO_PACKET_SIZE);
		BCM2835_AUDIO_UNLOCK(sc);

		if (count < VCHIQ_AUDIO_PACKET_SIZE)
			continue;

		buf = (uint8_t*)sndbuf_getbuf(ch->buffer) + readyptr;

		bcm2835_audio_write_samples(ch, buf, count);
		BCM2835_AUDIO_LOCK(sc);
		ch->unsubmittedptr = (ch->unsubmittedptr + count) % sndbuf_getsize(ch->buffer);
		ch->available_space -= count;
		ch->submitted_samples += count;
		KASSERT(ch->available_space >= 0, ("ch->available_space == %d\n", ch->available_space));
		BCM2835_AUDIO_UNLOCK(sc);
	}

	BCM2835_AUDIO_LOCK(sc);
	sc->worker_state = WORKER_STOPPED;
	cv_signal(&sc->worker_cv);
	BCM2835_AUDIO_UNLOCK(sc);

	kproc_exit(0);
}