static void
via_intr(void *p)
{
	struct via_info *via = p;
	int i, reg, stat;

	/* Poll playback channels */
	snd_mtxlock(via->lock);
	for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) {
		if (via->pch[i].channel == NULL)
			continue;
		reg = via->pch[i].rbase + VIA_RP_STATUS;
		stat = via_rd(via, reg, 1);
		if (stat & SGD_STATUS_INTR) {
			if (via->dma_eol_wake && ((stat & SGD_STATUS_EOL) ||
					!(stat & SGD_STATUS_ACTIVE))) {
				via_wr(via,
					via->pch[i].rbase + VIA_RP_CONTROL,
					SGD_CONTROL_START |
					SGD_CONTROL_AUTOSTART |
					SGD_CONTROL_I_EOL |
					SGD_CONTROL_I_FLAG, 1);
			}
			via_wr(via, reg, stat, 1);
			snd_mtxunlock(via->lock);
			chn_intr(via->pch[i].channel);
			snd_mtxlock(via->lock);
		}
	}

	/* Poll record channels */
	for (i = 0; i < NWRCHANS; i++) {
		if (via->rch[i].channel == NULL)
			continue;
		reg = via->rch[i].rbase + VIA_RP_STATUS;
		stat = via_rd(via, reg, 1);
		if (stat & SGD_STATUS_INTR) {
			if (via->dma_eol_wake && ((stat & SGD_STATUS_EOL) ||
					!(stat & SGD_STATUS_ACTIVE))) {
				via_wr(via,
					via->rch[i].rbase + VIA_RP_CONTROL,
					SGD_CONTROL_START |
					SGD_CONTROL_AUTOSTART |
					SGD_CONTROL_I_EOL |
					SGD_CONTROL_I_FLAG, 1);
			}
			via_wr(via, reg, stat, 1);
			snd_mtxunlock(via->lock);
			chn_intr(via->rch[i].channel);
			snd_mtxlock(via->lock);
		}
	}
	snd_mtxunlock(via->lock);
}
Esempio n. 2
0
/*
 * PCI driver interface
 */
