Module Name:    src
Committed By:   isaki
Date:           Wed May  1 06:34:46 UTC 2019

Modified Files:
        src/sys/dev/pci [isaki-audio2]: emuxki.c
Removed Files:
        src/sys/dev/pci [isaki-audio2]: emuxkivar.h

Log Message:
Reimplement emuxki driver.
- Use single voice per playback and per recording.
- Use fixed format, 2ch/48kHz, to simplify.
- Fix several problems in previous driver.
  And now it works even on alpha!
The driver is written by Y.Sugahara.  Thanks!


To generate a diff of this commit:
cvs rdiff -u -r1.67.2.3 -r1.67.2.4 src/sys/dev/pci/emuxki.c
cvs rdiff -u -r1.13 -r0 src/sys/dev/pci/emuxkivar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/emuxki.c
diff -u src/sys/dev/pci/emuxki.c:1.67.2.3 src/sys/dev/pci/emuxki.c:1.67.2.4
--- src/sys/dev/pci/emuxki.c:1.67.2.3	Wed May  1 06:03:14 2019
+++ src/sys/dev/pci/emuxki.c	Wed May  1 06:34:46 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: emuxki.c,v 1.67.2.3 2019/05/01 06:03:14 isaki Exp $	*/
+/*	$NetBSD: emuxki.c,v 1.67.2.4 2019/05/01 06:34:46 isaki Exp $	*/
 
 /*-
  * Copyright (c) 2001, 2007 The NetBSD Foundation, Inc.
@@ -30,147 +30,227 @@
  */
 
 /*
- * Driver for Creative Labs SBLive! series and probably PCI512.
- *
- * Known bugs:
- * - inversed stereo at ac97 codec level
- *   (XXX jdolecek - don't see the problem? maybe because auvia(4) has
- *    it swapped too?)
- * - bass disappear when you plug rear jack-in on Cambridge FPS2000 speakers
- *   (and presumably all speakers that support front and rear jack-in)
- *
- * TODO:
- * - Digital Outputs
- * - (midi/mpu),joystick support
- * - Multiple voices play (problem with /dev/audio architecture)
- * - Multiple sources recording (Pb with audio(4))
- * - Independent modification of each channel's parameters (via mixer ?)
- * - DSP FX patches (to make fx like chipmunk)
+ * EMU10K1 single voice driver
+ * o. only 1 voice playback, 1 recording
+ * o. only s16le 2ch 48k
+ * This makes it simple to control buffers and interrupts
+ * while satisfying playback and recording quality.
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: emuxki.c,v 1.67.2.3 2019/05/01 06:03:14 isaki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: emuxki.c,v 1.67.2.4 2019/05/01 06:34:46 isaki Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
 #include <sys/errno.h>
 #include <sys/systm.h>
 #include <sys/audioio.h>
-#include <sys/select.h>
 #include <sys/mutex.h>
 #include <sys/kmem.h>
 #include <sys/malloc.h>
 #include <sys/fcntl.h>
 
+#include <sys/bus.h>
+#include <sys/intr.h>
+
 #include <dev/audio_if.h>
 #include <dev/audiovar.h>
 
 #include <dev/ic/ac97reg.h>
 #include <dev/ic/ac97var.h>
 
+#include <dev/pci/pcidevs.h>
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
-#include <dev/pci/pcidevs.h>
+
 #include <dev/pci/emuxkireg.h>
-#include <dev/pci/emuxkivar.h>
 
-/* autoconf goo */
-static int	emuxki_match(device_t, cfdata_t, void *);
-static void	emuxki_attach(device_t, device_t, void *);
-static int	emuxki_detach(device_t, int);
+/* #define EMUXKI_DEBUG 1 */
+#ifdef EMUXKI_DEBUG
+#define emudebug EMUXKI_DEBUG
+# define DPRINTF(fmt...)	do { if (emudebug) printf(fmt); } while (0)
+# define DPRINTFN(n,fmt...)	do { if (emudebug>=(n)) printf(fmt); } while (0)
+#else
+# define DPRINTF(fmt...)	do { } while (0)
+# define DPRINTFN(n,fmt...)	do { } while (0)
+#endif
 
-/* DMA mem mgmt */
-static struct dmamem *dmamem_alloc(bus_dma_tag_t, size_t, bus_size_t,
-		int);
-static void	dmamem_free(struct dmamem *);
+/*
+ * PCI
+ * Note: emuxki's page table entry uses only 31bit addressing.
+ *       (Maybe, later chip has 32bit mode, but it isn't used now.)
+ */
 
-/* Emu10k1 init & shutdown */
-static int	emuxki_init(struct emuxki_softc *);
-static void	emuxki_shutdown(struct emuxki_softc *);
+#define EMU_PCI_CBIO		(0x10)
+#define EMU_SUBSYS_APS		(0x40011102)
 
-/* Emu10k1 mem mgmt */
-static void	*emuxki_pmem_alloc(struct emuxki_softc *, size_t);
-static void	*emuxki_rmem_alloc(struct emuxki_softc *, size_t);
+#define EMU_PTESIZE		(4096)
+#define EMU_MINPTE		(3)
+/*
+ * Hardware limit of PTE is 4096 entry but it's too big for single voice.
+ * Reasonable candidate is:
+ *  48kHz * 2ch * 2byte * 1sec * 3buf/EMU_PTESIZE = 141
+ * and then round it up to 2^n.
+ */
+#define EMU_MAXPTE		(256)
+#define EMU_NUMCHAN		(64)
+
+/*
+ * Internal recording DMA buffer
+ */
+/* Recommend the same size as EMU_PTESIZE to be symmetrical for play/rec */
+#define EMU_REC_DMABLKSIZE	(4096)
+/* must be EMU_REC_DMABLKSIZE * 2 */
+#define EMU_REC_DMASIZE		(8192)
+/* must be EMU_RECBS_BUFSIZE_(EMU_REC_DMASIZE) */
+#define EMU_REC_BUFSIZE_RECBS	EMU_RECBS_BUFSIZE_8192
 
 /*
- * Emu10k1 channels funcs : There is no direct access to channels, everything
- * is done through voices I will at least provide channel based fx params
- * modification, later...
+ * DMA memory management
  */
 
-/* Emu10k1 voice mgmt */
-static struct emuxki_voice *emuxki_voice_new(struct emuxki_softc *,
-		uint8_t);
-static void	emuxki_voice_delete(struct emuxki_voice *);
-static int	emuxki_voice_set_audioparms(struct emuxki_softc *,
-					    struct emuxki_voice *, uint8_t,
-					    uint8_t, uint32_t);
-/* emuxki_voice_set_fxparms will come later, it'll need channel distinction */
-static int	emuxki_voice_set_bufparms(struct emuxki_voice *,
-		void *, uint32_t, uint16_t);
-static void	emuxki_voice_commit_parms(struct emuxki_voice *);
-static int	emuxki_voice_adc_rate(struct emuxki_voice *);
-static uint32_t	emuxki_voice_curaddr(struct emuxki_voice *);
-static void	emuxki_voice_start(struct emuxki_voice *,
-		void (*) (void *), void *);
-static void	emuxki_voice_halt(struct emuxki_voice *);
+#define EMU_DMA_ALIGN		(4096)
+#define EMU_DMA_NSEGS		(1)
+
+struct dmamem {
+	bus_dma_tag_t		dmat;
+	bus_size_t		size;
+	bus_size_t		align;
+	bus_size_t		bound;
+	bus_dma_segment_t	*segs;
+	int			nsegs;
+	int			rsegs;
+	void *			kaddr;
+	bus_dmamap_t		map;
+};
 
+#define KERNADDR(ptr)		((void *)((ptr)->kaddr))
 /*
- * Emu10k1 stream mgmt : not done yet
+ * (ptr)->segs[] is CPU's PA translated by CPU's MMU.
+ * (ptr)->map->dm_segs[] is PCI device's PA translated by PCI's MMU.
  */
-#if 0
-static struct emuxki_stream *emuxki_stream_new(struct emu10k1 *);
-static void	emuxki_stream_delete(struct emuxki_stream *);
-static int	emuxki_stream_set_audio_params(struct emuxki_stream *,
-		uint8_t, uint8_t, uint8_t, uint16_t);
-static void	emuxki_stream_start(struct emuxki_stream *);
-static void	emuxki_stream_halt(struct emuxki_stream *);
-#endif
+#define DMASEGADDR(ptr, segno)	((ptr)->map->dm_segs[segno].ds_addr)
+#define DMAADDR(ptr)		DMASEGADDR(ptr, 0)
+#define DMASIZE(ptr)		((ptr)->size)
+
+struct emuxki_softc {
+	device_t		sc_dev;
+	device_t		sc_audev;
+	enum {
+		EMUXKI_SBLIVE = 0x00,
+		EMUXKI_AUDIGY = 0x01,
+		EMUXKI_AUDIGY2 = 0x02,
+		EMUXKI_LIVE_5_1 = 0x04,
+		EMUXKI_APS = 0x08
+	} sc_type;
+	audio_device_t		sc_audv;	/* for GETDEV */
+
+	/* 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 */
+	kmutex_t		sc_intr_lock;
+	kmutex_t		sc_lock;
+	kmutex_t		sc_index_lock;
+
+	/* register parameters */
+	struct dmamem		*ptb;		/* page table */
+
+	struct dmamem		*pmem;		/* play memory */
+	void			(*pintr)(void *);
+	void			*pintrarg;
+	audio_params_t		play;
+	int			pframesize;
+	int			pblksize;
+	int			plength;
+	int			poffset;
+
+	struct dmamem		*rmem;		/* rec internal memory */
+	void			(*rintr)(void *);
+	void			*rintrarg;
+	audio_params_t		rec;
+	void			*rptr;		/* rec MI ptr */
+	int			rcurrent;	/* rec software trans count */
+	int			rframesize;
+	int			rblksize;
+	int			rlength;
+	int			roffset;
+
+	/* others */
+
+	struct ac97_host_if	hostif;
+	struct ac97_codec_if	*codecif;
+};
 
-/* audio interface callbacks */
+/* blackmagic */
+#define X1(x)		((sc->sc_type & EMUXKI_AUDIGY) ? EMU_A_##x : EMU_##x)
+#define X2(x, y)	((sc->sc_type & EMUXKI_AUDIGY) \
+    ? EMU_A_##x(EMU_A_##y) : EMU_##x(EMU_##y))
+#define EMU_A_DSP_FX		EMU_DSP_FX
+#define EMU_A_DSP_IN_AC97	EMU_DSP_IN_AC97
+
+/* prototypes */
+static struct dmamem *dmamem_alloc(struct emuxki_softc *, size_t);
+static void	dmamem_free(struct dmamem *);
+static void	dmamem_sync(struct dmamem *, int);
+static uint8_t	emuxki_readio_1(struct emuxki_softc *, int) __unused;
+static uint16_t	emuxki_readio_2(struct emuxki_softc *, int);
+static uint32_t	emuxki_readio_4(struct emuxki_softc *, int);
+static void	emuxki_writeio_1(struct emuxki_softc *, int, uint8_t);
+static void	emuxki_writeio_2(struct emuxki_softc *, int, uint16_t);
+static void	emuxki_writeio_4(struct emuxki_softc *, int, uint32_t);
+static uint32_t	emuxki_readptr(struct emuxki_softc *, int, int, int);
+static void	emuxki_writeptr(struct emuxki_softc *, int, int, int, uint32_t);
+static uint32_t	emuxki_read(struct emuxki_softc *, int, int);
+static void	emuxki_write(struct emuxki_softc *, int, int, uint32_t);
+static int	emuxki_match(device_t, cfdata_t, void *);
+static void	emuxki_attach(device_t, device_t, void *);
+static int	emuxki_detach(device_t, int);
+static int	emuxki_init(struct emuxki_softc *);
+static void	emuxki_dsp_addop(struct emuxki_softc *, uint16_t *, uint8_t,
+		    uint16_t, uint16_t, uint16_t, uint16_t);
+static void	emuxki_initfx(struct emuxki_softc *);
+static void	emuxki_play_start(struct emuxki_softc *, int, uint32_t,
+		    uint32_t);
+static void	emuxki_play_stop(struct emuxki_softc *, int);
 
 static int	emuxki_open(void *, int);
 static void	emuxki_close(void *);
-
 static int	emuxki_query_format(void *, audio_format_query_t *);
 static int	emuxki_set_format(void *, int,
 		    const audio_params_t *, const audio_params_t *,
 		    audio_filter_reg_t *, audio_filter_reg_t *);
-
-static int	emuxki_round_blocksize(void *, int, int, const audio_params_t *);
-static size_t	emuxki_round_buffersize(void *, int, size_t);
-
-static int	emuxki_trigger_output(void *, void *, void *, int,
-		void (*)(void *), void *, const audio_params_t *);
-static int	emuxki_trigger_input(void *, void *, void *, int,
-		void (*) (void *), void *, const audio_params_t *);
 static int	emuxki_halt_output(void *);
 static int	emuxki_halt_input(void *);
-
+static int	emuxki_intr(void *);
 static int	emuxki_getdev(void *, struct audio_device *);
 static int	emuxki_set_port(void *, mixer_ctrl_t *);
 static int	emuxki_get_port(void *, mixer_ctrl_t *);
 static int	emuxki_query_devinfo(void *, mixer_devinfo_t *);
-
-static void    *emuxki_allocm(void *, int, size_t);
+static void	*emuxki_allocm(void *, int, size_t);
 static void	emuxki_freem(void *, void *, size_t);
-
+static int	emuxki_round_blocksize(void *, int, int,
+		    const audio_params_t *);
+static size_t	emuxki_round_buffersize(void *, int, size_t);
 static int	emuxki_get_props(void *);
+static int	emuxki_trigger_output(void *, void *, void *, int,
+		    void (*)(void *), void *, const audio_params_t *);
+static int	emuxki_trigger_input(void *, void *, void *, int,
+		    void (*)(void *), void *, const audio_params_t *);
 static void	emuxki_get_locks(void *, kmutex_t **, kmutex_t **);
 
-/* Interrupt handler */
-static int	emuxki_intr(void *);
-
-/* Emu10k1 AC97 interface callbacks */
+static int	emuxki_ac97_init(struct emuxki_softc *);
 static int	emuxki_ac97_attach(void *, struct ac97_codec_if *);
 static int	emuxki_ac97_read(void *, uint8_t, uint16_t *);
 static int	emuxki_ac97_write(void *, uint8_t, uint16_t);
 static int	emuxki_ac97_reset(void *);
-static enum ac97_host_flags emuxki_ac97_flags(void *);
+static enum ac97_host_flags	emuxki_ac97_flags(void *);
+
 
-/*
- * Autoconfig goo.
- */
 CFATTACH_DECL_NEW(emuxki, sizeof(struct emuxki_softc),
     emuxki_match, emuxki_attach, emuxki_detach, NULL);
 
@@ -195,110 +275,85 @@ static const struct audio_hw_if emuxki_h
 	.get_locks		= emuxki_get_locks,
 };
 
