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