Subject: Re: Aureal sound cards support
To: None <current-users@netbsd.org>
From: Pierre Pronchery <khorben@defora.org>
List: current-users
Date: 06/08/2007 02:41:11
This is a multi-part message in MIME format.
--------------070805080502010805040908
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

Jared D. McNeill wrote:
> On 6-Jun-07, at 11:14 AM, Pierre Pronchery wrote:
>> first here are the PCI device IDs for two (quite old) sound cards from
>> Aureal.
>>
>> Apparently there is no driver for them. About the process of porting one:
>> - which existing driver would be the most appropriate to start from?
>> (Linux OSS or ALSA, other BSD...)
> 
> FreeBSD apparently has a driver:
> 
>   http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/dev/sound/pci/ -- see
> au88x0.[ch].
> 
> NetBSD does not currently support any Aureal hardware.

I got this far:
vortex0 at pci0 dev 12 function 0: Aureal Semiconductor AU8830 Vortex 3D
Digital Audio Processor (audio multimedia, revision 0xfe)
vortex0: interrupting at irq 11
vortex0: ac97: SigmaTel STAC9704 codec; 18 bit DAC, 18 bit ADC, SigmaTel 3D
vortex0: ac97: ext id
ffff<SECONDARY10,SECONDARY01,AC97_23,AC97_22,AMAP,LDAC,SDAC,CDAC,VRM,SPDIF,DRA,VRA>
vortex0: ac97: Slot assignment: 10&11, 3&4, 7&8.
vortex0: Ignore these capabilities.

I get a working mixer, I attached the output of "mixerctl -av" here.

Sound playback still triggers an uvm_fault() though (invalid address 0
in the process accessing the card). Since I am not sure of what I am
doing, I attach the current version of my sources here as well. Please
let me know if you see anything that might help the inclusion of this
driver in -current.

Cheers,
-- 
khorben

--------------070805080502010805040908
Content-Type: text/plain;
 name="mixer.txt"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="mixer.txt"

outputs.master=127,127 volume delta=8
outputs.master.mute=off  [ off on ]
outputs.mono=255 volume delta=8
outputs.mono.mute=off  [ off on ]
outputs.mono.source=mixerout  [ mixerout mic ]
inputs.speaker=255 volume delta=16
inputs.speaker.mute=off  [ off on ]
inputs.phone=191 volume delta=8
inputs.phone.mute=on  [ off on ]
inputs.mic=191 volume delta=8
inputs.mic.mute=on  [ off on ]
inputs.mic.preamp=off  [ off on ]
inputs.mic.source=mic0  [ mic0 mic1 ]
inputs.line=191,191 volume delta=8
inputs.line.mute=off  [ off on ]
inputs.cd=191,191 volume delta=8
inputs.cd.mute=off  [ off on ]
inputs.video=191,191 volume delta=8
inputs.video.mute=off  [ off on ]
inputs.aux=191,191 volume delta=8
inputs.aux.mute=off  [ off on ]
inputs.dac=191,191 volume delta=8
inputs.dac.mute=off  [ off on ]
record.source=mic  [ mic cd video aux line mixerout mixeroutmono phone ]
record.volume=0,0 volume delta=16
record.volume.mute=off  [ off on ]
outputs.spatial=off  [ off on ]
outputs.spatial.center=0 volume delta=16
outputs.spatial.depth=0 volume delta=16

--------------070805080502010805040908
Content-Type: text/plain;
 name="vortex.c"
Content-Transfer-Encoding: 8bit
Content-Disposition: inline;
 filename="vortex.c"

/*	$NetBSD$	*/
/*	$FreeBSD: /repoman/r/ncvs/src/sys/dev/sound/pci/au88x0.c,v 1.12 2007/04/18 18:26:39 ariff Exp $	*/

/*
 * Writing:	Dag-Erling Coïdan Smørgrav
 * Porting:	Pierre Pronchery		<khorben@defora.org>
 */