-#if 0
-static const int emuxki_recsrc_intrmasks[EMU_NUMRECSRCS] =
-    { EMU_INTE_MICBUFENABLE, EMU_INTE_ADCBUFENABLE, EMU_INTE_EFXBUFENABLE };
-#endif
-static const uint32_t emuxki_recsrc_bufaddrreg[EMU_NUMRECSRCS] =
-    { EMU_MICBA, EMU_ADCBA, EMU_FXBA };
-static const uint32_t emuxki_recsrc_szreg[EMU_NUMRECSRCS] =
-    { EMU_MICBS, EMU_ADCBS, EMU_FXBS };
-static const int emuxki_recbuf_sz[] = {
-	0, 384, 448, 512, 640, 768, 896, 1024, 1280, 1536, 1792,
-	2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 10240,
-	12288, 14366, 16384, 20480, 24576, 28672, 32768, 40960, 49152,
-	57344, 65536
-};
-
-#define EMUXKI_NFORMATS	4
-#define EMUXKI_FORMAT_S16(aumode, ch, chmask) \
-	{ \
-		.mode		= (aumode), \
-		.encoding	= AUDIO_ENCODING_SLINEAR_LE, \
-		.validbits	= 16, \
-		.precision	= 16, \
-		.channels	= (ch), \
-		.channel_mask	= (chmask), \
-		.frequency_type	= 0, \
-		.frequency	= { 4000, 48000 }, \
-	}
-#define EMUXKI_FORMAT_U8(aumode, ch, chmask) \
-	{ \
-		.mode		= (aumode), \
-		.encoding	= AUDIO_ENCODING_ULINEAR_LE, \
-		.validbits	= 8, \
-		.precision	= 8, \
-		.channels	= (ch), \
-		.channel_mask	= (chmask), \
-		.frequency_type	= 0, \
-		.frequency	= { 4000, 48000 }, \
-	}
-static const struct audio_format emuxki_formats[EMUXKI_NFORMATS] = {
-	EMUXKI_FORMAT_S16(AUMODE_PLAY | AUMODE_RECORD, 2, AUFMT_STEREO),
-	EMUXKI_FORMAT_S16(AUMODE_PLAY | AUMODE_RECORD, 1, AUFMT_MONAURAL),
-	EMUXKI_FORMAT_U8 (AUMODE_PLAY                , 2, AUFMT_STEREO),
-	EMUXKI_FORMAT_U8 (AUMODE_PLAY                , 1, AUFMT_MONAURAL),
+static const struct audio_format emuxki_formats[] = {
+	{
+		.mode		= AUMODE_PLAY | AUMODE_RECORD,
+		.encoding	= AUDIO_ENCODING_SLINEAR_LE,
+		.validbits	= 16,
+		.precision	= 16,
+		.channels	= 2,
+		.channel_mask	= AUFMT_STEREO,
+		.frequency_type	= 1,
+		.frequency	= { 48000 },
+	}
 };
+#define EMUXKI_NFORMATS	__arraycount(emuxki_formats)
 
 /*
- * DMA memory mgmt
+ * dma memory
  */
 
-static void
-dmamem_delete(struct dmamem *mem)
-{
-
-	kmem_free(mem->segs, mem->nsegs * sizeof(*(mem->segs)));
-	kmem_free(mem, sizeof(*mem));
-}
-
 static struct dmamem *
-dmamem_alloc(bus_dma_tag_t dmat, size_t size, bus_size_t align, int nsegs)
+dmamem_alloc(struct emuxki_softc *sc, size_t size)
 {
-	struct dmamem	*mem;
+	struct dmamem *mem;
+
+	KASSERT(!mutex_owned(&sc->sc_intr_lock));
 
 	/* Allocate memory for structure */
 	mem = kmem_alloc(sizeof(*mem), KM_SLEEP);
-	mem->dmat = dmat;
+	mem->dmat = sc->sc_dmat;
 	mem->size = size;
-	mem->align = align;
-	mem->nsegs = nsegs;
+	mem->align = EMU_DMA_ALIGN;
+	mem->nsegs = EMU_DMA_NSEGS;
 	mem->bound = 0;
 
 	mem->segs = kmem_alloc(mem->nsegs * sizeof(*(mem->segs)), KM_SLEEP);
 
-	if (bus_dmamem_alloc(dmat, mem->size, mem->align, mem->bound,
-			     mem->segs, mem->nsegs, &(mem->rsegs),
-			     BUS_DMA_WAITOK)) {
-		dmamem_delete(mem);
-		return NULL;
-	}
-
-	if (bus_dmamem_map(dmat, mem->segs, mem->nsegs, mem->size,
-			   &(mem->kaddr), BUS_DMA_WAITOK | BUS_DMA_COHERENT)) {
-		bus_dmamem_free(dmat, mem->segs, mem->nsegs);
-		dmamem_delete(mem);
-		return NULL;
-	}
-
-	if (bus_dmamap_create(dmat, mem->size, mem->nsegs, mem->size,
-			      mem->bound, BUS_DMA_WAITOK, &(mem->map))) {
-		bus_dmamem_unmap(dmat, mem->kaddr, mem->size);
-		bus_dmamem_free(dmat, mem->segs, mem->nsegs);
-		dmamem_delete(mem);
-		return NULL;
-	}
-
-	if (bus_dmamap_load(dmat, mem->map, mem->kaddr,
-			    mem->size, NULL, BUS_DMA_WAITOK)) {
-		bus_dmamap_destroy(dmat, mem->map);
-		bus_dmamem_unmap(dmat, mem->kaddr, mem->size);
-		bus_dmamem_free(dmat, mem->segs, mem->nsegs);
-		dmamem_delete(mem);
-		return NULL;
+	if (bus_dmamem_alloc(mem->dmat, mem->size, mem->align, mem->bound,
+	    mem->segs, mem->nsegs, &mem->rsegs, BUS_DMA_WAITOK)) {
+		device_printf(sc->sc_dev,
+		    "%s bus_dmamem_alloc failed\n", __func__);
+		goto memfree;
+	}
+
+	if (bus_dmamem_map(mem->dmat, mem->segs, mem->nsegs, mem->size,
+	    &mem->kaddr, BUS_DMA_WAITOK | BUS_DMA_COHERENT)) {
+		device_printf(sc->sc_dev,
+		    "%s bus_dmamem_map failed\n", __func__);
+		goto free;
+	}
+
+	if (bus_dmamap_create(mem->dmat, mem->size, mem->nsegs, mem->size,
+	    mem->bound, BUS_DMA_WAITOK, &mem->map)) {
+		device_printf(sc->sc_dev,
+		    "%s bus_dmamap_create failed\n", __func__);
+		goto unmap;
+	}
+
+	if (bus_dmamap_load(mem->dmat, mem->map, mem->kaddr,
+	    mem->size, NULL, BUS_DMA_WAITOK)) {
+		device_printf(sc->sc_dev,
+		    "%s bus_dmamap_load failed\n", __func__);
+		goto destroy;
 	}
 
+	DPRINTF("map ds=%p\n", (char*)mem->map->dm_segs[0].ds_addr);
+	DPRINTF("segs ds=%p\n", (char*)mem->segs[0].ds_addr);
+
 	return mem;
+
+destroy:
+	bus_dmamap_destroy(mem->dmat, mem->map);
+unmap:
+	bus_dmamem_unmap(mem->dmat, mem->kaddr, mem->size);
+free:
+	bus_dmamem_free(mem->dmat, mem->segs, mem->nsegs);
+memfree:
+	kmem_free(mem->segs, mem->nsegs * sizeof(*(mem->segs)));
+	kmem_free(mem, sizeof(*mem));
+
+	return NULL;
 }
 
 static void
@@ -309,78 +364,112 @@ dmamem_free(struct dmamem *mem)
 	bus_dmamap_destroy(mem->dmat, mem->map);
 	bus_dmamem_unmap(mem->dmat, mem->kaddr, mem->size);
 	bus_dmamem_free(mem->dmat, mem->segs, mem->nsegs);
-	dmamem_delete(mem);
+
+	kmem_free(mem->segs, mem->nsegs * sizeof(*(mem->segs)));
+	kmem_free(mem, sizeof(*mem));
+}
+
+static void
+dmamem_sync(struct dmamem *mem, int ops)
+{
+
+	bus_dmamap_sync(mem->dmat, mem->map, 0, mem->size, ops);
 }
 
 
 /*
- * Autoconf device callbacks : attach and detach
+ * I/O register access
  */
 
+static uint8_t
+emuxki_readio_1(struct emuxki_softc *sc, int addr)
+{
+
+	return bus_space_read_1(sc->sc_iot, sc->sc_ioh, addr);
+}
+
 static void
-emuxki_pci_shutdown(struct emuxki_softc *sc)
+emuxki_writeio_1(struct emuxki_softc *sc, int addr, uint8_t data)
 {
 
-	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);
+	bus_space_write_1(sc->sc_iot, sc->sc_ioh, addr, data);
 }
 
-static int
-emuxki_scinit(struct emuxki_softc *sc)
+static uint16_t
+emuxki_readio_2(struct emuxki_softc *sc, int addr)
+{
+
+	return bus_space_read_2(sc->sc_iot, sc->sc_ioh, addr);
+}
+
+static void
+emuxki_writeio_2(struct emuxki_softc *sc, int addr, uint16_t data)
 {
-	int err;
 
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_HCFG,
-		EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK |
-		EMU_HCFG_MUTEBUTTONENABLE);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_INTE,
-		EMU_INTE_SAMPLERATER | EMU_INTE_PCIERRENABLE);
+	bus_space_write_2(sc->sc_iot, sc->sc_ioh, addr, data);
+}
 
-	if ((err = emuxki_init(sc)))
-		return err;
+static uint32_t
+emuxki_readio_4(struct emuxki_softc *sc, int addr)
+{
 
-	if (sc->sc_type & EMUXKI_AUDIGY2) {
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_HCFG,
-			EMU_HCFG_AUDIOENABLE | EMU_HCFG_AC3ENABLE_CDSPDIF |
-			EMU_HCFG_AC3ENABLE_GPSPDIF | EMU_HCFG_AUTOMUTE);
-	} else if (sc->sc_type & EMUXKI_AUDIGY) {
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_HCFG,
-			EMU_HCFG_AUDIOENABLE | EMU_HCFG_AUTOMUTE);
-	} else {
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_HCFG,
-			EMU_HCFG_AUDIOENABLE | EMU_HCFG_JOYENABLE |
-			EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_AUTOMUTE);
-	}
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_INTE,
-		bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_INTE) |
-		EMU_INTE_VOLINCRENABLE | EMU_INTE_VOLDECRENABLE |
-		EMU_INTE_MUTEENABLE);
-	if (sc->sc_type & EMUXKI_AUDIGY2) {
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_A_IOCFG,
-			EMU_A_IOCFG_GPOUT0 |
-			bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_A_IOCFG));
-	}
+	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, addr);
+}
 
-	/* No multiple voice support for now */
-	sc->pvoice = sc->rvoice = NULL;
+static void
+emuxki_writeio_4(struct emuxki_softc *sc, int addr, uint32_t data)
+{
 
-	return 0;
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, addr, data);
 }
 
-static int
-emuxki_ac97_init(struct emuxki_softc *sc)
+static uint32_t
+emuxki_readptr(struct emuxki_softc *sc, int aptr, int dptr, int addr)
 {
-	sc->hostif.arg = sc;
-	sc->hostif.attach = emuxki_ac97_attach;
-	sc->hostif.read = emuxki_ac97_read;
-	sc->hostif.write = emuxki_ac97_write;
-	sc->hostif.reset = emuxki_ac97_reset;
-	sc->hostif.flags = emuxki_ac97_flags;
-	return ac97_attach(&sc->hostif, sc->sc_dev, &sc->sc_lock);
+	uint32_t data;
+
+	mutex_spin_enter(&sc->sc_index_lock);
+	emuxki_writeio_4(sc, aptr, addr);
+	data = emuxki_readio_4(sc, dptr);
+	mutex_spin_exit(&sc->sc_index_lock);
+	return data;
+}
+
+static void
+emuxki_writeptr(struct emuxki_softc *sc, int aptr, int dptr, int addr,
+    uint32_t data)
+{
+
+	mutex_spin_enter(&sc->sc_index_lock);
+	emuxki_writeio_4(sc, aptr, addr);
+	emuxki_writeio_4(sc, dptr, data);
+	mutex_spin_exit(&sc->sc_index_lock);
+}
+
+static uint32_t
+emuxki_read(struct emuxki_softc *sc, int ch, int addr)
+{
+
+	/* Original HENTAI addressing is never supported. */
+	KASSERT((addr & 0xff000000) == 0);
+
+	return emuxki_readptr(sc, EMU_PTR, EMU_DATA, (addr << 16) + ch);
 }
 
+static void
+emuxki_write(struct emuxki_softc *sc, int ch, int addr, uint32_t data)
+{
+
+	/* Original HENTAI addressing is never supported. */
+	KASSERT((addr & 0xff000000) == 0);
+
+	emuxki_writeptr(sc, EMU_PTR, EMU_DATA, (addr << 16) + ch, data);
+}
+
+/*
+ * MD driver
+ */
+
 static int
 emuxki_match(device_t parent, cfdata_t match, void *aux)
 {
@@ -408,35 +497,36 @@ emuxki_attach(device_t parent, device_t 
 	pci_intr_handle_t ih;
 	const char *intrstr;
 	char intrbuf[PCI_INTRSTR_LEN];
+	pcireg_t reg;
 
 	sc = device_private(self);
 	sc->sc_dev = self;
 	pa = aux;
 
+	pci_aprint_devinfo(pa, "Audio controller");
+	DPRINTF("dmat=%p\n", (char *)pa->pa_dmat);
+
 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
 	mutex_init(&sc->sc_index_lock, MUTEX_DEFAULT, IPL_AUDIO);
-	mutex_init(&sc->sc_ac97_index_lock, MUTEX_DEFAULT, IPL_AUDIO);
+
+	sc->sc_pc   = pa->pa_pc;
+	sc->sc_dmat = pa->pa_dmat;
+
+	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+	reg |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE |
+	    PCI_COMMAND_MEM_ENABLE;
+	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg);
 
 	if (pci_mapreg_map(pa, EMU_PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
-	    &(sc->sc_iot), &(sc->sc_ioh), &(sc->sc_iob),
-			   &(sc->sc_ios))) {
+	    &sc->sc_iot, &sc->sc_ioh, &sc->sc_iob, &sc->sc_ios)) {
 		aprint_error(": can't map iospace\n");
 		return;
 	}
 
-	pci_aprint_devinfo(pa, "Audio controller");
-
-	sc->sc_pc   = pa->pa_pc;
-	sc->sc_dmat = pa->pa_dmat;
-	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
-		pci_conf_read(pa->pa_pc, pa->pa_tag,
-		(PCI_COMMAND_STATUS_REG) | PCI_COMMAND_MASTER_ENABLE));
-
 	if (pci_intr_map(pa, &ih)) {
 		aprint_error_dev(self, "couldn't map interrupt\n");
-		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
-		return;
+		goto unmap;
 	}
 
 	intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf));
@@ -447,8 +537,7 @@ emuxki_attach(device_t parent, device_t 
 		if (intrstr != NULL)
 			aprint_error(" at %s", intrstr);
 		aprint_error("\n");
-		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
-		return;
+		goto unmap;
 	}
 	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
 
@@ -458,36 +547,45 @@ emuxki_attach(device_t parent, device_t 
 		if (PCI_REVISION(pa->pa_class) == 0x04) {
 			sc->sc_type |= EMUXKI_AUDIGY2;
 			strlcpy(sc->sc_audv.name, "Audigy2",
-			    sizeof sc->sc_audv.name);
+			    sizeof(sc->sc_audv.name));
 		} else {
 			strlcpy(sc->sc_audv.name, "Audigy",
-			    sizeof sc->sc_audv.name);
+			    sizeof(sc->sc_audv.name));
 		}
 	} else if (pci_conf_read(pa->pa_pc, pa->pa_tag,
 	    PCI_SUBSYS_ID_REG) == EMU_SUBSYS_APS) {
 		sc->sc_type = EMUXKI_APS;
-		strlcpy(sc->sc_audv.name, "E-mu APS", sizeof sc->sc_audv.name);
+		strlcpy(sc->sc_audv.name, "E-mu APS", sizeof(sc->sc_audv.name));
 	} else {
 		sc->sc_type = EMUXKI_SBLIVE;
-		strlcpy(sc->sc_audv.name, "SB Live!", sizeof sc->sc_audv.name);
+		strlcpy(sc->sc_audv.name, "SB Live!", sizeof(sc->sc_audv.name));
 	}
-	snprintf(sc->sc_audv.version, sizeof sc->sc_audv.version, "0x%02x",
-		 PCI_REVISION(pa->pa_class));
-	strlcpy(sc->sc_audv.config, "emuxki", sizeof sc->sc_audv.config);
-
-	if (emuxki_scinit(sc) || emuxki_ac97_init(sc) ||
-	    (sc->sc_audev = audio_attach_mi(&emuxki_hw_if, sc, self)) == NULL) {
-		emuxki_pci_shutdown(sc);
-		return;
+	snprintf(sc->sc_audv.version, sizeof(sc->sc_audv.version), "0x%02x",
+	    PCI_REVISION(pa->pa_class));
+	strlcpy(sc->sc_audv.config, "emuxki", sizeof(sc->sc_audv.config));
+
+	if (emuxki_init(sc)) {
+		aprint_error("emuxki_init error\n");
+		goto intrdis;
 	}
-#if 0
-	mutex_enter(&sc->lock);
-	sc->rsourcectl.dev =
-	    sc->codecif->vtbl->get_portnum_by_name(sc->codec_if, AudioCrecord,
-						   AudioNsource, NULL);
-	sc->rsourcectl.cp = AUDIO_MIXER_ENUM;
-	mutex_exit(&sc->lock);
-#endif
+	if (emuxki_ac97_init(sc)) {
+		aprint_error("emuxki_ac97_init error\n");
+		goto intrdis;
+	}
+
+	sc->sc_audev = audio_attach_mi(&emuxki_hw_if, sc, self);
+	if (sc->sc_audev == NULL) {
+		aprint_error("audio_attach_mi error\n");
+		goto intrdis;
+	}
+
+	return;
+
+intrdis:
+	pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
+unmap:
+	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
+	return;
 }
 
 static int
@@ -500,285 +598,52 @@ emuxki_detach(device_t self, int flags)
 		config_detach(sc->sc_audev, 0);
 
 	/* All voices should be stopped now but add some code here if not */