static void
atiixp_intr(void *p)
{
	struct atiixp_info *sc = p;
	uint32_t status, enable, detected_codecs;

	atiixp_lock(sc);
	status = atiixp_rd(sc, ATI_REG_ISR);

	if (status == 0) {
		atiixp_unlock(sc);
		return;
	}

	if ((status & ATI_REG_ISR_IN_STATUS) && sc->rch.channel) {
		atiixp_unlock(sc);
		chn_intr(sc->rch.channel);
		atiixp_lock(sc);
	}
	if ((status & ATI_REG_ISR_OUT_STATUS) && sc->pch.channel) {
		atiixp_unlock(sc);
		chn_intr(sc->pch.channel);
		atiixp_lock(sc);
	}

#if 0
	if (status & ATI_REG_ISR_IN_XRUN) {
		device_printf(sc->dev,
			"Receive IN XRUN interrupt\n");
	}
	if (status & ATI_REG_ISR_OUT_XRUN) {
		device_printf(sc->dev,
			"Receive OUT XRUN interrupt\n");
	}
#endif

	if (status & CODEC_CHECK_BITS) {
		/* mark missing codecs as not ready */
		detected_codecs = status & CODEC_CHECK_BITS;
		sc->codec_not_ready_bits |= detected_codecs;

		/* disable detected interupt sources */
		enable  = atiixp_rd(sc, ATI_REG_IER);
		enable &= ~detected_codecs;
		atiixp_wr(sc, ATI_REG_IER, enable);
	}

	/* acknowledge */
	atiixp_wr(sc, ATI_REG_ISR, status);
	atiixp_unlock(sc);
}
Esempio n. 3
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);
}
Esempio n. 4
0
static void
bcm2835_audio_callback(void *param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle)
{
	struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)param;
	int32_t status;
	uint32_t msg_len;
	VC_AUDIO_MSG_T m;

	if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
		return;

	status = vchi_msg_dequeue(sc->vchi_handle,
	    &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
	if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
		sc->msg_result = m.u.result.success;
		cv_signal(&sc->msg_avail_cv);
	} else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
		struct bcm2835_audio_chinfo *ch = m.u.complete.cookie;

		int count = m.u.complete.count & 0xffff;
		int perr = (m.u.complete.count & (1U << 30)) != 0;

		ch->complete_pos = (ch->complete_pos + count) % sndbuf_getsize(ch->buffer);
		ch->free_buffer += count;

		if (perr || ch->free_buffer >= VCHIQ_AUDIO_PACKET_SIZE) {
			chn_intr(ch->channel);
			cv_signal(&sc->data_cv);
		}
	} else
		printf("%s: unknown m.type: %d\n", __func__, m.type);
}
Esempio n. 5
0
static int
bcmchan_trigger(kobj_t obj, void *data, int go)
{
	struct bcm2835_audio_chinfo *ch = data;
	struct bcm2835_audio_info *sc = ch->parent;

	if (!PCMTRIG_COMMON(go))
		return (0);

	switch (go) {
	case PCMTRIG_START:
		/* kickstart data flow */
		chn_intr(sc->pch.channel);
		ch->submitted_samples = 0;
		ch->retrieved_samples = 0;
		bcm2835_worker_play_start(sc);
		break;

	case PCMTRIG_STOP:
	case PCMTRIG_ABORT:
		bcm2835_worker_play_stop(sc);
		break;

	default:
		break;
	}
	return 0;
}
Esempio n. 6
0
/* The interrupt handler */
static void
nm_intr(void *p)
{
	struct sc_info *sc = (struct sc_info *)p;
	int status, x;

	status = nm_rd(sc, NM_INT_REG, sc->irsz);
	if (status == 0)
		return;

	if (status & sc->playint) {
		status &= ~sc->playint;
		sc->pch.wmark += sc->pch.blksize;
		sc->pch.wmark %= NM_BUFFSIZE;
		nm_wr(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pch.wmark, 4);

		nm_ackint(sc, sc->playint);
		chn_intr(sc->pch.channel);
	}
	if (status & sc->recint) {
		status &= ~sc->recint;
		sc->rch.wmark += sc->rch.blksize;
		sc->rch.wmark %= NM_BUFFSIZE;
		nm_wr(sc, NM_RBUFFER_WMARK, sc->rbuf + sc->rch.wmark, 4);

		nm_ackint(sc, sc->recint);
		chn_intr(sc->rch.channel);
	}
	if (status & sc->misc1int) {
		status &= ~sc->misc1int;
		nm_ackint(sc, sc->misc1int);
		x = nm_rd(sc, 0x400, 1);
		nm_wr(sc, 0x400, x | 2, 1);
	 	device_printf(sc->dev, "misc int 1\n");
	}
	if (status & sc->misc2int) {
		status &= ~sc->misc2int;
		nm_ackint(sc, sc->misc2int);
		x = nm_rd(sc, 0x400, 1);
		nm_wr(sc, 0x400, x & ~2, 1);
	 	device_printf(sc->dev, "misc int 2\n");
	}
	if (status) {
		nm_ackint(sc, status);
	 	device_printf(sc->dev, "unknown int\n");
	}
}
Esempio n. 7
0
/* The interrupt handler */
static void
nm_intr(void *p)
{
	struct sc_info *sc = (struct sc_info *)p;
	int status, x, active;

	active = (sc->pch.channel->buffer.dl || sc->rch.channel->buffer.dl);
	status = nm_rd(sc, NM_INT_REG, sc->irsz);
	if (status == 0 && active) {
		if (sc->badintr++ > 1000) {
			device_printf(sc->dev, "1000 bad intrs\n");
			sc->badintr = 0;
		}
		return;
	}
	sc->badintr = 0;

	if (status & sc->playint) {
		status &= ~sc->playint;
		nm_ackint(sc, sc->playint);
		chn_intr(sc->pch.channel);
	}
	if (status & sc->recint) {
		status &= ~sc->recint;
		nm_ackint(sc, sc->recint);
		chn_intr(sc->rch.channel);
	}
	if (status & sc->misc1int) {
		status &= ~sc->misc1int;
		nm_ackint(sc, sc->misc1int);
		x = nm_rd(sc, 0x400, 1);
		nm_wr(sc, 0x400, x | 2, 1);
	 	device_printf(sc->dev, "misc int 1\n");
	}
	if (status & sc->misc2int) {
		status &= ~sc->misc2int;
		nm_ackint(sc, sc->misc2int);
		x = nm_rd(sc, 0x400, 1);
		nm_wr(sc, 0x400, x & ~2, 1);
	 	device_printf(sc->dev, "misc int 2\n");
	}
	if (status) {
		status &= ~sc->misc2int;
		nm_ackint(sc, sc->misc2int);
	 	device_printf(sc->dev, "unknown int\n");
	}
}
Esempio n. 8
0
static void
bcm2835_audio_callback(void *param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle)
{
	struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)param;
	int32_t status;
	uint32_t msg_len;
	VC_AUDIO_MSG_T m;

	if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
		return;

	status = vchi_msg_dequeue(sc->vchi_handle,
	    &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
	if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
		if (m.u.result.success) {
			device_printf(sc->dev,
			    "msg type %08x failed\n",
			    m.type);
		}
	} else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
		struct bcm2835_audio_chinfo *ch = m.u.complete.cookie;

		int count = m.u.complete.count & 0xffff;
		int perr = (m.u.complete.count & (1U << 30)) != 0;
		ch->callbacks++;
		if (perr)
			ch->underruns++;

		BCM2835_AUDIO_LOCK(sc);
		if (ch->playback_state != PLAYBACK_IDLE) {
			/* Prevent LOR */
			BCM2835_AUDIO_UNLOCK(sc);
			chn_intr(sc->pch.channel);
			BCM2835_AUDIO_LOCK(sc);
		}
		/* We should check again, state might have changed */
		if (ch->playback_state != PLAYBACK_IDLE) {
			if (!perr) {
				if ((ch->available_space + count)> VCHIQ_AUDIO_BUFFER_SIZE) {
					device_printf(sc->dev, "inconsistent data in callback:\n");
					device_printf(sc->dev, "available_space == %d, count = %d, perr=%d\n",
					    ch->available_space, count, perr);
					device_printf(sc->dev,
					    "retrieved_samples = %lld, submitted_samples = %lld\n",
					    ch->retrieved_samples, ch->submitted_samples);
				}
				ch->available_space += count;
				ch->retrieved_samples += count;
			}
			if (perr || (ch->available_space >= VCHIQ_AUDIO_PACKET_SIZE))
				cv_signal(&sc->worker_cv);
		}
		BCM2835_AUDIO_UNLOCK(sc);
	} else
		printf("%s: unknown m.type: %d\n", __func__, m.type);
}
Esempio n. 9
0
static void
ad1816_intr(void *arg)
{
    struct ad1816_info *ad1816 = (struct ad1816_info *)arg;
    unsigned char   c, served = 0;

    ad1816_lock(ad1816);
    /* get interrupt status */
    c = io_rd(ad1816, AD1816_INT);

    /* check for stray interrupts */
    if (c & ~(AD1816_INTRCI | AD1816_INTRPI)) {
        printf("pcm: stray int (%x)\n", c);
        c &= AD1816_INTRCI | AD1816_INTRPI;
    }
    /* check for capture interrupt */
    if (sndbuf_runsz(ad1816->rch.buffer) && (c & AD1816_INTRCI)) {
        ad1816_unlock(ad1816);
        chn_intr(ad1816->rch.channel);
        ad1816_lock(ad1816);
        served |= AD1816_INTRCI;		/* cp served */
    }
    /* check for playback interrupt */
    if (sndbuf_runsz(ad1816->pch.buffer) && (c & AD1816_INTRPI)) {
        ad1816_unlock(ad1816);
        chn_intr(ad1816->pch.channel);
        ad1816_lock(ad1816);
        served |= AD1816_INTRPI;		/* pb served */
    }
    if (served == 0) {
        /* this probably means this is not a (working) ad1816 chip, */
        /* or an error in dma handling                              */
        printf("pcm: int without reason (%x)\n", c);
        c = 0;
    } else c &= ~served;
    io_wr(ad1816, AD1816_INT, c);
    c = io_rd(ad1816, AD1816_INT);
    if (c != 0) printf("pcm: int clear failed (%x)\n", c);
    ad1816_unlock(ad1816);
}
Esempio n. 10
0
/*
 * The interrupt handler
 */
