Пример #1
0
int
yds_halt_input(void *addr)
{
	struct yds_softc *sc = addr;

	DPRINTF(("yds: yds_halt_input\n"));
	mtx_enter(&audio_lock);
	if (sc->sc_rec.intr) {
		/* Stop the rec slot operation */
		YWRITE4(sc, YDS_MAPOF_REC, 0);
		sc->sc_rec.intr = 0;
		/* Sync rec slot control data */
		bus_dmamap_sync(sc->sc_dmatag, sc->sc_ctrldata.map,
				sc->rbankoff,
				sizeof(struct rec_slot_ctrl_bank)*
				    N_REC_SLOT_CTRL*N_REC_SLOT_CTRL_BANK,
				BUS_DMASYNC_POSTWRITE|BUS_DMASYNC_POSTREAD);
		/* Sync ring buffer */
		bus_dmamap_sync(sc->sc_dmatag, sc->sc_rec.dma->map,
				0, sc->sc_rec.length, BUS_DMASYNC_POSTREAD);
	}
	sc->sc_rec.intr = NULL;
	mtx_leave(&audio_lock);
	return 0;
}
Пример #2
0
int
yds_open(void *addr, int flags)
{
	struct yds_softc *sc = addr;
	int mode;

	/* Select bank 0. */
	YWRITE4(sc, YDS_CONTROL_SELECT, 0);

	/* Start the DSP operation. */
	mode = YREAD4(sc, YDS_MODE);
	mode |= YDS_MODE_ACTV;
	mode &= ~YDS_MODE_ACTV2;
	YWRITE4(sc, YDS_MODE, mode);

	return 0;
}
Пример #3
0
static int
yds_download_mcode(struct yds_softc *sc)
{
	static struct {
		const uint32_t *mcode;
		size_t size;
	} ctrls[] = {
		{yds_ds1_ctrl_mcode, sizeof(yds_ds1_ctrl_mcode)},
		{yds_ds1e_ctrl_mcode, sizeof(yds_ds1e_ctrl_mcode)},
	};
	u_int ctrl;
	const uint32_t *p;
	size_t size;
	int dstype;

	if (sc->sc_flags & YDS_CAP_MCODE_1)
		dstype = YDS_DS_1;
	else if (sc->sc_flags & YDS_CAP_MCODE_1E)
		dstype = YDS_DS_1E;
	else
		return 1;	/* unknown */

	if (yds_disable_dsp(sc))
		return 1;

	/* Software reset */
	YWRITE4(sc, YDS_MODE, YDS_MODE_RESET);
	YWRITE4(sc, YDS_MODE, 0);

	YWRITE4(sc, YDS_MAPOF_REC, 0);
	YWRITE4(sc, YDS_MAPOF_EFFECT, 0);
	YWRITE4(sc, YDS_PLAY_CTRLBASE, 0);
	YWRITE4(sc, YDS_REC_CTRLBASE, 0);
	YWRITE4(sc, YDS_EFFECT_CTRLBASE, 0);
	YWRITE4(sc, YDS_WORK_BASE, 0);

	ctrl = YREAD2(sc, YDS_GLOBAL_CONTROL);
	YWRITE2(sc, YDS_GLOBAL_CONTROL, ctrl & ~0x0007);

	/* Download DSP microcode. */
	p = yds_dsp_mcode;
	size = sizeof(yds_dsp_mcode);
	YWRITEREGION4(sc, YDS_DSP_INSTRAM, p, size);

	/* Download CONTROL microcode. */
	p = ctrls[dstype].mcode;
	size = ctrls[dstype].size;
	YWRITEREGION4(sc, YDS_CTRL_INSTRAM, p, size);

	yds_enable_dsp(sc);
	delay(10 * 1000);		/* nessesary on my 724F (??) */

	return 0;
}
Пример #4
0
static int
yds_disable_dsp(struct yds_softc *sc)
{
	int to;
	u_int32_t data;

	data = YREAD4(sc, YDS_CONFIG);
	if (data)
		YWRITE4(sc, YDS_CONFIG, YDS_DSP_DISABLE);

	for (to = 0; to < YDS_WORK_TIMEOUT; to++) {
		if ((YREAD4(sc, YDS_STATUS) & YDS_STAT_WORK) == 0)
			return 0;
		delay(1);
	}

	return 1;
}
Пример #5
0
static int
yds_halt(struct yds_softc *sc)
{
	u_int32_t mode;

	/* Stop the DSP operation. */
	mode = YREAD4(sc, YDS_MODE);
	YWRITE4(sc, YDS_MODE, mode & ~(YDS_MODE_ACTV|YDS_MODE_ACTV2));

	/* Paranoia...  mute all */
	YWRITE4(sc, YDS_P44_OUT_VOLUME, 0);
	YWRITE4(sc, YDS_DAC_OUT_VOLUME, 0);
	YWRITE4(sc, YDS_ADC_IN_VOLUME, 0);
	YWRITE4(sc, YDS_REC_IN_VOLUME, 0);
	YWRITE4(sc, YDS_DAC_REC_VOLUME, 0);
	YWRITE4(sc, YDS_P44_REC_VOLUME, 0);

	return 0;
}
Пример #6
0
int
yds_intr(void *p)
{
	struct yds_softc *sc = p;
	u_int status;

	mtx_enter(&audio_lock);
	status = YREAD4(sc, YDS_STATUS);
	DPRINTFN(1, ("yds_intr: status=%08x\n", status));
	if ((status & (YDS_STAT_INT|YDS_STAT_TINT)) == 0) {
#if 0
		if (sc->sc_mpu)
			return mpu_intr(sc->sc_mpu);
#endif
		mtx_leave(&audio_lock);
		return 0;
	}

	if (status & YDS_STAT_TINT) {
		YWRITE4(sc, YDS_STATUS, YDS_STAT_TINT);
		printf ("yds_intr: timeout!\n");
	}

	if (status & YDS_STAT_INT) {
		int nbank = (YREAD4(sc, YDS_CONTROL_SELECT) == 0);

		/* Clear interrupt flag */
		YWRITE4(sc, YDS_STATUS, YDS_STAT_INT);

		/* Buffer for the next frame is always ready. */
		YWRITE4(sc, YDS_MODE, YREAD4(sc, YDS_MODE) | YDS_MODE_ACTV2);

		if (sc->sc_play.intr) {
			u_int dma, cpu, blk, len;

			/* Sync play slot control data */
			bus_dmamap_sync(sc->sc_dmatag, sc->sc_ctrldata.map,
					sc->pbankoff,
					sizeof(struct play_slot_ctrl_bank)*
					    (*sc->ptbl)*
					    N_PLAY_SLOT_CTRL_BANK,
					BUS_DMASYNC_POSTWRITE|
					BUS_DMASYNC_POSTREAD);
			dma = sc->pbankp[nbank]->pgstart * sc->sc_play.factor;
			cpu = sc->sc_play.offset;
			blk = sc->sc_play.blksize;
			len = sc->sc_play.length;

			if (((dma > cpu) && (dma - cpu > blk * 2)) ||
			    ((cpu > dma) && (dma + len - cpu > blk * 2))) {
				/* We can fill the next block */
				/* Sync ring buffer for previous write */
				bus_dmamap_sync(sc->sc_dmatag,
						sc->sc_play.dma->map,
						cpu, blk,
						BUS_DMASYNC_POSTWRITE);
				sc->sc_play.intr(sc->sc_play.intr_arg);
				sc->sc_play.offset += blk;
				if (sc->sc_play.offset >= len) {
					sc->sc_play.offset -= len;
#ifdef DIAGNOSTIC
					if (sc->sc_play.offset != 0)
						printf ("Audio ringbuffer botch\n");
#endif
				}
				/* Sync ring buffer for next write */
				bus_dmamap_sync(sc->sc_dmatag,
						sc->sc_play.dma->map,
						cpu, blk,
						BUS_DMASYNC_PREWRITE);
			}
		}
		if (sc->sc_rec.intr) {
			u_int dma, cpu, blk, len;

			/* Sync rec slot control data */
			bus_dmamap_sync(sc->sc_dmatag, sc->sc_ctrldata.map,
					sc->rbankoff,
					sizeof(struct rec_slot_ctrl_bank)*
					    N_REC_SLOT_CTRL*
					    N_REC_SLOT_CTRL_BANK,
					BUS_DMASYNC_POSTWRITE|
					BUS_DMASYNC_POSTREAD);
			dma = sc->rbank[YDS_INPUT_SLOT*2 + nbank].pgstartadr;
			cpu = sc->sc_rec.offset;
			blk = sc->sc_rec.blksize;
			len = sc->sc_rec.length;

			if (((dma > cpu) && (dma - cpu > blk * 2)) ||
			    ((cpu > dma) && (dma + len - cpu > blk * 2))) {
				/* We can drain the current block */
				/* Sync ring buffer first */
				bus_dmamap_sync(sc->sc_dmatag,
						sc->sc_rec.dma->map,
						cpu, blk,
						BUS_DMASYNC_POSTREAD);
				sc->sc_rec.intr(sc->sc_rec.intr_arg);
				sc->sc_rec.offset += blk;
				if (sc->sc_rec.offset >= len) {
					sc->sc_rec.offset -= len;
#ifdef DIAGNOSTIC
					if (sc->sc_rec.offset != 0)
						printf ("Audio ringbuffer botch\n");
#endif
				}
				/* Sync ring buffer for next read */
				bus_dmamap_sync(sc->sc_dmatag,
						sc->sc_rec.dma->map,
						cpu, blk,
						BUS_DMASYNC_PREREAD);
			}
		}
	}
	mtx_leave(&audio_lock);
	return 1;
}
Пример #7
0
/*
 * This routine is called after all the ISA devices are configured,
 * to avoid conflict.
 */