+	emuxki_writeio_4(sc, EMU_HCFG,
+	    EMU_HCFG_LOCKSOUNDCACHE |
+	    EMU_HCFG_LOCKTANKCACHE_MASK |
+	    EMU_HCFG_MUTEBUTTONENABLE);
+	emuxki_writeio_4(sc, EMU_INTE, 0);
+
+	/* Disable any Channels interrupts */
+	emuxki_write(sc, 0, EMU_CLIEL, 0);
+	emuxki_write(sc, 0, EMU_CLIEH, 0);
+	emuxki_write(sc, 0, EMU_SOLEL, 0);
+	emuxki_write(sc, 0, EMU_SOLEH, 0);
+
+	/* stop DSP */
+	emuxki_write(sc, 0, X1(DBG), X1(DBG_SINGLE_STEP));
 
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_HCFG,
-		EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK |
-		EMU_HCFG_MUTEBUTTONENABLE);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_INTE, 0);
-
-	mutex_enter(&sc->sc_lock);
-	emuxki_shutdown(sc);
-	mutex_exit(&sc->sc_lock);
+	dmamem_free(sc->ptb);
 
-	emuxki_pci_shutdown(sc);
+	pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
+	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
 
 	mutex_destroy(&sc->sc_lock);
 	mutex_destroy(&sc->sc_intr_lock);
 	mutex_destroy(&sc->sc_index_lock);
-	mutex_destroy(&sc->sc_ac97_index_lock);
 
 	return 0;
 }
 
-
-/* Misc stuff relative to emu10k1 */
-
-static uint32_t
-emuxki_rate_to_pitch(uint32_t rate)
-{
-	static const uint32_t logMagTable[128] = {
-		0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3,
-		0x13aa2, 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a,
-		0x2655d, 0x28ed5, 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb,
-		0x381b6, 0x3a93d, 0x3d081, 0x3f782, 0x41e42, 0x444c1, 0x46b01,
-		0x49101, 0x4b6c4, 0x4dc49, 0x50191, 0x5269e, 0x54b6f, 0x57006,
-		0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7, 0x646ee, 0x66a00,
-		0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829, 0x759d4,
-		0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
-		0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20,
-		0x93d26, 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec,
-		0xa11d8, 0xa2f9d, 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241,
-		0xadf26, 0xafbe7, 0xb1885, 0xb3500, 0xb5157, 0xb6d8c, 0xb899f,
-		0xba58f, 0xbc15e, 0xbdd0c, 0xbf899, 0xc1404, 0xc2f50, 0xc4a7b,
-		0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c, 0xceaec, 0xd053f,
-		0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3, 0xdba4a,
-		0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
-		0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a,
-		0xf2c83, 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57,
-		0xfd1a7, 0xfe8df
-	};
-	static const uint8_t logSlopeTable[128] = {
-		0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
-		0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
-		0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
-		0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
-		0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
-		0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
-		0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
-		0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
-		0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
-		0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
-		0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
-		0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
-		0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
-		0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
-		0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
-		0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
-	};
-	int8_t i;
-
-	if (rate == 0)
-		return 0;	/* Bail out if no leading "1" */
-	rate *= 11185;		/* Scale 48000 to 0x20002380 */
-	for (i = 31; i > 0; i--) {
-		if (rate & 0x80000000) {	/* Detect leading "1" */
-			return (((uint32_t) (i - 15) << 20) +
-				logMagTable[0x7f & (rate >> 24)] +
-				(0x7f & (rate >> 17)) *
-				logSlopeTable[0x7f & (rate >> 24)]);
-		}
-		rate <<= 1;
-	}
-
-	return 0;		/* Should never reach this point */
-}
-
-/* Emu10k1 Low level */
-
-static uint32_t
-emuxki_read(struct emuxki_softc *sc, uint16_t chano, uint32_t reg)
-{
-	uint32_t ptr, mask;
-	uint8_t  size, offset;
-
-	mask = 0xffffffff;
-	offset = 0;
-	ptr = ((((u_int32_t) reg) << 16) &
-		(sc->sc_type & EMUXKI_AUDIGY ?
-			EMU_A_PTR_ADDR_MASK : EMU_PTR_ADDR_MASK)) |
-		(chano & EMU_PTR_CHNO_MASK);
-	if (reg & 0xff000000) {
-		size = (reg >> 24) & 0x3f;
-		offset = (reg >> 16) & 0x1f;
-		mask = ((1 << size) - 1) << offset;
-	}
-
-	mutex_spin_enter(&sc->sc_index_lock);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_PTR, ptr);
-	ptr = (bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_DATA) & mask)
-		>> offset;
-	mutex_spin_exit(&sc->sc_index_lock);
-
-	return ptr;
-}
-
-static void
-emuxki_write(struct emuxki_softc *sc, uint16_t chano,
-	      uint32_t reg, uint32_t data)
-{
-	uint32_t ptr, mask;
-	uint8_t size, offset;
-
-	ptr = ((((u_int32_t) reg) << 16) &
-		(sc->sc_type & EMUXKI_AUDIGY ?
-			EMU_A_PTR_ADDR_MASK : EMU_PTR_ADDR_MASK)) |
-		(chano & EMU_PTR_CHNO_MASK);
-	if (reg & 0xff000000) {
-		size = (reg >> 24) & 0x3f;
-		offset = (reg >> 16) & 0x1f;
-		mask = ((1 << size) - 1) << offset;
-		data = ((data << offset) & mask) |
-			(emuxki_read(sc, chano, reg & 0xffff) & ~mask);
-	}
-
-	mutex_spin_enter(&sc->sc_index_lock);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_PTR, ptr);
-	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_DATA, data);
-	mutex_spin_exit(&sc->sc_index_lock);
-}
-
-/* Microcode should this go in /sys/dev/microcode ? */
-
-static void
-emuxki_write_micro(struct emuxki_softc *sc, uint32_t pc, uint32_t data)
-{
-
-	emuxki_write(sc, 0,
-		(sc->sc_type & EMUXKI_AUDIGY ?
-			EMU_A_MICROCODEBASE : EMU_MICROCODEBASE) + pc,
-		 data);
-}
-
-static void
-emuxki_dsp_addop(struct emuxki_softc *sc, uint16_t *pc, uint8_t op,
-		  uint16_t r, uint16_t a, uint16_t x, uint16_t y)
-{
-
-	if (sc->sc_type & EMUXKI_AUDIGY) {
-		emuxki_write_micro(sc, *pc << 1,
-			((x << 12) & EMU_A_DSP_LOWORD_OPX_MASK) |
-			(y & EMU_A_DSP_LOWORD_OPY_MASK));
-		emuxki_write_micro(sc, (*pc << 1) + 1,
-			((op << 24) & EMU_A_DSP_HIWORD_OPCODE_MASK) |
-			((r << 12) & EMU_A_DSP_HIWORD_RESULT_MASK) |
-			(a & EMU_A_DSP_HIWORD_OPA_MASK));
-	} else {
-		emuxki_write_micro(sc, *pc << 1,
-			((x << 10) & EMU_DSP_LOWORD_OPX_MASK) |
-			(y & EMU_DSP_LOWORD_OPY_MASK));
-		emuxki_write_micro(sc, (*pc << 1) + 1,
-			((op << 20) & EMU_DSP_HIWORD_OPCODE_MASK) |
-			((r << 10) & EMU_DSP_HIWORD_RESULT_MASK) |
-			(a & EMU_DSP_HIWORD_OPA_MASK));
-	}
-	(*pc)++;
-}
-
-/* init and shutdown */
-
-static void
-emuxki_initfx(struct emuxki_softc *sc)
-{
-	uint16_t pc;
-
-	/* Set all GPRs to 0 */
-	for (pc = 0; pc < 256; pc++)
-		emuxki_write(sc, 0, EMU_DSP_GPR(pc), 0);
-	for (pc = 0; pc < 160; pc++) {
-		emuxki_write(sc, 0, EMU_TANKMEMDATAREGBASE + pc, 0);
-		emuxki_write(sc, 0, EMU_TANKMEMADDRREGBASE + pc, 0);
-	}
-	pc = 0;
-
-	if (sc->sc_type & EMUXKI_AUDIGY) {
-		/* AC97 Out (l/r) = AC97 In (l/r) + FX[0/1] * 4 */
-		emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
-				  EMU_A_DSP_OUTL(EMU_A_DSP_OUT_A_FRONT),
-				  EMU_A_DSP_CST(0),
-				  EMU_DSP_FX(0), EMU_A_DSP_CST(4));
-		emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
-				  EMU_A_DSP_OUTR(EMU_A_DSP_OUT_A_FRONT),
-				  EMU_A_DSP_CST(0),
-				  EMU_DSP_FX(1), EMU_A_DSP_CST(4));
-
-		/* Rear channel OUT (l/r) = FX[2/3] * 4 */
-#if 0
-		emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
-				  EMU_A_DSP_OUTL(EMU_A_DSP_OUT_A_REAR),
-				  EMU_A_DSP_OUTL(EMU_A_DSP_OUT_A_FRONT),
-				  EMU_DSP_FX(0), EMU_A_DSP_CST(4));
-		emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
-				  EMU_A_DSP_OUTR(EMU_A_DSP_OUT_A_REAR),
-				  EMU_A_DSP_OUTR(EMU_A_DSP_OUT_A_FRONT),
-				  EMU_DSP_FX(1), EMU_A_DSP_CST(4));
-#endif
-		/* ADC recording (l/r) = AC97 In (l/r) */
-		emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
-				  EMU_A_DSP_OUTL(EMU_A_DSP_OUT_ADC),
-				  EMU_A_DSP_INL(EMU_DSP_IN_AC97),
-				  EMU_A_DSP_CST(0), EMU_A_DSP_CST(0));
-		emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
-				  EMU_A_DSP_OUTR(EMU_A_DSP_OUT_ADC),
-				  EMU_A_DSP_INR(EMU_DSP_IN_AC97),
-				  EMU_A_DSP_CST(0), EMU_A_DSP_CST(0));
-
-		/* zero out the rest of the microcode */
-		while (pc < 512)
-			emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
-					  EMU_A_DSP_CST(0), EMU_A_DSP_CST(0),
-					  EMU_A_DSP_CST(0), EMU_A_DSP_CST(0));
-
-		emuxki_write(sc, 0, EMU_A_DBG, 0);	/* Is it really necessary ? */
-	} else {
-		/* AC97 Out (l/r) = AC97 In (l/r) + FX[0/1] * 4 */
-		emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
-				  EMU_DSP_OUTL(EMU_DSP_OUT_A_FRONT),
-				  EMU_DSP_CST(0),
-				  EMU_DSP_FX(0), EMU_DSP_CST(4));
-		emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
-				  EMU_DSP_OUTR(EMU_DSP_OUT_A_FRONT),
-				  EMU_DSP_CST(0),
-				  EMU_DSP_FX(1), EMU_DSP_CST(4));
-
-		/* Rear channel OUT (l/r) = FX[2/3] * 4 */
-#if 0
-		emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
-				  EMU_DSP_OUTL(EMU_DSP_OUT_AD_REAR),
-				  EMU_DSP_OUTL(EMU_DSP_OUT_A_FRONT),
-				  EMU_DSP_FX(0), EMU_DSP_CST(4));
-		emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
-				  EMU_DSP_OUTR(EMU_DSP_OUT_AD_REAR),
-				  EMU_DSP_OUTR(EMU_DSP_OUT_A_FRONT),
-				  EMU_DSP_FX(1), EMU_DSP_CST(4));
-#endif
-		/* ADC recording (l/r) = AC97 In (l/r) */
-		emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
-				  EMU_DSP_OUTL(EMU_DSP_OUT_ADC),
-				  EMU_DSP_INL(EMU_DSP_IN_AC97),
-				  EMU_DSP_CST(0), EMU_DSP_CST(0));
-		emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
-				  EMU_DSP_OUTR(EMU_DSP_OUT_ADC),
-				  EMU_DSP_INR(EMU_DSP_IN_AC97),
-				  EMU_DSP_CST(0), EMU_DSP_CST(0));
-
-		/* zero out the rest of the microcode */
-		while (pc < 512)
-			emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
-					  EMU_DSP_CST(0), EMU_DSP_CST(0),
-					  EMU_DSP_CST(0), EMU_DSP_CST(0));
-
-		emuxki_write(sc, 0, EMU_DBG, 0);	/* Is it really necessary ? */
-	}
-}
-
 static int
 emuxki_init(struct emuxki_softc *sc)
 {
-	uint16_t i;
-	uint32_t spcs, *ptb;
-	bus_addr_t silentpage;
+	int i;
+	uint32_t spcs;
+	uint32_t hcfg;
+
+	/* clear AUDIO bit */
+	emuxki_writeio_4(sc, EMU_HCFG,
+	    EMU_HCFG_LOCKSOUNDCACHE |
+	    EMU_HCFG_LOCKTANKCACHE_MASK |
+	    EMU_HCFG_MUTEBUTTONENABLE);
+
+	/* mask interrupt without PCIERR */
+	emuxki_writeio_4(sc, EMU_INTE,
+	    EMU_INTE_SAMPLERATER | /* always on this bit */
+	    EMU_INTE_PCIERRENABLE);
 
-	/* disable any channel interrupt */
+	/* disable all channel interrupt */
 	emuxki_write(sc, 0, EMU_CLIEL, 0);
 	emuxki_write(sc, 0, EMU_CLIEH, 0);
 	emuxki_write(sc, 0, EMU_SOLEL, 0);
@@ -794,1543 +659,719 @@ emuxki_init(struct emuxki_softc *sc)
 
 	if(sc->sc_type & EMUXKI_AUDIGY) {
 		emuxki_write(sc, 0, EMU_SPBYPASS, EMU_SPBYPASS_24_BITS);
-		emuxki_write(sc, 0, EMU_AC97SLOT, EMU_AC97SLOT_CENTER | EMU_AC97SLOT_LFE);
+		emuxki_write(sc, 0, EMU_AC97SLOT,
+		    EMU_AC97SLOT_CENTER | EMU_AC97SLOT_LFE);
 	}
 
 	/* Initialize all channels to stopped and no effects */
 	for (i = 0; i < EMU_NUMCHAN; i++) {
-		emuxki_write(sc, i, EMU_CHAN_DCYSUSV, 0);
-		emuxki_write(sc, i, EMU_CHAN_IP, 0);
+		emuxki_write(sc, i, EMU_CHAN_DCYSUSV, 0x7f7f);
+		emuxki_write(sc, i, EMU_CHAN_IP, EMU_CHAN_IP_UNITY);
 		emuxki_write(sc, i, EMU_CHAN_VTFT, 0xffff);
 		emuxki_write(sc, i, EMU_CHAN_CVCF, 0xffff);
 		emuxki_write(sc, i, EMU_CHAN_PTRX, 0);
 		emuxki_write(sc, i, EMU_CHAN_CPF, 0);
 		emuxki_write(sc, i, EMU_CHAN_CCR, 0);
 		emuxki_write(sc, i, EMU_CHAN_PSST, 0);
-		emuxki_write(sc, i, EMU_CHAN_DSL, 0x10);	/* Why 16 ? */
-		emuxki_write(sc, i, EMU_CHAN_CCCA, 0);
+		emuxki_write(sc, i, EMU_CHAN_DSL, 0);
+		emuxki_write(sc, i, EMU_CHAN_CCCA, EMU_CHAN_CCCA_INTERPROM_1);
 		emuxki_write(sc, i, EMU_CHAN_Z1, 0);
 		emuxki_write(sc, i, EMU_CHAN_Z2, 0);
+		emuxki_write(sc, i, EMU_CHAN_MAPA, 0xffffffff);
+		emuxki_write(sc, i, EMU_CHAN_MAPB, 0xffffffff);
 		emuxki_write(sc, i, EMU_CHAN_FXRT, 0x32100000);
 		emuxki_write(sc, i, EMU_CHAN_ATKHLDM, 0);
 		emuxki_write(sc, i, EMU_CHAN_DCYSUSM, 0);
 		emuxki_write(sc, i, EMU_CHAN_IFATN, 0xffff);
-		emuxki_write(sc, i, EMU_CHAN_PEFE, 0);
+		emuxki_write(sc, i, EMU_CHAN_PEFE, 0x007f);
 		emuxki_write(sc, i, EMU_CHAN_FMMOD, 0);
-		emuxki_write(sc, i, EMU_CHAN_TREMFRQ, 24);
-		emuxki_write(sc, i, EMU_CHAN_FM2FRQ2, 24);
+		emuxki_write(sc, i, EMU_CHAN_TREMFRQ, 0);
+		emuxki_write(sc, i, EMU_CHAN_FM2FRQ2, 0);
 		emuxki_write(sc, i, EMU_CHAN_TEMPENV, 0);
 
 		/* these are last so OFF prevents writing */
-		emuxki_write(sc, i, EMU_CHAN_LFOVAL2, 0);
-		emuxki_write(sc, i, EMU_CHAN_LFOVAL1, 0);
-		emuxki_write(sc, i, EMU_CHAN_ATKHLDV, 0);
+		emuxki_write(sc, i, EMU_CHAN_LFOVAL2, 0x8000);
+		emuxki_write(sc, i, EMU_CHAN_LFOVAL1, 0x8000);
+		emuxki_write(sc, i, EMU_CHAN_ATKHLDV, 0x7f7f);
 		emuxki_write(sc, i, EMU_CHAN_ENVVOL, 0);
-		emuxki_write(sc, i, EMU_CHAN_ENVVAL, 0);
+		emuxki_write(sc, i, EMU_CHAN_ENVVAL, 0x8000);
 	}
 
 	/* set digital outputs format */
-	spcs = (EMU_SPCS_CLKACCY_1000PPM | EMU_SPCS_SAMPLERATE_48 |
-	      EMU_SPCS_CHANNELNUM_LEFT | EMU_SPCS_SOURCENUM_UNSPEC |
-		EMU_SPCS_GENERATIONSTATUS | 0x00001200 /* Cat code. */ |
-		0x00000000 /* IEC-958 Mode */ | EMU_SPCS_EMPHASIS_NONE |
-		EMU_SPCS_COPYRIGHT);
+	spcs = EMU_SPCS_CLKACCY_1000PPM |
+	       EMU_SPCS_SAMPLERATE_48 |
+	       EMU_SPCS_CHANNELNUM_LEFT |
+	       EMU_SPCS_SOURCENUM_UNSPEC |
+	       EMU_SPCS_GENERATIONSTATUS |
+	       0x00001200 /* Cat code. */ |
+	       0x00000000 /* IEC-958 Mode */ |
+	       EMU_SPCS_EMPHASIS_NONE |
+	       EMU_SPCS_COPYRIGHT;
 	emuxki_write(sc, 0, EMU_SPCS0, spcs);
 	emuxki_write(sc, 0, EMU_SPCS1, spcs);
 	emuxki_write(sc, 0, EMU_SPCS2, spcs);
 
-	if(sc->sc_type & EMUXKI_AUDIGY2) {
-		emuxki_write(sc, 0, EMU_A2_SPDIF_SAMPLERATE, EMU_A2_SPDIF_UNKNOWN);
+	if (sc->sc_type & EMUXKI_AUDIGY2) {
+		emuxki_write(sc, 0, EMU_A2_SPDIF_SAMPLERATE,
+		    EMU_A2_SPDIF_UNKNOWN);
 
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_A2_PTR, EMU_A2_SRCSEL);
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_A2_DATA,
-			EMU_A2_SRCSEL_ENABLE_SPDIF | EMU_A2_SRCSEL_ENABLE_SRCMULTI);
+		emuxki_writeptr(sc, EMU_A2_PTR, EMU_A2_DATA, EMU_A2_SRCSEL,
+		    EMU_A2_SRCSEL_ENABLE_SPDIF | EMU_A2_SRCSEL_ENABLE_SRCMULTI);
 
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_A2_PTR, EMU_A2_SRCMULTI);
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_A2_DATA, EMU_A2_SRCMULTI_ENABLE_INPUT);
+		emuxki_writeptr(sc, EMU_A2_PTR, EMU_A2_DATA, EMU_A2_SRCMULTI,
+		    EMU_A2_SRCMULTI_ENABLE_INPUT);
 	}
 