static void
fm801_intr(void *p)
{
	struct fm801_info 	*fm801 = (struct fm801_info *)p;
	u_int32_t       	intsrc = fm801_rd(fm801, FM_INTSTATUS, 2);

	DPRINT("\nfm801_intr intsrc 0x%x ", intsrc);

	if(intsrc & FM_INTSTATUS_PLAY) {
		fm801->play_flip++;
		if(fm801->play_flip & 1) {
			fm801_wr(fm801, FM_PLAY_DMABUF1, fm801->play_start,4);
		} else
			fm801_wr(fm801, FM_PLAY_DMABUF2, fm801->play_nextblk,4);
		chn_intr(fm801->pch.channel);
	}

	if(intsrc & FM_INTSTATUS_REC) {
		fm801->rec_flip++;
		if(fm801->rec_flip & 1) {
			fm801_wr(fm801, FM_REC_DMABUF1, fm801->rec_start,4);
		} else
			fm801_wr(fm801, FM_REC_DMABUF2, fm801->rec_nextblk,4);
		chn_intr(fm801->rch.channel);
	}

	if ( intsrc & FM_INTSTATUS_MPU ) {
		/* This is a TODOish thing... */
		fm801_wr(fm801, FM_INTSTATUS, intsrc & FM_INTSTATUS_MPU,2);
	}

	if ( intsrc & FM_INTSTATUS_VOL ) {
		/* This is a TODOish thing... */
		fm801_wr(fm801, FM_INTSTATUS, intsrc & FM_INTSTATUS_VOL,2);
	}

	DPRINT("fm801_intr clear\n\n");
	fm801_wr(fm801, FM_INTSTATUS, intsrc & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC), 2);
}
Esempio n. 11
0
/* The interrupt handler */
static void
ds_intr(void *p)
{
	struct sc_info *sc = (struct sc_info *)p;
	u_int32_t i, x;

	snd_mtxlock(sc->lock);
	i = ds_rd(sc, YDSXGR_STATUS, 4);
	if (i & 0x00008000)
		device_printf(sc->dev, "timeout irq\n");
	if (i & 0x80008000) {
		ds_wr(sc, YDSXGR_STATUS, i & 0x80008000, 4);
		sc->currbank = ds_rd(sc, YDSXGR_CTRLSELECT, 4) & 0x00000001;

		x = 0;
		for (i = 0; i < DS1_CHANS; i++) {
			if (sc->pch[i].run) {
				x = 1;
				snd_mtxunlock(sc->lock);
				chn_intr(sc->pch[i].channel);
				snd_mtxlock(sc->lock);
			}
		}
		for (i = 0; i < 2; i++) {
			if (sc->rch[i].run) {
				x = 1;
				snd_mtxunlock(sc->lock);
				chn_intr(sc->rch[i].channel);
				snd_mtxlock(sc->lock);
			}
		}
		i = ds_rd(sc, YDSXGR_MODE, 4);
		if (x)
			ds_wr(sc, YDSXGR_MODE, i | 0x00000002, 4);

	}
	snd_mtxunlock(sc->lock);
}
Esempio n. 12
0
static void
cs4281_intr(void *p)
{
    struct sc_info *sc = (struct sc_info *)p;
    u_int32_t hisr;

    hisr = cs4281_rd(sc, CS4281PCI_HISR);

    if (hisr == 0) return;

    if (hisr & CS4281PCI_HISR_DMA(CS4281_DMA_PLAY)) {
	chn_intr(sc->pch.channel);
	cs4281_rd(sc, CS4281PCI_HDSR(CS4281_DMA_PLAY)); /* Clear interrupt */
    }

    if (hisr & CS4281PCI_HISR_DMA(CS4281_DMA_REC)) {
	chn_intr(sc->rch.channel);
	cs4281_rd(sc, CS4281PCI_HDSR(CS4281_DMA_REC)); /* Clear interrupt */
    }

    /* Signal End-of-Interrupt */
    cs4281_wr(sc, CS4281PCI_HICR, CS4281PCI_HICR_EOI);
}
Esempio n. 13
0
static void
via_intr(void *p)
{
	struct via_info *via = p;

	/* DEB(kprintf("viachan_intr\n")); */
	/* Read channel */
	snd_mtxlock(via->lock);
	if (via_rd(via, VIA_PLAY_STAT, 1) & VIA_RPSTAT_INTR) {
		via_wr(via, VIA_PLAY_STAT, VIA_RPSTAT_INTR, 1);
		snd_mtxunlock(via->lock);
		chn_intr(via->pch.channel);
		snd_mtxlock(via->lock);
	}

	/* Write channel */
	if (via_rd(via, VIA_RECORD_STAT, 1) & VIA_RPSTAT_INTR) {
		via_wr(via, VIA_RECORD_STAT, VIA_RPSTAT_INTR, 1);
		snd_mtxunlock(via->lock);
		chn_intr(via->rch.channel);
		return;
	}
	snd_mtxunlock(via->lock);
}