/*
 * Aureal Vortex cards
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD$");

#include <sys/param.h>
#include <sys/device.h>
#include <sys/audioio.h>
#include <sys/select.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>
#include <dev/audio_if.h>
#include <dev/audiovar.h>
#include <dev/auconv.h>
#include <dev/ic/ac97reg.h>
#include <dev/ic/ac97var.h>
#include <dev/pci/vortexreg.h>
#include <dev/pci/vortexvar.h>

#define PCI_CBIO 0x10

static struct vortex_chipset vortex_chipsets[] = {
	{
		.voc_audev			= {"Vortex","","vortex"},
		.voc_pa_id			= PCI_PRODUCT_AUREAL_AU8820,

		.voc_control			= 0x1280c,

		.voc_irq_source			= 0x12800,
		.voc_irq_mask			= 0x12804,
		.voc_irq_control		= 0x12808,
		.voc_irq_status			= 0x1199c,

		.voc_dma_control		= 0x1060c,

		.voc_fifo_size			= 0x20,
		.voc_wt_fifos			= 32,
		.voc_wt_fifo_base		= 0x0e800,
		.voc_wt_fifo_ctl		= 0x0f800,
		.voc_wt_dma_ctl			= 0x10500,
		.voc_adb_fifos			= 16,
		.voc_adb_fifo_base		= 0x0e000,
		.voc_adb_fifo_ctl		= 0x0f840,
		.voc_adb_dma_ctl		= 0x10580,

		.voc_adb_route_base		= 0x10800,
		.voc_adb_route_bits		= 7,
		.voc_adb_codec_in		= 0x48,
		.voc_adb_codec_out		= 0x58
	},
	{
		.voc_audev			= {"Vortex 3D","","vortex"},
		.voc_pa_id			= PCI_PRODUCT_AUREAL_AU8830,

		.voc_control			= 0x2a00c,

		.voc_irq_source			= 0x2a000,
		.voc_irq_mask			= 0x2a004,
		.voc_irq_control		= 0x2a008,
		.voc_irq_status			= 0x2919c,

		.voc_dma_control		= 0x27ae8,

		.voc_fifo_size			= 0x40,
		.voc_wt_fifos			= 64,
		.voc_wt_fifo_base		= 0x10000,
		.voc_wt_fifo_ctl		= 0x16000,
		.voc_wt_dma_ctl			= 0x27900,
		.voc_adb_fifos			= 32,
		.voc_adb_fifo_base		= 0x14000,
		.voc_adb_fifo_ctl		= 0x16100,
		.voc_adb_dma_ctl		= 0x27a00,

		.voc_adb_route_base		= 0x28000,
		.voc_adb_route_bits		= 8,
		.voc_adb_codec_in		= 0x70,
		.voc_adb_codec_out		= 0x88
	},
	{
		.voc_audev			= {"Vortex","","vortex"},
		.voc_pa_id			= PCI_PRODUCT_AUREAL_AU8810,

		.voc_control			= 0x2a00c,

		.voc_irq_source			= 0x2a000,
		.voc_irq_mask			= 0x2a004,
		.voc_irq_control		= 0x2a008,
		.voc_irq_status			= 0x2919c,

		.voc_dma_control		= 0x27ae8,

		.voc_fifo_size			= 0x20,
		.voc_wt_fifos			= 32,
		.voc_wt_fifo_base		= 0x10000,
		.voc_wt_fifo_ctl		= 0x16000,
		.voc_wt_dma_ctl			= 0x27fd8,
		.voc_adb_fifos			= 16,
		.voc_adb_fifo_base		= 0x14000,
		.voc_adb_fifo_ctl		= 0x16100,
		.voc_adb_dma_ctl		= 0x27180,

		.voc_adb_route_base		= 0x28000,
		.voc_adb_route_bits		= 8,
		.voc_adb_codec_in		= 0x70,
		.voc_adb_codec_out		= 0x88
	},
	{
		.voc_pa_id			= 0
	}
};

/* autoconf */
static int	vortex_match(struct device *, struct cfdata *, void *);
static void	vortex_attach(struct device *, struct device *, void *);
static int	vortex_detach(struct device *, int);

/* init & shutdown */
static void	vortex_init(struct vortex_softc *);

/* interrupt handler */
static int	vortex_intr(void *);