-
-	/* Let's play with sound processor */
-	emuxki_initfx(sc);
-
-	/* Here is our Page Table */
-	if ((sc->ptb = dmamem_alloc(sc->sc_dmat,
-	    EMU_MAXPTE * sizeof(u_int32_t),
-	    EMU_DMA_ALIGN, EMU_DMAMEM_NSEG)) == NULL)
-		return ENOMEM;
-
-	/* This is necessary unless you like Metallic noise... */
-	if ((sc->silentpage = dmamem_alloc(sc->sc_dmat, EMU_PTESIZE,
-	    EMU_DMA_ALIGN, EMU_DMAMEM_NSEG))==NULL){ 
-		dmamem_free(sc->ptb);
+	/* page table */
+	sc->ptb = dmamem_alloc(sc, EMU_MAXPTE * sizeof(uint32_t));
+	if (sc->ptb == NULL) {
+		device_printf(sc->sc_dev, "ptb allocation error\n");
 		return ENOMEM;
 	}
-
-	/* Zero out the silent page */
-	/* This might not be always true, it might be 128 for 8bit channels */
-	memset(KERNADDR(sc->silentpage), 0, DMASIZE(sc->silentpage));
-
-	/*
-	 * Set all the PTB Entries to the silent page We shift the physical
-	 * address by one and OR it with the page number. I don't know what
-	 * the ORed index is for, might be a very useful unused feature...
-	 */
-	silentpage = DMAADDR(sc->silentpage) << 1;
-	ptb = KERNADDR(sc->ptb);
-	for (i = 0; i < EMU_MAXPTE; i++)
-		ptb[i] = htole32(silentpage | i);
-
-	/* Write PTB address and set TCB to none */
 	emuxki_write(sc, 0, EMU_PTB, DMAADDR(sc->ptb));
+
 	emuxki_write(sc, 0, EMU_TCBS, 0);	/* This means 16K TCB */
 	emuxki_write(sc, 0, EMU_TCB, 0);	/* No TCB use for now */
 
-	/*
-	 * Set channels MAPs to the silent page.
-	 * I don't know what MAPs are for.
-	 */
-	silentpage |= EMU_CHAN_MAP_PTI_MASK;
-	for (i = 0; i < EMU_NUMCHAN; i++) {
-		emuxki_write(sc, i, EMU_CHAN_MAPA, silentpage);
-		emuxki_write(sc, i, EMU_CHAN_MAPB, silentpage);
-		sc->channel[i] = NULL;
+	/* Let's play with sound processor */
+	emuxki_initfx(sc);
+
+	/* enable interrupt */
+	emuxki_writeio_4(sc, EMU_INTE,
+	    emuxki_readio_4(sc, EMU_INTE) |
+	    EMU_INTE_VOLINCRENABLE |
+	    EMU_INTE_VOLDECRENABLE |
+	    EMU_INTE_MUTEENABLE);
+
+	if (sc->sc_type & EMUXKI_AUDIGY2) {
+		emuxki_writeio_4(sc, EMU_A_IOCFG,
+		    emuxki_readio_4(sc, EMU_A_IOCFG) |
+		        EMU_A_IOCFG_GPOUT0);
 	}
 
-	/* Init voices list */
-	LIST_INIT(&(sc->voices));
+	/* enable AUDIO bit */
+	hcfg = EMU_HCFG_AUDIOENABLE | EMU_HCFG_AUTOMUTE;
+
+	if (sc->sc_type & EMUXKI_AUDIGY2) {
+		hcfg |= EMU_HCFG_AC3ENABLE_CDSPDIF |
+		        EMU_HCFG_AC3ENABLE_GPSPDIF;
+	} else if (sc->sc_type & EMUXKI_AUDIGY) {
+	} else {
+		hcfg |= EMU_HCFG_LOCKTANKCACHE_MASK;
+	}
+	/* joystick not supported now */
+	emuxki_writeio_4(sc, EMU_HCFG, hcfg);
 
-	/* Timer is stopped */
-	sc->timerstate &= ~EMU_TIMER_STATE_ENABLED;
 	return 0;
 }
 
+/*
+ * dsp programming
+ */
+
 static void
-emuxki_shutdown(struct emuxki_softc *sc)
+emuxki_dsp_addop(struct emuxki_softc *sc, uint16_t *pc, uint8_t op,
+    uint16_t r, uint16_t a, uint16_t x, uint16_t y)
 {
-	uint32_t i;
-
-	/* Disable any Channels interrupts */
-	emuxki_write(sc, 0, EMU_CLIEL, 0);
-	emuxki_write(sc, 0, EMU_CLIEH, 0);
-	emuxki_write(sc, 0, EMU_SOLEL, 0);
-	emuxki_write(sc, 0, EMU_SOLEH, 0);
-
-	/*
-	 * Should do some voice(stream) stopping stuff here, that's what will
-	 * stop and deallocate all channels.
-	 */
-
-	/* Stop all channels */
-	/* XXX This shouldn't be necessary, I'll remove once everything works */
-	for (i = 0; i < EMU_NUMCHAN; i++)
-		emuxki_write(sc, i, EMU_CHAN_DCYSUSV, 0);
-	for (i = 0; i < EMU_NUMCHAN; i++) {
-		emuxki_write(sc, i, EMU_CHAN_VTFT, 0);
-		emuxki_write(sc, i, EMU_CHAN_CVCF, 0);
-		emuxki_write(sc, i, EMU_CHAN_PTRX, 0);
-		emuxki_write(sc, i, EMU_CHAN_CPF, 0);
-	}
+	uint32_t loword;
+	uint32_t hiword;
+	int reg;
 
-	/*
-	 * Deallocate Emu10k1 caches and recording buffers. Again it will be
-	 * removed because it will be done in voice shutdown.
-	 */
-	emuxki_write(sc, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE);
-	emuxki_write(sc, 0, EMU_MICBA, 0);
-	emuxki_write(sc, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE);
-	emuxki_write(sc, 0, EMU_FXBA, 0);
-	if(sc->sc_type & EMUXKI_AUDIGY) {
-		emuxki_write(sc, 0, EMU_A_FXWC1, 0);
-		emuxki_write(sc, 0, EMU_A_FXWC2, 0);
+	if (sc->sc_type & EMUXKI_AUDIGY) {
+		reg = EMU_A_MICROCODEBASE;
+		loword = (x << 12) & EMU_A_DSP_LOWORD_OPX_MASK;
+		loword |= y & EMU_A_DSP_LOWORD_OPY_MASK;
+		hiword = (op << 24) & EMU_A_DSP_HIWORD_OPCODE_MASK;
+		hiword |= (r << 12) & EMU_A_DSP_HIWORD_RESULT_MASK;
+		hiword |= a & EMU_A_DSP_HIWORD_OPA_MASK;
 	} else {
-		emuxki_write(sc, 0, EMU_FXWC, 0);
+		reg = EMU_MICROCODEBASE;
+		loword = (x << 10) & EMU_DSP_LOWORD_OPX_MASK;
+		loword |= y & EMU_DSP_LOWORD_OPY_MASK;
+		hiword = (op << 20) & EMU_DSP_HIWORD_OPCODE_MASK;
+		hiword |= (r << 10) & EMU_DSP_HIWORD_RESULT_MASK;
+		hiword |= a & EMU_DSP_HIWORD_OPA_MASK;
 	}
-	emuxki_write(sc, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE);
-	emuxki_write(sc, 0, EMU_ADCBA, 0);
-
-	/*
-	 * XXX I don't know yet how I will handle tank cache buffer,
-	 * I don't even clearly  know what it is for.
-	 */
-	emuxki_write(sc, 0, EMU_TCB, 0);	/* 16K again */
-	emuxki_write(sc, 0, EMU_TCBS, 0);
 
-	emuxki_write(sc, 0, EMU_DBG, 0x8000);	/* necessary ? */
+	reg += (*pc) * 2;
+	/* must ordering; lo, hi */
+	emuxki_write(sc, 0, reg, loword);
+	emuxki_write(sc, 0, reg + 1, hiword);
 
-	dmamem_free(sc->silentpage);
-	dmamem_free(sc->ptb);
+	(*pc)++;
 }
 
-/* Emu10k1 Memory management */
-
-static struct emuxki_mem *
-emuxki_mem_new(struct emuxki_softc *sc, int ptbidx, size_t size)
+static void
+emuxki_initfx(struct emuxki_softc *sc)
 {
-	struct emuxki_mem *mem;
+	uint16_t pc;
 
-	mem = kmem_alloc(sizeof(*mem), KM_SLEEP);
-	mem->ptbidx = ptbidx;
-	if ((mem->dmamem = dmamem_alloc(sc->sc_dmat, size, EMU_DMA_ALIGN,
-	    EMU_DMAMEM_NSEG)) == NULL) {
-		kmem_free(mem, sizeof(*mem));
-		return NULL;
+	/* Set all GPRs to 0 */
+	for (pc = 0; pc < 256; pc++)
+		emuxki_write(sc, 0, EMU_DSP_GPR(pc), 0);
+	for (pc = 0; pc < 160; pc++) {
+		emuxki_write(sc, 0, EMU_TANKMEMDATAREGBASE + pc, 0);
+		emuxki_write(sc, 0, EMU_TANKMEMADDRREGBASE + pc, 0);
 	}
-	return mem;
-}
-
-static void
-emuxki_mem_delete(struct emuxki_mem *mem, size_t size)
-{
 
-	dmamem_free(mem->dmamem);
-	kmem_free(mem, sizeof(*mem));
-}
+	/* stop DSP, single step mode */
+	emuxki_write(sc, 0, X1(DBG), X1(DBG_SINGLE_STEP));
 
-static void *
-emuxki_pmem_alloc(struct emuxki_softc *sc, size_t size)
-{
-	int i, j;
-	size_t numblocks;
-	struct emuxki_mem *mem;
-	uint32_t *ptb, silentpage;
-
-	ptb = KERNADDR(sc->ptb);
-	silentpage = DMAADDR(sc->silentpage) << 1;
-	numblocks = size / EMU_PTESIZE;
-	if (size % EMU_PTESIZE)
-		numblocks++;
-
-	for (i = 0; i < EMU_MAXPTE; i++) {
-		mutex_spin_enter(&sc->sc_intr_lock);
-		if ((le32toh(ptb[i]) & EMU_CHAN_MAP_PTE_MASK) == silentpage) {
-			/* We look for a free PTE */
-			for (j = 0; j < numblocks; j++)
-				if ((le32toh(ptb[i + j])
-				    & EMU_CHAN_MAP_PTE_MASK) != silentpage)
-					break;
-			if (j == numblocks) {
-				mutex_spin_exit(&sc->sc_intr_lock);
-				if ((mem = emuxki_mem_new(sc, i,
-						size)) == NULL) {
-					return NULL;
-				}
-				mutex_spin_enter(&sc->sc_intr_lock);
-				for (j = 0; j < numblocks; j++)
-					ptb[i + j] =
-					    htole32((((DMAADDR(mem->dmamem) +
-					    j * EMU_PTESIZE)) << 1) | (i + j));
-				LIST_INSERT_HEAD(&(sc->mem), mem, next);
-				mutex_spin_exit(&sc->sc_intr_lock);
-				return (KERNADDR(mem->dmamem));
-			} else
-				i += j;
-		}
-		mutex_spin_exit(&sc->sc_intr_lock);
-	}
-	return NULL;
-}
+	/* XXX: delay (48kHz equiv. 21us) if needed */
 
-static void *
-emuxki_rmem_alloc(struct emuxki_softc *sc, size_t size)
-{
-	struct emuxki_mem *mem;
+	/* start DSP programming */
+	pc = 0;
 
-	mem = emuxki_mem_new(sc, EMU_RMEM, size);
-	if (mem == NULL)
-		return NULL;
+	/* OUT[L/R] = 0 + FX[L/R] * 1 */
+	emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
+	    X2(DSP_OUTL, DSP_OUT_A_FRONT),
+	    X1(DSP_CST(0)),
+	    X1(DSP_FX(0)),
+	    X1(DSP_CST(1)));
+	emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
+	    X2(DSP_OUTR, DSP_OUT_A_FRONT),
+	    X1(DSP_CST(0)),
+	    X1(DSP_FX(1)),
+	    X1(DSP_CST(1)));
+#if 0
+	/* XXX: rear feature??? */
+	/* Rear OUT[L/R] = 0 + FX[L/R] * 1 */
+	emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
+	    X2(DSP_OUTL, DSP_OUT_A_REAR),
+	    X1(DSP_CST(0)),
+	    X1(DSP_FX(0)),
+	    X1(DSP_CST(1)));
+	emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
+	    X2(DSP_OUTR, DSP_OUT_A_REAR),
+	    X1(DSP_CST(0)),
+	    X1(DSP_FX(1)),
+	    X1(DSP_CST(1)));
+#endif
+	/* ADC recording[L/R] = AC97 In[L/R] */
+	emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
+	    X2(DSP_OUTL, DSP_OUT_ADC),
+	    X2(DSP_INL, DSP_IN_AC97),
+	    X1(DSP_CST(0)),
+	    X1(DSP_CST(0)));
+	emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
+	    X2(DSP_OUTR, DSP_OUT_ADC),
+	    X2(DSP_INR, DSP_IN_AC97),
+	    X1(DSP_CST(0)),
+	    X1(DSP_CST(0)));
 
