Ejemplo n.º 1
0
static int
bcmchan_free(kobj_t obj, void *data)
{
	struct bcm2835_audio_chinfo *ch = data;
	void *buffer;

	buffer = sndbuf_getbuf(ch->buffer);
	if (buffer)
		free(buffer, M_DEVBUF);

	return (0);
}
Ejemplo n.º 2
0
static int
ichchan_free(kobj_t obj, void *data)
{
	struct sc_chinfo *ch;
	struct sc_info *sc;

	ch = (struct sc_chinfo *)data;
	sc = (ch != NULL) ? ch->parent : NULL;
	if (ch != NULL && sc != NULL) {
		ICH_DMA_ATTR(sc, sndbuf_getbuf(ch->buffer),
		    sndbuf_getmaxsize(ch->buffer), PAT_WRITE_BACK);
	}

	return (1);
}
Ejemplo n.º 3
0
static void
adcdac_prog(struct sc_chinfo *ch)
{
    struct sc_info *sc = ch->parent;
    u_int32_t go;

    if (!ch->dma_setup) {
	go = adcdac_go(ch, 0);
	cs4281_wr(sc, CS4281PCI_DBA(ch->dma_chan),
		  vtophys(sndbuf_getbuf(ch->buffer)));
	cs4281_wr(sc, CS4281PCI_DBC(ch->dma_chan),
		  sndbuf_getsize(ch->buffer) / ch->bps - 1);
	ch->dma_setup = 1;
	adcdac_go(ch, go);
    }
}
Ejemplo n.º 4
0
static void *
ua_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
	device_t pa_dev;
	u_char *buf,*end;

	struct ua_info *sc = devinfo;
	struct ua_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch;

	ch->parent = sc;
	ch->channel = c;
	ch->buffer = b;

	pa_dev = device_get_parent(sc->sc_dev);
     	/* Create ua_playfmt[] & ua_recfmt[] */
	uaudio_query_formats(pa_dev, (u_int32_t *)&ua_playfmt, (u_int32_t *)&ua_recfmt);
	if (ua_playfmt[0] == 0) {
		printf("%s channel supported format list invalid\n", dir == PCMDIR_PLAY? "play" : "record");
		return NULL;
	}

	/* allocate PCM side DMA buffer */
	if (sndbuf_alloc(ch->buffer, sc->parent_dmat, UAUDIO_PCM_BUFF_SIZE) != 0) {
	    return NULL;
        }

	buf = end = sndbuf_getbuf(b);
	end += sndbuf_getsize(b);
	uaudio_chan_set_param_pcm_dma_buff(pa_dev, buf, end, ch->channel);

	ch->dir = dir;
#ifndef NO_RECORDING
	ch->hwch = 1;
	if (dir == PCMDIR_PLAY)
		ch->hwch = 2;
#else
	ch->hwch = 2;