/* ac97 interface callbacks */
static int	vortex_ac97_attach(void *, struct ac97_codec_if *);
static int	vortex_ac97_read(void *, uint8_t, uint16_t *);
static int	vortex_ac97_write(void *, uint8_t, uint16_t);


/* autoconfig */
CFATTACH_DECL(vortex, sizeof(struct vortex_softc),
	vortex_match, vortex_attach, vortex_detach, NULL);

static int	vortex_query_encoding(void *, struct audio_encoding *);
static int	vortex_set_params(void *, int, int, audio_params_t *,
		audio_params_t *, stream_filter_list_t *,
		stream_filter_list_t *);
static int	vortex_getdev(void *, struct audio_device *);
static int	vortex_set_port(void *, mixer_ctrl_t *);
static int	vortex_get_port(void *, mixer_ctrl_t *);
static int	vortex_query_devinfo(void *, mixer_devinfo_t *);
static int	vortex_get_props(void *);

static const struct audio_hw_if vortex_hw_if = {
	NULL,			/* open */
	NULL,			/* close */
	NULL,			/* drain */
	vortex_query_encoding,
	vortex_set_params,
	NULL,			/* round_blocksize */
	NULL,			/* commit_settings */
	NULL,			/* init_output */
	NULL,			/* init_input */
	NULL,			/* start_output */
	NULL,			/* start_input */
	NULL,			/* halt_output */
	NULL,			/* halt_input */
	NULL,			/* speaker_ctl */
	vortex_getdev,
	NULL,			/* setfd */
	vortex_set_port,
	vortex_get_port,
	vortex_query_devinfo,
	NULL,			/* allocm */
	NULL,			/* freem */
	NULL,			/* round_buffersize */
	NULL,			/* mappage */
	vortex_get_props,
	NULL,			/* trigger_output */
	NULL,			/* trigger_input */
	NULL,			/* dev_ioctl */
	NULL,			/* powerstate */
};

#define VORTEX_NFORMATS	4
static const struct audio_format vortex_formats[VORTEX_NFORMATS] = {
	{NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
		2, AUFMT_STEREO, 0, {4000, 48000}},
	{NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
		1, AUFMT_MONAURAL, 0, {4000, 48000}},
	{NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 8, 8,
		2, AUFMT_STEREO, 0, {4000, 48000}},
	{NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 8, 8,
		1, AUFMT_MONAURAL, 0, {4000, 48000}},
};

#define vortex_read(sc, reg, n) \
	bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg);
#define vortex_write(sc, reg, data, n) \
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, data)

/*
 * autoconf device callbacks: attach and detach
 */

static void
vortex_pci_shutdown(struct vortex_softc *sc)
{
	if (sc->sc_ih != NULL)
		pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
	if (sc->sc_ios)
		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
}

static int
vortex_match(struct device *parent, struct cfdata *match,
		void *aux)
{
	struct pci_attach_args *pa;

	pa = aux;
	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_AUREAL)
		return 0;

	switch (PCI_PRODUCT(pa->pa_id)) {
		case PCI_PRODUCT_AUREAL_AU8810:
		case PCI_PRODUCT_AUREAL_AU8820:
		case PCI_PRODUCT_AUREAL_AU8830:
			return 1;
		default:
			return 0;
	}
}