-	mutex_spin_enter(&sc->sc_intr_lock);
-	LIST_INSERT_HEAD(&(sc->mem), mem, next);
-	mutex_spin_exit(&sc->sc_intr_lock);
+	/* fill NOP the rest of the microcode */
+	while (pc < 512) {
+		emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
+		    X1(DSP_CST(0)),
+		    X1(DSP_CST(0)),
+		    X1(DSP_CST(0)),
+		    X1(DSP_CST(0)));
+	}
 
-	return KERNADDR(mem->dmamem);
+	/* clear single step flag, run DSP */
+	emuxki_write(sc, 0, X1(DBG), 0);
 }
 
 /*
- * emuxki_channel_* : Channel management functions
- * emuxki_chanparms_* : Channel parameters modification functions
+ * operations
  */
 
-/*
- * is splaudio necessary here, can the same voice be manipulated by two
- * different threads at a time ?
- */
 static void
-emuxki_chanparms_set_defaults(struct emuxki_channel *chan)
+emuxki_play_start(struct emuxki_softc *sc, int ch, uint32_t start, uint32_t end)
 {
+	uint32_t pitch;
+	uint32_t volume;
 
-	chan->fxsend.a.level = chan->fxsend.b.level =
-	chan->fxsend.c.level = chan->fxsend.d.level =
-	/* for audigy */
-	chan->fxsend.e.level = chan->fxsend.f.level =
-	chan->fxsend.g.level = chan->fxsend.h.level =
-		chan->voice->sc->sc_type & EMUXKI_AUDIGY ?
-			0xc0 : 0xff;	/* not max */
-
-	chan->fxsend.a.dest = 0x0;
-	chan->fxsend.b.dest = 0x1;
-	chan->fxsend.c.dest = 0x2;
-	chan->fxsend.d.dest = 0x3;
-	/* for audigy */
-	chan->fxsend.e.dest = 0x4;
-	chan->fxsend.f.dest = 0x5;
-	chan->fxsend.g.dest = 0x6;
-	chan->fxsend.h.dest = 0x7;
-
-	chan->pitch.initial = 0x0000;	/* shouldn't it be 0xE000 ? */
-	chan->pitch.current = 0x0000;	/* should it be 0x0400 */
-	chan->pitch.target = 0x0000;	/* the unity pitch shift ? */
-	chan->pitch.envelope_amount = 0x00;	/* none */
-
-	chan->initial_attenuation = 0x00;	/* no attenuation */
-	chan->volume.current = 0x0000;	/* no volume */
-	chan->volume.target = 0xffff;
-	chan->volume.envelope.current_state = 0x8000;	/* 0 msec delay */
-	chan->volume.envelope.hold_time = 0x7f;	/* 0 msec */
-	chan->volume.envelope.attack_time = 0x7F;	/* 5.5msec */
-	chan->volume.envelope.sustain_level = 0x7F;	/* full  */
-	chan->volume.envelope.decay_time = 0x7F;	/* 22msec  */
-
-	chan->filter.initial_cutoff_frequency = 0xff;	/* no filter */
-	chan->filter.current_cutoff_frequency = 0xffff;	/* no filtering */
-	chan->filter.target_cutoff_frequency = 0xffff;	/* no filtering */
-	chan->filter.lowpass_resonance_height = 0x0;
-	chan->filter.interpolation_ROM = 0x1;	/* full band */
-	chan->filter.envelope_amount = 0x7f;	/* none */
-	chan->filter.LFO_modulation_depth = 0x00;	/* none */
-
-	chan->loop.start = 0x000000;
-	chan->loop.end = 0x000010;	/* Why ? */
-
-	chan->modulation.envelope.current_state = 0x8000;
-	chan->modulation.envelope.hold_time = 0x00;	/* 127 better ? */
-	chan->modulation.envelope.attack_time = 0x00;	/* infinite */
-	chan->modulation.envelope.sustain_level = 0x00;	/* off */
-	chan->modulation.envelope.decay_time = 0x7f;	/* 22 msec */
-	chan->modulation.LFO_state = 0x8000;
-
-	chan->vibrato_LFO.state = 0x8000;
-	chan->vibrato_LFO.modulation_depth = 0x00;	/* none */
-	chan->vibrato_LFO.vibrato_depth = 0x00;
-	chan->vibrato_LFO.frequency = 0x00;	/* Why set to 24 when
-						 * initialized ? */
-
-	chan->tremolo_depth = 0x00;
-}
-
-/* only call it at splaudio */
-static struct emuxki_channel *
-emuxki_channel_new(struct emuxki_voice *voice, u_int8_t num)
-{
-	struct emuxki_channel *chan;
-
-	chan = malloc(sizeof(struct emuxki_channel), M_DEVBUF, M_WAITOK);
-	if (chan == NULL)
-		return NULL;
-
-	chan->voice = voice;
-	chan->num = num;
-	emuxki_chanparms_set_defaults(chan);
-	chan->voice->sc->channel[num] = chan;
-	return chan;
-}
-
-/* only call it at splaudio */
-static void
-emuxki_channel_delete(struct emuxki_channel *chan)
-{
+	/* 48kHz:16384 = 128/375 */
+	pitch = sc->play.sample_rate * 128 / 375;
+	volume = 32767;
 
-	chan->voice->sc->channel[chan->num] = NULL;
-	free(chan, M_DEVBUF);
-}
+	emuxki_write(sc, ch, EMU_CHAN_DSL,
+	    (0 << 24) |	/* send amound D = 0 */
+	    end);
 
-static void
-emuxki_channel_set_fxsend(struct emuxki_channel *chan,
-    struct emuxki_chanparms_fxsend *fxsend)
-{
-	/* Could do a memcpy ...*/
-	chan->fxsend.a.level = fxsend->a.level;
-	chan->fxsend.b.level = fxsend->b.level;
-	chan->fxsend.c.level = fxsend->c.level;
-	chan->fxsend.d.level = fxsend->d.level;
-	chan->fxsend.a.dest = fxsend->a.dest;
-	chan->fxsend.b.dest = fxsend->b.dest;
-	chan->fxsend.c.dest = fxsend->c.dest;
-	chan->fxsend.d.dest = fxsend->d.dest;
-
-	/* for audigy */
-	chan->fxsend.e.level = fxsend->e.level;
-	chan->fxsend.f.level = fxsend->f.level;
-	chan->fxsend.g.level = fxsend->g.level;
-	chan->fxsend.h.level = fxsend->h.level;
-	chan->fxsend.e.dest = fxsend->e.dest;
-	chan->fxsend.f.dest = fxsend->f.dest;
-	chan->fxsend.g.dest = fxsend->g.dest;
-	chan->fxsend.h.dest = fxsend->h.dest;
-}
+	emuxki_write(sc, ch, EMU_CHAN_PSST,
+	    (0 << 24) |	/* send amount C = 0 */
+	    start);
 
-static void
-emuxki_channel_set_srate(struct emuxki_channel *chan, uint32_t srate)
-{
+	emuxki_write(sc, ch, EMU_CHAN_VTFT,
+	    (volume << 16) |
+	    (0xffff));	/* cutoff filter = none */
 
-	chan->pitch.target = (srate << 8) / 375;
-	chan->pitch.target = (chan->pitch.target >> 1) +
-		(chan->pitch.target & 1);
-	chan->pitch.target &= 0xffff;
-	chan->pitch.current = chan->pitch.target;
-	chan->pitch.initial =
-		(emuxki_rate_to_pitch(srate) >> 8) & EMU_CHAN_IP_MASK;
-}
+	emuxki_write(sc, ch, EMU_CHAN_CVCF,
+	    (volume << 16) |
+	    (0xffff));	/* cutoff filter = none */
 
-/* voice params must be set before calling this */
-static void
-emuxki_channel_set_bufparms(struct emuxki_channel *chan,
-    uint32_t start, uint32_t end)
-{
+	emuxki_write(sc, ch, EMU_CHAN_PTRX,
+	    (pitch << 16) |
+	    ((ch == 0 ? 0x7f : 0) << 8) |	/* send amount A = 255,0(L) */
+	    ((ch == 0 ? 0 : 0x7f)));		/* send amount B = 0,255(R) */
 
-	chan->loop.start = start & EMU_CHAN_PSST_LOOPSTARTADDR_MASK;
-	chan->loop.end = end & EMU_CHAN_DSL_LOOPENDADDR_MASK;
+	/* set the pitch to start */
+	emuxki_write(sc, ch, EMU_CHAN_CPF,
+	    (pitch << 16) |
+	    EMU_CHAN_CPF_STEREO_MASK);	/* stereo only */
 }
 
 static void
-emuxki_channel_commit_fx(struct emuxki_channel *chan)
+emuxki_play_stop(struct emuxki_softc *sc, int ch)
 {
-	struct emuxki_softc *sc;
-	u_int8_t chano;
-
-	sc = chan->voice->sc;
-	chano = chan->num;
-	if(sc->sc_type & EMUXKI_AUDIGY) {
-		emuxki_write(sc, chano, EMU_A_CHAN_FXRT1,
-			      (chan->fxsend.d.dest << 24) |
-			      (chan->fxsend.c.dest << 16) |
-			      (chan->fxsend.b.dest << 8) |
-			      (chan->fxsend.a.dest));
-		emuxki_write(sc, chano, EMU_A_CHAN_FXRT2,
-			      (chan->fxsend.h.dest << 24) |
-			      (chan->fxsend.g.dest << 16) |
-			      (chan->fxsend.f.dest << 8) |
-			      (chan->fxsend.e.dest));
-		emuxki_write(sc, chano, EMU_A_CHAN_SENDAMOUNTS,
-			      (chan->fxsend.e.level << 24) |
-			      (chan->fxsend.f.level << 16) |
-			      (chan->fxsend.g.level << 8) |
-			      (chan->fxsend.h.level));
-	} else {
-		emuxki_write(sc, chano, EMU_CHAN_FXRT,
-			      (chan->fxsend.d.dest << 28) |
-			      (chan->fxsend.c.dest << 24) |
-			      (chan->fxsend.b.dest << 20) |
-			      (chan->fxsend.a.dest << 16));
-	}
 
-	emuxki_write(sc, chano, 0x10000000 | EMU_CHAN_PTRX,
-		      (chan->fxsend.a.level << 8) | chan->fxsend.b.level);
-	emuxki_write(sc, chano, EMU_CHAN_DSL,
-		      (chan->fxsend.d.level << 24) | chan->loop.end);
-	emuxki_write(sc, chano, EMU_CHAN_PSST,
-		      (chan->fxsend.c.level << 24) | chan->loop.start);
+	/* pitch = 0 to stop playing */
+	emuxki_write(sc, ch, EMU_CHAN_CPF, EMU_CHAN_CPF_STOP_MASK);
+	/* volume = 0 */
+	emuxki_write(sc, ch, EMU_CHAN_CVCF, 0);
 }
 
 static void
-emuxki_channel_commit_parms(struct emuxki_channel *chan)
+emuxki_timer_start(struct emuxki_softc *sc)
 {
-	struct emuxki_voice *voice;
-	struct emuxki_softc *sc;
-	uint32_t start, mapval;
-	uint8_t chano;
+	uint32_t timer;
 
-	voice = chan->voice;
-	sc = voice->sc;
-	chano = chan->num;
-	start = chan->loop.start +
-		(voice->stereo ? 28 : 30) * (voice->b16 + 1);
-	mapval = DMAADDR(sc->silentpage) << 1 | EMU_CHAN_MAP_PTI_MASK;
-
-	KASSERT(mutex_owned(&sc->sc_intr_lock));
-	emuxki_write(sc, chano, EMU_CHAN_CPF_STEREO, voice->stereo);
-
-	emuxki_channel_commit_fx(chan);
-
-	emuxki_write(sc, chano, EMU_CHAN_CCCA,
-		(chan->filter.lowpass_resonance_height << 28) |
-		(chan->filter.interpolation_ROM << 25) |
-		(voice->b16 ? 0 : EMU_CHAN_CCCA_8BITSELECT) | start);
-	emuxki_write(sc, chano, EMU_CHAN_Z1, 0);
-	emuxki_write(sc, chano, EMU_CHAN_Z2, 0);
-	emuxki_write(sc, chano, EMU_CHAN_MAPA, mapval);
-	emuxki_write(sc, chano, EMU_CHAN_MAPB, mapval);
-	emuxki_write(sc, chano, EMU_CHAN_CVCF_CURRFILTER,
-		chan->filter.current_cutoff_frequency);
-	emuxki_write(sc, chano, EMU_CHAN_VTFT_FILTERTARGET,
-		chan->filter.target_cutoff_frequency);
-	emuxki_write(sc, chano, EMU_CHAN_ATKHLDM,
-		(chan->modulation.envelope.hold_time << 8) |
-		chan->modulation.envelope.attack_time);
-	emuxki_write(sc, chano, EMU_CHAN_DCYSUSM,
-		(chan->modulation.envelope.sustain_level << 8) |
-		chan->modulation.envelope.decay_time);
-	emuxki_write(sc, chano, EMU_CHAN_LFOVAL1,
-		chan->modulation.LFO_state);
-	emuxki_write(sc, chano, EMU_CHAN_LFOVAL2,
-		chan->vibrato_LFO.state);
-	emuxki_write(sc, chano, EMU_CHAN_FMMOD,
-		(chan->vibrato_LFO.modulation_depth << 8) |
-		chan->filter.LFO_modulation_depth);
-	emuxki_write(sc, chano, EMU_CHAN_TREMFRQ,
-		(chan->tremolo_depth << 8));
-	emuxki_write(sc, chano, EMU_CHAN_FM2FRQ2,
-		(chan->vibrato_LFO.vibrato_depth << 8) |
-		chan->vibrato_LFO.frequency);
-	emuxki_write(sc, chano, EMU_CHAN_ENVVAL,
-		chan->modulation.envelope.current_state);
-	emuxki_write(sc, chano, EMU_CHAN_ATKHLDV,
-		(chan->volume.envelope.hold_time << 8) |
-		chan->volume.envelope.attack_time);
-	emuxki_write(sc, chano, EMU_CHAN_ENVVOL,
-		chan->volume.envelope.current_state);
-	emuxki_write(sc, chano, EMU_CHAN_PEFE,
-		(chan->pitch.envelope_amount << 8) |
-		chan->filter.envelope_amount);
-}
-
-static void
-emuxki_channel_start(struct emuxki_channel *chan)
-{
-	struct emuxki_voice *voice;
-	struct emuxki_softc *sc;
-	u_int8_t cache_sample, cache_invalid_size, chano;
-	u_int32_t sample;
+	/* frame count of half PTE at 16bit, 2ch, 48kHz */
+	timer = EMU_PTESIZE / 4 / 2;
 
-	voice = chan->voice;
-	sc = voice->sc;
-	chano = chan->num;
-	cache_sample = voice->stereo ? 4 : 2;
-	sample = voice->b16 ? 0x00000000 : 0x80808080;
-	cache_invalid_size = (voice->stereo ? 28 : 30) * (voice->b16 + 1);
-
-	KASSERT(mutex_owned(&sc->sc_intr_lock));
-	while (cache_sample--) {
-		emuxki_write(sc, chano, EMU_CHAN_CD0 + cache_sample,
-			sample);
-	}
-	emuxki_write(sc, chano, EMU_CHAN_CCR_CACHEINVALIDSIZE, 0);
-	emuxki_write(sc, chano, EMU_CHAN_CCR_READADDRESS, 64);
-	emuxki_write(sc, chano, EMU_CHAN_CCR_CACHEINVALIDSIZE,
-		cache_invalid_size);
-	emuxki_write(sc, chano, EMU_CHAN_IFATN,
-		(chan->filter.target_cutoff_frequency << 8) |
-		chan->initial_attenuation);
-	emuxki_write(sc, chano, EMU_CHAN_VTFT_VOLUMETARGET,
-		chan->volume.target);
-	emuxki_write(sc, chano, EMU_CHAN_CVCF_CURRVOL,
-		chan->volume.current);
-	emuxki_write(sc, 0,
-		EMU_MKSUBREG(1, chano, EMU_SOLEL + (chano >> 5)),
-		0);	/* Clear stop on loop */
-	emuxki_write(sc, 0,
-		EMU_MKSUBREG(1, chano, EMU_CLIEL + (chano >> 5)),
-		0);	/* Clear loop interrupt */
-	emuxki_write(sc, chano, EMU_CHAN_DCYSUSV,
-		(chan->volume.envelope.sustain_level << 8) |
-		chan->volume.envelope.decay_time);
-	emuxki_write(sc, chano, EMU_CHAN_PTRX_PITCHTARGET,
-		chan->pitch.target);
-	emuxki_write(sc, chano, EMU_CHAN_CPF_PITCH,
-		chan->pitch.current);
-	emuxki_write(sc, chano, EMU_CHAN_IP, chan->pitch.initial);
+	/* EMU_TIMER is 16bit register */
+	emuxki_writeio_2(sc, EMU_TIMER, timer);
+	emuxki_writeio_4(sc, EMU_INTE,
+	    emuxki_readio_4(sc, EMU_INTE) |
+	        EMU_INTE_INTERTIMERENB);
+	DPRINTF("timer start\n");
 }
 
 static void
