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