static void
vortex_attach(struct device *parent, struct device *self, void *aux)
{
	struct vortex_softc *sc;
	struct pci_attach_args *pa;
	pcireg_t v;
	struct vortex_chipset *voc;
	char devinfo[256];
	pci_intr_handle_t ih;
	const char *intrstr;

	sc = (struct vortex_softc *)self;
	pa = aux;
	aprint_naive(": Audio controller\n");

	/* model-specific parameters */
	v = PCI_PRODUCT(pa->pa_id);
	for (voc = vortex_chipsets; voc->voc_pa_id; ++voc)
		if (voc->voc_pa_id == v) {
			sc->sc_voc = voc;
			break;
		}
#ifdef DIAGNOSTIC
	if (voc->voc_pa_id == 0)
	{
		aprint_error(": unknown variant");
		return;
	}
#endif

	/* enable the device */
	v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
			v | PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE
			| PCI_COMMAND_MASTER_ENABLE);

	/* map i/o register */
	v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
	if (v & PCI_COMMAND_MEM_ENABLE) {
		if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_MEM, 0,
					&(sc->sc_iot), &(sc->sc_ioh),
					&(sc->sc_iob), &(sc->sc_ios))) {
			aprint_error("%s: couldn't map i/o space\n",
					sc->sc_dev.dv_xname);
			return;
		}
	}
	pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo));
	aprint_normal(": %s\n", devinfo);

	/* initialize softc */
	sc->sc_pc = pa->pa_pc;
	sc->sc_dmat = pa->pa_dmat;

	/* map and establish the interrupt */
	if (pci_intr_map(pa, &ih)) {
		aprint_error("%s: couldn't map interrupt\n",
				sc->sc_dev.dv_xname);
		return;
	}
	intrstr = pci_intr_string(pa->pa_pc, ih);
	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, vortex_intr,
			sc);
	if (sc->sc_ih == NULL) {
		aprint_error("%s: couldn't establish interrupt\n",
				sc->sc_dev.dv_xname);
		if (intrstr != NULL)
			aprint_normal(" at %s", intrstr);
		aprint_normal("\n");
		return;
	}
	aprint_normal("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);

	/* FIXME DMA mapping, is it already done? */

	/* initialize the hardware */
	vortex_init(sc);

	/* initialize the ac97 codec and mixer */
	sc->host_if.arg = sc;
	sc->host_if.attach = vortex_ac97_attach;
	sc->host_if.read = vortex_ac97_read;
	sc->host_if.write = vortex_ac97_write;
	sc->host_if.reset = NULL;
	sc->host_if.flags = NULL;
	if (ac97_attach(&sc->host_if, self)) {
		vortex_pci_shutdown(sc);
		return;
	}

	/* attach audio */
	if ((sc->sc_audev = audio_attach_mi(&vortex_hw_if, sc, self)) == NULL) {
		vortex_pci_shutdown(sc);
		return;
	}
}

static int
vortex_detach(struct device *self, int flags)
{
	struct vortex_softc *sc;
	int res;

	sc = (struct vortex_softc *)self;
	if (sc->sc_audev != NULL) { /* Test in case audio didn't attach */
		res = config_detach(sc->sc_audev, 0);
		if (res)
			return res;
	}

	vortex_pci_shutdown(sc);

	return 0;
}

static int
vortex_intr(void *p)
{
	struct vortex_softc *sc;
	struct vortex_chipset *voc;
	int pending, source;

	sc = p;
	voc = sc->sc_voc;
	pending = vortex_read(sc, voc->voc_irq_control, 4);
	if ((pending & VORTEX_IRQ_PENDING_BIT) == 0)
		return 0;
	source = vortex_read(sc, voc->voc_irq_source, 4);
	if (source & VORTEX_IRQ_FATAL_ERR)
		aprint_error("%s: fatal error interrupt received\n",
				sc->sc_dev.dv_xname);
	if (source & VORTEX_IRQ_PARITY_ERR)
		aprint_error("%s: parity error interrupt received\n",
				sc->sc_dev.dv_xname);
	/* XXX handle the others... */

	/* acknowledge the interrupts we just handled */
	vortex_write(sc, voc->voc_irq_source, source, 4);
	vortex_read(sc, voc->voc_irq_source, 4);
	return 1;
}


/* init and shutdown */
static void
vortex_codec_init(struct vortex_softc *sc)
{
	uint32_t data;
	int i;

	/* wave that chicken */
	vortex_write(sc, VORTEX_CODEC_CONTROL, 0x8068, 4);
	DELAY(VORTEX_SETTLE_DELAY);
	vortex_write(sc, VORTEX_CODEC_CONTROL, 0x00e8, 4);
	DELAY(1000);
	for (i = 0; i < 32; ++i) {
		vortex_write(sc, VORTEX_CODEC_CHANNEL + i * 4, 0, 4);
		DELAY(VORTEX_SETTLE_DELAY);
	}
	vortex_write(sc, VORTEX_CODEC_CONTROL, 0x00e8, 4);
	DELAY(VORTEX_SETTLE_DELAY);

	/* enable both codec channels */
	data = vortex_read(sc, VORTEX_CODEC_ENABLE, 4);
	data |= (1 << (8 + 0)) | (1 << (8 + 1));
	vortex_write(sc, VORTEX_CODEC_ENABLE, data, 4);
	DELAY(VORTEX_SETTLE_DELAY);
}