-emuxki_channel_stop(struct emuxki_channel *chan)
+emuxki_timer_stop(struct emuxki_softc *sc)
 {
-	struct emuxki_softc *sc;
-	u_int8_t chano;
 
-	sc = chan->voice->sc;
-	chano = chan->num;
-	KASSERT(mutex_owned(&sc->sc_intr_lock));
-	emuxki_write(sc, chano, EMU_CHAN_PTRX_PITCHTARGET, 0);
-	emuxki_write(sc, chano, EMU_CHAN_CPF_PITCH, 0);
-	emuxki_write(sc, chano, EMU_CHAN_IFATN_ATTENUATION, 0xff);
-	emuxki_write(sc, chano, EMU_CHAN_VTFT_VOLUMETARGET, 0);
-	emuxki_write(sc, chano, EMU_CHAN_CVCF_CURRVOL, 0);
-	emuxki_write(sc, chano, EMU_CHAN_IP, 0);
+	emuxki_writeio_4(sc, EMU_INTE,
+	    emuxki_readio_4(sc, EMU_INTE) &
+	        ~EMU_INTE_INTERTIMERENB);
+	/* EMU_TIMER is 16bit register */
+	emuxki_writeio_2(sc, EMU_TIMER, 0);
+	DPRINTF("timer stop\n");
 }
 
 /*
- * Voices management
- * emuxki_voice_dataloc : use(play or rec) independent dataloc union helpers
- * emuxki_voice_channel_* : play part of dataloc union helpers
- * emuxki_voice_recsrc_* : rec part of dataloc union helpers
+ * audio interface
  */
 
-/* Allocate channels for voice in case of play voice */
 static int
-emuxki_voice_channel_create(struct emuxki_voice *voice)
+emuxki_open(void *hdl, int flags)
 {
-	struct emuxki_channel **channel;
-	uint8_t i, stereo;
 
-	channel = voice->sc->channel;
-	stereo = voice->stereo;
-	for (i = 0; i < EMU_NUMCHAN - stereo; i += stereo + 1) {
-		if ((stereo && (channel[i + 1] != NULL)) ||
-		    (channel[i] != NULL))	/* Looking for free channels */
-			continue;
-			
-		if (stereo) {
-			voice->dataloc.chan[1] =
-				emuxki_channel_new(voice, i + 1);
-			if (voice->dataloc.chan[1] == NULL)
-				return ENOMEM;
-		}
-		voice->dataloc.chan[0] = emuxki_channel_new(voice, i);
-		if (voice->dataloc.chan[0] == NULL) {
-			if (stereo) {
-				emuxki_channel_delete(voice->dataloc.chan[1]);
-				voice->dataloc.chan[1] = NULL;
-			}
-			return ENOMEM;
-		}
-		return 0;
-	}
-	return EAGAIN;
+	DPRINTF("%s for %s%s\n", __func__,
+	    (flags & FWRITE) ? "P" : "",
+	    (flags & FREAD)  ? "R" : "");
+
+	return 0;
 }
 
-/* When calling this function we assume no one can access the voice */
 static void
-emuxki_voice_channel_destroy(struct emuxki_voice *voice)
+emuxki_close(void *hdl)
 {
 
-	emuxki_channel_delete(voice->dataloc.chan[0]);
-	voice->dataloc.chan[0] = NULL;
-	if (voice->stereo)
-		emuxki_channel_delete(voice->dataloc.chan[1]);
-	voice->dataloc.chan[1] = NULL;
+	DPRINTF("%s\n", __func__);
 }
 
-/*
- * Will come back when used in voice_dataloc_create
- */
 static int
-emuxki_recsrc_reserve(struct emuxki_voice *voice, emuxki_recsrc_t source)
-{
-
-	if (source >= EMU_NUMRECSRCS) {
-#ifdef EMUXKI_DEBUG
-		printf("Tried to reserve invalid source: %d\n", source);
-#endif
-		return EINVAL;
-	}
-	if (voice->sc->recsrc[source] == voice)
-		return 0;			/* XXX */
-	if (voice->sc->recsrc[source] != NULL)
-		return EBUSY;
-	voice->sc->recsrc[source] = voice;
-	return 0;
-}
-
-/* When calling this function we assume the voice is stopped */
-static void
-emuxki_voice_recsrc_release(struct emuxki_softc *sc, emuxki_recsrc_t source)
+emuxki_query_format(void *hdl, audio_format_query_t *afp)
 {
 
-	sc->recsrc[source] = NULL;
+	return audio_query_format(emuxki_formats, EMUXKI_NFORMATS, afp);
 }
 
 static int