static void
yds_configure_legacy(struct yds_softc *sc)
#define FLEXIBLE	(sc->sc_flags & YDS_CAP_LEGACY_FLEXIBLE)
#define SELECTABLE	(sc->sc_flags & YDS_CAP_LEGACY_SELECTABLE)
{
	pcireg_t reg;
	struct device *dev;
	int i;
	bus_addr_t opl_addrs[] = {0x388, 0x398, 0x3A0, 0x3A8};
	bus_addr_t mpu_addrs[] = {0x330, 0x300, 0x332, 0x334};

	if (!FLEXIBLE && !SELECTABLE)
		return;

	reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, YDS_PCI_LEGACY);
	reg &= ~0x8133c03f;	/* these bits are out of interest */
	reg |= (YDS_PCI_EX_LEGACY_IMOD | YDS_PCI_LEGACY_FMEN |
		YDS_PCI_LEGACY_MEN /*| YDS_PCI_LEGACY_MIEN*/);
	if (sc->sc_flags & YDS_CAP_LEGACY_SMOD_DISABLE)
		reg |= YDS_PCI_EX_LEGACY_SMOD_DISABLE;
	if (FLEXIBLE) {
		pci_conf_write(sc->sc_pc, sc->sc_pcitag, YDS_PCI_LEGACY, reg);
		delay(100*1000);
	}

	/* Look for OPL */
	dev = 0;
	for (i = 0; i < sizeof(opl_addrs) / sizeof (bus_addr_t); i++) {
		if (SELECTABLE) {
			pci_conf_write(sc->sc_pc, sc->sc_pcitag,
				       YDS_PCI_LEGACY, reg | (i << (0+16)));
			delay(100*1000);	/* wait 100ms */
		} else
			pci_conf_write(sc->sc_pc, sc->sc_pcitag,
				       YDS_PCI_FM_BA, opl_addrs[i]);
		if (bus_space_map(sc->sc_opl_iot,
				  opl_addrs[i], 4, 0, &sc->sc_opl_ioh) == 0) {
			struct audio_attach_args aa; 

			aa.type = AUDIODEV_TYPE_OPL;
			aa.hwif = aa.hdl = NULL;
			dev = config_found(&sc->sc_dev, &aa, audioprint);
			if (dev == 0)
				bus_space_unmap(sc->sc_opl_iot,
						sc->sc_opl_ioh, 4);
			else {
				if (SELECTABLE)
					reg |= (i << (0+16));
				break;
			}
		} 
	}
	if (dev == 0) {
		reg &= ~YDS_PCI_LEGACY_FMEN;
		pci_conf_write(sc->sc_pc, sc->sc_pcitag,
			       YDS_PCI_LEGACY, reg);
	} else {
		/* Max. volume */
		YWRITE4(sc, YDS_LEGACY_OUT_VOLUME, 0x3fff3fff);
		YWRITE4(sc, YDS_LEGACY_REC_VOLUME, 0x3fff3fff);
	}

	/* Look for MPU */
	dev = 0;
	for (i = 0; i < sizeof(mpu_addrs) / sizeof (bus_addr_t); i++) {
		if (SELECTABLE)
			pci_conf_write(sc->sc_pc, sc->sc_pcitag,
				       YDS_PCI_LEGACY, reg | (i << (4+16)));
		else
			pci_conf_write(sc->sc_pc, sc->sc_pcitag,
				       YDS_PCI_MPU_BA, mpu_addrs[i]);
		if (bus_space_map(sc->sc_mpu_iot,
				  mpu_addrs[i], 2, 0, &sc->sc_mpu_ioh) == 0) {
			struct audio_attach_args aa; 

			aa.type = AUDIODEV_TYPE_MPU;
			aa.hwif = aa.hdl = NULL;
			dev = config_found(&sc->sc_dev, &aa, audioprint);
			if (dev == 0)
				bus_space_unmap(sc->sc_mpu_iot,
						sc->sc_mpu_ioh, 2);
			else {
				if (SELECTABLE)
					reg |= (i << (4+16));
				break;
			}
		}
	}
	if (dev == 0) {
		reg &= ~(YDS_PCI_LEGACY_MEN | YDS_PCI_LEGACY_MIEN);
		pci_conf_write(sc->sc_pc, sc->sc_pcitag,
			       YDS_PCI_LEGACY, reg);
	}
	sc->sc_mpu = dev;
} 
Пример #8
0
static void
yds_enable_dsp(struct yds_softc *sc)
{
	YWRITE4(sc, YDS_CONFIG, YDS_DSP_SETUP);
}
Пример #9
0
static int
yds_allocate_slots(struct yds_softc *sc, int resuming)
{
	size_t pcs, rcs, ecs, ws, memsize;
	void *mp;
	u_int32_t da;		/* DMA address */
	char *va;		/* KVA */
	off_t cb;
	int i;
	struct yds_dma *p;

	/* Alloc DSP Control Data */
	pcs = YREAD4(sc, YDS_PLAY_CTRLSIZE) * sizeof(u_int32_t);
	rcs = YREAD4(sc, YDS_REC_CTRLSIZE) * sizeof(u_int32_t);
	ecs = YREAD4(sc, YDS_EFFECT_CTRLSIZE) * sizeof(u_int32_t);
	ws = WORK_SIZE;
	YWRITE4(sc, YDS_WORK_SIZE, ws / sizeof(u_int32_t));

	DPRINTF(("play control size : %d\n", (unsigned int)pcs));
	DPRINTF(("rec control size : %d\n", (unsigned int)rcs));
	DPRINTF(("eff control size : %d\n", (unsigned int)ecs));
	DPRINTF(("work size : %d\n", (unsigned int)ws));
#ifdef DIAGNOSTIC
	if (pcs != sizeof(struct play_slot_ctrl_bank)) {
		printf("%s: invalid play slot ctrldata %d != %d\n",
		       sc->sc_dev.dv_xname, (unsigned int)pcs,
		       (unsigned int)sizeof(struct play_slot_ctrl_bank));
	}
	if (rcs != sizeof(struct rec_slot_ctrl_bank)) {
		printf("%s: invalid rec slot ctrldata %d != %d\n",
		       sc->sc_dev.dv_xname, (unsigned int)rcs,
		       (unsigned int)sizeof(struct rec_slot_ctrl_bank));
        }
#endif

	memsize = N_PLAY_SLOTS*N_PLAY_SLOT_CTRL_BANK*pcs +
		  N_REC_SLOT_CTRL*N_REC_SLOT_CTRL_BANK*rcs + ws;
	memsize += (N_PLAY_SLOTS+1)*sizeof(u_int32_t);

	p = &sc->sc_ctrldata;
	if (!resuming) {
		i = yds_allocmem(sc, memsize, 16, p);
		if (i) {
			printf("%s: couldn't alloc/map DSP DMA buffer, reason %d\n",
			       sc->sc_dev.dv_xname, i);
			free(p, M_DEVBUF);
			return 1;
		}
	}
	mp = KERNADDR(p);
	da = DMAADDR(p);

	DPRINTF(("mp:%p, DMA addr:%p\n",
		 mp, (void *) sc->sc_ctrldata.map->dm_segs[0].ds_addr));

	bzero(mp, memsize);

	/* Work space */
        cb = 0;
	va = (u_int8_t*)mp;
	YWRITE4(sc, YDS_WORK_BASE, da + cb);
        cb += ws;

	/* Play control data table */
        sc->ptbl = (u_int32_t *)(va + cb);
	sc->ptbloff = cb;
        YWRITE4(sc, YDS_PLAY_CTRLBASE, da + cb);
        cb += (N_PLAY_SLOT_CTRL + 1) * sizeof(u_int32_t);

	/* Record slot control data */
        sc->rbank = (struct rec_slot_ctrl_bank *)(va + cb);
        YWRITE4(sc, YDS_REC_CTRLBASE, da + cb);
	sc->rbankoff = cb;
        cb += N_REC_SLOT_CTRL * N_REC_SLOT_CTRL_BANK * rcs;

#if 0
	/* Effect slot control data -- unused */
        YWRITE4(sc, YDS_EFFECT_CTRLBASE, da + cb);
        cb += N_EFFECT_SLOT_CTRL * N_EFFECT_SLOT_CTRL_BANK * ecs;
#endif

	/* Play slot control data */
        sc->pbankoff = da + cb;
        for (i=0; i<N_PLAY_SLOT_CTRL; i++) {
		sc->pbankp[i*2] = (struct play_slot_ctrl_bank *)(va + cb);
		*(sc->ptbl + i+1) = da + cb;
                cb += pcs;

                sc->pbankp[i*2+1] = (struct play_slot_ctrl_bank *)(va + cb);
                cb += pcs;
        }
	/* Sync play control data table */
	bus_dmamap_sync(sc->sc_dmatag, p->map,
			sc->ptbloff, (N_PLAY_SLOT_CTRL+1) * sizeof(u_int32_t),
			BUS_DMASYNC_PREWRITE);

	return 0;
}
Пример #10
0
static int
yds_download_mcode(struct yds_softc *sc)
{
	u_int ctrl;
	const u_int32_t *p;
	size_t size;
	u_char *buf;
	size_t buflen;
	int error;
	struct yds_firmware *yf;

	error = loadfirmware("yds", &buf, &buflen);
	if (error)
		return 1;
	yf = (struct yds_firmware *)buf;

	if (sc->sc_flags & YDS_CAP_MCODE_1) {
		p = (u_int32_t *)&yf->data[ntohl(yf->dsplen)];
		size = ntohl(yf->ds1len);
	} else if (sc->sc_flags & YDS_CAP_MCODE_1E) {
		p = (u_int32_t *)&yf->data[ntohl(yf->dsplen) + ntohl(yf->ds1len)];
		size = ntohl(yf->ds1elen);
	} else {
		free(buf, M_DEVBUF);
		return 1;	/* unknown */
	}

	if (size > buflen) {
		printf("%s: old firmware file, update please\n",
		    sc->sc_dev.dv_xname);
		free(buf, M_DEVBUF);
		return 1;
	}

	if (yds_disable_dsp(sc)) {
		free(buf, M_DEVBUF);
		return 1;
	}

	/* Software reset */
        YWRITE4(sc, YDS_MODE, YDS_MODE_RESET);
        YWRITE4(sc, YDS_MODE, 0);

        YWRITE4(sc, YDS_MAPOF_REC, 0);
        YWRITE4(sc, YDS_MAPOF_EFFECT, 0);
        YWRITE4(sc, YDS_PLAY_CTRLBASE, 0);
        YWRITE4(sc, YDS_REC_CTRLBASE, 0);
        YWRITE4(sc, YDS_EFFECT_CTRLBASE, 0);
        YWRITE4(sc, YDS_WORK_BASE, 0);

        ctrl = YREAD2(sc, YDS_GLOBAL_CONTROL);
        YWRITE2(sc, YDS_GLOBAL_CONTROL, ctrl & ~0x0007);

	/* Download DSP microcode. */
	nswaph((u_int32_t *)&yf->data[0], ntohl(yf->dsplen));
	YWRITEREGION4(sc, YDS_DSP_INSTRAM, (u_int32_t *)&yf->data[0],
	    ntohl(yf->dsplen));

	/* Download CONTROL microcode. */
	nswaph((u_int32_t *)p, size);
	YWRITEREGION4(sc, YDS_CTRL_INSTRAM, p, size);

	yds_enable_dsp(sc);
	delay(10*1000);		/* neccesary on my 724F (??) */

	free(buf, M_DEVBUF);
	return 0;
}
Пример #11
0
int
yds_trigger_input(void *addr, void *start, void *end, int blksize,
    void (*intr)(void *), void *arg, struct audio_params *param)
{
	struct yds_softc *sc = addr;
	struct yds_dma *p;
	u_int srate, format;
	struct rec_slot_ctrl_bank *rsb;
	bus_addr_t s;
	size_t l;

	mtx_enter(&audio_lock);
#ifdef DIAGNOSTIC
	if (sc->sc_rec.intr)
		panic("yds_trigger_input: already running");
#endif
	sc->sc_rec.intr = intr;
	sc->sc_rec.intr_arg = arg;
	sc->sc_rec.offset = 0;
	sc->sc_rec.blksize = blksize;

	DPRINTFN(1, ("yds_trigger_input: "
	    "sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n", 
	    addr, start, end, blksize, intr, arg));
	DPRINTFN(1, (" parameters: rate=%lu, precision=%u, channels=%u\n",
	    param->sample_rate, param->precision, param->channels));

	p = yds_find_dma(sc, start);
	if (!p) {
		printf("yds_trigger_input: bad addr %p\n", start);
		mtx_leave(&audio_lock);
		return (EINVAL);
	}
	sc->sc_rec.dma = p;

	s = DMAADDR(p);
	l = ((char *)end - (char *)start);
	sc->sc_rec.length = l;

	sc->sc_rec.factor = 1;
	if (param->channels == 2)
		sc->sc_rec.factor *= 2;
	if (param->precision != 8)
		sc->sc_rec.factor *= 2;

	rsb = &sc->rbank[0];
	memset(rsb, 0, sizeof(*rsb));
	rsb->pgbase = s;
	rsb->pgloopendadr = l;
	/* Seems all 4 banks must be set up... */
	sc->rbank[1] = *rsb;
	sc->rbank[2] = *rsb;
	sc->rbank[3] = *rsb;

	YWRITE4(sc, YDS_ADC_IN_VOLUME, 0x3fff3fff);
	YWRITE4(sc, YDS_REC_IN_VOLUME, 0x3fff3fff);
	srate = 48000 * 4096 / param->sample_rate - 1;
	format = ((param->precision == 8 ? YDS_FORMAT_8BIT : 0) |
		  (param->channels == 2 ? YDS_FORMAT_STEREO : 0));
	DPRINTF(("srate=%d, format=%08x\n", srate, format));
#ifdef YDS_USE_REC_SLOT
	YWRITE4(sc, YDS_DAC_REC_VOLUME, 0x3fff3fff);
	YWRITE4(sc, YDS_P44_REC_VOLUME, 0x3fff3fff);
	YWRITE4(sc, YDS_MAPOF_REC, YDS_RECSLOT_VALID);
	YWRITE4(sc, YDS_REC_SAMPLE_RATE, srate);
	YWRITE4(sc, YDS_REC_FORMAT, format);
#else
	YWRITE4(sc, YDS_MAPOF_REC, YDS_ADCSLOT_VALID);
	YWRITE4(sc, YDS_ADC_SAMPLE_RATE, srate);
	YWRITE4(sc, YDS_ADC_FORMAT, format);
#endif
	/* Now the rec slot for the next frame is set up!! */
	/* Sync record slot control data */
	bus_dmamap_sync(sc->sc_dmatag, sc->sc_ctrldata.map,
			sc->rbankoff,
			sizeof(struct rec_slot_ctrl_bank)*
			    N_REC_SLOT_CTRL*
			    N_REC_SLOT_CTRL_BANK,
			BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
	/* Sync ring buffer */
	bus_dmamap_sync(sc->sc_dmatag, p->map, 0, blksize,
			BUS_DMASYNC_PREREAD);
	/* HERE WE GO!! */
	YWRITE4(sc, YDS_MODE,
		YREAD4(sc, YDS_MODE) | YDS_MODE_ACTV | YDS_MODE_ACTV2);
	mtx_leave(&audio_lock);
	return 0;
}
Пример #12
0
int
yds_trigger_output(void *addr, void *start, void *end, int blksize,
    void (*intr)(void *), void *arg, struct audio_params *param)
#define P44		(sc->sc_flags & YDS_CAP_HAS_P44)
{
	struct yds_softc *sc = addr;
	struct yds_dma *p;
	struct play_slot_ctrl_bank *psb;
	const u_int gain = 0x40000000;
	bus_addr_t s;
	size_t l;
	int i;
	int p44, channels;

	mtx_enter(&audio_lock);
#ifdef DIAGNOSTIC
	if (sc->sc_play.intr)
		panic("yds_trigger_output: already running");
#endif
	sc->sc_play.intr = intr;
	sc->sc_play.intr_arg = arg;
	sc->sc_play.offset = 0;
	sc->sc_play.blksize = blksize;

	DPRINTFN(1, ("yds_trigger_output: sc=%p start=%p end=%p "
	    "blksize=%d intr=%p(%p)\n", addr, start, end, blksize, intr, arg));

	p = yds_find_dma(sc, start);
	if (!p) {
		printf("yds_trigger_output: bad addr %p\n", start);
		mtx_leave(&audio_lock);
		return (EINVAL);
	}
	sc->sc_play.dma = p;

#ifdef DIAGNOSTIC
	{
		u_int32_t ctrlsize;
		if ((ctrlsize = YREAD4(sc, YDS_PLAY_CTRLSIZE)) !=
		    sizeof(struct play_slot_ctrl_bank) / sizeof(u_int32_t))
			panic("%s: invalid play slot ctrldata %d %d",
			      sc->sc_dev.dv_xname, ctrlsize,
			      sizeof(struct play_slot_ctrl_bank));
	}
#endif

#ifdef YDS_USE_P44
	/* The document says the P44 SRC supports only stereo, 16bit PCM. */
	if (P44)
		p44 = ((param->sample_rate == 44100) &&
		       (param->channels == 2) &&
		       (param->precision == 16));
	else
#endif
		p44 = 0;
	channels = p44 ? 1 : param->channels;

	s = DMAADDR(p);
	l = ((char *)end - (char *)start);
	sc->sc_play.length = l;

	*sc->ptbl = channels;	/* Num of play */

	sc->sc_play.factor = 1;
	if (param->channels == 2)
		sc->sc_play.factor *= 2;
	if (param->precision != 8)
		sc->sc_play.factor *= 2;
	l /= sc->sc_play.factor;

	psb = sc->pbankp[0];
	memset(psb, 0, sizeof(*psb));
	psb->format = ((channels == 2 ? PSLT_FORMAT_STEREO : 0) |
		       (param->precision == 8 ? PSLT_FORMAT_8BIT : 0) |
		       (p44 ? PSLT_FORMAT_SRC441 : 0));
	psb->pgbase = s;
	psb->pgloopend = l;
	if (!p44) {
		psb->pgdeltaend = (param->sample_rate * 65536 / 48000) << 12;
		psb->lpfkend = yds_get_lpfk(param->sample_rate);
		psb->eggainend = gain;
		psb->lpfq = yds_get_lpfq(param->sample_rate);
		psb->pgdelta = psb->pgdeltaend;
		psb->lpfk = yds_get_lpfk(param->sample_rate);
		psb->eggain = gain;
	}

	for (i = 0; i < channels; i++) {
		/* i == 0: left or mono, i == 1: right */
		psb = sc->pbankp[i*2];
		if (i)
			/* copy from left */
			*psb = *(sc->pbankp[0]);
		if (channels == 2) {
			/* stereo */
			if (i == 0) {
				psb->lchgain = psb->lchgainend = gain;
			} else {
				psb->lchgain = psb->lchgainend = 0;
				psb->rchgain = psb->rchgainend = gain;
				psb->format |= PSLT_FORMAT_RCH;
			}
		} else if (!p44) {
			/* mono */
			psb->lchgain = psb->rchgain = gain;
			psb->lchgainend = psb->rchgainend = gain;
		}
		/* copy to the other bank */
		*(sc->pbankp[i*2+1]) = *psb;
	}

	YDS_DUMP_PLAY_SLOT(5, sc, 0);
	YDS_DUMP_PLAY_SLOT(5, sc, 1);

	if (p44)
		YWRITE4(sc, YDS_P44_OUT_VOLUME, 0x3fff3fff);
	else
		YWRITE4(sc, YDS_DAC_OUT_VOLUME, 0x3fff3fff);

	/* Now the play slot for the next frame is set up!! */
	/* Sync play slot control data for both directions */
	bus_dmamap_sync(sc->sc_dmatag, sc->sc_ctrldata.map,
			sc->ptbloff,
			sizeof(struct play_slot_ctrl_bank) *
			    channels * N_PLAY_SLOT_CTRL_BANK,
			BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
	/* Sync ring buffer */
	bus_dmamap_sync(sc->sc_dmatag, p->map, 0, blksize,
			BUS_DMASYNC_PREWRITE);
	/* HERE WE GO!! */
	YWRITE4(sc, YDS_MODE,
		YREAD4(sc, YDS_MODE) | YDS_MODE_ACTV | YDS_MODE_ACTV2);
	mtx_leave(&audio_lock);
	return 0;
}