static void
vortex_fifo_init(struct vortex_softc *sc)
{
	struct vortex_chipset *voc = sc->sc_voc;
	int i;

	/* reset, then clear the ADB FIFOs */
	for (i = 0; i < voc->voc_adb_fifos; ++i)
		vortex_write(sc, voc->voc_adb_fifo_ctl + i * 4, 0x42000, 4);
	/* XXX could it be optimized? */
	for (i = 0; i < voc->voc_adb_fifos * voc->voc_fifo_size; ++i)
		vortex_write(sc, voc->voc_adb_fifo_base + i * 4, 0, 4);

	/* reset, then clear the WT FIFOs */
	for (i = 0; i < voc->voc_wt_fifos; ++i)
		vortex_write(sc, voc->voc_wt_fifo_ctl + i * 4, 0x42000, 4);
	for (i = 0; i < voc->voc_wt_fifos * voc->voc_fifo_size; ++i)
		vortex_write(sc, voc->voc_wt_fifo_base + i * 4, 0, 4);
}

static void
vortex_init(struct vortex_softc *sc)
{
	struct vortex_chipset *voc = sc->sc_voc;

	/* reset the chip */
	vortex_write(sc, voc->voc_control, 0xffffffff, 4);
	DELAY(10000);

	/* clear all interrupts */
	vortex_write(sc, voc->voc_irq_source, 0xffffffff, 4);
	vortex_read(sc, voc->voc_irq_source, 4);
	vortex_read(sc, voc->voc_irq_status, 4);

	/* initialize the codec */
	vortex_codec_init(sc);

	/* initialize the fifos */
	vortex_fifo_init(sc);

	/* initialize the DMA engine */
	/* XXX chicken-waving! ...?!? */
	vortex_write(sc, voc->voc_dma_control, 0x1380000, 4);
}

static int
vortex_ac97_attach(void *arg, struct ac97_codec_if *codec_if)
{
	struct vortex_softc *sc;

	sc = arg;
	sc->codec_if = codec_if;
	return 0;
}

static int
vortex_ac97_wait(struct vortex_softc *sc)
{
	uint32_t data;
	int i;

	for (i = 0; i < VORTEX_RETRY_COUNT; ++i) {
		data = vortex_read(sc, VORTEX_CODEC_CONTROL, 4);
		if (data & VORTEX_CDCTL_WROK)
			return (0);
		DELAY(VORTEX_SETTLE_DELAY);
	}
	aprint_error("%s: timeout while waiting for codec\n",
			sc->sc_dev.dv_xname);

	return -1;
}

static int
vortex_ac97_read(void *arg, uint8_t reg, uint16_t * val)
{
	struct vortex_softc * sc;
	uint32_t data;
	int s;

	sc = arg;
	s = splaudio();
	vortex_ac97_wait(sc);
	vortex_write(sc, VORTEX_CODEC_IO, VORTEX_CDIO_READ(reg), 4);
	DELAY(1000);
	data = vortex_read(sc, VORTEX_CODEC_IO, 4);
	splx(s);
	*val = (data & VORTEX_CDIO_DATA_MASK) >> VORTEX_CDIO_DATA_SHIFT;

	return 0;
}

static int
vortex_ac97_write(void *arg, uint8_t reg, uint16_t val)
{
	struct vortex_softc * sc;
	int s;

	sc = arg;
	s = splaudio();
	vortex_ac97_wait(sc);
	vortex_write(sc, VORTEX_CODEC_IO, VORTEX_CDIO_WRITE(reg, val), 4);
	splx(s);

	return 0;
}

static int
vortex_getdev(void *addr, struct audio_device *dev)
{
	struct vortex_softc *sc;

	sc = addr;
	*dev = sc->sc_voc->voc_audev;
	return 0;
}

static int
vortex_set_port(void *addr, mixer_ctrl_t *mctl)
{
	struct vortex_softc * sc;

	sc = addr;
	return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, mctl);
}