-emuxki_voice_dataloc_create(struct emuxki_voice *voice)
+emuxki_set_format(void *hdl, int setmode,
+    const audio_params_t *play, const audio_params_t *rec,
+    audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
 {
-	int error;
+	struct emuxki_softc *sc = hdl;
 
-	if (voice->use & EMU_VOICE_USE_PLAY) {
-		if ((error = emuxki_voice_channel_create(voice)))
-			return error;
-	} else {
-		if ((error =
-		    emuxki_recsrc_reserve(voice, voice->dataloc.source)))
-			return error;
-	}
+	if ((setmode & AUMODE_PLAY))
+		sc->play = *play;
+	if ((setmode & AUMODE_RECORD))
+		sc->rec = *rec;
 	return 0;
 }
 
-static void
-emuxki_voice_dataloc_destroy(struct emuxki_voice *voice)
+static int
+emuxki_halt_output(void *hdl)
 {
+	struct emuxki_softc *sc = hdl;
 
-	if (voice->use & EMU_VOICE_USE_PLAY) {
-		if (voice->dataloc.chan[0] != NULL)
-			emuxki_voice_channel_destroy(voice);
-	} else {
-		if (voice->dataloc.source != EMU_RECSRC_NOTSET) {
-			emuxki_voice_recsrc_release(voice->sc,
-						     voice->dataloc.source);
-			voice->dataloc.source = EMU_RECSRC_NOTSET;
-		}
-	}
+	emuxki_timer_stop(sc);
+	emuxki_play_stop(sc, 0);
+	emuxki_play_stop(sc, 1);
+	return 0;
 }
 
-static struct emuxki_voice *
-emuxki_voice_new(struct emuxki_softc *sc, uint8_t use)
+static int
+emuxki_halt_input(void *hdl)
 {
-	struct emuxki_voice *voice;
-
-	KASSERT(mutex_owned(&sc->sc_intr_lock));
-
-	voice = sc->lvoice;
-	sc->lvoice = NULL;
-
-	if (!voice) {
-		mutex_exit(&sc->sc_intr_lock);
-		voice = kmem_alloc(sizeof(*voice), KM_SLEEP);
-		mutex_enter(&sc->sc_intr_lock);
-	} else if (voice->use != use) {
-		mutex_exit(&sc->sc_intr_lock);
-		emuxki_voice_dataloc_destroy(voice);
-		mutex_enter(&sc->sc_intr_lock);
-	} else
-		goto skip_initialize;
-
-	voice->sc = sc;
-	voice->state = !EMU_VOICE_STATE_STARTED;
-	voice->stereo = EMU_VOICE_STEREO_NOTSET;
-	voice->b16 = 0;
-	voice->sample_rate = 0;
-	if (use & EMU_VOICE_USE_PLAY)
-		voice->dataloc.chan[0] = voice->dataloc.chan[1] = NULL;
-	else
-		voice->dataloc.source = EMU_RECSRC_NOTSET;
-	voice->buffer = NULL;
-	voice->blksize = 0;
-	voice->trigblk = 0;
-	voice->blkmod = 0;
-	voice->inth = NULL;
-	voice->inthparam = NULL;
-	voice->use = use;
-
-skip_initialize:
-	LIST_INSERT_HEAD((&sc->voices), voice, next);
+	struct emuxki_softc *sc = hdl;
 
-	return voice;
-}
-
-static void
-emuxki_voice_delete(struct emuxki_voice *voice)
-{
-	struct emuxki_softc *sc;
-	struct emuxki_voice *lvoice;
+	/* stop ADC */
+	emuxki_write(sc, 0, EMU_ADCCR, 0);
 
-	sc = voice->sc;
-	if (voice->state & EMU_VOICE_STATE_STARTED)
-		emuxki_voice_halt(voice);
-
-	LIST_REMOVE(voice, next);
-	lvoice = sc->lvoice;
-	sc->lvoice = voice;
-
-	if (lvoice) {
-		mutex_exit(&sc->sc_lock);
-		emuxki_voice_dataloc_destroy(lvoice);
-		kmem_free(lvoice, sizeof(*lvoice));
-		mutex_enter(&sc->sc_lock);
-	}
-}
+	/* disable interrupt */
+	emuxki_writeio_4(sc, EMU_INTE,
+	    emuxki_readio_4(sc, EMU_INTE) &
+	        ~EMU_INTE_ADCBUFENABLE);
 
-static int
-emuxki_voice_set_stereo(struct emuxki_softc *sc,
-    			struct emuxki_voice *voice, uint8_t stereo)
-{
-	int error;
-	emuxki_recsrc_t source;
-	struct emuxki_chanparms_fxsend fxsend;
-
-	source = 0;		/* XXX: gcc */
-	if (! (voice->use & EMU_VOICE_USE_PLAY))
-		source = voice->dataloc.source;
-	mutex_exit(&sc->sc_lock);
-	emuxki_voice_dataloc_destroy(voice);
-	if (! (voice->use & EMU_VOICE_USE_PLAY))
-		voice->dataloc.source = source;
-	voice->stereo = stereo;
-	error = emuxki_voice_dataloc_create(voice);
-	mutex_enter(&sc->sc_lock);
-	if (error)
-		return error;
-	if (voice->use & EMU_VOICE_USE_PLAY) {
-		fxsend.a.dest = 0x0;
-		fxsend.b.dest = 0x1;
-		fxsend.c.dest = 0x2;
-		fxsend.d.dest = 0x3;
-		/* for audigy */
-		fxsend.e.dest = 0x4;
-		fxsend.f.dest = 0x5;
-		fxsend.g.dest = 0x6;
-		fxsend.h.dest = 0x7;
-		if (voice->stereo) {
-			fxsend.a.level = fxsend.c.level = 0xc0;
-			fxsend.b.level = fxsend.d.level = 0x00;
-			fxsend.e.level = fxsend.g.level = 0xc0;
-			fxsend.f.level = fxsend.h.level = 0x00;
-			emuxki_channel_set_fxsend(voice->dataloc.chan[0],
-						   &fxsend);
-			fxsend.a.level = fxsend.c.level = 0x00;
-			fxsend.b.level = fxsend.d.level = 0xc0;
-			fxsend.e.level = fxsend.g.level = 0x00;
-			fxsend.f.level = fxsend.h.level = 0xc0;
-			emuxki_channel_set_fxsend(voice->dataloc.chan[1],
-						   &fxsend);
-		} /* No else : default is good for mono */
-	}
 	return 0;
 }
 
 static int
-emuxki_voice_set_srate(struct emuxki_voice *voice, uint32_t srate)
+emuxki_intr(void *hdl)
 {
+	struct emuxki_softc *sc = hdl;
+	uint32_t ipr;
+	uint32_t curaddr;
+	int handled = 0;
 
-	if (voice->use & EMU_VOICE_USE_PLAY) {
-		if ((srate < 4000) || (srate > 48000))
-			return EINVAL;
-		voice->sample_rate = srate;
-		emuxki_channel_set_srate(voice->dataloc.chan[0], srate);
-		if (voice->stereo)
-			emuxki_channel_set_srate(voice->dataloc.chan[1],
-						  srate);
-	} else {
-		if ((srate < 8000) || (srate > 48000))
-			return EINVAL;
-		voice->sample_rate = srate;
-		if (emuxki_voice_adc_rate(voice) < 0) {
-			voice->sample_rate = 0;
-			return EINVAL;
+	mutex_spin_enter(&sc->sc_intr_lock);
+
+	ipr = emuxki_readio_4(sc, EMU_IPR);
+	DPRINTFN(3, "emuxki: ipr=%08x\n", ipr);
+	if (sc->pintr && (ipr & EMU_IPR_INTERVALTIMER)) {
+		/* read ch 0 */
+		curaddr = emuxki_read(sc, 0, EMU_CHAN_CCCA) &
+		    EMU_CHAN_CCCA_CURRADDR_MASK;
+		DPRINTFN(3, "curaddr=%08x\n", curaddr);
+		curaddr *= sc->pframesize;
+
+		if (curaddr < sc->poffset)
+			curaddr += sc->plength;
+		if (curaddr >= sc->poffset + sc->pblksize) {
+			dmamem_sync(sc->pmem, BUS_DMASYNC_POSTWRITE);
+			sc->pintr(sc->pintrarg);
+			sc->poffset += sc->pblksize;
+			if (sc->poffset >= sc->plength) {
+				sc->poffset -= sc->plength;
+			}
+			dmamem_sync(sc->pmem, BUS_DMASYNC_PREWRITE);
 		}
+		handled = 1;
 	}
-	return 0;
-}
-
-static int
-emuxki_voice_set_audioparms(struct emuxki_softc *sc,
-    struct emuxki_voice *voice, uint8_t stereo, uint8_t b16, uint32_t srate)
-{
-	int error;
 
-	if (voice->stereo == stereo && voice->b16 == b16 &&
-	    voice->sample_rate == srate)
-		return 0;
+	if (sc->rintr &&
+	    (ipr & (EMU_IPR_ADCBUFHALFFULL | EMU_IPR_ADCBUFFULL))) {
+		char *src;
+		char *dst;
+
+		/* Record DMA buffer has just 2 blocks */
+		src = KERNADDR(sc->rmem);
+		if (ipr & EMU_IPR_ADCBUFFULL) {
+			/* 2nd block */
+			src += EMU_REC_DMABLKSIZE;
+		}
+		dst = (char *)sc->rptr + sc->rcurrent;
 
-#ifdef EMUXKI_DEBUG
-	printf("Setting %s voice params : %s, %u bits, %u Hz\n",
-	       (voice->use & EMU_VOICE_USE_PLAY) ? "play" : "record",
-	       stereo ? "stereo" : "mono", (b16 + 1) * 8, srate);
-#endif
-	error = 0;
-	if (voice->stereo != stereo) {
-		if ((error = emuxki_voice_set_stereo(sc, voice, stereo)))
-			return error;
-	 }
-	voice->b16 = b16;
-	if (voice->sample_rate != srate)
-		error = emuxki_voice_set_srate(voice, srate);
-	return error;
-}
-
-/* voice audio parms (see just before) must be set prior to this */
-static int
-emuxki_voice_set_bufparms(struct emuxki_voice *voice, void *ptr,
-    uint32_t bufsize, uint16_t blksize)
-{
-	struct emuxki_mem *mem;
-	struct emuxki_channel **chan;
-	uint32_t start, end;
-	uint8_t sample_size;
-	int idx;
-	int error;
-
-	error = EFAULT;
-	LIST_FOREACH(mem, &voice->sc->mem, next) {
-		if (KERNADDR(mem->dmamem) != ptr)
-			continue;
-
-		voice->buffer = mem;
-		sample_size = (voice->b16 + 1) * (voice->stereo + 1);
-		voice->trigblk = 0;	/* This shouldn't be needed */
-		voice->blkmod = bufsize / blksize;
-		if (bufsize % blksize)	  /* This should not happen */
-			voice->blkmod++;
-		error = 0;
-
-		if (voice->use & EMU_VOICE_USE_PLAY) {
-			voice->blksize = blksize / sample_size;
-			chan = voice->dataloc.chan;
-			start = mem->ptbidx << 12;
-			end = start + bufsize / sample_size;
-			emuxki_channel_set_bufparms(chan[0],
-						     start, end);
-			if (voice->stereo)
-				emuxki_channel_set_bufparms(chan[1],
-				     start, end);
-			voice->timerate = (uint32_t) 48000 *
-			    voice->blksize / voice->sample_rate;
-			if (voice->timerate < 5)
-				error = EINVAL;
-		} else {
-			voice->blksize = blksize;
-			for(idx = sizeof(emuxki_recbuf_sz) /
-			    sizeof(emuxki_recbuf_sz[0]); --idx >= 0;)
-				if (emuxki_recbuf_sz[idx] == bufsize)
-					break;
-			if (idx < 0) {
-#ifdef EMUXKI_DEBUG
-				printf("Invalid bufsize: %d\n", bufsize);
-#endif
-				return EINVAL;
-			}
-			emuxki_write(voice->sc, 0,
-			    emuxki_recsrc_szreg[voice->dataloc.source], idx);
-			emuxki_write(voice->sc, 0,
-			    emuxki_recsrc_bufaddrreg[voice->dataloc.source],
-			    DMAADDR(mem->dmamem));
-
-			/* Use timer to emulate DMA completion interrupt */
-			voice->timerate = (u_int32_t) 48000 * blksize /
-			    (voice->sample_rate * sample_size);
-			if (voice->timerate < 5) {
-#ifdef EMUXKI_DEBUG
-				printf("Invalid timerate: %d, blksize %d\n",
-				    voice->timerate, blksize);
-#endif
-				error = EINVAL;
+		dmamem_sync(sc->rmem, BUS_DMASYNC_POSTREAD);
+		memcpy(dst, src, EMU_REC_DMABLKSIZE);
+		/* for next trans */
+		dmamem_sync(sc->rmem, BUS_DMASYNC_PREREAD);
+		sc->rcurrent += EMU_REC_DMABLKSIZE;
+
+		if (sc->rcurrent >= sc->roffset + sc->rblksize) {
+			sc->rintr(sc->rintrarg);
+			sc->roffset += sc->rblksize;
+			if (sc->roffset >= sc->rlength) {
+				sc->roffset = 0;
+				sc->rcurrent = 0;
 			}
 		}
 
-		break;
+		handled = 1;
 	}
 
-	return error;
-}
+#if defined(EMUXKI_DEBUG)
+	if (!handled) {
+		char buf[1024];
+		snprintb(buf, sizeof(buf),
+		    "\20"
+		    "\x19""RATETRCHANGE"
+		    "\x18""FXDSP"
+		    "\x17""FORCEINT"
+		    "\x16""PCIERROR"
+		    "\x15""VOLINCR"
+		    "\x14""VOLDECR"
+		    "\x13""MUTE"
+		    "\x12""MICBUFFULL"
+		    "\x11""MICBUFHALFFULL"
+		    "\x10""ADCBUFFULL"
+		    "\x0f""ADCBUFHALFFULL"
+		    "\x0e""EFXBUFFULL"
+		    "\x0d""EFXBUFHALFFULL"
+		    "\x0c""GPSPDIFSTCHANGE"
+		    "\x0b""CDROMSTCHANGE"
+		    /*     INTERVALTIMER */
+		    "\x09""MIDITRANSBUFE"
+		    "\x08""MIDIRECVBUFE"
+		    "\x07""CHANNELLOOP"
+		    , ipr);
+		DPRINTF("unexpected intr: %s\n", buf);
 
-static void
-emuxki_voice_commit_parms(struct emuxki_voice *voice)
-{
-	if (voice->use & EMU_VOICE_USE_PLAY) {
-		emuxki_channel_commit_parms(voice->dataloc.chan[0]);
-		if (voice->stereo)
-			emuxki_channel_commit_parms(voice->dataloc.chan[1]);
+		/* for debugging (must not handle if !DEBUG) */
+		handled = 1;
 	}
+#endif
+
+	/* Reset interrupt bit */
+	emuxki_writeio_4(sc, EMU_IPR, ipr);
+
+	mutex_spin_exit(&sc->sc_intr_lock);
+
+	/* Interrupt handler must return !=0 if handled */
+	return handled;
 }
 
-static uint32_t
-emuxki_voice_curaddr(struct emuxki_voice *voice)
+static int
+emuxki_getdev(void *hdl, struct audio_device *dev)
 {
-	int idxreg;
-	int rv;
+	struct emuxki_softc *sc = hdl;
 
-	/* XXX different semantics in these cases */
-	if (voice->use & EMU_VOICE_USE_PLAY) {
-		/* returns number of samples (an l/r pair counts 1) */
-		rv = emuxki_read(voice->sc,
-		    voice->dataloc.chan[0]->num, EMU_CHAN_CCCA_CURRADDR) -
-		    voice->dataloc.chan[0]->loop.start;
-	} else {
-		idxreg = 0;
-		/* returns number of bytes */
-		switch (voice->dataloc.source) {
-			case EMU_RECSRC_MIC:
-				idxreg = (voice->sc->sc_type & EMUXKI_AUDIGY) ?
-					EMU_A_MICIDX : EMU_MICIDX;
-				break;
-			case EMU_RECSRC_ADC:
-				idxreg = (voice->sc->sc_type & EMUXKI_AUDIGY) ?
-					EMU_A_ADCIDX : EMU_ADCIDX;
-				break;
-			case EMU_RECSRC_FX:
-				idxreg = EMU_FXIDX;
-				break;
-			default:
-#ifdef EMUXKI_DEBUG
-				printf("emu: bad recording source!\n");
-#endif
-				break;
-		}
-		rv = emuxki_read(voice->sc, 0, EMU_RECIDX(idxreg)
-				& EMU_RECIDX_MASK);
-	}
-	return rv;
+	*dev = sc->sc_audv;
+	return 0;
 }
 
-static void
-emuxki_resched_timer(struct emuxki_softc *sc)
+static int
+emuxki_set_port(void *hdl, mixer_ctrl_t *mctl)
 {
-	struct emuxki_voice *voice;
-	uint16_t timerate;
-	uint8_t active;
-
-	timerate = 1024;
-	active = 0;
-	KASSERT(mutex_owned(&sc->sc_intr_lock));
-	LIST_FOREACH(voice, &sc->voices, next) {
-		if ((voice->state & EMU_VOICE_STATE_STARTED) == 0)
-			continue;
-		active = 1;
-		if (voice->timerate < timerate)
-			timerate = voice->timerate;
-	}
-
-	if (timerate & ~EMU_TIMER_RATE_MASK)
-		timerate = 0;
-	bus_space_write_2(sc->sc_iot, sc->sc_ioh, EMU_TIMER, timerate);
-	if (!active && (sc->timerstate & EMU_TIMER_STATE_ENABLED)) {
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_INTE,
-			bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_INTE) &
-			~EMU_INTE_INTERTIMERENB);
-		sc->timerstate &= ~EMU_TIMER_STATE_ENABLED;
-	} else if (active && !(sc->timerstate & EMU_TIMER_STATE_ENABLED)) {
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_INTE,
-			bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_INTE) |
-			EMU_INTE_INTERTIMERENB);
-		sc->timerstate |= EMU_TIMER_STATE_ENABLED;
-	}
+	struct emuxki_softc *sc = hdl;
+
+	return sc->codecif->vtbl->mixer_set_port(sc->codecif, mctl);
 }
 
 static int
-emuxki_voice_adc_rate(struct emuxki_voice *voice)
-{
-
-	switch(voice->sample_rate) {
-		case 48000:
-			return EMU_ADCCR_SAMPLERATE_48;
-			break;
-		case 44100:
-			return EMU_ADCCR_SAMPLERATE_44;
-			break;
-		case 32000:
-			return EMU_ADCCR_SAMPLERATE_32;
-			break;
-		case 24000:
-			return EMU_ADCCR_SAMPLERATE_24;
-			break;
-		case 22050:
-			return EMU_ADCCR_SAMPLERATE_22;
-			break;
-		case 16000:
-			return EMU_ADCCR_SAMPLERATE_16;
-			break;
-		case 12000:
-			if(voice->sc->sc_type & EMUXKI_AUDIGY)
-				return EMU_A_ADCCR_SAMPLERATE_12;
-			else {
-#ifdef EMUXKI_DEBUG
-				printf("recording sample_rate not supported : %u\n", voice->sample_rate);
-#endif
-				return -1;
-			}
-			break;
-		case 11000:
-			if(voice->sc->sc_type & EMUXKI_AUDIGY)
-				return EMU_A_ADCCR_SAMPLERATE_11;
-			else
-				return EMU_ADCCR_SAMPLERATE_11;
-			break;
-		case 8000:
-			if(voice->sc->sc_type & EMUXKI_AUDIGY)
-				return EMU_A_ADCCR_SAMPLERATE_8;
-			else
-				return EMU_ADCCR_SAMPLERATE_8;
-			break;
-		default:
-#ifdef EMUXKI_DEBUG
-				printf("recording sample_rate not supported : %u\n", voice->sample_rate);
-#endif
-				return -1;
-	}
-	return -1;		/* shouldn't get here */
-}
+emuxki_get_port(void *hdl, mixer_ctrl_t *mctl)
+{
+	struct emuxki_softc *sc = hdl;
 
+	return sc->codecif->vtbl->mixer_get_port(sc->codecif, mctl);
+}
 
-static void
-emuxki_voice_start(struct emuxki_voice *voice,
-    void (*inth) (void *), void *inthparam)
+static int
+emuxki_query_devinfo(void *hdl, mixer_devinfo_t *minfo)
 {
-	uint32_t val;
+	struct emuxki_softc *sc = hdl;
 
-	voice->inth = inth;
-	voice->inthparam = inthparam;
-	if (voice->use & EMU_VOICE_USE_PLAY) {
-		voice->trigblk = 1;
-		emuxki_channel_start(voice->dataloc.chan[0]);
-		if (voice->stereo)
-			emuxki_channel_start(voice->dataloc.chan[1]);
-	} else {
-		voice->trigblk = 1;
-		switch (voice->dataloc.source) {
-		case EMU_RECSRC_ADC:
-			/* XXX need to program DSP to output L+R
-			 * XXX in monaural case? */
-			if (voice->sc->sc_type & EMUXKI_AUDIGY) {
-				val = EMU_A_ADCCR_LCHANENABLE;
-				if (voice->stereo)
-					val |= EMU_A_ADCCR_RCHANENABLE;
-			} else {
-				val = EMU_ADCCR_LCHANENABLE;
-				if (voice->stereo)
-					val |= EMU_ADCCR_RCHANENABLE;
-			}
-			val |= emuxki_voice_adc_rate(voice);
-			emuxki_write(voice->sc, 0, EMU_ADCCR, 0);
-			emuxki_write(voice->sc, 0, EMU_ADCCR, val);
-			break;
-		case EMU_RECSRC_MIC:
-		case EMU_RECSRC_FX:
-			printf("unimplemented\n");
-			break;
-		case EMU_RECSRC_NOTSET:
-		default:
-			printf("Bad dataloc.source %d\n",
-			    voice->dataloc.source);
-			break;
-		}
-#if 0
-		switch (voice->dataloc.source) {
-		case EMU_RECSRC_ADC:
-		case EMU_RECSRC_FX:
-		case EMU_RECSRC_MIC:
-			/* DMA completion interrupt is useless; use timer */
-			KASSERT(mutex_owned(&sc->sc_intr_lock));
-			val = emu_rd(sc, INTE, 4);
-			val |= emuxki_recsrc_intrmasks[voice->dataloc.source];
-			emu_wr(sc, INTE, val, 4);
-			break;
-		default:
-			break;
-		}
-#endif
-	}
-	voice->state |= EMU_VOICE_STATE_STARTED;
-	emuxki_resched_timer(voice->sc);
+	return sc->codecif->vtbl->query_devinfo(sc->codecif, minfo);
 }
 
-static void
-emuxki_voice_halt(struct emuxki_voice *voice)
+static void *
+emuxki_allocm(void *hdl, int direction, size_t size)
 {
+	struct emuxki_softc *sc = hdl;
 
-	if (voice->use & EMU_VOICE_USE_PLAY) {
-		emuxki_channel_stop(voice->dataloc.chan[0]);
-		if (voice->stereo)
-			emuxki_channel_stop(voice->dataloc.chan[1]);
+	if (direction == AUMODE_PLAY) {
+		if (sc->pmem) {
+			panic("pmem already allocated\n");
+			return NULL;
+		}
+		sc->pmem = dmamem_alloc(sc, size);
+		return KERNADDR(sc->pmem);
 	} else {
-		switch (voice->dataloc.source) {
-		case EMU_RECSRC_ADC:
-			emuxki_write(voice->sc, 0, EMU_ADCCR, 0);
-			break;
-		case EMU_RECSRC_FX:
-		case EMU_RECSRC_MIC:
-			printf("unimplemented\n");
-			break;
-		default:
-		case EMU_RECSRC_NOTSET:
-			printf("Bad dataloc.source %d\n",
-			    voice->dataloc.source);
-			break;
+		/* rmem is fixed size internal DMA buffer */
+		if (sc->rmem) {
+			panic("rmem already allocated\n");
+			return NULL;
 		}
+		/* rmem fixed size */
+		sc->rmem = dmamem_alloc(sc, EMU_REC_DMASIZE);
 
-		switch (voice->dataloc.source) {
-		case EMU_RECSRC_ADC:
-		case EMU_RECSRC_FX:
-		case EMU_RECSRC_MIC:
-			/* This should reset buffer pointer */
-			emuxki_write(voice->sc, 0,
-			    emuxki_recsrc_szreg[voice->dataloc.source],
-			    EMU_RECBS_BUFSIZE_NONE);
-#if 0
-			KASSERT(mutex_owned(&sc->sc_intr_lock));
-			val = emu_rd(sc, INTE, 4);
-			val &= ~emuxki_recsrc_intrmasks[voice->dataloc.source];
-			emu_wr(sc, INTE, val, 4);
-#endif
-			break;
-		default:
-			break;
-		}
+		/* recording MI buffer is normal kmem, software trans. */
+		sc->rptr = kmem_alloc(size, KM_SLEEP);
+		return sc->rptr;
 	}
-	voice->state &= ~EMU_VOICE_STATE_STARTED;
-	emuxki_resched_timer(voice->sc);
 }
 
-/*
- * The interrupt handler
- */
-static int
-emuxki_intr(void *arg)
+static void
+emuxki_freem(void *hdl, void *ptr, size_t size)
 {
-	struct emuxki_softc *sc;
-	struct emuxki_voice *voice;
-	uint32_t ipr, curblk;
-	int claim;
-
-	sc = arg;
-	claim = 0;
-
-	mutex_spin_enter(&sc->sc_intr_lock);
-
-	while ((ipr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_IPR))) {
-		if (ipr & EMU_IPR_INTERVALTIMER) {
-			LIST_FOREACH(voice, &sc->voices, next) {
-				if ((voice->state &
-				      EMU_VOICE_STATE_STARTED) == 0)
-					continue;
-
-				curblk = emuxki_voice_curaddr(voice) /
-				       voice->blksize;
-#if 0
-				if (curblk == voice->trigblk) {
-					voice->inth(voice->inthparam);
-					voice->trigblk++;
-					voice->trigblk %= voice->blkmod;
-				}
-#else
-				while ((curblk >= voice->trigblk &&
-				    curblk < (voice->trigblk + voice->blkmod / 2)) ||
-				    ((int)voice->trigblk - (int)curblk) >
-				    (voice->blkmod / 2 + 1)) {
-					voice->inth(voice->inthparam);
-					voice->trigblk++;
-					voice->trigblk %= voice->blkmod;
-				}
-#endif
-			}
-		}
-
-		/* Got interrupt */
-		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_IPR, ipr);
+	struct emuxki_softc *sc = hdl;
 
-		claim = 1;
+	if (sc->pmem && ptr == KERNADDR(sc->pmem)) {
+		dmamem_free(sc->pmem);
+		sc->pmem = NULL;
+	}
+	if (sc->rmem && ptr == sc->rptr) {
+		dmamem_free(sc->rmem);
+		sc->rmem = NULL;
+		kmem_free(sc->rptr, size);
+		sc->rptr = NULL;
 	}
-
-	mutex_spin_exit(&sc->sc_intr_lock);
-
-	return claim;
 }
 
-
 /*
- * Audio Architecture callbacks
+ * blocksize rounding to EMU_PTESIZE. It is for easy to drive.
  */
-
 static int
-emuxki_open(void *addr, int flags)
+emuxki_round_blocksize(void *hdl, int blksize,
+    int mode, const audio_params_t* param)
 {
-	struct emuxki_softc *sc;
-
-	sc = addr;
-#ifdef EMUXKI_DEBUG
-	printf("%s: emuxki_open called\n", device_xname(sc->sc_dev));
-#endif
-
-	/*
-	 * Multiple voice support would be added as soon as I find a way to
-	 * trick the audio arch into supporting multiple voices.
-	 * Or I might integrate a modified audio arch supporting
-	 * multiple voices.
-	 */
 
 	/*
-	 * I did this because i have problems identifying the selected
-	 * recording source(s) which is necessary when setting recording
-	 * params This will be addressed very soon
+	 * This is not necessary for recording, but symmetric for easy.
+	 * For recording buffer/block size requirements of hardware,
+	 * see EMU_RECBS_BUFSIZE_*
 	 */
-	if (flags & FREAD) {
-		sc->rvoice = emuxki_voice_new(sc, 0 /* EMU_VOICE_USE_RECORD */);
-		if (sc->rvoice == NULL)
-			return EBUSY;
-
-		/* XXX Hardcode RECSRC_ADC for now */
-		sc->rvoice->dataloc.source = EMU_RECSRC_ADC;
-	}
-
-	if (flags & FWRITE) {
-		sc->pvoice = emuxki_voice_new(sc, EMU_VOICE_USE_PLAY);
-		if (sc->pvoice == NULL) {
-			if (sc->rvoice) {
-				emuxki_voice_delete(sc->rvoice);
-				sc->rvoice = NULL;
-			}
-			return EBUSY;
-		}
-	}
-
-	return 0;
+	if (blksize < EMU_PTESIZE)
+		blksize = EMU_PTESIZE;
+	return rounddown(blksize, EMU_PTESIZE);
 }
 
-static void
-emuxki_close(void *addr)
+static size_t
+emuxki_round_buffersize(void *hdl, int direction, size_t bsize)
 {
-	struct emuxki_softc *sc;
-
-	sc = addr;
-#ifdef EMUXKI_DEBUG
-	printf("%s: emu10K1_close called\n", device_xname(sc->sc_dev));
-#endif
 
-	/* No multiple voice support for now */
-	if (sc->rvoice != NULL) {
-		emuxki_voice_delete(sc->rvoice);
-		sc->rvoice = NULL;
-	}
-	if (sc->pvoice != NULL) {
-		emuxki_voice_delete(sc->pvoice);
-		sc->pvoice = NULL;
+	/* This is not necessary for recording, but symmetric for easy */
+	if (bsize < EMU_MINPTE * EMU_PTESIZE) {
+		bsize = EMU_MINPTE * EMU_PTESIZE;
+	} else if (bsize > EMU_MAXPTE * EMU_PTESIZE) {
+		bsize = EMU_MAXPTE * EMU_PTESIZE;
 	}
+	return roundup(bsize, EMU_PTESIZE);
 }
 
 static int
-emuxki_query_format(void *addr, audio_format_query_t *afp)
+emuxki_get_props(void *hdl)
 {
 
-	return audio_query_format(emuxki_formats, EMUXKI_NFORMATS, afp);
+	return AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
 }
 
 static int
-emuxki_set_format(void *addr, int setmode,
-    const audio_params_t *play, const audio_params_t *rec,
-    audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
+emuxki_trigger_output(void *hdl, void *start, void *end, int blksize,
+    void (*intr)(void *), void *arg, const audio_params_t *params)
 {
+	struct emuxki_softc *sc = hdl;
+	int npage;
+	uint32_t *kptb;
+	bus_addr_t dpmem;
+	int i;
+	uint32_t hwstart;
+	uint32_t hwend;
 
-	/* XXX impossible to use this driver as is */
-	return ENXIO;
-}
+	if (sc->pmem == NULL)
+		panic("pmem == NULL\n");
+	if (start != KERNADDR(sc->pmem))
+		panic("start != KERNADDR(sc->pmem)\n");
 
-static int
-emuxki_halt_output(void *addr)
-{
-	struct emuxki_softc *sc;
+	sc->pframesize = 4;	/* channels * bit / 8 = 2*16/8=4 */
+	sc->pblksize = blksize;
+	sc->plength = (char *)end - (char *)start;
+	sc->poffset = 0;
+	npage = roundup(sc->plength, EMU_PTESIZE);
 
-	sc = addr;
-	/* No multiple voice support for now */
-	if (sc->pvoice == NULL)
-		return ENXIO;
+	kptb = KERNADDR(sc->ptb);
+	dpmem = DMAADDR(sc->pmem);
+	for (i = 0; i < npage; i++) {
+		kptb[i] = htole32(dpmem << 1);
+		dpmem += EMU_PTESIZE;
+	}
+	dmamem_sync(sc->ptb, BUS_DMASYNC_PREWRITE);
 
-	emuxki_voice_halt(sc->pvoice);
-	return 0;
-}
+	hwstart = 0;
+	hwend = hwstart + sc->plength / sc->pframesize;
 
-static int
-emuxki_halt_input(void *addr)
-{
-	struct emuxki_softc *sc;
+	sc->pintr = intr;
+	sc->pintrarg = arg;
 
-	sc = addr;
-#ifdef EMUXKI_DEBUG
-	printf("%s: emuxki_halt_input called\n", device_xname(sc->sc_dev));
-#endif
+	dmamem_sync(sc->pmem, BUS_DMASYNC_PREWRITE);
 
-	/* No multiple voice support for now */
-	if (sc->rvoice == NULL)
-		return ENXIO;
-	emuxki_voice_halt(sc->rvoice);
-	return 0;
-}
+	emuxki_play_start(sc, 0, hwstart, hwend);
+	emuxki_play_start(sc, 1, hwstart, hwend);
 
-static int
-emuxki_getdev(void *addr, struct audio_device *dev)
-{
-	struct emuxki_softc *sc;
+	emuxki_timer_start(sc);
 
-	sc = addr;
-	*dev = sc->sc_audv;
 	return 0;
 }
 
-static int
-emuxki_set_port(void *addr, mixer_ctrl_t *mctl)
-{
-	struct emuxki_softc *sc;
-
-	sc = addr;
-	return sc->codecif->vtbl->mixer_set_port(sc->codecif, mctl);
-}
-
-static int
-emuxki_get_port(void *addr, mixer_ctrl_t *mctl)
-{
-	struct emuxki_softc *sc;
-
-	sc = addr;
-	return sc->codecif->vtbl->mixer_get_port(sc->codecif, mctl);
-}
+/*
+ * Recording uses temporary buffer.  Because it can use ADC_HALF/FULL
+ * interrupts and this method doesn't conflict with playback.
+ */
 
 static int
-emuxki_query_devinfo(void *addr, mixer_devinfo_t *minfo)
+emuxki_trigger_input(void *hdl, void *start, void *end, int blksize,
+    void (*intr)(void *), void *arg, const audio_params_t *params)
 {
-	struct emuxki_softc *sc;
-
-	sc = addr;
-	return sc->codecif->vtbl->query_devinfo(sc->codecif, minfo);
-}
+	struct emuxki_softc *sc = hdl;
 
-static void *
-emuxki_allocm(void *addr, int direction, size_t size)
-{
-	if (direction == AUMODE_PLAY)
-		return emuxki_pmem_alloc(addr, size);
-	else
-		return emuxki_rmem_alloc(addr, size);
-}
+	if (sc->rmem == NULL)
+		panic("rmem == NULL\n");
+	if (start != sc->rptr)
+		panic("start != sc->rptr\n");
+
+	sc->rframesize = 4;	/* channels * bit / 8 = 2*16/8=4 */
+	sc->rblksize = blksize;
+	sc->rlength = (char *)end - (char *)start;
+	sc->roffset = 0;
+	sc->rcurrent = 0;
 
-static void
-emuxki_freem(void *addr, void *ptr, size_t size)
-{
-	struct emuxki_softc *sc;
-	struct emuxki_mem *mem;
-	uint32_t *ptb, silentpage;
-	size_t numblocks;
-	int i;
+	sc->rintr = intr;
+	sc->rintrarg = arg;
 
-	sc = addr;
-	ptb = KERNADDR(sc->ptb);
-	silentpage = DMAADDR(sc->silentpage) << 1;
-	LIST_FOREACH(mem, &sc->mem, next) {
-		if (KERNADDR(mem->dmamem) != ptr)
-			continue;
-
-		mutex_spin_enter(&sc->sc_intr_lock);
-		if (mem->ptbidx != EMU_RMEM) {
-			numblocks = DMASIZE(mem->dmamem) / EMU_PTESIZE;
-			if (DMASIZE(mem->dmamem) % EMU_PTESIZE)
-				numblocks++;
-			for (i = 0; i < numblocks; i++)
-				ptb[mem->ptbidx + i] =
-				    htole32(silentpage | (mem->ptbidx + i));
-		}
-		LIST_REMOVE(mem, next);
-		mutex_spin_exit(&sc->sc_intr_lock);
+	/*
+	 * Memo:
+	 *  recording source is selected by AC97
+	 *  AC97 input source routes to ADC by FX(DSP)
+	 *
+	 * Must keep following sequence order
+	 */
 
-		emuxki_mem_delete(mem, size);
-		break;
-	}
-}
+	/* first, stop ADC */
+	emuxki_write(sc, 0, EMU_ADCCR, 0);
+	emuxki_write(sc, 0, EMU_ADCBA, 0);
+	emuxki_write(sc, 0, EMU_ADCBS, 0);
 
-/* blocksize should be a divisor of allowable buffersize */
-/* XXX probably this could be done better */
-static int
-emuxki_round_blocksize(void *addr, int blksize,
-    int mode, const audio_params_t* param)
-{
-#if 0
-	struct emuxki_softc *sc;
-	struct audio_softc *au;
-#endif
-	int bufsize;
-#if 0
-	sc = addr;
-	if (sc == NULL)
-		return blksize;
-
-	au = device_private(sc->sc_audev);
-	if (au == NULL)
-		return blksize;
+	dmamem_sync(sc->rmem, BUS_DMASYNC_PREREAD);
 
-	bufsize = emuxki_round_buffersize(sc, AUMODE_RECORD,
-	    au->sc_rr.bufsize);
-#else
-	bufsize = 65536;
-#endif
+	/* ADC interrupt enable */
+	emuxki_writeio_4(sc, EMU_INTE,
+	    emuxki_readio_4(sc, EMU_INTE) |
+	        EMU_INTE_ADCBUFENABLE);
+
+	/* ADC Enable */
+	/* stereo, 48kHz, enable */
+	emuxki_write(sc, 0, EMU_ADCCR,
+	    X1(ADCCR_LCHANENABLE) | X1(ADCCR_RCHANENABLE));
+
+	/* ADC buffer address */
+	emuxki_write(sc, 0, X1(ADCIDX), 0);
+	emuxki_write(sc, 0, EMU_ADCBA, DMAADDR(sc->rmem));
 
-	while (bufsize > blksize)
-		bufsize /= 2;
+	/* ADC buffer size, to start */
+	emuxki_write(sc, 0, EMU_ADCBS, EMU_REC_BUFSIZE_RECBS);
 
-	return bufsize;
+	return 0;
 }
 
-static size_t
-emuxki_round_buffersize(void *addr, int direction, size_t bsize)
+static void
+emuxki_get_locks(void *hdl, kmutex_t **intr, kmutex_t **proc)
 {
+	struct emuxki_softc *sc = hdl;
 
-	if (direction == AUMODE_PLAY) {
-		if (bsize < EMU_PTESIZE)
-			bsize = EMU_PTESIZE;
-		else if (bsize > (EMU_PTESIZE * EMU_MAXPTE))
-			bsize = EMU_PTESIZE * EMU_MAXPTE;
-		/* Would be better if set to max available */
-		else if (bsize % EMU_PTESIZE)
-			bsize = bsize -
-				(bsize % EMU_PTESIZE) +
-				EMU_PTESIZE;
-	} else {
-		int idx;
-
-		/* find nearest lower recbuf size */
-		for(idx = sizeof(emuxki_recbuf_sz) /
-		    sizeof(emuxki_recbuf_sz[0]); --idx >= 0; ) {
-			if (bsize >= emuxki_recbuf_sz[idx]) {
-				bsize = emuxki_recbuf_sz[idx];
-				break;
-			}
-		}
-
-		if (bsize == 0)
-			bsize = 384;
-	}
-
-	return bsize;
-}
-
-static int
-emuxki_get_props(void *addr)
-{
-	return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
-	    AUDIO_PROP_FULLDUPLEX;
+	*intr = &sc->sc_intr_lock;
+	*proc = &sc->sc_lock;
 }
 
-static int
-emuxki_trigger_output(void *addr, void *start, void *end, int blksize,
-    void (*inth) (void *), void *inthparam, const audio_params_t *params)
-{
-	struct emuxki_softc *sc;
-	/* No multiple voice support for now */
-	struct emuxki_voice *voice;
-	int error;
-
-	sc = addr;
-	voice = sc->pvoice;
-	if (voice == NULL)
-		return ENXIO;
-	if ((error = emuxki_voice_set_audioparms(sc, voice, params->channels == 2,
-	    params->precision == 16, params->sample_rate)))
-		return error;
-	if ((error = emuxki_voice_set_bufparms(voice, start,
-	    (char *)end - (char *)start, blksize)))
-		return error;
-	emuxki_voice_commit_parms(voice);
-	emuxki_voice_start(voice, inth, inthparam);
-
-	return 0;
-}
+/*
+ * AC97
+ */
 
 static int
-emuxki_trigger_input(void *addr, void *start, void *end, int blksize,
-    void (*inth) (void *), void *inthparam, const audio_params_t *params)
+emuxki_ac97_init(struct emuxki_softc *sc)
 {
-	struct emuxki_softc *sc;
-	/* No multiple voice support for now */
-	struct emuxki_voice *voice;
-	int	error;
-
-	sc = addr;
-	voice = sc->rvoice;
-	if (voice == NULL)
-		return ENXIO;
-	if ((error = emuxki_voice_set_audioparms(sc, voice,
-	    params->channels == 2, params->precision == 16,
-	    params->sample_rate)))
-		return error;
-	if ((error = emuxki_voice_set_bufparms(voice, start,
-	    (char *)end - (char *)start, blksize)))
-		return error;
-	emuxki_voice_start(voice, inth, inthparam);
 
-	return 0;
+	sc->hostif.arg = sc;
+	sc->hostif.attach = emuxki_ac97_attach;
+	sc->hostif.read = emuxki_ac97_read;
+	sc->hostif.write = emuxki_ac97_write;
+	sc->hostif.reset = emuxki_ac97_reset;
+	sc->hostif.flags = emuxki_ac97_flags;
+	return ac97_attach(&sc->hostif, sc->sc_dev, &sc->sc_lock);
 }
 
 /*
@@ -2338,63 +1379,50 @@ emuxki_trigger_input(void *addr, void *s
  */
 
 static int
-emuxki_ac97_attach(void *arg, struct ac97_codec_if *codecif)
+emuxki_ac97_attach(void *hdl, struct ac97_codec_if *codecif)
 {
-	struct emuxki_softc *sc;
+	struct emuxki_softc *sc = hdl;
 
-	sc = arg;
 	sc->codecif = codecif;
 	return 0;
 }
 
 static int
-emuxki_ac97_read(void *arg, uint8_t reg, uint16_t *val)
+emuxki_ac97_read(void *hdl, uint8_t reg, uint16_t *val)
 {
-	struct emuxki_softc *sc;
+	struct emuxki_softc *sc = hdl;
 
-	sc = arg;
-	mutex_spin_enter(&sc->sc_ac97_index_lock);
-	bus_space_write_1(sc->sc_iot, sc->sc_ioh, EMU_AC97ADDR, reg);
-	*val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, EMU_AC97DATA);
-	mutex_spin_exit(&sc->sc_ac97_index_lock);
+	mutex_spin_enter(&sc->sc_index_lock);
+	emuxki_writeio_1(sc, EMU_AC97ADDR, reg);
+	*val = emuxki_readio_2(sc, EMU_AC97DATA);
+	mutex_spin_exit(&sc->sc_index_lock);
 
 	return 0;
 }
 
 static int
-emuxki_ac97_write(void *arg, uint8_t reg, uint16_t val)
+emuxki_ac97_write(void *hdl, uint8_t reg, uint16_t val)
 {
-	struct emuxki_softc *sc;
+	struct emuxki_softc *sc = hdl;
 
-	sc = arg;
-	mutex_spin_enter(&sc->sc_ac97_index_lock);
-	bus_space_write_1(sc->sc_iot, sc->sc_ioh, EMU_AC97ADDR, reg);
-	bus_space_write_2(sc->sc_iot, sc->sc_ioh, EMU_AC97DATA, val);
-	mutex_spin_exit(&sc->sc_ac97_index_lock);
+	mutex_spin_enter(&sc->sc_index_lock);
+	emuxki_writeio_1(sc, EMU_AC97ADDR, reg);
+	emuxki_writeio_2(sc, EMU_AC97DATA, val);
+	mutex_spin_exit(&sc->sc_index_lock);
 
 	return 0;
 }
 
 static int
-emuxki_ac97_reset(void *arg)
+emuxki_ac97_reset(void *hdl)
 {
 
 	return 0;
 }
 
-enum ac97_host_flags
-emuxki_ac97_flags(void *arg)
+static enum ac97_host_flags
+emuxki_ac97_flags(void *hdl)
 {
 
 	return AC97_HOST_SWAPPED_CHANNELS;
 }
-
-static void
-emuxki_get_locks(void *arg, kmutex_t **intr, kmutex_t **proc)
-{
-	struct emuxki_softc *sc;
-
-	sc = arg;
-	*intr = &sc->sc_intr_lock;
-	*proc = &sc->sc_lock;
-}

Reply via email to