#endif

	return ch;
}
Ejemplo n.º 5
0
/* channel interface */
static void *
nmchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
	struct sc_info *sc = devinfo;
	struct sc_chinfo *ch;
	u_int32_t chnbuf;

	chnbuf = (dir == PCMDIR_PLAY)? sc->pbuf : sc->rbuf;
	ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch;
	ch->active = 0;
	ch->blksize = 0;
	ch->wmark = 0;
	ch->buffer = b;
	sndbuf_setup(ch->buffer, (u_int8_t *)rman_get_virtual(sc->buf) + chnbuf, NM_BUFFSIZE);
	if (bootverbose)
		device_printf(sc->dev, "%s buf %p\n", (dir == PCMDIR_PLAY)?
			      "play" : "rec", sndbuf_getbuf(ch->buffer));
	ch->parent = sc;
	ch->channel = c;
	ch->dir = dir;
	return ch;
}
Ejemplo n.º 6
0
static void
bcm2835_audio_write_samples(struct bcm2835_audio_chinfo *ch)
{
	struct bcm2835_audio_info *sc = ch->parent;
	VC_AUDIO_MSG_T m;
	void *buf;
	uint32_t count, size;
	int ret;

	VCHIQ_VCHI_LOCK(sc);
	if (sc->vchi_handle == VCHIQ_SERVICE_HANDLE_INVALID) {
		VCHIQ_VCHI_UNLOCK(sc);
		return;
	}

	vchi_service_use(sc->vchi_handle);

	size = sndbuf_getsize(ch->buffer);
	count = vchiq_unbuffered_bytes(ch);
	buf = (uint8_t*)sndbuf_getbuf(ch->buffer) + ch->buffered_ptr;

	if (ch->buffered_ptr + count > size)
		count = size - ch->buffered_ptr;

	if (count < VCHIQ_AUDIO_PACKET_SIZE)
		goto done;

	count = min(count, ch->free_buffer);
	count -= count % VCHIQ_AUDIO_PACKET_SIZE;

	m.type = VC_AUDIO_MSG_TYPE_WRITE;
	m.u.write.count = count;
	m.u.write.max_packet = VCHIQ_AUDIO_PACKET_SIZE;
	m.u.write.callback = NULL;
	m.u.write.cookie = ch;
	if (buf)
		m.u.write.silence = 0;
	else
		m.u.write.silence = 1;

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

	if (buf) {
		while (count > 0) {
			int bytes = MIN((int)m.u.write.max_packet, (int)count);
			ch->free_buffer -= bytes;
			ch->buffered_ptr += bytes;
			ch->buffered_ptr = ch->buffered_ptr % size;
			ret = vchi_msg_queue(sc->vchi_handle,
			    buf, bytes, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
			if (ret != 0)
				printf("%s: vchi_msg_queue failed: %d\n",
				    __func__, ret);
			buf = (char *)buf + bytes;
			count -= bytes;
		}
	}
done:

	vchi_service_release(sc->vchi_handle);
	VCHIQ_VCHI_UNLOCK(sc);
}
Ejemplo n.º 7
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);
}
Ejemplo n.º 8
0
static void *
ichchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
	struct sc_info *sc = devinfo;
	struct sc_chinfo *ch;
	unsigned int num;

	ICH_LOCK(sc);
	num = sc->chnum++;
	ch = &sc->ch[num];
	ch->num = num;
	ch->buffer = b;
	ch->channel = c;
	ch->parent = sc;
	ch->run = 0;
	ch->dtbl = sc->dtbl + (ch->num * ICH_DTBL_LENGTH);
	ch->desc_addr = sc->desc_addr +
	    (ch->num * ICH_DTBL_LENGTH * sizeof(struct ich_desc));
	ch->blkcnt = sc->blkcnt;
	ch->blksz = sc->bufsz / ch->blkcnt;

	switch(ch->num) {
	case 0: /* play */
		KASSERT(dir == PCMDIR_PLAY, ("wrong direction"));
		ch->regbase = ICH_REG_PO_BASE;
		ch->spdreg = (sc->hasvra) ? AC97_REGEXT_FDACRATE : 0;
		ch->imask = ICH_GLOB_STA_POINT;
		break;

	case 1: /* record */
		KASSERT(dir == PCMDIR_REC, ("wrong direction"));
		ch->regbase = ICH_REG_PI_BASE;
		ch->spdreg = (sc->hasvra) ? AC97_REGEXT_LADCRATE : 0;
		ch->imask = ICH_GLOB_STA_PIINT;
		break;

	case 2: /* mic */
		KASSERT(dir == PCMDIR_REC, ("wrong direction"));
		ch->regbase = ICH_REG_MC_BASE;
		ch->spdreg = (sc->hasvrm) ? AC97_REGEXT_MADCRATE : 0;
		ch->imask = ICH_GLOB_STA_MINT;
		break;

	default:
		return (NULL);
	}

	if (sc->flags & ICH_FIXED_RATE)
		ch->spdreg = 0;

	ICH_UNLOCK(sc);
	if (sndbuf_alloc(ch->buffer, sc->chan_dmat, sc->bufsz) != 0)
		return (NULL);

	ICH_DMA_ATTR(sc, sndbuf_getbuf(ch->buffer),
	    sndbuf_getmaxsize(ch->buffer), PAT_UNCACHEABLE);

	ICH_LOCK(sc);
	ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (uint32_t)(ch->desc_addr), 4);
	ICH_UNLOCK(sc);

	return (ch);
}