static int
vortex_get_port(void *addr, mixer_ctrl_t *mctl)
{
	struct vortex_softc * sc;

	sc = addr;
	return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, mctl);
}

static int
vortex_query_devinfo(void *hdl, mixer_devinfo_t *di)
{
	struct vortex_softc * sc;

	sc = hdl;
	return sc->codec_if->vtbl->query_devinfo(sc->codec_if, di);
}

static int
vortex_get_props(void * addr)
{
	return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
		AUDIO_PROP_FULLDUPLEX;
}

static int
vortex_query_encoding(void *addr, struct audio_encoding *fp)
{
	struct vortex_softp *sc;

	sc = addr;
	switch (fp->index) {
		case 0:
			strcpy(fp->name, AudioEulinear);
			fp->encoding = AUDIO_ENCODING_ULINEAR;
			fp->precision = 8;
			fp->flags = 0;
			break;
		case 1:
			strcpy(fp->name, AudioEmulaw);
			fp->encoding = AUDIO_ENCODING_ULAW;
			fp->precision = 8;
			fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
			break;
		case 2:
			strcpy(fp->name, AudioEalaw);
			fp->encoding = AUDIO_ENCODING_ALAW;
			fp->precision = 8;
			fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
			break;
		case 3:
			strcpy(fp->name, AudioEslinear);
			fp->encoding = AUDIO_ENCODING_SLINEAR;
			fp->precision = 8;
			fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
			break;
		case 4:
			strcpy(fp->name, AudioEslinear_le);
			fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
			fp->precision = 16;
			fp->flags = 0;
			break;
		case 5:
			strcpy(fp->name, AudioEulinear_le);
			fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
			fp->precision = 16;
			fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
			break;
		case 6:
			strcpy(fp->name, AudioEslinear_be);
			fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
			fp->precision = 16;
			fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
			break;
		case 7:
			strcpy(fp->name, AudioEulinear_be);
			fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
			fp->precision = 16;
			fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
			break;
		default:
			return EINVAL;
	}
	return 0;
}

static int
vortex_set_params(void *addr, int setmode, int usemode,
		audio_params_t *play, audio_params_t *rec,
		stream_filter_list_t *pfil, stream_filter_list_t *rfil)
{
	struct vortex_softc *sc;
	struct audio_params *p;
	stream_filter_list_t *fil;
	int mode;
	int index;

	sc = addr;
	for (mode = AUMODE_RECORD; mode != -1;
			mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
		if ((setmode & mode) == 0)
			continue;

		if (mode == AUMODE_PLAY) {
			p = play;
			fil = pfil;
		} else {
			p = rec;
			fil = rfil;
		}

		if (p->sample_rate < 4000 || p->sample_rate > 48000 ||
				(p->precision != 8 && p->precision != 16))
			return EINVAL;
		index = auconv_set_converter(vortex_formats, VORTEX_NFORMATS,
				mode, p, FALSE, fil);
		if (index < 0)
			return EINVAL;
	}

	/* set speed */
	/* XXX */

	return 0;
}

--------------070805080502010805040908
Content-Type: text/plain;
 name="vortexreg.h"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="vortexreg.h"

/*	$NetBSD$	*/

#ifndef _DEV_PCI_VORTEXREG_H_
#define _DEV_PCI_VORTEXREG_H_

/*
 * Common parameters
 */
#define VORTEX_SETTLE_DELAY	1000
#define VORTEX_RETRY_COUNT	10
#define VORTEX_BUFSIZE_MIN	0x1000
#define VORTEX_BUFSIZE_DFLT	0x4000
#define VORTEX_BUFSIZE_MAX	0x4000

/*
 * Codec control registers
 *
 * VORTEX_CODEC_CHANNEL array of 32 32-bits words
 *
 * VORTEX_CODEC_CONTROL control register
 *
 * 	bit	16	ready
 *
 * VORTEX_CODEC_IO	I/O register
 *
 * 	bits  0-15	contents of codec register
 * 	bits 16-22	address of codec register
 * 	bit	23	0 for read, 1 for write
 */
#define VORTEX_CODEC_CHANNEL	0x29080
#define VORTEX_CODEC_CONTROL	0x29184
#define VORTEX_CDCTL_WROK	0x00000100
#define VORTEX_CODEC_IO		0x29188
#define VORTEX_CDIO_DATA_SHIFT	0
#define VORTEX_CDIO_DATA_MASK	0x0000ffff
#define VORTEX_CDIO_ADDR_SHIFT	16
#define VORTEX_CDIO_ADDR_MASK	0x007f0000
#define VORTEX_CDIO_RDBIT	0x00000000
#define VORTEX_CDIO_WRBIT	0x00800000
#define VORTEX_CDIO_READ(a) (VORTEX_CDIO_RDBIT | \
		(((a) << VORTEX_CDIO_ADDR_SHIFT) & VORTEX_CDIO_ADDR_MASK))
#define VORTEX_CDIO_WRITE(a, d) (VORTEX_CDIO_WRBIT | \
		(((a) << VORTEX_CDIO_ADDR_SHIFT) & VORTEX_CDIO_ADDR_MASK) | \
		(((d) << VORTEX_CDIO_DATA_SHIFT) & VORTEX_CDIO_DATA_MASK))
#define VORTEX_CODEC_ENABLE	0x29190

#endif				/* !_DEV_PCI_VORTEXREG_H_ */

--------------070805080502010805040908
Content-Type: text/plain;
 name="vortexvar.h"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="vortexvar.h"

/*	$NetBSD$	*/

#ifndef _DEV_PCI_VORTEXVAR_H_
#define _DEV_PCI_VORTEXVAR_H_

struct vortex_chipset {
	struct audio_device	voc_audev;
	pcireg_t		voc_pa_id;

	/* General control register */
	uint32_t		voc_control;
#define VORTEX_CTL_MIDI_ENABLE		0x0001
#define VORTEX_CTL_GAME_ENABLE		0x0008
#define VORTEX_CLT_IRQ_ENABLE		0x4000

	/* IRQ control register */
	uint32_t		voc_irq_source;
#define VORTEX_IRQ_FATAL_ERR		0x0001
#define VORTEX_IRQ_PARITY_ERR		0x0002
#define VORTEX_IRQ_REG_ERR		0x0004
#define VORTEX_IRQ_FIFO_ERR		0x0008
#define VORTEX_IRQ_DMA_ERR		0x0010
#define VORTEX_IRQ_PCMOUT		0x0020
#define VORTEX_IRQ_TIMER		0x1000
#define VORTEX_IRQ_MIDI			0x2000
#define VORTEX_IRQ_MODEM		0x4000
	uint32_t		voc_irq_mask;
	uint32_t		voc_irq_control;
#define		VORTEX_IRQ_PENDING_BIT		0x0001
	uint32_t		voc_irq_status;

	/* DMA control registers */
	uint32_t		voc_dma_control;

	/* FIFOs */
	int			voc_fifo_size;
	int			voc_wt_fifos;
	uint32_t		voc_wt_fifo_base;
	uint32_t		voc_wt_fifo_ctl;
	uint32_t		voc_wt_dma_ctl;
	int			voc_adb_fifos;
	uint32_t		voc_adb_fifo_base;
	uint32_t		voc_adb_fifo_ctl;
	uint32_t		voc_adb_dma_ctl;

	/* Routing */
	uint32_t		voc_adb_route_base;
	int			voc_adb_route_bits;
	int			voc_adb_codec_in;
	int			voc_adb_codec_out;
};

struct vortex_softc {
	struct device	sc_dev;
	audio_device_t	sc_audv;

	/* autoconfig parameters */
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	bus_addr_t		sc_iob;
	bus_size_t		sc_ios;
	pci_chipset_tag_t	sc_pc;		/* PCI tag */
	bus_dma_tag_t		sc_dmat;
	void			*sc_ih;		/* interrupt handler */

	/* vortex device structures */
	struct device		*sc_audev;

	struct vortex_chipset	*sc_voc;

	struct ac97_host_if	host_if;
	struct ac97_codec_if	*codec_if;
};

#endif				/* !_DEV_PCI_VORTEXVAR_H_ */

--------------070805080502010805040908--