1d056fa04SAlexander Leidinger /*- 2d056fa04SAlexander Leidinger * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3b28624fdSAriff Abdullah * Copyright (c) 2003-2007 Yuriy Tsibizov <yuriy.tsibizov@gfk.ru> 4d056fa04SAlexander Leidinger * All rights reserved. 5d056fa04SAlexander Leidinger * 6d056fa04SAlexander Leidinger * Redistribution and use in source and binary forms, with or without 7d056fa04SAlexander Leidinger * modification, are permitted provided that the following conditions 8d056fa04SAlexander Leidinger * are met: 9d056fa04SAlexander Leidinger * 1. Redistributions of source code must retain the above copyright 10d056fa04SAlexander Leidinger * notice, this list of conditions and the following disclaimer. 11d056fa04SAlexander Leidinger * 2. Redistributions in binary form must reproduce the above copyright 12d056fa04SAlexander Leidinger * notice, this list of conditions and the following disclaimer in the 13d056fa04SAlexander Leidinger * documentation and/or other materials provided with the distribution. 14d056fa04SAlexander Leidinger * 15d056fa04SAlexander Leidinger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16d056fa04SAlexander Leidinger * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17d056fa04SAlexander Leidinger * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18d056fa04SAlexander Leidinger * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19d056fa04SAlexander Leidinger * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20d056fa04SAlexander Leidinger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21d056fa04SAlexander Leidinger * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22d056fa04SAlexander Leidinger * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 23d056fa04SAlexander Leidinger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24d056fa04SAlexander Leidinger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25d056fa04SAlexander Leidinger * SUCH DAMAGE. 26d056fa04SAlexander Leidinger * 27d056fa04SAlexander Leidinger * $FreeBSD$ 28d056fa04SAlexander Leidinger */ 29d056fa04SAlexander Leidinger 30d056fa04SAlexander Leidinger #include <sys/param.h> 31d056fa04SAlexander Leidinger #include <sys/types.h> 32d056fa04SAlexander Leidinger #include <sys/bus.h> 33d056fa04SAlexander Leidinger #include <machine/bus.h> 34d056fa04SAlexander Leidinger #include <sys/rman.h> 35d056fa04SAlexander Leidinger #include <sys/systm.h> 36d056fa04SAlexander Leidinger #include <sys/sbuf.h> 37d056fa04SAlexander Leidinger #include <sys/queue.h> 38d056fa04SAlexander Leidinger #include <sys/lock.h> 39d056fa04SAlexander Leidinger #include <sys/mutex.h> 40d056fa04SAlexander Leidinger #include <sys/sysctl.h> 41b28624fdSAriff Abdullah #include <sys/kdb.h> 42d056fa04SAlexander Leidinger 43d056fa04SAlexander Leidinger #include <dev/pci/pcireg.h> 44d056fa04SAlexander Leidinger #include <dev/pci/pcivar.h> 45d056fa04SAlexander Leidinger 46d056fa04SAlexander Leidinger #include <machine/clock.h> /* for DELAY */ 47d056fa04SAlexander Leidinger 4890da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS 4990da2b28SAriff Abdullah #include "opt_snd.h" 5090da2b28SAriff Abdullah #endif 5190da2b28SAriff Abdullah 52d056fa04SAlexander Leidinger #include <dev/sound/chip.h> 53d056fa04SAlexander Leidinger #include <dev/sound/pcm/sound.h> 54d056fa04SAlexander Leidinger #include <dev/sound/pcm/ac97.h> 55d056fa04SAlexander Leidinger 5670e0bbedSPedro F. Giffuni #include <dev/sound/pci/emuxkireg.h> 57d056fa04SAlexander Leidinger #include <dev/sound/pci/emu10kx.h> 58d056fa04SAlexander Leidinger 59d056fa04SAlexander Leidinger /* hw flags */ 60d056fa04SAlexander Leidinger #define HAS_51 0x0001 61d056fa04SAlexander Leidinger #define HAS_71 0x0002 62d056fa04SAlexander Leidinger #define HAS_AC97 0x0004 63d056fa04SAlexander Leidinger 64d056fa04SAlexander Leidinger #define IS_EMU10K1 0x0008 65d056fa04SAlexander Leidinger #define IS_EMU10K2 0x0010 66d056fa04SAlexander Leidinger #define IS_CA0102 0x0020 67d056fa04SAlexander Leidinger #define IS_CA0108 0x0040 68d056fa04SAlexander Leidinger #define IS_UNKNOWN 0x0080 69d056fa04SAlexander Leidinger 70d056fa04SAlexander Leidinger #define BROKEN_DIGITAL 0x0100 71d056fa04SAlexander Leidinger #define DIGITAL_ONLY 0x0200 72d056fa04SAlexander Leidinger 73d056fa04SAlexander Leidinger #define IS_CARDBUS 0x0400 74d056fa04SAlexander Leidinger 75d056fa04SAlexander Leidinger #define MODE_ANALOG 1 76d056fa04SAlexander Leidinger #define MODE_DIGITAL 2 77d056fa04SAlexander Leidinger #define SPDIF_MODE_PCM 1 78d056fa04SAlexander Leidinger #define SPDIF_MODE_AC3 2 79d056fa04SAlexander Leidinger 80d056fa04SAlexander Leidinger #define MACS 0x0 81d056fa04SAlexander Leidinger #define MACS1 0x1 82d056fa04SAlexander Leidinger #define MACW 0x2 83d056fa04SAlexander Leidinger #define MACW1 0x3 84d056fa04SAlexander Leidinger #define MACINTS 0x4 85d056fa04SAlexander Leidinger #define MACINTW 0x5 86d056fa04SAlexander Leidinger #define ACC3 0x6 87d056fa04SAlexander Leidinger #define MACMV 0x7 88d056fa04SAlexander Leidinger #define ANDXOR 0x8 89d056fa04SAlexander Leidinger #define TSTNEG 0x9 90d056fa04SAlexander Leidinger #define LIMIT 0xA 91d056fa04SAlexander Leidinger #define LIMIT1 0xB 92d056fa04SAlexander Leidinger #define LOG 0xC 93d056fa04SAlexander Leidinger #define EXP 0xD 94d056fa04SAlexander Leidinger #define INTERP 0xE 95d056fa04SAlexander Leidinger #define SKIP 0xF 96d056fa04SAlexander Leidinger 97d056fa04SAlexander Leidinger #define GPR(i) (sc->gpr_base+(i)) 98d056fa04SAlexander Leidinger #define INP(i) (sc->input_base+(i)) 99d056fa04SAlexander Leidinger #define OUTP(i) (sc->output_base+(i)) 100d056fa04SAlexander Leidinger #define FX(i) (i) 101d056fa04SAlexander Leidinger #define FX2(i) (sc->efxc_base+(i)) 102d056fa04SAlexander Leidinger #define DSP_CONST(i) (sc->dsp_zero+(i)) 103d056fa04SAlexander Leidinger 104d056fa04SAlexander Leidinger #define COND_NORMALIZED DSP_CONST(0x1) 105d056fa04SAlexander Leidinger #define COND_BORROW DSP_CONST(0x2) 106d056fa04SAlexander Leidinger #define COND_MINUS DSP_CONST(0x3) 107d056fa04SAlexander Leidinger #define COND_LESS_ZERO DSP_CONST(0x4) 108d056fa04SAlexander Leidinger #define COND_EQ_ZERO DSP_CONST(0x5) 109d056fa04SAlexander Leidinger #define COND_SATURATION DSP_CONST(0x6) 110d056fa04SAlexander Leidinger #define COND_NEQ_ZERO DSP_CONST(0x8) 111d056fa04SAlexander Leidinger 112b28624fdSAriff Abdullah #define DSP_ACCUM DSP_CONST(0x16) 113b28624fdSAriff Abdullah #define DSP_CCR DSP_CONST(0x17) 114b28624fdSAriff Abdullah 115d056fa04SAlexander Leidinger /* Live! Inputs */ 116d056fa04SAlexander Leidinger #define IN_AC97_L 0x00 117d056fa04SAlexander Leidinger #define IN_AC97_R 0x01 118d056fa04SAlexander Leidinger #define IN_AC97 IN_AC97_L 119d056fa04SAlexander Leidinger #define IN_SPDIF_CD_L 0x02 120d056fa04SAlexander Leidinger #define IN_SPDIF_CD_R 0x03 121d056fa04SAlexander Leidinger #define IN_SPDIF_CD IN_SPDIF_CD_L 122d056fa04SAlexander Leidinger #define IN_ZOOM_L 0x04 123d056fa04SAlexander Leidinger #define IN_ZOOM_R 0x05 124d056fa04SAlexander Leidinger #define IN_ZOOM IN_ZOOM_L 125d056fa04SAlexander Leidinger #define IN_TOSLINK_L 0x06 126d056fa04SAlexander Leidinger #define IN_TOSLINK_R 0x07 127d056fa04SAlexander Leidinger #define IN_TOSLINK IN_TOSLINK_L 128d056fa04SAlexander Leidinger #define IN_LINE1_L 0x08 129d056fa04SAlexander Leidinger #define IN_LINE1_R 0x09 130d056fa04SAlexander Leidinger #define IN_LINE1 IN_LINE1_L 131d056fa04SAlexander Leidinger #define IN_COAX_SPDIF_L 0x0a 132d056fa04SAlexander Leidinger #define IN_COAX_SPDIF_R 0x0b 133d056fa04SAlexander Leidinger #define IN_COAX_SPDIF IN_COAX_SPDIF_L 134d056fa04SAlexander Leidinger #define IN_LINE2_L 0x0c 135d056fa04SAlexander Leidinger #define IN_LINE2_R 0x0d 136d056fa04SAlexander Leidinger #define IN_LINE2 IN_LINE2_L 137d056fa04SAlexander Leidinger #define IN_0E 0x0e 138d056fa04SAlexander Leidinger #define IN_0F 0x0f 139d056fa04SAlexander Leidinger 140d056fa04SAlexander Leidinger /* Outputs */ 141d056fa04SAlexander Leidinger #define OUT_AC97_L 0x00 142d056fa04SAlexander Leidinger #define OUT_AC97_R 0x01 143d056fa04SAlexander Leidinger #define OUT_AC97 OUT_AC97_L 144d056fa04SAlexander Leidinger #define OUT_A_FRONT OUT_AC97 145d056fa04SAlexander Leidinger #define OUT_TOSLINK_L 0x02 146d056fa04SAlexander Leidinger #define OUT_TOSLINK_R 0x03 147d056fa04SAlexander Leidinger #define OUT_TOSLINK OUT_TOSLINK_L 148d056fa04SAlexander Leidinger #define OUT_D_CENTER 0x04 149d056fa04SAlexander Leidinger #define OUT_D_SUB 0x05 150d056fa04SAlexander Leidinger #define OUT_HEADPHONE_L 0x06 151d056fa04SAlexander Leidinger #define OUT_HEADPHONE_R 0x07 152d056fa04SAlexander Leidinger #define OUT_HEADPHONE OUT_HEADPHONE_L 153d056fa04SAlexander Leidinger #define OUT_REAR_L 0x08 154d056fa04SAlexander Leidinger #define OUT_REAR_R 0x09 155d056fa04SAlexander Leidinger #define OUT_REAR OUT_REAR_L 156d056fa04SAlexander Leidinger #define OUT_ADC_REC_L 0x0a 157d056fa04SAlexander Leidinger #define OUT_ADC_REC_R 0x0b 158d056fa04SAlexander Leidinger #define OUT_ADC_REC OUT_ADC_REC_L 159d056fa04SAlexander Leidinger #define OUT_MIC_CAP 0x0c 160f856af04SAlexander Leidinger 1612fc83448SJoel Dahl /* Live! 5.1 Digital, non-standard 5.1 (center & sub) outputs */ 162d056fa04SAlexander Leidinger #define OUT_A_CENTER 0x11 163d056fa04SAlexander Leidinger #define OUT_A_SUB 0x12 164d056fa04SAlexander Leidinger 165d056fa04SAlexander Leidinger /* Audigy Inputs */ 166d056fa04SAlexander Leidinger #define A_IN_AC97_L 0x00 167d056fa04SAlexander Leidinger #define A_IN_AC97_R 0x01 168d056fa04SAlexander Leidinger #define A_IN_AC97 A_IN_AC97_L 169d056fa04SAlexander Leidinger #define A_IN_SPDIF_CD_L 0x02 170d056fa04SAlexander Leidinger #define A_IN_SPDIF_CD_R 0x03 171d056fa04SAlexander Leidinger #define A_IN_SPDIF_CD A_IN_SPDIF_CD_L 172d056fa04SAlexander Leidinger #define A_IN_O_SPDIF_L 0x04 173d056fa04SAlexander Leidinger #define A_IN_O_SPDIF_R 0x05 174d056fa04SAlexander Leidinger #define A_IN_O_SPDIF A_IN_O_SPDIF_L 175d056fa04SAlexander Leidinger #define A_IN_LINE2_L 0x08 176d056fa04SAlexander Leidinger #define A_IN_LINE2_R 0x09 177d056fa04SAlexander Leidinger #define A_IN_LINE2 A_IN_LINE2_L 178d056fa04SAlexander Leidinger #define A_IN_R_SPDIF_L 0x0a 179d056fa04SAlexander Leidinger #define A_IN_R_SPDIF_R 0x0b 180d056fa04SAlexander Leidinger #define A_IN_R_SPDIF A_IN_R_SPDIF_L 181d056fa04SAlexander Leidinger #define A_IN_AUX2_L 0x0c 182d056fa04SAlexander Leidinger #define A_IN_AUX2_R 0x0d 183d056fa04SAlexander Leidinger #define A_IN_AUX2 A_IN_AUX2_L 184d056fa04SAlexander Leidinger 18570e0bbedSPedro F. Giffuni /* Audigy Outputs */ 186d056fa04SAlexander Leidinger #define A_OUT_D_FRONT_L 0x00 187d056fa04SAlexander Leidinger #define A_OUT_D_FRONT_R 0x01 188d056fa04SAlexander Leidinger #define A_OUT_D_FRONT A_OUT_D_FRONT_L 189d056fa04SAlexander Leidinger #define A_OUT_D_CENTER 0x02 190d056fa04SAlexander Leidinger #define A_OUT_D_SUB 0x03 191d056fa04SAlexander Leidinger #define A_OUT_D_SIDE_L 0x04 192d056fa04SAlexander Leidinger #define A_OUT_D_SIDE_R 0x05 193d056fa04SAlexander Leidinger #define A_OUT_D_SIDE A_OUT_D_SIDE_L 194d056fa04SAlexander Leidinger #define A_OUT_D_REAR_L 0x06 195d056fa04SAlexander Leidinger #define A_OUT_D_REAR_R 0x07 196d056fa04SAlexander Leidinger #define A_OUT_D_REAR A_OUT_D_REAR_L 197d056fa04SAlexander Leidinger 198d056fa04SAlexander Leidinger /* on Audigy Platinum only */ 199d056fa04SAlexander Leidinger #define A_OUT_HPHONE_L 0x04 200d056fa04SAlexander Leidinger #define A_OUT_HPHONE_R 0x05 201d056fa04SAlexander Leidinger #define A_OUT_HPHONE A_OUT_HPHONE_L 202d056fa04SAlexander Leidinger 203d056fa04SAlexander Leidinger #define A_OUT_A_FRONT_L 0x08 204d056fa04SAlexander Leidinger #define A_OUT_A_FRONT_R 0x09 205d056fa04SAlexander Leidinger #define A_OUT_A_FRONT A_OUT_A_FRONT_L 206d056fa04SAlexander Leidinger #define A_OUT_A_CENTER 0x0a 207d056fa04SAlexander Leidinger #define A_OUT_A_SUB 0x0b 208d056fa04SAlexander Leidinger #define A_OUT_A_SIDE_L 0x0c 209d056fa04SAlexander Leidinger #define A_OUT_A_SIDE_R 0x0d 210d056fa04SAlexander Leidinger #define A_OUT_A_SIDE A_OUT_A_SIDE_L 211d056fa04SAlexander Leidinger #define A_OUT_A_REAR_L 0x0e 212d056fa04SAlexander Leidinger #define A_OUT_A_REAR_R 0x0f 213d056fa04SAlexander Leidinger #define A_OUT_A_REAR A_OUT_A_REAR_L 214d056fa04SAlexander Leidinger #define A_OUT_AC97_L 0x10 215d056fa04SAlexander Leidinger #define A_OUT_AC97_R 0x11 216d056fa04SAlexander Leidinger #define A_OUT_AC97 A_OUT_AC97_L 217d056fa04SAlexander Leidinger #define A_OUT_ADC_REC_L 0x16 218d056fa04SAlexander Leidinger #define A_OUT_ADC_REC_R 0x17 219d056fa04SAlexander Leidinger #define A_OUT_ADC_REC A_OUT_ADC_REC_L 220d056fa04SAlexander Leidinger 22170e0bbedSPedro F. Giffuni #define EMU_DATA2 0x24 22270e0bbedSPedro F. Giffuni #define EMU_IPR2 0x28 22370e0bbedSPedro F. Giffuni #define EMU_INTE2 0x2c 22470e0bbedSPedro F. Giffuni #define EMU_IPR3 0x38 22570e0bbedSPedro F. Giffuni #define EMU_INTE3 0x3c 22670e0bbedSPedro F. Giffuni 22770e0bbedSPedro F. Giffuni #define EMU_A2_SRCSel 0x60 22870e0bbedSPedro F. Giffuni #define EMU_A2_SRCMULTI_ENABLE 0x6e 22970e0bbedSPedro F. Giffuni 23070e0bbedSPedro F. Giffuni #define EMU_A_I2S_CAPTURE_96000 0x00000400 23170e0bbedSPedro F. Giffuni 23270e0bbedSPedro F. Giffuni #define EMU_A2_MIXER_I2S_ENABLE 0x7B 23370e0bbedSPedro F. Giffuni #define EMU_A2_MIXER_SPDIF_ENABLE 0x7A 234d056fa04SAlexander Leidinger 235d056fa04SAlexander Leidinger #define C_FRONT_L 0 236d056fa04SAlexander Leidinger #define C_FRONT_R 1 237d056fa04SAlexander Leidinger #define C_REC_L 2 238d056fa04SAlexander Leidinger #define C_REC_R 3 239d056fa04SAlexander Leidinger #define C_REAR_L 4 240d056fa04SAlexander Leidinger #define C_REAR_R 5 241d056fa04SAlexander Leidinger #define C_CENTER 6 242d056fa04SAlexander Leidinger #define C_SUB 7 243d056fa04SAlexander Leidinger #define C_SIDE_L 8 244d056fa04SAlexander Leidinger #define C_SIDE_R 9 245d056fa04SAlexander Leidinger #define NUM_CACHES 10 246d056fa04SAlexander Leidinger 247b28624fdSAriff Abdullah #define CDSPDIFMUTE 0 248b28624fdSAriff Abdullah #define ANALOGMUTE 1 249b28624fdSAriff Abdullah #define NUM_MUTE 2 250f856af04SAlexander Leidinger 251d056fa04SAlexander Leidinger #define EMU_MAX_GPR 512 252d056fa04SAlexander Leidinger #define EMU_MAX_IRQ_CONSUMERS 32 253d056fa04SAlexander Leidinger 254d056fa04SAlexander Leidinger struct emu_voice { 255d056fa04SAlexander Leidinger int vnum; 256feaa7fe1SAlexander Leidinger unsigned int b16:1, stereo:1, busy:1, running:1, ismaster:1; 257d056fa04SAlexander Leidinger int speed; 258d056fa04SAlexander Leidinger int start; 259d056fa04SAlexander Leidinger int end; 260d056fa04SAlexander Leidinger int vol; 261d056fa04SAlexander Leidinger uint32_t buf; 262d056fa04SAlexander Leidinger void *vbuf; 263d056fa04SAlexander Leidinger struct emu_voice *slave; 264d056fa04SAlexander Leidinger uint32_t sa; 265d056fa04SAlexander Leidinger uint32_t ea; 266b28624fdSAriff Abdullah uint32_t routing[8]; 267b28624fdSAriff Abdullah uint32_t amounts[8]; 268d056fa04SAlexander Leidinger }; 269d056fa04SAlexander Leidinger 270d056fa04SAlexander Leidinger struct emu_memblk { 271d056fa04SAlexander Leidinger SLIST_ENTRY(emu_memblk) link; 272d056fa04SAlexander Leidinger void *buf; 273d056fa04SAlexander Leidinger char owner[16]; 274d056fa04SAlexander Leidinger bus_addr_t buf_addr; 275d056fa04SAlexander Leidinger uint32_t pte_start, pte_size; 27686843ea8SJohn Baldwin bus_dmamap_t buf_map; 277d056fa04SAlexander Leidinger }; 278d056fa04SAlexander Leidinger 279d056fa04SAlexander Leidinger struct emu_mem { 280e4c87b14SAlexander Leidinger uint8_t bmap[EMU_MAXPAGES / 8]; 281d056fa04SAlexander Leidinger uint32_t *ptb_pages; 282d056fa04SAlexander Leidinger void *silent_page; 283d056fa04SAlexander Leidinger bus_addr_t ptb_pages_addr; 28486843ea8SJohn Baldwin bus_addr_t silent_page_addr; 28586843ea8SJohn Baldwin bus_dmamap_t ptb_map; 28686843ea8SJohn Baldwin bus_dmamap_t silent_map; 287d056fa04SAlexander Leidinger bus_dma_tag_t dmat; 288b28624fdSAriff Abdullah struct emu_sc_info *card; 289d056fa04SAlexander Leidinger SLIST_HEAD(, emu_memblk) blocks; 290d056fa04SAlexander Leidinger }; 291d056fa04SAlexander Leidinger 292d056fa04SAlexander Leidinger /* rm */ 293d056fa04SAlexander Leidinger struct emu_rm { 294d056fa04SAlexander Leidinger struct emu_sc_info *card; 295d056fa04SAlexander Leidinger struct mtx gpr_lock; 296d056fa04SAlexander Leidinger signed int allocmap[EMU_MAX_GPR]; 297d056fa04SAlexander Leidinger int num_gprs; 298d056fa04SAlexander Leidinger int last_free_gpr; 299d056fa04SAlexander Leidinger int num_used; 300d056fa04SAlexander Leidinger }; 301d056fa04SAlexander Leidinger 302d056fa04SAlexander Leidinger struct emu_intr_handler { 303d056fa04SAlexander Leidinger void* softc; 304d056fa04SAlexander Leidinger uint32_t intr_mask; 305d056fa04SAlexander Leidinger uint32_t inte_mask; 306d056fa04SAlexander Leidinger uint32_t(*irq_func) (void *softc, uint32_t irq); 307d056fa04SAlexander Leidinger }; 308d056fa04SAlexander Leidinger 309d056fa04SAlexander Leidinger struct emu_sc_info { 310d056fa04SAlexander Leidinger struct mtx lock; 311d056fa04SAlexander Leidinger struct mtx rw; /* Hardware exclusive access lock */ 312d056fa04SAlexander Leidinger 313d056fa04SAlexander Leidinger /* Hardware and subdevices */ 314d056fa04SAlexander Leidinger device_t dev; 315f856af04SAlexander Leidinger device_t pcm[RT_COUNT]; 316d056fa04SAlexander Leidinger device_t midi[2]; 317d056fa04SAlexander Leidinger uint32_t type; 318d056fa04SAlexander Leidinger uint32_t rev; 319d056fa04SAlexander Leidinger 320d056fa04SAlexander Leidinger bus_space_tag_t st; 321d056fa04SAlexander Leidinger bus_space_handle_t sh; 322d056fa04SAlexander Leidinger 323d056fa04SAlexander Leidinger struct cdev *cdev; /* /dev/emu10k character device */ 324d056fa04SAlexander Leidinger struct mtx emu10kx_lock; 325d056fa04SAlexander Leidinger int emu10kx_isopen; 326d056fa04SAlexander Leidinger struct sbuf emu10kx_sbuf; 327d056fa04SAlexander Leidinger int emu10kx_bufptr; 328d056fa04SAlexander Leidinger 329d056fa04SAlexander Leidinger 330d056fa04SAlexander Leidinger /* Resources */ 331d056fa04SAlexander Leidinger struct resource *reg; 332d056fa04SAlexander Leidinger struct resource *irq; 333d056fa04SAlexander Leidinger void *ih; 334d056fa04SAlexander Leidinger 335d056fa04SAlexander Leidinger /* IRQ handlers */ 336d056fa04SAlexander Leidinger struct emu_intr_handler ihandler[EMU_MAX_IRQ_CONSUMERS]; 337d056fa04SAlexander Leidinger 338d056fa04SAlexander Leidinger /* Card HW configuration */ 339b28624fdSAriff Abdullah unsigned int mode; /* analog / digital */ 340d056fa04SAlexander Leidinger unsigned int mchannel_fx; 341d056fa04SAlexander Leidinger unsigned int dsp_zero; 342d056fa04SAlexander Leidinger unsigned int code_base; 343d056fa04SAlexander Leidinger unsigned int code_size; 344d056fa04SAlexander Leidinger unsigned int gpr_base; 345d056fa04SAlexander Leidinger unsigned int num_gprs; 346d056fa04SAlexander Leidinger unsigned int input_base; 347d056fa04SAlexander Leidinger unsigned int output_base; 348d056fa04SAlexander Leidinger unsigned int efxc_base; 349d056fa04SAlexander Leidinger unsigned int opcode_shift; 350d056fa04SAlexander Leidinger unsigned int high_operand_shift; 351d056fa04SAlexander Leidinger unsigned int address_mask; 352d056fa04SAlexander Leidinger uint32_t is_emu10k1:1, is_emu10k2, is_ca0102, is_ca0108:1, 353d056fa04SAlexander Leidinger has_ac97:1, has_51:1, has_71:1, 354b28624fdSAriff Abdullah enable_ir:1, 355d056fa04SAlexander Leidinger broken_digital:1, is_cardbus:1; 356d056fa04SAlexander Leidinger 357b28624fdSAriff Abdullah signed int mch_disabled, mch_rec, dbg_level; 358b28624fdSAriff Abdullah signed int num_inputs; 359d056fa04SAlexander Leidinger unsigned int num_outputs; 360d056fa04SAlexander Leidinger unsigned int num_fxbuses; 361d056fa04SAlexander Leidinger unsigned int routing_code_start; 362d056fa04SAlexander Leidinger unsigned int routing_code_end; 363d056fa04SAlexander Leidinger 364d056fa04SAlexander Leidinger /* HW resources */ 365d056fa04SAlexander Leidinger struct emu_voice voice[NUM_G]; /* Hardware voices */ 366d056fa04SAlexander Leidinger uint32_t irq_mask[EMU_MAX_IRQ_CONSUMERS]; /* IRQ manager data */ 367d056fa04SAlexander Leidinger int timer[EMU_MAX_IRQ_CONSUMERS]; /* timer */ 368d056fa04SAlexander Leidinger int timerinterval; 369d056fa04SAlexander Leidinger struct emu_rm *rm; 370d056fa04SAlexander Leidinger struct emu_mem mem; /* memory */ 371d056fa04SAlexander Leidinger 372d056fa04SAlexander Leidinger /* Mixer */ 373d056fa04SAlexander Leidinger int mixer_gpr[NUM_MIXERS]; 374d056fa04SAlexander Leidinger int mixer_volcache[NUM_MIXERS]; 375d056fa04SAlexander Leidinger int cache_gpr[NUM_CACHES]; 376b28624fdSAriff Abdullah int dummy_gpr; 377b28624fdSAriff Abdullah int mute_gpr[NUM_MUTE]; 378d056fa04SAlexander Leidinger struct sysctl_ctx_list *ctx; 379d056fa04SAlexander Leidinger struct sysctl_oid *root; 380d056fa04SAlexander Leidinger }; 381d056fa04SAlexander Leidinger 382d056fa04SAlexander Leidinger static void emu_setmap(void *arg, bus_dma_segment_t * segs, int nseg, int error); 38386843ea8SJohn Baldwin static void* emu_malloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr, bus_dmamap_t *map); 38486843ea8SJohn Baldwin static void emu_free(struct emu_mem *mem, void *dmabuf, bus_dmamap_t map); 385d056fa04SAlexander Leidinger static void* emu_memalloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr, const char * owner); 386d056fa04SAlexander Leidinger static int emu_memfree(struct emu_mem *mem, void *membuf); 387d056fa04SAlexander Leidinger static int emu_memstart(struct emu_mem *mem, void *membuf); 388d056fa04SAlexander Leidinger 389d056fa04SAlexander Leidinger /* /dev */ 390d056fa04SAlexander Leidinger static int emu10kx_dev_init(struct emu_sc_info *sc); 391d056fa04SAlexander Leidinger static int emu10kx_dev_uninit(struct emu_sc_info *sc); 392d056fa04SAlexander Leidinger static int emu10kx_prepare(struct emu_sc_info *sc, struct sbuf *s); 393d056fa04SAlexander Leidinger 394d056fa04SAlexander Leidinger static void emumix_set_mode(struct emu_sc_info *sc, int mode); 395d056fa04SAlexander Leidinger static void emumix_set_spdif_mode(struct emu_sc_info *sc, int mode); 396d056fa04SAlexander Leidinger static void emumix_set_fxvol(struct emu_sc_info *sc, unsigned gpr, int32_t vol); 397d056fa04SAlexander Leidinger static void emumix_set_gpr(struct emu_sc_info *sc, unsigned gpr, int32_t val); 398d056fa04SAlexander Leidinger static int sysctl_emu_mixer_control(SYSCTL_HANDLER_ARGS); 399d056fa04SAlexander Leidinger 400d056fa04SAlexander Leidinger static int emu_rm_init(struct emu_sc_info *sc); 401d056fa04SAlexander Leidinger static int emu_rm_uninit(struct emu_sc_info *sc); 402d056fa04SAlexander Leidinger static int emu_rm_gpr_alloc(struct emu_rm *rm, int count); 403d056fa04SAlexander Leidinger 404f856af04SAlexander Leidinger static unsigned int emu_getcard(device_t dev); 405d056fa04SAlexander Leidinger static uint32_t emu_rd_nolock(struct emu_sc_info *sc, unsigned int regno, unsigned int size); 406d056fa04SAlexander Leidinger static void emu_wr_nolock(struct emu_sc_info *sc, unsigned int regno, uint32_t data, unsigned int size); 407d056fa04SAlexander Leidinger static void emu_wr_cbptr(struct emu_sc_info *sc, uint32_t data); 408d056fa04SAlexander Leidinger 409d056fa04SAlexander Leidinger static void emu_vstop(struct emu_sc_info *sc, char channel, int enable); 410d056fa04SAlexander Leidinger 411d056fa04SAlexander Leidinger static void emu_intr(void *p); 412d056fa04SAlexander Leidinger static void emu_wrefx(struct emu_sc_info *sc, unsigned int pc, unsigned int data); 413d056fa04SAlexander Leidinger static void emu_addefxop(struct emu_sc_info *sc, unsigned int op, unsigned int z, unsigned int w, unsigned int x, unsigned int y, uint32_t * pc); 414d056fa04SAlexander Leidinger static void emu_initefx(struct emu_sc_info *sc); 415d056fa04SAlexander Leidinger 416d056fa04SAlexander Leidinger static int emu_cardbus_init(struct emu_sc_info *sc); 41755837609SAriff Abdullah static int emu_init(struct emu_sc_info *sc); 418d056fa04SAlexander Leidinger static int emu_uninit(struct emu_sc_info *sc); 419d056fa04SAlexander Leidinger 420d056fa04SAlexander Leidinger static int emu_read_ivar(device_t bus __unused, device_t dev, int ivar_index, uintptr_t * result); 421d056fa04SAlexander Leidinger static int emu_write_ivar(device_t bus __unused, device_t dev __unused, 422d056fa04SAlexander Leidinger int ivar_index, uintptr_t value __unused); 423d056fa04SAlexander Leidinger 424d056fa04SAlexander Leidinger static int emu_pci_probe(device_t dev); 425d056fa04SAlexander Leidinger static int emu_pci_attach(device_t dev); 426d056fa04SAlexander Leidinger static int emu_pci_detach(device_t dev); 427d056fa04SAlexander Leidinger static int emu_modevent(module_t mod __unused, int cmd, void *data __unused); 428d056fa04SAlexander Leidinger 429b28624fdSAriff Abdullah #ifdef SND_EMU10KX_DEBUG 430b28624fdSAriff Abdullah 431b28624fdSAriff Abdullah #define EMU_MTX_DEBUG() do { \ 432b28624fdSAriff Abdullah if (mtx_owned(&sc->rw)) { \ 433b28624fdSAriff Abdullah printf("RW owned in %s line %d for %s\n", __func__, \ 434b28624fdSAriff Abdullah __LINE__ , device_get_nameunit(sc->dev)); \ 435b28624fdSAriff Abdullah printf("rw lock owned: %d\n", mtx_owned(&sc->rw)); \ 436b28624fdSAriff Abdullah printf("rw lock: value %x thread %x\n", \ 437b28624fdSAriff Abdullah ((&sc->rw)->mtx_lock & ~MTX_FLAGMASK), \ 438b28624fdSAriff Abdullah (uintptr_t)curthread); \ 439b28624fdSAriff Abdullah printf("rw lock: recursed %d\n", mtx_recursed(&sc->rw));\ 440b28624fdSAriff Abdullah db_show_mtx(&sc->rw); \ 441b28624fdSAriff Abdullah } \ 442b28624fdSAriff Abdullah } while (0) 443b28624fdSAriff Abdullah #else 444b28624fdSAriff Abdullah #define EMU_MTX_DEBUG() do { \ 445b28624fdSAriff Abdullah } while (0) 446b28624fdSAriff Abdullah #endif 447b28624fdSAriff Abdullah 448b28624fdSAriff Abdullah #define EMU_RWLOCK() do { \ 449b28624fdSAriff Abdullah EMU_MTX_DEBUG(); \ 450b28624fdSAriff Abdullah mtx_lock(&(sc->rw)); \ 451b28624fdSAriff Abdullah } while (0) 452b28624fdSAriff Abdullah 453b28624fdSAriff Abdullah #define EMU_RWUNLOCK() do { \ 454b28624fdSAriff Abdullah mtx_unlock(&(sc->rw)); \ 455b28624fdSAriff Abdullah EMU_MTX_DEBUG(); \ 456b28624fdSAriff Abdullah } while (0) 457b28624fdSAriff Abdullah 458d056fa04SAlexander Leidinger /* Supported cards */ 459d056fa04SAlexander Leidinger struct emu_hwinfo { 460d056fa04SAlexander Leidinger uint16_t vendor; 461d056fa04SAlexander Leidinger uint16_t device; 462d056fa04SAlexander Leidinger uint16_t subvendor; 463d056fa04SAlexander Leidinger uint16_t subdevice; 464d056fa04SAlexander Leidinger char SBcode[8]; 465d056fa04SAlexander Leidinger char desc[32]; 466d056fa04SAlexander Leidinger int flags; 467d056fa04SAlexander Leidinger }; 468d056fa04SAlexander Leidinger 469d056fa04SAlexander Leidinger static struct emu_hwinfo emu_cards[] = { 470f856af04SAlexander Leidinger {0xffff, 0xffff, 0xffff, 0xffff, "BADCRD", "Not a compatible card", 0}, 471d056fa04SAlexander Leidinger /* 0x0020..0x002f 4.0 EMU10K1 cards */ 472d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x0020, "CT4850", "SBLive! Value", HAS_AC97 | IS_EMU10K1}, 473d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x0021, "CT4620", "SBLive!", HAS_AC97 | IS_EMU10K1}, 474d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x002f, "CT????", "SBLive! mainboard implementation", HAS_AC97 | IS_EMU10K1}, 475d056fa04SAlexander Leidinger 476d056fa04SAlexander Leidinger /* (range unknown) 5.1 EMU10K1 cards */ 477d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x100a, "CT????", "SBLive! 5.1", HAS_AC97 | HAS_51 | IS_EMU10K1}, 478d056fa04SAlexander Leidinger 479d056fa04SAlexander Leidinger /* 0x80??..0x805? 4.0 EMU10K1 cards */ 480d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8022, "CT4780", "SBLive! Value", HAS_AC97 | IS_EMU10K1}, 481d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8023, "CT4790", "SB PCI512", HAS_AC97 | IS_EMU10K1}, 482d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8024, "CT4760", "SBLive!", HAS_AC97 | IS_EMU10K1}, 483d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8025, "CT????", "SBLive! Mainboard Implementation", HAS_AC97 | IS_EMU10K1}, 484d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8026, "CT4830", "SBLive! Value", HAS_AC97 | IS_EMU10K1}, 485d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8027, "CT4832", "SBLive! Value", HAS_AC97 | IS_EMU10K1}, 486d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8028, "CT4760", "SBLive! OEM version", HAS_AC97 | IS_EMU10K1}, 487d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8031, "CT4831", "SBLive! Value", HAS_AC97 | IS_EMU10K1}, 488d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8040, "CT4760", "SBLive!", HAS_AC97 | IS_EMU10K1}, 489d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8051, "CT4850", "SBLive! Value", HAS_AC97 | IS_EMU10K1}, 490d056fa04SAlexander Leidinger 491d056fa04SAlexander Leidinger /* 0x8061..0x???? 5.1 EMU10K1 cards */ 492d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8061, "SB????", "SBLive! Player 5.1", HAS_AC97 | HAS_51 | IS_EMU10K1}, 493b28624fdSAriff Abdullah {0x1102, 0x0002, 0x1102, 0x8062, "CT4830", "SBLive! 1024", HAS_AC97 | HAS_51 | IS_EMU10K1}, 494d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8064, "SB????", "SBLive! 5.1", HAS_AC97 | HAS_51 | IS_EMU10K1}, 495d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8065, "SB0220", "SBLive! 5.1 Digital", HAS_AC97 | HAS_51 | IS_EMU10K1}, 496d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8066, "CT4780", "SBLive! 5.1 Digital", HAS_AC97 | HAS_51 | IS_EMU10K1}, 497d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x8067, "SB????", "SBLive!", HAS_AC97 | HAS_51 | IS_EMU10K1}, 498d056fa04SAlexander Leidinger 499d056fa04SAlexander Leidinger /* Generic SB Live! */ 500d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x0000, "SB????", "SBLive! (Unknown model)", HAS_AC97 | IS_EMU10K1}, 501d056fa04SAlexander Leidinger 502d056fa04SAlexander Leidinger /* 0x0041..0x0043 EMU10K2 (some kind of Audigy) cards */ 503d056fa04SAlexander Leidinger 504d056fa04SAlexander Leidinger /* 0x0051..0x0051 5.1 CA0100-IAF cards */ 505d056fa04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x0051, "SB0090", "Audigy", HAS_AC97 | HAS_51 | IS_EMU10K2}, 506d056fa04SAlexander Leidinger /* ES is CA0100-IDF chip that don't work in digital mode */ 507d056fa04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x0052, "SB0160", "Audigy ES", HAS_AC97 | HAS_71 | IS_EMU10K2 | BROKEN_DIGITAL}, 508d056fa04SAlexander Leidinger /* 0x0053..0x005C 5.1 CA0101-NAF cards */ 509d056fa04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x0053, "SB0090", "Audigy Player/OEM", HAS_AC97 | HAS_51 | IS_EMU10K2}, 510d056fa04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x0058, "SB0090", "Audigy Player/OEM", HAS_AC97 | HAS_51 | IS_EMU10K2}, 511d056fa04SAlexander Leidinger 512d056fa04SAlexander Leidinger /* 0x1002..0x1009 5.1 CA0102-IAT cards */ 513d056fa04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x1002, "SB????", "Audigy 2 Platinum", HAS_51 | IS_CA0102}, 514d056fa04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x1005, "SB????", "Audigy 2 Platinum EX", HAS_51 | IS_CA0102}, 515d056fa04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x1007, "SB0240", "Audigy 2", HAS_AC97 | HAS_51 | IS_CA0102}, 516d056fa04SAlexander Leidinger 517d056fa04SAlexander Leidinger /* 0x2001..0x2003 7.1 CA0102-ICT cards */ 518d056fa04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x2001, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102}, 519d056fa04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x2002, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102}, 520f856af04SAlexander Leidinger /* XXX No reports about 0x2003 & 0x2004 cards */ 521f856af04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x2003, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102}, 522f856af04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x2004, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102}, 523f856af04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x2005, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102}, 524d056fa04SAlexander Leidinger 525d056fa04SAlexander Leidinger /* (range unknown) 7.1 CA0102-xxx Audigy 4 cards */ 526d056fa04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x2007, "SB0380", "Audigy 4 Pro", HAS_AC97 | HAS_71 | IS_CA0102}, 527d056fa04SAlexander Leidinger 528d056fa04SAlexander Leidinger /* Generic Audigy or Audigy 2 */ 529d056fa04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x0000, "SB????", "Audigy (Unknown model)", HAS_AC97 | HAS_51 | IS_EMU10K2}, 530d056fa04SAlexander Leidinger 531d056fa04SAlexander Leidinger /* We don't support CA0103-DAT (Audigy LS) cards */ 532d056fa04SAlexander Leidinger /* There is NO CA0104-xxx cards */ 533d056fa04SAlexander Leidinger /* There is NO CA0105-xxx cards */ 534d056fa04SAlexander Leidinger /* We don't support CA0106-DAT (SB Live! 24 bit) cards */ 535d056fa04SAlexander Leidinger /* There is NO CA0107-xxx cards */ 536d056fa04SAlexander Leidinger 537d056fa04SAlexander Leidinger /* 0x1000..0x1001 7.1 CA0108-IAT cards */ 538d056fa04SAlexander Leidinger {0x1102, 0x0008, 0x1102, 0x1000, "SB????", "Audigy 2 LS", HAS_AC97 | HAS_51 | IS_CA0108 | DIGITAL_ONLY}, 539d056fa04SAlexander Leidinger {0x1102, 0x0008, 0x1102, 0x1001, "SB0400", "Audigy 2 Value", HAS_AC97 | HAS_71 | IS_CA0108 | DIGITAL_ONLY}, 540d056fa04SAlexander Leidinger {0x1102, 0x0008, 0x1102, 0x1021, "SB0610", "Audigy 4", HAS_AC97 | HAS_71 | IS_CA0108 | DIGITAL_ONLY}, 541d056fa04SAlexander Leidinger 542d056fa04SAlexander Leidinger {0x1102, 0x0008, 0x1102, 0x2001, "SB0530", "Audigy 2 ZS CardBus", HAS_AC97 | HAS_71 | IS_CA0108 | IS_CARDBUS}, 543d056fa04SAlexander Leidinger 544d056fa04SAlexander Leidinger {0x1102, 0x0008, 0x0000, 0x0000, "SB????", "Audigy 2 Value (Unknown model)", HAS_AC97 | HAS_51 | IS_CA0108}, 545d056fa04SAlexander Leidinger }; 546d056fa04SAlexander Leidinger /* Unsupported cards */ 547d056fa04SAlexander Leidinger 548d056fa04SAlexander Leidinger static struct emu_hwinfo emu_bad_cards[] = { 549d056fa04SAlexander Leidinger /* APS cards should be possible to support */ 550d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x4001, "EMUAPS", "E-mu APS", 0}, 551d056fa04SAlexander Leidinger {0x1102, 0x0002, 0x1102, 0x4002, "EMUAPS", "E-mu APS", 0}, 552d056fa04SAlexander Leidinger {0x1102, 0x0004, 0x1102, 0x4001, "EMU???", "E-mu 1212m [4001]", 0}, 553d056fa04SAlexander Leidinger /* Similar-named ("Live!" or "Audigy") cards on different chipsets */ 554d056fa04SAlexander Leidinger {0x1102, 0x8064, 0x0000, 0x0000, "SB0100", "SBLive! 5.1 OEM", 0}, 555d056fa04SAlexander Leidinger {0x1102, 0x0006, 0x0000, 0x0000, "SB0200", "DELL OEM SBLive! Value", 0}, 556d056fa04SAlexander Leidinger {0x1102, 0x0007, 0x0000, 0x0000, "SB0310", "Audigy LS", 0}, 557d056fa04SAlexander Leidinger }; 558d056fa04SAlexander Leidinger 559d056fa04SAlexander Leidinger /* 560d056fa04SAlexander Leidinger * Get best known information about device. 561d056fa04SAlexander Leidinger */ 562f856af04SAlexander Leidinger static unsigned int 563d056fa04SAlexander Leidinger emu_getcard(device_t dev) 564d056fa04SAlexander Leidinger { 565d056fa04SAlexander Leidinger uint16_t device; 566d056fa04SAlexander Leidinger uint16_t subdevice; 567d056fa04SAlexander Leidinger int n_cards; 568f856af04SAlexander Leidinger unsigned int thiscard; 569d056fa04SAlexander Leidinger int i; 570d056fa04SAlexander Leidinger 571d056fa04SAlexander Leidinger device = pci_read_config(dev, PCIR_DEVICE, /* bytes */ 2); 572d056fa04SAlexander Leidinger subdevice = pci_read_config(dev, PCIR_SUBDEV_0, /* bytes */ 2); 573d056fa04SAlexander Leidinger 574d056fa04SAlexander Leidinger n_cards = sizeof(emu_cards) / sizeof(struct emu_hwinfo); 575f856af04SAlexander Leidinger thiscard = 0; 576f856af04SAlexander Leidinger for (i = 1; i < n_cards; i++) { 577d056fa04SAlexander Leidinger if (device == emu_cards[i].device) { 578d056fa04SAlexander Leidinger if (subdevice == emu_cards[i].subdevice) { 579d056fa04SAlexander Leidinger thiscard = i; 580d056fa04SAlexander Leidinger break; 581d056fa04SAlexander Leidinger } 582d056fa04SAlexander Leidinger if (0x0000 == emu_cards[i].subdevice) { 583d056fa04SAlexander Leidinger thiscard = i; 584b28624fdSAriff Abdullah /* 585b28624fdSAriff Abdullah * don't break, we can get more specific card 586b28624fdSAriff Abdullah * later in the list. 587b28624fdSAriff Abdullah */ 588d056fa04SAlexander Leidinger } 589d056fa04SAlexander Leidinger } 590d056fa04SAlexander Leidinger } 591d056fa04SAlexander Leidinger 592d056fa04SAlexander Leidinger n_cards = sizeof(emu_bad_cards) / sizeof(struct emu_hwinfo); 593d056fa04SAlexander Leidinger for (i = 0; i < n_cards; i++) { 594d056fa04SAlexander Leidinger if (device == emu_bad_cards[i].device) { 595d056fa04SAlexander Leidinger if (subdevice == emu_bad_cards[i].subdevice) { 596f856af04SAlexander Leidinger thiscard = 0; 597d056fa04SAlexander Leidinger break; 598d056fa04SAlexander Leidinger } 599d056fa04SAlexander Leidinger if (0x0000 == emu_bad_cards[i].subdevice) { 600f856af04SAlexander Leidinger thiscard = 0; 601d056fa04SAlexander Leidinger break; /* we avoid all this cards */ 602d056fa04SAlexander Leidinger } 603d056fa04SAlexander Leidinger } 604d056fa04SAlexander Leidinger } 605d056fa04SAlexander Leidinger return (thiscard); 606d056fa04SAlexander Leidinger } 607d056fa04SAlexander Leidinger 608d056fa04SAlexander Leidinger 609d056fa04SAlexander Leidinger /* 610d056fa04SAlexander Leidinger * Base hardware interface are 32 (Audigy) or 64 (Audigy2) registers. 611d056fa04SAlexander Leidinger * Some of them are used directly, some of them provide pointer / data pairs. 612d056fa04SAlexander Leidinger */ 613d056fa04SAlexander Leidinger static uint32_t 614d056fa04SAlexander Leidinger emu_rd_nolock(struct emu_sc_info *sc, unsigned int regno, unsigned int size) 615d056fa04SAlexander Leidinger { 616d056fa04SAlexander Leidinger 617d056fa04SAlexander Leidinger KASSERT(sc != NULL, ("emu_rd: NULL sc")); 618d056fa04SAlexander Leidinger switch (size) { 619d056fa04SAlexander Leidinger case 1: 620d056fa04SAlexander Leidinger return (bus_space_read_1(sc->st, sc->sh, regno)); 621d056fa04SAlexander Leidinger case 2: 622d056fa04SAlexander Leidinger return (bus_space_read_2(sc->st, sc->sh, regno)); 623d056fa04SAlexander Leidinger case 4: 624d056fa04SAlexander Leidinger return (bus_space_read_4(sc->st, sc->sh, regno)); 625d056fa04SAlexander Leidinger } 626d056fa04SAlexander Leidinger return (0xffffffff); 627d056fa04SAlexander Leidinger } 628d056fa04SAlexander Leidinger 629d056fa04SAlexander Leidinger static void 630d056fa04SAlexander Leidinger emu_wr_nolock(struct emu_sc_info *sc, unsigned int regno, uint32_t data, unsigned int size) 631d056fa04SAlexander Leidinger { 632d056fa04SAlexander Leidinger 633d056fa04SAlexander Leidinger KASSERT(sc != NULL, ("emu_rd: NULL sc")); 634d056fa04SAlexander Leidinger switch (size) { 635d056fa04SAlexander Leidinger case 1: 636d056fa04SAlexander Leidinger bus_space_write_1(sc->st, sc->sh, regno, data); 637d056fa04SAlexander Leidinger break; 638d056fa04SAlexander Leidinger case 2: 639d056fa04SAlexander Leidinger bus_space_write_2(sc->st, sc->sh, regno, data); 640d056fa04SAlexander Leidinger break; 641d056fa04SAlexander Leidinger case 4: 642d056fa04SAlexander Leidinger bus_space_write_4(sc->st, sc->sh, regno, data); 643d056fa04SAlexander Leidinger break; 644d056fa04SAlexander Leidinger } 645d056fa04SAlexander Leidinger } 646d056fa04SAlexander Leidinger /* 64770e0bbedSPedro F. Giffuni * EMU_PTR / EMU_DATA interface. Access to EMU10Kx is made 648d056fa04SAlexander Leidinger * via (channel, register) pair. Some registers are channel-specific, 649d056fa04SAlexander Leidinger * some not. 650d056fa04SAlexander Leidinger */ 651d056fa04SAlexander Leidinger uint32_t 652d056fa04SAlexander Leidinger emu_rdptr(struct emu_sc_info *sc, unsigned int chn, unsigned int reg) 653d056fa04SAlexander Leidinger { 654d056fa04SAlexander Leidinger uint32_t ptr, val, mask, size, offset; 655d056fa04SAlexander Leidinger 65670e0bbedSPedro F. Giffuni ptr = ((reg << 16) & sc->address_mask) | (chn & EMU_PTR_CHNO_MASK); 657b28624fdSAriff Abdullah 658b28624fdSAriff Abdullah EMU_RWLOCK(); 65970e0bbedSPedro F. Giffuni emu_wr_nolock(sc, EMU_PTR, ptr, 4); 66070e0bbedSPedro F. Giffuni val = emu_rd_nolock(sc, EMU_DATA, 4); 661b28624fdSAriff Abdullah EMU_RWUNLOCK(); 662b28624fdSAriff Abdullah 663d056fa04SAlexander Leidinger /* 664d056fa04SAlexander Leidinger * XXX Some register numbers has data size and offset encoded in 665d056fa04SAlexander Leidinger * it to get only part of 32bit register. This use is not described 666d056fa04SAlexander Leidinger * in register name, be careful! 667d056fa04SAlexander Leidinger */ 668d056fa04SAlexander Leidinger if (reg & 0xff000000) { 669d056fa04SAlexander Leidinger size = (reg >> 24) & 0x3f; 670d056fa04SAlexander Leidinger offset = (reg >> 16) & 0x1f; 671d056fa04SAlexander Leidinger mask = ((1 << size) - 1) << offset; 672d056fa04SAlexander Leidinger val &= mask; 673d056fa04SAlexander Leidinger val >>= offset; 674d056fa04SAlexander Leidinger } 675d056fa04SAlexander Leidinger return (val); 676d056fa04SAlexander Leidinger } 677d056fa04SAlexander Leidinger 678d056fa04SAlexander Leidinger void 679d056fa04SAlexander Leidinger emu_wrptr(struct emu_sc_info *sc, unsigned int chn, unsigned int reg, uint32_t data) 680d056fa04SAlexander Leidinger { 681d056fa04SAlexander Leidinger uint32_t ptr, mask, size, offset; 682b28624fdSAriff Abdullah 68370e0bbedSPedro F. Giffuni ptr = ((reg << 16) & sc->address_mask) | (chn & EMU_PTR_CHNO_MASK); 684b28624fdSAriff Abdullah 685b28624fdSAriff Abdullah EMU_RWLOCK(); 68670e0bbedSPedro F. Giffuni emu_wr_nolock(sc, EMU_PTR, ptr, 4); 687d056fa04SAlexander Leidinger /* 688d056fa04SAlexander Leidinger * XXX Another kind of magic encoding in register number. This can 689d056fa04SAlexander Leidinger * give you side effect - it will read previous data from register 690d056fa04SAlexander Leidinger * and change only required bits. 691d056fa04SAlexander Leidinger */ 692d056fa04SAlexander Leidinger if (reg & 0xff000000) { 693d056fa04SAlexander Leidinger size = (reg >> 24) & 0x3f; 694d056fa04SAlexander Leidinger offset = (reg >> 16) & 0x1f; 695d056fa04SAlexander Leidinger mask = ((1 << size) - 1) << offset; 696d056fa04SAlexander Leidinger data <<= offset; 697d056fa04SAlexander Leidinger data &= mask; 69870e0bbedSPedro F. Giffuni data |= emu_rd_nolock(sc, EMU_DATA, 4) & ~mask; 699d056fa04SAlexander Leidinger } 70070e0bbedSPedro F. Giffuni emu_wr_nolock(sc, EMU_DATA, data, 4); 701b28624fdSAriff Abdullah EMU_RWUNLOCK(); 702d056fa04SAlexander Leidinger } 703d056fa04SAlexander Leidinger /* 70470e0bbedSPedro F. Giffuni * EMU_A2_PTR / EMU_DATA2 interface. Access to P16v is made 705d056fa04SAlexander Leidinger * via (channel, register) pair. Some registers are channel-specific, 706d056fa04SAlexander Leidinger * some not. This interface is supported by CA0102 and CA0108 chips only. 707d056fa04SAlexander Leidinger */ 708d056fa04SAlexander Leidinger uint32_t 709d056fa04SAlexander Leidinger emu_rd_p16vptr(struct emu_sc_info *sc, uint16_t chn, uint16_t reg) 710d056fa04SAlexander Leidinger { 711d056fa04SAlexander Leidinger uint32_t val; 712d056fa04SAlexander Leidinger 713b28624fdSAriff Abdullah /* XXX separate lock? */ 714b28624fdSAriff Abdullah EMU_RWLOCK(); 71570e0bbedSPedro F. Giffuni emu_wr_nolock(sc, EMU_A2_PTR, (reg << 16) | chn, 4); 71670e0bbedSPedro F. Giffuni val = emu_rd_nolock(sc, EMU_DATA2, 4); 717b28624fdSAriff Abdullah 718b28624fdSAriff Abdullah EMU_RWUNLOCK(); 719b28624fdSAriff Abdullah 720d056fa04SAlexander Leidinger return (val); 721d056fa04SAlexander Leidinger } 722d056fa04SAlexander Leidinger 723d056fa04SAlexander Leidinger void 724d056fa04SAlexander Leidinger emu_wr_p16vptr(struct emu_sc_info *sc, uint16_t chn, uint16_t reg, uint32_t data) 725d056fa04SAlexander Leidinger { 726d056fa04SAlexander Leidinger 727b28624fdSAriff Abdullah EMU_RWLOCK(); 72870e0bbedSPedro F. Giffuni emu_wr_nolock(sc, EMU_A2_PTR, (reg << 16) | chn, 4); 72970e0bbedSPedro F. Giffuni emu_wr_nolock(sc, EMU_DATA2, data, 4); 730b28624fdSAriff Abdullah EMU_RWUNLOCK(); 731d056fa04SAlexander Leidinger } 732d056fa04SAlexander Leidinger /* 733d056fa04SAlexander Leidinger * XXX CardBus interface. Not tested on any real hardware. 734d056fa04SAlexander Leidinger */ 735d056fa04SAlexander Leidinger static void 736d056fa04SAlexander Leidinger emu_wr_cbptr(struct emu_sc_info *sc, uint32_t data) 737d056fa04SAlexander Leidinger { 738d056fa04SAlexander Leidinger uint32_t val; 739d056fa04SAlexander Leidinger 740b28624fdSAriff Abdullah /* 741b28624fdSAriff Abdullah * 0x38 is IPE3 (CD S/PDIF interrupt pending register) on CA0102. Seems 742d056fa04SAlexander Leidinger * to be some reg/value accessible kind of config register on CardBus 743b28624fdSAriff Abdullah * CA0108, with value(?) in top 16 bit, address(?) in low 16 744b28624fdSAriff Abdullah */ 745b28624fdSAriff Abdullah 746d056fa04SAlexander Leidinger val = emu_rd_nolock(sc, 0x38, 4); 747d056fa04SAlexander Leidinger emu_wr_nolock(sc, 0x38, data, 4); 748d056fa04SAlexander Leidinger val = emu_rd_nolock(sc, 0x38, 4); 749b28624fdSAriff Abdullah 750d056fa04SAlexander Leidinger } 751d056fa04SAlexander Leidinger 752d056fa04SAlexander Leidinger /* 753d056fa04SAlexander Leidinger * Direct hardware register access 75470e0bbedSPedro F. Giffuni * Assume that it is never used to access EMU_PTR-based registers and can run unlocked. 755d056fa04SAlexander Leidinger */ 756d056fa04SAlexander Leidinger void 757d056fa04SAlexander Leidinger emu_wr(struct emu_sc_info *sc, unsigned int regno, uint32_t data, unsigned int size) 758d056fa04SAlexander Leidinger { 75970e0bbedSPedro F. Giffuni KASSERT(regno != EMU_PTR, ("emu_wr: attempt to write to EMU_PTR")); 76070e0bbedSPedro F. Giffuni KASSERT(regno != EMU_A2_PTR, ("emu_wr: attempt to write to EMU_A2_PTR")); 761d056fa04SAlexander Leidinger 762d056fa04SAlexander Leidinger emu_wr_nolock(sc, regno, data, size); 763d056fa04SAlexander Leidinger } 764d056fa04SAlexander Leidinger 765d056fa04SAlexander Leidinger uint32_t 766d056fa04SAlexander Leidinger emu_rd(struct emu_sc_info *sc, unsigned int regno, unsigned int size) 767d056fa04SAlexander Leidinger { 768d056fa04SAlexander Leidinger uint32_t rd; 769d056fa04SAlexander Leidinger 77070e0bbedSPedro F. Giffuni KASSERT(regno != EMU_DATA, ("emu_rd: attempt to read DATA")); 77170e0bbedSPedro F. Giffuni KASSERT(regno != EMU_DATA2, ("emu_rd: attempt to read DATA2")); 772b28624fdSAriff Abdullah 773d056fa04SAlexander Leidinger rd = emu_rd_nolock(sc, regno, size); 774d056fa04SAlexander Leidinger return (rd); 775d056fa04SAlexander Leidinger } 776d056fa04SAlexander Leidinger 777d056fa04SAlexander Leidinger /* 778d056fa04SAlexander Leidinger * Enabling IR MIDI messages is another kind of black magic. It just 779d056fa04SAlexander Leidinger * has to be made this way. It really do it. 780d056fa04SAlexander Leidinger */ 781d056fa04SAlexander Leidinger void 782d056fa04SAlexander Leidinger emu_enable_ir(struct emu_sc_info *sc) 783d056fa04SAlexander Leidinger { 784d056fa04SAlexander Leidinger uint32_t iocfg; 785d056fa04SAlexander Leidinger 786d056fa04SAlexander Leidinger if (sc->is_emu10k2 || sc->is_ca0102) { 78770e0bbedSPedro F. Giffuni iocfg = emu_rd_nolock(sc, EMU_A_IOCFG, 2); 78870e0bbedSPedro F. Giffuni emu_wr_nolock(sc, EMU_A_IOCFG, iocfg | EMU_A_IOCFG_GPOUT2, 2); 789d056fa04SAlexander Leidinger DELAY(500); 79070e0bbedSPedro F. Giffuni emu_wr_nolock(sc, EMU_A_IOCFG, iocfg | EMU_A_IOCFG_GPOUT1 | EMU_A_IOCFG_GPOUT2, 2); 791d056fa04SAlexander Leidinger DELAY(500); 79270e0bbedSPedro F. Giffuni emu_wr_nolock(sc, EMU_A_IOCFG, iocfg | EMU_A_IOCFG_GPOUT1, 2); 793d056fa04SAlexander Leidinger DELAY(100); 79470e0bbedSPedro F. Giffuni emu_wr_nolock(sc, EMU_A_IOCFG, iocfg, 2); 795d056fa04SAlexander Leidinger device_printf(sc->dev, "Audigy IR MIDI events enabled.\n"); 796d056fa04SAlexander Leidinger sc->enable_ir = 1; 797d056fa04SAlexander Leidinger } 798d056fa04SAlexander Leidinger if (sc->is_emu10k1) { 79970e0bbedSPedro F. Giffuni iocfg = emu_rd_nolock(sc, EMU_HCFG, 4); 80070e0bbedSPedro F. Giffuni emu_wr_nolock(sc, EMU_HCFG, iocfg | EMU_HCFG_GPOUT2, 4); 801d056fa04SAlexander Leidinger DELAY(500); 80270e0bbedSPedro F. Giffuni emu_wr_nolock(sc, EMU_HCFG, iocfg | EMU_HCFG_GPOUT1 | EMU_HCFG_GPOUT2, 4); 803d056fa04SAlexander Leidinger DELAY(100); 80470e0bbedSPedro F. Giffuni emu_wr_nolock(sc, EMU_HCFG, iocfg, 4); 805d056fa04SAlexander Leidinger device_printf(sc->dev, "SB Live! IR MIDI events enabled.\n"); 806d056fa04SAlexander Leidinger sc->enable_ir = 1; 807d056fa04SAlexander Leidinger } 808d056fa04SAlexander Leidinger } 809d056fa04SAlexander Leidinger 810d056fa04SAlexander Leidinger 811d056fa04SAlexander Leidinger /* 8122fc83448SJoel Dahl * emu_timer_ - HW timer management 813d056fa04SAlexander Leidinger */ 814d056fa04SAlexander Leidinger int 815d056fa04SAlexander Leidinger emu_timer_create(struct emu_sc_info *sc) 816d056fa04SAlexander Leidinger { 817d056fa04SAlexander Leidinger int i, timer; 818d056fa04SAlexander Leidinger 819d056fa04SAlexander Leidinger timer = -1; 820b28624fdSAriff Abdullah 821b28624fdSAriff Abdullah mtx_lock(&sc->lock); 822d056fa04SAlexander Leidinger for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) 823d056fa04SAlexander Leidinger if (sc->timer[i] == 0) { 824d056fa04SAlexander Leidinger sc->timer[i] = -1; /* disable it */ 825d056fa04SAlexander Leidinger timer = i; 826b28624fdSAriff Abdullah mtx_unlock(&sc->lock); 827d056fa04SAlexander Leidinger return (timer); 828d056fa04SAlexander Leidinger } 829b28624fdSAriff Abdullah mtx_unlock(&sc->lock); 830d056fa04SAlexander Leidinger 831d056fa04SAlexander Leidinger return (-1); 832d056fa04SAlexander Leidinger } 833d056fa04SAlexander Leidinger 834d056fa04SAlexander Leidinger int 835d056fa04SAlexander Leidinger emu_timer_set(struct emu_sc_info *sc, int timer, int delay) 836d056fa04SAlexander Leidinger { 837d056fa04SAlexander Leidinger int i; 838d056fa04SAlexander Leidinger 839f856af04SAlexander Leidinger if (timer < 0) 840f856af04SAlexander Leidinger return (-1); 841f856af04SAlexander Leidinger 842d056fa04SAlexander Leidinger RANGE(delay, 16, 1024); 843f856af04SAlexander Leidinger RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1); 844d056fa04SAlexander Leidinger 845b28624fdSAriff Abdullah mtx_lock(&sc->lock); 846d056fa04SAlexander Leidinger sc->timer[timer] = delay; 847d056fa04SAlexander Leidinger for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) 848d056fa04SAlexander Leidinger if (sc->timerinterval > sc->timer[i]) 849d056fa04SAlexander Leidinger sc->timerinterval = sc->timer[i]; 850d056fa04SAlexander Leidinger 851b28624fdSAriff Abdullah /* XXX */ 85270e0bbedSPedro F. Giffuni emu_wr(sc, EMU_TIMER, sc->timerinterval & 0x03ff, 2); 853b28624fdSAriff Abdullah mtx_unlock(&sc->lock); 854b28624fdSAriff Abdullah 855d056fa04SAlexander Leidinger return (timer); 856d056fa04SAlexander Leidinger } 857d056fa04SAlexander Leidinger 858d056fa04SAlexander Leidinger int 859d056fa04SAlexander Leidinger emu_timer_enable(struct emu_sc_info *sc, int timer, int go) 860d056fa04SAlexander Leidinger { 861d056fa04SAlexander Leidinger uint32_t x; 862d056fa04SAlexander Leidinger int ena_int; 863d056fa04SAlexander Leidinger int i; 864d056fa04SAlexander Leidinger 865f856af04SAlexander Leidinger if (timer < 0) 866f856af04SAlexander Leidinger return (-1); 867f856af04SAlexander Leidinger 868f856af04SAlexander Leidinger RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1); 869f856af04SAlexander Leidinger 870d056fa04SAlexander Leidinger mtx_lock(&sc->lock); 871d056fa04SAlexander Leidinger 872d056fa04SAlexander Leidinger if ((go == 1) && (sc->timer[timer] < 0)) 873d056fa04SAlexander Leidinger sc->timer[timer] = -sc->timer[timer]; 874d056fa04SAlexander Leidinger if ((go == 0) && (sc->timer[timer] > 0)) 875d056fa04SAlexander Leidinger sc->timer[timer] = -sc->timer[timer]; 876d056fa04SAlexander Leidinger 877d056fa04SAlexander Leidinger ena_int = 0; 878d056fa04SAlexander Leidinger for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) { 879d056fa04SAlexander Leidinger if (sc->timerinterval > sc->timer[i]) 880d056fa04SAlexander Leidinger sc->timerinterval = sc->timer[i]; 881d056fa04SAlexander Leidinger if (sc->timer[i] > 0) 882d056fa04SAlexander Leidinger ena_int = 1; 883d056fa04SAlexander Leidinger } 884d056fa04SAlexander Leidinger 88570e0bbedSPedro F. Giffuni emu_wr(sc, EMU_TIMER, sc->timerinterval & 0x03ff, 2); 886d056fa04SAlexander Leidinger 887d056fa04SAlexander Leidinger if (ena_int == 1) { 88870e0bbedSPedro F. Giffuni x = emu_rd(sc, EMU_INTE, 4); 88970e0bbedSPedro F. Giffuni x |= EMU_INTE_INTERTIMERENB; 89070e0bbedSPedro F. Giffuni emu_wr(sc, EMU_INTE, x, 4); 891d056fa04SAlexander Leidinger } else { 89270e0bbedSPedro F. Giffuni x = emu_rd(sc, EMU_INTE, 4); 89370e0bbedSPedro F. Giffuni x &= ~EMU_INTE_INTERTIMERENB; 89470e0bbedSPedro F. Giffuni emu_wr(sc, EMU_INTE, x, 4); 895d056fa04SAlexander Leidinger } 896d056fa04SAlexander Leidinger mtx_unlock(&sc->lock); 897d056fa04SAlexander Leidinger return (0); 898d056fa04SAlexander Leidinger } 899d056fa04SAlexander Leidinger 900d056fa04SAlexander Leidinger int 901d056fa04SAlexander Leidinger emu_timer_clear(struct emu_sc_info *sc, int timer) 902d056fa04SAlexander Leidinger { 903f856af04SAlexander Leidinger if (timer < 0) 904f856af04SAlexander Leidinger return (-1); 905f856af04SAlexander Leidinger 906f856af04SAlexander Leidinger RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1); 907f856af04SAlexander Leidinger 908d056fa04SAlexander Leidinger emu_timer_enable(sc, timer, 0); 909d056fa04SAlexander Leidinger 910d056fa04SAlexander Leidinger mtx_lock(&sc->lock); 911d056fa04SAlexander Leidinger if (sc->timer[timer] != 0) 912d056fa04SAlexander Leidinger sc->timer[timer] = 0; 913d056fa04SAlexander Leidinger mtx_unlock(&sc->lock); 914d056fa04SAlexander Leidinger 915d056fa04SAlexander Leidinger return (timer); 916d056fa04SAlexander Leidinger } 917d056fa04SAlexander Leidinger 918d056fa04SAlexander Leidinger /* 9192fc83448SJoel Dahl * emu_intr_ - HW interrupt handler management 920d056fa04SAlexander Leidinger */ 921d056fa04SAlexander Leidinger int 922d056fa04SAlexander Leidinger emu_intr_register(struct emu_sc_info *sc, uint32_t inte_mask, uint32_t intr_mask, uint32_t(*func) (void *softc, uint32_t irq), void *isc) 923d056fa04SAlexander Leidinger { 924d056fa04SAlexander Leidinger int i; 925d056fa04SAlexander Leidinger uint32_t x; 926d056fa04SAlexander Leidinger 927d056fa04SAlexander Leidinger mtx_lock(&sc->lock); 928d056fa04SAlexander Leidinger for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) 929d056fa04SAlexander Leidinger if (sc->ihandler[i].inte_mask == 0) { 930d056fa04SAlexander Leidinger sc->ihandler[i].inte_mask = inte_mask; 931d056fa04SAlexander Leidinger sc->ihandler[i].intr_mask = intr_mask; 932d056fa04SAlexander Leidinger sc->ihandler[i].softc = isc; 933d056fa04SAlexander Leidinger sc->ihandler[i].irq_func = func; 93470e0bbedSPedro F. Giffuni x = emu_rd(sc, EMU_INTE, 4); 935d056fa04SAlexander Leidinger x |= inte_mask; 93670e0bbedSPedro F. Giffuni emu_wr(sc, EMU_INTE, x, 4); 937d056fa04SAlexander Leidinger mtx_unlock(&sc->lock); 938b28624fdSAriff Abdullah if (sc->dbg_level > 1) 939f856af04SAlexander Leidinger device_printf(sc->dev, "ihandle %d registered\n", i); 940b28624fdSAriff Abdullah 941d056fa04SAlexander Leidinger return (i); 942d056fa04SAlexander Leidinger } 943d056fa04SAlexander Leidinger mtx_unlock(&sc->lock); 944b28624fdSAriff Abdullah if (sc->dbg_level > 1) 945f856af04SAlexander Leidinger device_printf(sc->dev, "ihandle not registered\n"); 946b28624fdSAriff Abdullah 947d056fa04SAlexander Leidinger return (-1); 948d056fa04SAlexander Leidinger } 949d056fa04SAlexander Leidinger 950d056fa04SAlexander Leidinger int 951d056fa04SAlexander Leidinger emu_intr_unregister(struct emu_sc_info *sc, int hnumber) 952d056fa04SAlexander Leidinger { 953d056fa04SAlexander Leidinger uint32_t x; 954d056fa04SAlexander Leidinger int i; 955d056fa04SAlexander Leidinger 956d056fa04SAlexander Leidinger mtx_lock(&sc->lock); 957d056fa04SAlexander Leidinger 958d056fa04SAlexander Leidinger if (sc->ihandler[hnumber].inte_mask == 0) { 959d056fa04SAlexander Leidinger mtx_unlock(&sc->lock); 960d056fa04SAlexander Leidinger return (-1); 961d056fa04SAlexander Leidinger } 962d056fa04SAlexander Leidinger 96370e0bbedSPedro F. Giffuni x = emu_rd(sc, EMU_INTE, 4); 964d056fa04SAlexander Leidinger x &= ~sc->ihandler[hnumber].inte_mask; 965d056fa04SAlexander Leidinger 966d056fa04SAlexander Leidinger sc->ihandler[hnumber].inte_mask = 0; 967d056fa04SAlexander Leidinger sc->ihandler[hnumber].intr_mask = 0; 968d056fa04SAlexander Leidinger sc->ihandler[hnumber].softc = NULL; 969d056fa04SAlexander Leidinger sc->ihandler[hnumber].irq_func = NULL; 970d056fa04SAlexander Leidinger 97170e0bbedSPedro F. Giffuni /* other interrupt handlers may use this EMU_INTE value */ 972d056fa04SAlexander Leidinger for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) 973d056fa04SAlexander Leidinger if (sc->ihandler[i].inte_mask != 0) 974d056fa04SAlexander Leidinger x |= sc->ihandler[i].inte_mask; 975d056fa04SAlexander Leidinger 97670e0bbedSPedro F. Giffuni emu_wr(sc, EMU_INTE, x, 4); 977d056fa04SAlexander Leidinger 978d056fa04SAlexander Leidinger mtx_unlock(&sc->lock); 979d056fa04SAlexander Leidinger return (hnumber); 980d056fa04SAlexander Leidinger } 981d056fa04SAlexander Leidinger 982d056fa04SAlexander Leidinger static void 983d056fa04SAlexander Leidinger emu_intr(void *p) 984d056fa04SAlexander Leidinger { 985d056fa04SAlexander Leidinger struct emu_sc_info *sc = (struct emu_sc_info *)p; 986d056fa04SAlexander Leidinger uint32_t stat, ack; 987d056fa04SAlexander Leidinger int i; 988d056fa04SAlexander Leidinger 989d056fa04SAlexander Leidinger for (;;) { 99070e0bbedSPedro F. Giffuni stat = emu_rd(sc, EMU_IPR, 4); 991d056fa04SAlexander Leidinger ack = 0; 992d056fa04SAlexander Leidinger if (stat == 0) 993d056fa04SAlexander Leidinger break; 99470e0bbedSPedro F. Giffuni emu_wr(sc, EMU_IPR, stat, 4); 995d056fa04SAlexander Leidinger for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) { 996d056fa04SAlexander Leidinger if ((((sc->ihandler[i].intr_mask) & stat) != 0) && 997d056fa04SAlexander Leidinger (((void *)sc->ihandler[i].irq_func) != NULL)) { 998d056fa04SAlexander Leidinger ack |= sc->ihandler[i].irq_func(sc->ihandler[i].softc, 999d056fa04SAlexander Leidinger (sc->ihandler[i].intr_mask) & stat); 1000d056fa04SAlexander Leidinger } 1001d056fa04SAlexander Leidinger } 1002b28624fdSAriff Abdullah if (sc->dbg_level > 1) 1003f856af04SAlexander Leidinger if (stat & (~ack)) 1004f856af04SAlexander Leidinger device_printf(sc->dev, "Unhandled interrupt: %08x\n", stat & (~ack)); 1005b28624fdSAriff Abdullah 1006d056fa04SAlexander Leidinger } 1007d056fa04SAlexander Leidinger 1008d056fa04SAlexander Leidinger if ((sc->is_ca0102) || (sc->is_ca0108)) 1009d056fa04SAlexander Leidinger for (;;) { 101070e0bbedSPedro F. Giffuni stat = emu_rd(sc, EMU_IPR2, 4); 1011d056fa04SAlexander Leidinger ack = 0; 1012d056fa04SAlexander Leidinger if (stat == 0) 1013d056fa04SAlexander Leidinger break; 101470e0bbedSPedro F. Giffuni emu_wr(sc, EMU_IPR2, stat, 4); 1015b28624fdSAriff Abdullah if (sc->dbg_level > 1) 101670e0bbedSPedro F. Giffuni device_printf(sc->dev, "EMU_IPR2: %08x\n", stat); 1017b28624fdSAriff Abdullah 10182fc83448SJoel Dahl break; /* to avoid infinite loop. should be removed 1019d056fa04SAlexander Leidinger * after completion of P16V interface. */ 1020d056fa04SAlexander Leidinger } 1021d056fa04SAlexander Leidinger 1022d056fa04SAlexander Leidinger if (sc->is_ca0102) 1023d056fa04SAlexander Leidinger for (;;) { 102470e0bbedSPedro F. Giffuni stat = emu_rd(sc, EMU_IPR3, 4); 1025d056fa04SAlexander Leidinger ack = 0; 1026d056fa04SAlexander Leidinger if (stat == 0) 1027d056fa04SAlexander Leidinger break; 102870e0bbedSPedro F. Giffuni emu_wr(sc, EMU_IPR3, stat, 4); 1029b28624fdSAriff Abdullah if (sc->dbg_level > 1) 103070e0bbedSPedro F. Giffuni device_printf(sc->dev, "EMU_IPR3: %08x\n", stat); 1031b28624fdSAriff Abdullah 1032d056fa04SAlexander Leidinger break; /* to avoid infinite loop. should be removed 1033d056fa04SAlexander Leidinger * after completion of S/PDIF interface */ 1034d056fa04SAlexander Leidinger } 1035d056fa04SAlexander Leidinger } 1036d056fa04SAlexander Leidinger 1037d056fa04SAlexander Leidinger 1038d056fa04SAlexander Leidinger /* 1039d056fa04SAlexander Leidinger * Get data from private emu10kx structure for PCM buffer allocation. 1040d056fa04SAlexander Leidinger * Used by PCM code only. 1041d056fa04SAlexander Leidinger */ 1042d056fa04SAlexander Leidinger bus_dma_tag_t 1043d056fa04SAlexander Leidinger emu_gettag(struct emu_sc_info *sc) 1044d056fa04SAlexander Leidinger { 1045d056fa04SAlexander Leidinger return (sc->mem.dmat); 1046d056fa04SAlexander Leidinger } 1047d056fa04SAlexander Leidinger 1048d056fa04SAlexander Leidinger static void 1049d056fa04SAlexander Leidinger emu_setmap(void *arg, bus_dma_segment_t * segs, int nseg, int error) 1050d056fa04SAlexander Leidinger { 1051d056fa04SAlexander Leidinger bus_addr_t *phys = (bus_addr_t *) arg; 1052d056fa04SAlexander Leidinger 1053d056fa04SAlexander Leidinger *phys = error ? 0 : (bus_addr_t) segs->ds_addr; 1054d056fa04SAlexander Leidinger 1055d056fa04SAlexander Leidinger if (bootverbose) { 1056d056fa04SAlexander Leidinger printf("emu10kx: setmap (%lx, %lx), nseg=%d, error=%d\n", 1057d056fa04SAlexander Leidinger (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len, 1058d056fa04SAlexander Leidinger nseg, error); 1059d056fa04SAlexander Leidinger } 1060d056fa04SAlexander Leidinger } 1061d056fa04SAlexander Leidinger 1062d056fa04SAlexander Leidinger static void * 106386843ea8SJohn Baldwin emu_malloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr, 106486843ea8SJohn Baldwin bus_dmamap_t *map) 1065d056fa04SAlexander Leidinger { 1066d056fa04SAlexander Leidinger void *dmabuf; 1067b28624fdSAriff Abdullah int error; 1068d056fa04SAlexander Leidinger 1069d056fa04SAlexander Leidinger *addr = 0; 107086843ea8SJohn Baldwin if ((error = bus_dmamem_alloc(mem->dmat, &dmabuf, BUS_DMA_NOWAIT, map))) { 1071b28624fdSAriff Abdullah if (mem->card->dbg_level > 2) 1072b28624fdSAriff Abdullah device_printf(mem->card->dev, "emu_malloc: failed to alloc DMA map: %d\n", error); 1073d056fa04SAlexander Leidinger return (NULL); 1074b28624fdSAriff Abdullah } 107586843ea8SJohn Baldwin if ((error = bus_dmamap_load(mem->dmat, *map, dmabuf, sz, emu_setmap, addr, 0)) || !*addr) { 1076b28624fdSAriff Abdullah if (mem->card->dbg_level > 2) 1077b28624fdSAriff Abdullah device_printf(mem->card->dev, "emu_malloc: failed to load DMA memory: %d\n", error); 107886843ea8SJohn Baldwin bus_dmamem_free(mem->dmat, dmabuf, *map); 1079d056fa04SAlexander Leidinger return (NULL); 1080b28624fdSAriff Abdullah } 1081d056fa04SAlexander Leidinger return (dmabuf); 1082d056fa04SAlexander Leidinger } 1083d056fa04SAlexander Leidinger 1084d056fa04SAlexander Leidinger static void 108586843ea8SJohn Baldwin emu_free(struct emu_mem *mem, void *dmabuf, bus_dmamap_t map) 1086d056fa04SAlexander Leidinger { 108786843ea8SJohn Baldwin bus_dmamap_unload(mem->dmat, map); 108886843ea8SJohn Baldwin bus_dmamem_free(mem->dmat, dmabuf, map); 1089d056fa04SAlexander Leidinger } 1090d056fa04SAlexander Leidinger 1091d056fa04SAlexander Leidinger static void * 1092d056fa04SAlexander Leidinger emu_memalloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr, const char *owner) 1093d056fa04SAlexander Leidinger { 1094d056fa04SAlexander Leidinger uint32_t blksz, start, idx, ofs, tmp, found; 1095d056fa04SAlexander Leidinger struct emu_memblk *blk; 1096d056fa04SAlexander Leidinger void *membuf; 1097d056fa04SAlexander Leidinger 1098d056fa04SAlexander Leidinger blksz = sz / EMUPAGESIZE; 1099d056fa04SAlexander Leidinger if (sz > (blksz * EMUPAGESIZE)) 1100d056fa04SAlexander Leidinger blksz++; 1101b28624fdSAriff Abdullah if (blksz > EMU_MAX_BUFSZ / EMUPAGESIZE) { 1102b28624fdSAriff Abdullah if (mem->card->dbg_level > 2) 1103b28624fdSAriff Abdullah device_printf(mem->card->dev, "emu_memalloc: memory request tool large\n"); 1104e4c87b14SAlexander Leidinger return (NULL); 1105b28624fdSAriff Abdullah } 1106d056fa04SAlexander Leidinger /* find a free block in the bitmap */ 1107d056fa04SAlexander Leidinger found = 0; 1108d056fa04SAlexander Leidinger start = 1; 1109e4c87b14SAlexander Leidinger while (!found && start + blksz < EMU_MAXPAGES) { 1110d056fa04SAlexander Leidinger found = 1; 1111d056fa04SAlexander Leidinger for (idx = start; idx < start + blksz; idx++) 1112d056fa04SAlexander Leidinger if (mem->bmap[idx >> 3] & (1 << (idx & 7))) 1113d056fa04SAlexander Leidinger found = 0; 1114d056fa04SAlexander Leidinger if (!found) 1115d056fa04SAlexander Leidinger start++; 1116d056fa04SAlexander Leidinger } 1117b28624fdSAriff Abdullah if (!found) { 1118b28624fdSAriff Abdullah if (mem->card->dbg_level > 2) 1119b28624fdSAriff Abdullah device_printf(mem->card->dev, "emu_memalloc: no free space in bitmap\n"); 1120d056fa04SAlexander Leidinger return (NULL); 1121b28624fdSAriff Abdullah } 1122d056fa04SAlexander Leidinger blk = malloc(sizeof(*blk), M_DEVBUF, M_NOWAIT); 1123b28624fdSAriff Abdullah if (blk == NULL) { 1124b28624fdSAriff Abdullah if (mem->card->dbg_level > 2) 1125b28624fdSAriff Abdullah device_printf(mem->card->dev, "emu_memalloc: buffer allocation failed\n"); 1126d056fa04SAlexander Leidinger return (NULL); 1127b28624fdSAriff Abdullah } 1128d056fa04SAlexander Leidinger bzero(blk, sizeof(*blk)); 112986843ea8SJohn Baldwin membuf = emu_malloc(mem, sz, &blk->buf_addr, &blk->buf_map); 1130d056fa04SAlexander Leidinger *addr = blk->buf_addr; 1131d056fa04SAlexander Leidinger if (membuf == NULL) { 1132b28624fdSAriff Abdullah if (mem->card->dbg_level > 2) 1133b28624fdSAriff Abdullah device_printf(mem->card->dev, "emu_memalloc: can't setup HW memory\n"); 1134d056fa04SAlexander Leidinger free(blk, M_DEVBUF); 1135d056fa04SAlexander Leidinger return (NULL); 1136d056fa04SAlexander Leidinger } 1137d056fa04SAlexander Leidinger blk->buf = membuf; 1138d056fa04SAlexander Leidinger blk->pte_start = start; 1139d056fa04SAlexander Leidinger blk->pte_size = blksz; 1140d056fa04SAlexander Leidinger strncpy(blk->owner, owner, 15); 1141d056fa04SAlexander Leidinger blk->owner[15] = '\0'; 1142d056fa04SAlexander Leidinger ofs = 0; 1143d056fa04SAlexander Leidinger for (idx = start; idx < start + blksz; idx++) { 1144d056fa04SAlexander Leidinger mem->bmap[idx >> 3] |= 1 << (idx & 7); 1145d02a6470SJohn Baldwin tmp = (uint32_t) (blk->buf_addr + ofs); 1146d056fa04SAlexander Leidinger mem->ptb_pages[idx] = (tmp << 1) | idx; 1147d056fa04SAlexander Leidinger ofs += EMUPAGESIZE; 1148d056fa04SAlexander Leidinger } 1149d056fa04SAlexander Leidinger SLIST_INSERT_HEAD(&mem->blocks, blk, link); 1150d056fa04SAlexander Leidinger return (membuf); 1151d056fa04SAlexander Leidinger } 1152d056fa04SAlexander Leidinger 1153d056fa04SAlexander Leidinger static int 1154d056fa04SAlexander Leidinger emu_memfree(struct emu_mem *mem, void *membuf) 1155d056fa04SAlexander Leidinger { 1156d056fa04SAlexander Leidinger uint32_t idx, tmp; 1157d056fa04SAlexander Leidinger struct emu_memblk *blk, *i; 1158d056fa04SAlexander Leidinger 1159d056fa04SAlexander Leidinger blk = NULL; 1160d056fa04SAlexander Leidinger SLIST_FOREACH(i, &mem->blocks, link) { 1161d056fa04SAlexander Leidinger if (i->buf == membuf) 1162d056fa04SAlexander Leidinger blk = i; 1163d056fa04SAlexander Leidinger } 1164d056fa04SAlexander Leidinger if (blk == NULL) 1165d056fa04SAlexander Leidinger return (EINVAL); 1166d056fa04SAlexander Leidinger SLIST_REMOVE(&mem->blocks, blk, emu_memblk, link); 116786843ea8SJohn Baldwin emu_free(mem, membuf, blk->buf_map); 1168d056fa04SAlexander Leidinger tmp = (uint32_t) (mem->silent_page_addr) << 1; 1169d056fa04SAlexander Leidinger for (idx = blk->pte_start; idx < blk->pte_start + blk->pte_size; idx++) { 1170d056fa04SAlexander Leidinger mem->bmap[idx >> 3] &= ~(1 << (idx & 7)); 1171d056fa04SAlexander Leidinger mem->ptb_pages[idx] = tmp | idx; 1172d056fa04SAlexander Leidinger } 1173d056fa04SAlexander Leidinger free(blk, M_DEVBUF); 1174d056fa04SAlexander Leidinger return (0); 1175d056fa04SAlexander Leidinger } 1176d056fa04SAlexander Leidinger 1177d056fa04SAlexander Leidinger static int 1178d056fa04SAlexander Leidinger emu_memstart(struct emu_mem *mem, void *membuf) 1179d056fa04SAlexander Leidinger { 1180d056fa04SAlexander Leidinger struct emu_memblk *blk, *i; 1181d056fa04SAlexander Leidinger 1182d056fa04SAlexander Leidinger blk = NULL; 1183d056fa04SAlexander Leidinger SLIST_FOREACH(i, &mem->blocks, link) { 1184d056fa04SAlexander Leidinger if (i->buf == membuf) 1185d056fa04SAlexander Leidinger blk = i; 1186d056fa04SAlexander Leidinger } 1187d056fa04SAlexander Leidinger if (blk == NULL) 1188d056fa04SAlexander Leidinger return (-1); 1189d056fa04SAlexander Leidinger return (blk->pte_start); 1190d056fa04SAlexander Leidinger } 1191d056fa04SAlexander Leidinger 1192d056fa04SAlexander Leidinger 1193d056fa04SAlexander Leidinger static uint32_t 1194d056fa04SAlexander Leidinger emu_rate_to_pitch(uint32_t rate) 1195d056fa04SAlexander Leidinger { 1196d056fa04SAlexander Leidinger static uint32_t logMagTable[128] = { 1197d056fa04SAlexander Leidinger 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2, 1198d056fa04SAlexander Leidinger 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5, 1199d056fa04SAlexander Leidinger 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081, 1200d056fa04SAlexander Leidinger 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191, 1201d056fa04SAlexander Leidinger 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7, 1202d056fa04SAlexander Leidinger 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829, 1203d056fa04SAlexander Leidinger 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e, 1204d056fa04SAlexander Leidinger 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26, 1205d056fa04SAlexander Leidinger 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d, 1206d056fa04SAlexander Leidinger 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885, 1207d056fa04SAlexander Leidinger 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899, 1208d056fa04SAlexander Leidinger 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c, 1209d056fa04SAlexander Leidinger 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3, 1210d056fa04SAlexander Leidinger 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3, 1211d056fa04SAlexander Leidinger 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83, 1212d056fa04SAlexander Leidinger 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df 1213d056fa04SAlexander Leidinger }; 1214d056fa04SAlexander Leidinger static char logSlopeTable[128] = { 1215d056fa04SAlexander Leidinger 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58, 1216d056fa04SAlexander Leidinger 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53, 1217d056fa04SAlexander Leidinger 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f, 1218d056fa04SAlexander Leidinger 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b, 1219d056fa04SAlexander Leidinger 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47, 1220d056fa04SAlexander Leidinger 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, 1221d056fa04SAlexander Leidinger 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41, 1222d056fa04SAlexander Leidinger 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 1223d056fa04SAlexander Leidinger 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 1224d056fa04SAlexander Leidinger 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 1225d056fa04SAlexander Leidinger 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37, 1226d056fa04SAlexander Leidinger 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35, 1227d056fa04SAlexander Leidinger 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34, 1228d056fa04SAlexander Leidinger 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32, 1229d056fa04SAlexander Leidinger 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, 1230d056fa04SAlexander Leidinger 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f 1231d056fa04SAlexander Leidinger }; 1232d056fa04SAlexander Leidinger int i; 1233d056fa04SAlexander Leidinger 1234d056fa04SAlexander Leidinger if (rate == 0) 1235d056fa04SAlexander Leidinger return (0); 1236d056fa04SAlexander Leidinger rate *= 11185; /* Scale 48000 to 0x20002380 */ 1237d056fa04SAlexander Leidinger for (i = 31; i > 0; i--) { 1238d056fa04SAlexander Leidinger if (rate & 0x80000000) { /* Detect leading "1" */ 1239d056fa04SAlexander Leidinger return (((uint32_t) (i - 15) << 20) + 1240d056fa04SAlexander Leidinger logMagTable[0x7f & (rate >> 24)] + 1241d056fa04SAlexander Leidinger (0x7f & (rate >> 17)) * 1242d056fa04SAlexander Leidinger logSlopeTable[0x7f & (rate >> 24)]); 1243d056fa04SAlexander Leidinger } 1244d056fa04SAlexander Leidinger rate <<= 1; 1245d056fa04SAlexander Leidinger } 1246d056fa04SAlexander Leidinger /* NOTREACHED */ 1247d056fa04SAlexander Leidinger return (0); 1248d056fa04SAlexander Leidinger } 1249d056fa04SAlexander Leidinger 1250d056fa04SAlexander Leidinger static uint32_t 1251d056fa04SAlexander Leidinger emu_rate_to_linearpitch(uint32_t rate) 1252d056fa04SAlexander Leidinger { 1253d056fa04SAlexander Leidinger rate = (rate << 8) / 375; 1254d056fa04SAlexander Leidinger return ((rate >> 1) + (rate & 1)); 1255d056fa04SAlexander Leidinger } 1256d056fa04SAlexander Leidinger 1257d056fa04SAlexander Leidinger struct emu_voice * 1258d056fa04SAlexander Leidinger emu_valloc(struct emu_sc_info *sc) 1259d056fa04SAlexander Leidinger { 1260d056fa04SAlexander Leidinger struct emu_voice *v; 1261d056fa04SAlexander Leidinger int i; 1262d056fa04SAlexander Leidinger 1263d056fa04SAlexander Leidinger v = NULL; 1264d056fa04SAlexander Leidinger mtx_lock(&sc->lock); 1265d056fa04SAlexander Leidinger for (i = 0; i < NUM_G && sc->voice[i].busy; i++); 1266d056fa04SAlexander Leidinger if (i < NUM_G) { 1267d056fa04SAlexander Leidinger v = &sc->voice[i]; 1268d056fa04SAlexander Leidinger v->busy = 1; 1269d056fa04SAlexander Leidinger } 1270d056fa04SAlexander Leidinger mtx_unlock(&sc->lock); 1271d056fa04SAlexander Leidinger return (v); 1272d056fa04SAlexander Leidinger } 1273d056fa04SAlexander Leidinger 1274d056fa04SAlexander Leidinger void 1275d056fa04SAlexander Leidinger emu_vfree(struct emu_sc_info *sc, struct emu_voice *v) 1276d056fa04SAlexander Leidinger { 1277d056fa04SAlexander Leidinger int i, r; 1278d056fa04SAlexander Leidinger 1279d056fa04SAlexander Leidinger mtx_lock(&sc->lock); 1280d056fa04SAlexander Leidinger for (i = 0; i < NUM_G; i++) { 1281d056fa04SAlexander Leidinger if (v == &sc->voice[i] && sc->voice[i].busy) { 1282d056fa04SAlexander Leidinger v->busy = 0; 1283b28624fdSAriff Abdullah /* 1284b28624fdSAriff Abdullah * XXX What we should do with mono channels? 1285b28624fdSAriff Abdullah * See -pcm.c emupchan_init for other side of 1286b28624fdSAriff Abdullah * this problem 1287b28624fdSAriff Abdullah */ 1288d056fa04SAlexander Leidinger if (v->slave != NULL) 1289d056fa04SAlexander Leidinger r = emu_memfree(&sc->mem, v->vbuf); 1290d056fa04SAlexander Leidinger } 1291d056fa04SAlexander Leidinger } 1292d056fa04SAlexander Leidinger mtx_unlock(&sc->lock); 1293d056fa04SAlexander Leidinger } 1294d056fa04SAlexander Leidinger 1295d056fa04SAlexander Leidinger int 1296d056fa04SAlexander Leidinger emu_vinit(struct emu_sc_info *sc, struct emu_voice *m, struct emu_voice *s, 1297d056fa04SAlexander Leidinger uint32_t sz, struct snd_dbuf *b) 1298d056fa04SAlexander Leidinger { 1299d056fa04SAlexander Leidinger void *vbuf; 1300d056fa04SAlexander Leidinger bus_addr_t tmp_addr; 1301d056fa04SAlexander Leidinger 1302d056fa04SAlexander Leidinger vbuf = emu_memalloc(&sc->mem, sz, &tmp_addr, "vinit"); 1303b28624fdSAriff Abdullah if (vbuf == NULL) { 1304b28624fdSAriff Abdullah if(sc->dbg_level > 2) 1305b28624fdSAriff Abdullah device_printf(sc->dev, "emu_memalloc returns NULL in enu_vinit\n"); 1306d056fa04SAlexander Leidinger return (ENOMEM); 1307b28624fdSAriff Abdullah } 1308d056fa04SAlexander Leidinger if (b != NULL) 1309d056fa04SAlexander Leidinger sndbuf_setup(b, vbuf, sz); 1310d056fa04SAlexander Leidinger m->start = emu_memstart(&sc->mem, vbuf) * EMUPAGESIZE; 1311b28624fdSAriff Abdullah if (m->start < 0) { 1312b28624fdSAriff Abdullah if(sc->dbg_level > 2) 1313b28624fdSAriff Abdullah device_printf(sc->dev, "emu_memstart returns (-1) in enu_vinit\n"); 1314d056fa04SAlexander Leidinger emu_memfree(&sc->mem, vbuf); 1315d056fa04SAlexander Leidinger return (ENOMEM); 1316d056fa04SAlexander Leidinger } 1317d056fa04SAlexander Leidinger m->end = m->start + sz; 1318d056fa04SAlexander Leidinger m->speed = 0; 1319d056fa04SAlexander Leidinger m->b16 = 0; 1320d056fa04SAlexander Leidinger m->stereo = 0; 1321d056fa04SAlexander Leidinger m->running = 0; 1322d056fa04SAlexander Leidinger m->ismaster = 1; 1323d056fa04SAlexander Leidinger m->vol = 0xff; 1324d056fa04SAlexander Leidinger m->buf = tmp_addr; 1325d056fa04SAlexander Leidinger m->vbuf = vbuf; 1326d056fa04SAlexander Leidinger m->slave = s; 1327d056fa04SAlexander Leidinger if (s != NULL) { 1328d056fa04SAlexander Leidinger s->start = m->start; 1329d056fa04SAlexander Leidinger s->end = m->end; 1330d056fa04SAlexander Leidinger s->speed = 0; 1331d056fa04SAlexander Leidinger s->b16 = 0; 1332d056fa04SAlexander Leidinger s->stereo = 0; 1333d056fa04SAlexander Leidinger s->running = 0; 1334d056fa04SAlexander Leidinger s->ismaster = 0; 1335d056fa04SAlexander Leidinger s->vol = m->vol; 1336d056fa04SAlexander Leidinger s->buf = m->buf; 1337d056fa04SAlexander Leidinger s->vbuf = NULL; 1338d056fa04SAlexander Leidinger s->slave = NULL; 1339d056fa04SAlexander Leidinger } 1340d056fa04SAlexander Leidinger return (0); 1341d056fa04SAlexander Leidinger } 1342d056fa04SAlexander Leidinger 1343d056fa04SAlexander Leidinger void 1344d056fa04SAlexander Leidinger emu_vsetup(struct emu_voice *v, int fmt, int spd) 1345d056fa04SAlexander Leidinger { 1346d056fa04SAlexander Leidinger if (fmt) { 1347d056fa04SAlexander Leidinger v->b16 = (fmt & AFMT_16BIT) ? 1 : 0; 134890da2b28SAriff Abdullah v->stereo = (AFMT_CHANNEL(fmt) > 1) ? 1 : 0; 1349d056fa04SAlexander Leidinger if (v->slave != NULL) { 1350d056fa04SAlexander Leidinger v->slave->b16 = v->b16; 1351d056fa04SAlexander Leidinger v->slave->stereo = v->stereo; 1352d056fa04SAlexander Leidinger } 1353d056fa04SAlexander Leidinger } 1354d056fa04SAlexander Leidinger if (spd) { 1355d056fa04SAlexander Leidinger v->speed = spd; 1356d056fa04SAlexander Leidinger if (v->slave != NULL) 1357d056fa04SAlexander Leidinger v->slave->speed = v->speed; 1358d056fa04SAlexander Leidinger } 1359d056fa04SAlexander Leidinger } 1360d056fa04SAlexander Leidinger 1361d056fa04SAlexander Leidinger void 1362d056fa04SAlexander Leidinger emu_vroute(struct emu_sc_info *sc, struct emu_route *rt, struct emu_voice *v) 1363d056fa04SAlexander Leidinger { 1364d056fa04SAlexander Leidinger int i; 1365d056fa04SAlexander Leidinger 1366d056fa04SAlexander Leidinger for (i = 0; i < 8; i++) { 1367b28624fdSAriff Abdullah v->routing[i] = rt->routing_left[i]; 1368b28624fdSAriff Abdullah v->amounts[i] = rt->amounts_left[i]; 1369d056fa04SAlexander Leidinger } 1370d056fa04SAlexander Leidinger if ((v->stereo) && (v->ismaster == 0)) 1371d056fa04SAlexander Leidinger for (i = 0; i < 8; i++) { 1372b28624fdSAriff Abdullah v->routing[i] = rt->routing_right[i]; 1373b28624fdSAriff Abdullah v->amounts[i] = rt->amounts_right[i]; 1374d056fa04SAlexander Leidinger } 1375d056fa04SAlexander Leidinger 1376d056fa04SAlexander Leidinger if ((v->stereo) && (v->slave != NULL)) 1377d056fa04SAlexander Leidinger emu_vroute(sc, rt, v->slave); 1378d056fa04SAlexander Leidinger } 1379d056fa04SAlexander Leidinger 1380d056fa04SAlexander Leidinger void 1381d056fa04SAlexander Leidinger emu_vwrite(struct emu_sc_info *sc, struct emu_voice *v) 1382d056fa04SAlexander Leidinger { 1383d056fa04SAlexander Leidinger int s; 1384b28624fdSAriff Abdullah uint32_t start, val, silent_page; 1385d056fa04SAlexander Leidinger 1386d056fa04SAlexander Leidinger s = (v->stereo ? 1 : 0) + (v->b16 ? 1 : 0); 1387d056fa04SAlexander Leidinger 1388d056fa04SAlexander Leidinger v->sa = v->start >> s; 1389d056fa04SAlexander Leidinger v->ea = v->end >> s; 1390d056fa04SAlexander Leidinger 1391d056fa04SAlexander Leidinger 1392d056fa04SAlexander Leidinger if (v->stereo) { 139370e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CPF, EMU_CHAN_CPF_STEREO_MASK); 1394d056fa04SAlexander Leidinger } else { 139570e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CPF, 0); 1396d056fa04SAlexander Leidinger } 1397d056fa04SAlexander Leidinger val = v->stereo ? 28 : 30; 1398d056fa04SAlexander Leidinger val *= v->b16 ? 1 : 2; 1399d056fa04SAlexander Leidinger start = v->sa + val; 1400d056fa04SAlexander Leidinger 1401b28624fdSAriff Abdullah if (sc->is_emu10k1) { 140270e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_FXRT, ((v->routing[3] << 12) | 1403b28624fdSAriff Abdullah (v->routing[2] << 8) | 1404b28624fdSAriff Abdullah (v->routing[1] << 4) | 1405b28624fdSAriff Abdullah (v->routing[0] << 0)) << 16); 1406b28624fdSAriff Abdullah } else { 140770e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_A_CHAN_FXRT1, (v->routing[3] << 24) | 1408b28624fdSAriff Abdullah (v->routing[2] << 16) | 1409b28624fdSAriff Abdullah (v->routing[1] << 8) | 1410b28624fdSAriff Abdullah (v->routing[0] << 0)); 141170e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_A_CHAN_FXRT2, (v->routing[7] << 24) | 1412b28624fdSAriff Abdullah (v->routing[6] << 16) | 1413b28624fdSAriff Abdullah (v->routing[5] << 8) | 1414b28624fdSAriff Abdullah (v->routing[4] << 0)); 141570e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_A_CHAN_SENDAMOUNTS, (v->amounts[7] << 24) | 1416b28624fdSAriff Abdullah (v->amounts[6] << 26) | 1417b28624fdSAriff Abdullah (v->amounts[5] << 8) | 1418b28624fdSAriff Abdullah (v->amounts[4] << 0)); 1419b28624fdSAriff Abdullah } 142070e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX, (v->amounts[0] << 8) | (v->amounts[1] << 0)); 142170e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_DSL, v->ea | (v->amounts[3] << 24)); 142270e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_PSST, v->sa | (v->amounts[2] << 24)); 1423d056fa04SAlexander Leidinger 142470e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CCCA, start | (v->b16 ? 0 : EMU_CHAN_CCCA_8BITSELECT)); 142570e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_Z1, 0); 142670e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_Z2, 0); 1427d056fa04SAlexander Leidinger 142870e0bbedSPedro F. Giffuni silent_page = ((uint32_t) (sc->mem.silent_page_addr) << 1) | EMU_CHAN_MAP_PTI_MASK; 142970e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_MAPA, silent_page); 143070e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_MAPB, silent_page); 1431d056fa04SAlexander Leidinger 143270e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, EMU_CHAN_CVCF_CURRFILTER_MASK); 143370e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, EMU_CHAN_VTFT_FILTERTARGET_MASK); 143470e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_ATKHLDM, 0); 143570e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_DCYSUSM, EMU_CHAN_DCYSUSM_DECAYTIME_MASK); 143670e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_LFOVAL1, 0x8000); 143770e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_LFOVAL2, 0x8000); 143870e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_FMMOD, 0); 143970e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_TREMFRQ, 0); 144070e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_FM2FRQ2, 0); 144170e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_ENVVAL, 0x8000); 1442d056fa04SAlexander Leidinger 144370e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_ATKHLDV, EMU_CHAN_ATKHLDV_HOLDTIME_MASK | EMU_CHAN_ATKHLDV_ATTACKTIME_MASK); 144470e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_ENVVOL, 0x8000); 1445d056fa04SAlexander Leidinger 144670e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_PEFE_FILTERAMOUNT, 0x7f); 144770e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_PEFE_PITCHAMOUNT, 0); 1448d056fa04SAlexander Leidinger if ((v->stereo) && (v->slave != NULL)) 1449d056fa04SAlexander Leidinger emu_vwrite(sc, v->slave); 1450d056fa04SAlexander Leidinger } 1451d056fa04SAlexander Leidinger 1452d056fa04SAlexander Leidinger static void 1453d056fa04SAlexander Leidinger emu_vstop(struct emu_sc_info *sc, char channel, int enable) 1454d056fa04SAlexander Leidinger { 1455d056fa04SAlexander Leidinger int reg; 1456d056fa04SAlexander Leidinger 145770e0bbedSPedro F. Giffuni reg = (channel & 0x20) ? EMU_SOLEH : EMU_SOLEL; 1458d056fa04SAlexander Leidinger channel &= 0x1f; 1459d056fa04SAlexander Leidinger reg |= 1 << 24; 1460d056fa04SAlexander Leidinger reg |= channel << 16; 1461d056fa04SAlexander Leidinger emu_wrptr(sc, 0, reg, enable); 1462d056fa04SAlexander Leidinger } 1463d056fa04SAlexander Leidinger 1464d056fa04SAlexander Leidinger void 1465d056fa04SAlexander Leidinger emu_vtrigger(struct emu_sc_info *sc, struct emu_voice *v, int go) 1466d056fa04SAlexander Leidinger { 1467d056fa04SAlexander Leidinger uint32_t pitch_target, initial_pitch; 1468d056fa04SAlexander Leidinger uint32_t cra, cs, ccis; 1469d056fa04SAlexander Leidinger uint32_t sample, i; 1470d056fa04SAlexander Leidinger 1471d056fa04SAlexander Leidinger if (go) { 1472d056fa04SAlexander Leidinger cra = 64; 1473d056fa04SAlexander Leidinger cs = v->stereo ? 4 : 2; 1474d056fa04SAlexander Leidinger ccis = v->stereo ? 28 : 30; 1475d056fa04SAlexander Leidinger ccis *= v->b16 ? 1 : 2; 1476d056fa04SAlexander Leidinger sample = v->b16 ? 0x00000000 : 0x80808080; 1477d056fa04SAlexander Leidinger for (i = 0; i < cs; i++) 147870e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CD0 + i, sample); 147970e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_CACHEINVALIDSIZE, 0); 148070e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_READADDRESS, cra); 148170e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_CACHEINVALIDSIZE, ccis); 1482d056fa04SAlexander Leidinger 148370e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_IFATN, 0xff00); 148470e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, 0xffffffff); 148570e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, 0xffffffff); 148670e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_DCYSUSV, 0x00007f7f); 1487d056fa04SAlexander Leidinger emu_vstop(sc, v->vnum, 0); 1488d056fa04SAlexander Leidinger 1489d056fa04SAlexander Leidinger pitch_target = emu_rate_to_linearpitch(v->speed); 1490d056fa04SAlexander Leidinger initial_pitch = emu_rate_to_pitch(v->speed) >> 8; 149170e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX_PITCHTARGET, pitch_target); 149270e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CPF_PITCH, pitch_target); 149370e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_IP, initial_pitch); 1494d056fa04SAlexander Leidinger } else { 149570e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX_PITCHTARGET, 0); 149670e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CPF_PITCH, 0); 149770e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_IFATN, 0xffff); 149870e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, 0x0000ffff); 149970e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, 0x0000ffff); 150070e0bbedSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_IP, 0); 1501d056fa04SAlexander Leidinger emu_vstop(sc, v->vnum, 1); 1502d056fa04SAlexander Leidinger } 1503d056fa04SAlexander Leidinger if ((v->stereo) && (v->slave != NULL)) 1504d056fa04SAlexander Leidinger emu_vtrigger(sc, v->slave, go); 1505d056fa04SAlexander Leidinger } 1506d056fa04SAlexander Leidinger 1507d056fa04SAlexander Leidinger int 1508d056fa04SAlexander Leidinger emu_vpos(struct emu_sc_info *sc, struct emu_voice *v) 1509d056fa04SAlexander Leidinger { 1510d056fa04SAlexander Leidinger int s, ptr; 1511d056fa04SAlexander Leidinger 1512d056fa04SAlexander Leidinger s = (v->b16 ? 1 : 0) + (v->stereo ? 1 : 0); 151370e0bbedSPedro F. Giffuni ptr = (emu_rdptr(sc, v->vnum, EMU_CHAN_CCCA_CURRADDR) - (v->start >> s)) << s; 1514d056fa04SAlexander Leidinger return (ptr & ~0x0000001f); 1515d056fa04SAlexander Leidinger } 1516d056fa04SAlexander Leidinger 1517d056fa04SAlexander Leidinger 1518d056fa04SAlexander Leidinger /* fx */ 1519d056fa04SAlexander Leidinger static void 1520d056fa04SAlexander Leidinger emu_wrefx(struct emu_sc_info *sc, unsigned int pc, unsigned int data) 1521d056fa04SAlexander Leidinger { 1522d056fa04SAlexander Leidinger emu_wrptr(sc, 0, sc->code_base + pc, data); 1523d056fa04SAlexander Leidinger } 1524d056fa04SAlexander Leidinger 1525d056fa04SAlexander Leidinger 1526d056fa04SAlexander Leidinger static void 1527d056fa04SAlexander Leidinger emu_addefxop(struct emu_sc_info *sc, unsigned int op, unsigned int z, unsigned int w, unsigned int x, unsigned int y, uint32_t * pc) 1528d056fa04SAlexander Leidinger { 1529d056fa04SAlexander Leidinger if ((*pc) + 1 > sc->code_size) { 1530d056fa04SAlexander Leidinger device_printf(sc->dev, "DSP CODE OVERRUN: attept to write past code_size (pc=%d)\n", (*pc)); 1531d056fa04SAlexander Leidinger return; 1532d056fa04SAlexander Leidinger } 1533d056fa04SAlexander Leidinger emu_wrefx(sc, (*pc) * 2, (x << sc->high_operand_shift) | y); 1534d056fa04SAlexander Leidinger emu_wrefx(sc, (*pc) * 2 + 1, (op << sc->opcode_shift) | (z << sc->high_operand_shift) | w); 1535d056fa04SAlexander Leidinger (*pc)++; 1536d056fa04SAlexander Leidinger } 1537d056fa04SAlexander Leidinger 1538d056fa04SAlexander Leidinger static int 1539d056fa04SAlexander Leidinger sysctl_emu_mixer_control(SYSCTL_HANDLER_ARGS) 1540d056fa04SAlexander Leidinger { 1541d056fa04SAlexander Leidinger struct emu_sc_info *sc; 1542d056fa04SAlexander Leidinger int mixer_id; 1543d056fa04SAlexander Leidinger int new_vol; 1544d056fa04SAlexander Leidinger int err; 1545d056fa04SAlexander Leidinger 1546d056fa04SAlexander Leidinger sc = arg1; 1547d056fa04SAlexander Leidinger mixer_id = arg2; 1548d056fa04SAlexander Leidinger 1549d056fa04SAlexander Leidinger new_vol = emumix_get_volume(sc, mixer_id); 1550041b706bSDavid Malone err = sysctl_handle_int(oidp, &new_vol, 0, req); 1551d056fa04SAlexander Leidinger 1552d056fa04SAlexander Leidinger if (err || req->newptr == NULL) 1553d056fa04SAlexander Leidinger return (err); 1554d056fa04SAlexander Leidinger if (new_vol < 0 || new_vol > 100) 1555d056fa04SAlexander Leidinger return (EINVAL); 1556d056fa04SAlexander Leidinger emumix_set_volume(sc, mixer_id, new_vol); 1557d056fa04SAlexander Leidinger 1558d056fa04SAlexander Leidinger return (0); 1559d056fa04SAlexander Leidinger } 1560d056fa04SAlexander Leidinger 1561d056fa04SAlexander Leidinger static int 1562d056fa04SAlexander Leidinger emu_addefxmixer(struct emu_sc_info *sc, const char *mix_name, const int mix_id, uint32_t defvolume) 1563d056fa04SAlexander Leidinger { 1564d056fa04SAlexander Leidinger int volgpr; 15654002c392SAlexander Leidinger char sysctl_name[32]; 1566d056fa04SAlexander Leidinger 1567d056fa04SAlexander Leidinger volgpr = emu_rm_gpr_alloc(sc->rm, 1); 1568d056fa04SAlexander Leidinger emumix_set_fxvol(sc, volgpr, defvolume); 1569b28624fdSAriff Abdullah /* 1570b28624fdSAriff Abdullah * Mixer controls with NULL mix_name are handled 1571b28624fdSAriff Abdullah * by AC97 emulation code or PCM mixer. 1572b28624fdSAriff Abdullah */ 1573d056fa04SAlexander Leidinger if (mix_name != NULL) { 1574b28624fdSAriff Abdullah /* 1575b28624fdSAriff Abdullah * Temporary sysctls should start with underscore, 15764002c392SAlexander Leidinger * see freebsd-current mailing list, emu10kx driver 1577b28624fdSAriff Abdullah * discussion around 2006-05-24. 1578b28624fdSAriff Abdullah */ 15794002c392SAlexander Leidinger snprintf(sysctl_name, 32, "_%s", mix_name); 1580d056fa04SAlexander Leidinger SYSCTL_ADD_PROC(sc->ctx, 1581d056fa04SAlexander Leidinger SYSCTL_CHILDREN(sc->root), 15824002c392SAlexander Leidinger OID_AUTO, sysctl_name, 1583d056fa04SAlexander Leidinger CTLTYPE_INT | CTLFLAG_RW, sc, mix_id, 1584d056fa04SAlexander Leidinger sysctl_emu_mixer_control, "I", ""); 1585d056fa04SAlexander Leidinger } 1586d056fa04SAlexander Leidinger 1587d056fa04SAlexander Leidinger return (volgpr); 1588d056fa04SAlexander Leidinger } 1589d056fa04SAlexander Leidinger 1590b28624fdSAriff Abdullah static int 1591b28624fdSAriff Abdullah sysctl_emu_digitalswitch_control(SYSCTL_HANDLER_ARGS) 1592b28624fdSAriff Abdullah { 1593b28624fdSAriff Abdullah struct emu_sc_info *sc; 1594b28624fdSAriff Abdullah int new_val; 1595b28624fdSAriff Abdullah int err; 1596b28624fdSAriff Abdullah 1597b28624fdSAriff Abdullah sc = arg1; 1598b28624fdSAriff Abdullah 1599b28624fdSAriff Abdullah new_val = (sc->mode == MODE_DIGITAL) ? 1 : 0; 1600b28624fdSAriff Abdullah err = sysctl_handle_int(oidp, &new_val, 0, req); 1601b28624fdSAriff Abdullah 1602b28624fdSAriff Abdullah if (err || req->newptr == NULL) 1603b28624fdSAriff Abdullah return (err); 1604b28624fdSAriff Abdullah if (new_val < 0 || new_val > 1) 1605b28624fdSAriff Abdullah return (EINVAL); 1606b28624fdSAriff Abdullah 1607b28624fdSAriff Abdullah switch (new_val) { 1608b28624fdSAriff Abdullah case 0: 1609b28624fdSAriff Abdullah emumix_set_mode(sc, MODE_ANALOG); 1610b28624fdSAriff Abdullah break; 1611b28624fdSAriff Abdullah case 1: 1612b28624fdSAriff Abdullah emumix_set_mode(sc, MODE_DIGITAL); 1613b28624fdSAriff Abdullah break; 1614b28624fdSAriff Abdullah } 1615b28624fdSAriff Abdullah return (0); 1616b28624fdSAriff Abdullah } 1617b28624fdSAriff Abdullah 1618b28624fdSAriff Abdullah static void 1619b28624fdSAriff Abdullah emu_digitalswitch(struct emu_sc_info *sc) 1620b28624fdSAriff Abdullah { 1621b28624fdSAriff Abdullah /* XXX temporary? */ 1622b28624fdSAriff Abdullah SYSCTL_ADD_PROC(sc->ctx, 1623b28624fdSAriff Abdullah SYSCTL_CHILDREN(sc->root), 1624b28624fdSAriff Abdullah OID_AUTO, "_digital", 1625b28624fdSAriff Abdullah CTLTYPE_INT | CTLFLAG_RW, sc, 0, 1626b28624fdSAriff Abdullah sysctl_emu_digitalswitch_control, "I", "Enable digital output"); 1627b28624fdSAriff Abdullah 1628b28624fdSAriff Abdullah return; 1629b28624fdSAriff Abdullah } 1630b28624fdSAriff Abdullah 1631b28624fdSAriff Abdullah /* 1632b28624fdSAriff Abdullah * Allocate cache GPRs that will hold mixed output channels 1633d056fa04SAlexander Leidinger * and clear it on every DSP run. 1634d056fa04SAlexander Leidinger */ 1635d056fa04SAlexander Leidinger #define EFX_CACHE(CACHE_IDX) do { \ 1636d056fa04SAlexander Leidinger sc->cache_gpr[CACHE_IDX] = emu_rm_gpr_alloc(sc->rm, 1); \ 1637d056fa04SAlexander Leidinger emu_addefxop(sc, ACC3, \ 1638d056fa04SAlexander Leidinger GPR(sc->cache_gpr[CACHE_IDX]), \ 1639d056fa04SAlexander Leidinger DSP_CONST(0), \ 1640d056fa04SAlexander Leidinger DSP_CONST(0), \ 1641d056fa04SAlexander Leidinger DSP_CONST(0), \ 1642d056fa04SAlexander Leidinger &pc); \ 1643d056fa04SAlexander Leidinger } while (0) 1644d056fa04SAlexander Leidinger 1645d056fa04SAlexander Leidinger /* Allocate GPR for volume control and route sound: OUT = OUT + IN * VOL */ 1646d056fa04SAlexander Leidinger #define EFX_ROUTE(TITLE, INP_NR, IN_GPR_IDX, OUT_CACHE_IDX, DEF) do { \ 1647d056fa04SAlexander Leidinger sc->mixer_gpr[IN_GPR_IDX] = emu_addefxmixer(sc, TITLE, IN_GPR_IDX, DEF); \ 1648d056fa04SAlexander Leidinger sc->mixer_volcache[IN_GPR_IDX] = DEF; \ 1649d056fa04SAlexander Leidinger emu_addefxop(sc, MACS, \ 1650d056fa04SAlexander Leidinger GPR(sc->cache_gpr[OUT_CACHE_IDX]), \ 1651d056fa04SAlexander Leidinger GPR(sc->cache_gpr[OUT_CACHE_IDX]), \ 1652d056fa04SAlexander Leidinger INP_NR, \ 1653d056fa04SAlexander Leidinger GPR(sc->mixer_gpr[IN_GPR_IDX]), \ 1654d056fa04SAlexander Leidinger &pc); \ 1655d056fa04SAlexander Leidinger } while (0) 1656d056fa04SAlexander Leidinger 1657d056fa04SAlexander Leidinger /* allocate GPR, OUT = IN * VOL */ 1658d056fa04SAlexander Leidinger #define EFX_OUTPUT(TITLE, OUT_CACHE_IDX, OUT_GPR_IDX, OUTP_NR, DEF) do { \ 1659d056fa04SAlexander Leidinger sc->mixer_gpr[OUT_GPR_IDX] = emu_addefxmixer(sc, TITLE, OUT_GPR_IDX, DEF); \ 1660d056fa04SAlexander Leidinger sc->mixer_volcache[OUT_GPR_IDX] = DEF; \ 1661d056fa04SAlexander Leidinger emu_addefxop(sc, MACS, \ 1662d056fa04SAlexander Leidinger OUTP(OUTP_NR), \ 1663d056fa04SAlexander Leidinger DSP_CONST(0), \ 1664d056fa04SAlexander Leidinger GPR(sc->cache_gpr[OUT_CACHE_IDX]), \ 1665d056fa04SAlexander Leidinger GPR(sc->mixer_gpr[OUT_GPR_IDX]), \ 1666d056fa04SAlexander Leidinger &pc); \ 1667d056fa04SAlexander Leidinger } while (0) 1668d056fa04SAlexander Leidinger 1669d056fa04SAlexander Leidinger /* like EFX_OUTPUT, but don't allocate mixer gpr */ 1670d056fa04SAlexander Leidinger #define EFX_OUTPUTD(OUT_CACHE_IDX, OUT_GPR_IDX, OUTP_NR) do { \ 1671d056fa04SAlexander Leidinger emu_addefxop(sc, MACS, \ 1672d056fa04SAlexander Leidinger OUTP(OUTP_NR), \ 1673d056fa04SAlexander Leidinger DSP_CONST(0), \ 1674d056fa04SAlexander Leidinger GPR(sc->cache_gpr[OUT_CACHE_IDX]), \ 1675d056fa04SAlexander Leidinger GPR(sc->mixer_gpr[OUT_GPR_IDX]), \ 1676d056fa04SAlexander Leidinger &pc); \ 1677d056fa04SAlexander Leidinger } while (0) 1678d056fa04SAlexander Leidinger 1679b28624fdSAriff Abdullah /* skip next OPCOUNT instructions if FLAG != 0 */ 1680b28624fdSAriff Abdullah #define EFX_SKIP(OPCOUNT, FLAG_GPR) do { \ 1681b28624fdSAriff Abdullah emu_addefxop(sc, MACS, \ 1682b28624fdSAriff Abdullah DSP_CONST(0), \ 1683b28624fdSAriff Abdullah GPR(sc->mute_gpr[FLAG_GPR]), \ 1684b28624fdSAriff Abdullah DSP_CONST(0), \ 1685b28624fdSAriff Abdullah DSP_CONST(0), \ 1686b28624fdSAriff Abdullah &pc); \ 1687b28624fdSAriff Abdullah emu_addefxop(sc, SKIP, \ 1688b28624fdSAriff Abdullah DSP_CCR, \ 1689b28624fdSAriff Abdullah DSP_CCR, \ 1690b28624fdSAriff Abdullah COND_NEQ_ZERO, \ 1691b28624fdSAriff Abdullah OPCOUNT, \ 1692b28624fdSAriff Abdullah &pc); \ 1693f856af04SAlexander Leidinger } while (0) 1694f856af04SAlexander Leidinger 1695b28624fdSAriff Abdullah #define EFX_COPY(TO, FROM) do { \ 1696f856af04SAlexander Leidinger emu_addefxop(sc, ACC3, \ 1697b28624fdSAriff Abdullah TO, \ 1698f856af04SAlexander Leidinger DSP_CONST(0), \ 1699f856af04SAlexander Leidinger DSP_CONST(0), \ 1700b28624fdSAriff Abdullah FROM, \ 1701f856af04SAlexander Leidinger &pc); \ 1702f856af04SAlexander Leidinger } while (0) 1703f856af04SAlexander Leidinger 1704f856af04SAlexander Leidinger 1705d056fa04SAlexander Leidinger static void 1706d056fa04SAlexander Leidinger emu_initefx(struct emu_sc_info *sc) 1707d056fa04SAlexander Leidinger { 1708f856af04SAlexander Leidinger unsigned int i; 1709d056fa04SAlexander Leidinger uint32_t pc; 1710d056fa04SAlexander Leidinger 1711d056fa04SAlexander Leidinger /* stop DSP */ 1712d056fa04SAlexander Leidinger if (sc->is_emu10k1) { 171370e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_DBG, EMU_DBG_SINGLE_STEP); 1714d056fa04SAlexander Leidinger } else { 171570e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_A_DBG, EMU_A_DBG_SINGLE_STEP); 1716d056fa04SAlexander Leidinger } 1717d056fa04SAlexander Leidinger 1718d056fa04SAlexander Leidinger /* code size is in instructions */ 1719d056fa04SAlexander Leidinger pc = 0; 1720f856af04SAlexander Leidinger for (i = 0; i < sc->code_size; i++) { 1721d056fa04SAlexander Leidinger if (sc->is_emu10k1) { 1722d056fa04SAlexander Leidinger emu_addefxop(sc, ACC3, DSP_CONST(0x0), DSP_CONST(0x0), DSP_CONST(0x0), DSP_CONST(0x0), &pc); 1723d056fa04SAlexander Leidinger } else { 1724d056fa04SAlexander Leidinger emu_addefxop(sc, SKIP, DSP_CONST(0x0), DSP_CONST(0x0), DSP_CONST(0xf), DSP_CONST(0x0), &pc); 1725d056fa04SAlexander Leidinger } 1726d056fa04SAlexander Leidinger } 1727d056fa04SAlexander Leidinger 1728b28624fdSAriff Abdullah /* allocate GPRs for mute switches (EFX_SKIP). Mute by default */ 1729b28624fdSAriff Abdullah for (i = 0; i < NUM_MUTE; i++) { 1730b28624fdSAriff Abdullah sc->mute_gpr[i] = emu_rm_gpr_alloc(sc->rm, 1); 1731b28624fdSAriff Abdullah emumix_set_gpr(sc, sc->mute_gpr[i], 1); 1732b28624fdSAriff Abdullah } 1733b28624fdSAriff Abdullah emu_digitalswitch(sc); 1734b28624fdSAriff Abdullah 1735d056fa04SAlexander Leidinger pc = 0; 1736d056fa04SAlexander Leidinger 1737d056fa04SAlexander Leidinger /* 1738d056fa04SAlexander Leidinger * DSP code below is not good, because: 1739d056fa04SAlexander Leidinger * 1. It can be written smaller, if it can use DSP accumulator register 1740d056fa04SAlexander Leidinger * instead of cache_gpr[]. 1741d056fa04SAlexander Leidinger * 2. It can be more careful when volume is 100%, because in DSP 1742d056fa04SAlexander Leidinger * x*0x7fffffff may not be equal to x ! 1743d056fa04SAlexander Leidinger */ 1744d056fa04SAlexander Leidinger 1745d056fa04SAlexander Leidinger /* clean outputs */ 1746f856af04SAlexander Leidinger for (i = 0; i < 16 ; i++) { 1747f856af04SAlexander Leidinger emu_addefxop(sc, ACC3, OUTP(i), DSP_CONST(0), DSP_CONST(0), DSP_CONST(0), &pc); 1748d056fa04SAlexander Leidinger } 1749d056fa04SAlexander Leidinger 1750d056fa04SAlexander Leidinger 1751d056fa04SAlexander Leidinger if (sc->is_emu10k1) { 1752d056fa04SAlexander Leidinger EFX_CACHE(C_FRONT_L); 1753d056fa04SAlexander Leidinger EFX_CACHE(C_FRONT_R); 1754d056fa04SAlexander Leidinger EFX_CACHE(C_REC_L); 1755d056fa04SAlexander Leidinger EFX_CACHE(C_REC_R); 1756d056fa04SAlexander Leidinger 1757d056fa04SAlexander Leidinger /* fx0 to front/record, 100%/muted by default */ 1758d056fa04SAlexander Leidinger EFX_ROUTE("pcm_front_l", FX(0), M_FX0_FRONT_L, C_FRONT_L, 100); 1759d056fa04SAlexander Leidinger EFX_ROUTE("pcm_front_r", FX(1), M_FX1_FRONT_R, C_FRONT_R, 100); 1760b28624fdSAriff Abdullah EFX_ROUTE(NULL, FX(0), M_FX0_REC_L, C_REC_L, 0); 1761b28624fdSAriff Abdullah EFX_ROUTE(NULL, FX(1), M_FX1_REC_R, C_REC_R, 0); 1762d056fa04SAlexander Leidinger 1763d056fa04SAlexander Leidinger /* in0, from AC97 codec output */ 1764d056fa04SAlexander Leidinger EFX_ROUTE("ac97_front_l", INP(IN_AC97_L), M_IN0_FRONT_L, C_FRONT_L, 0); 1765d056fa04SAlexander Leidinger EFX_ROUTE("ac97_front_r", INP(IN_AC97_R), M_IN0_FRONT_R, C_FRONT_R, 0); 1766d056fa04SAlexander Leidinger EFX_ROUTE("ac97_rec_l", INP(IN_AC97_L), M_IN0_REC_L, C_REC_L, 0); 1767d056fa04SAlexander Leidinger EFX_ROUTE("ac97_rec_r", INP(IN_AC97_R), M_IN0_REC_R, C_REC_R, 0); 1768d056fa04SAlexander Leidinger 1769d056fa04SAlexander Leidinger /* in1, from CD S/PDIF */ 1770b28624fdSAriff Abdullah /* XXX EFX_SKIP 4 assumes that each EFX_ROUTE is one DSP op */ 1771b28624fdSAriff Abdullah EFX_SKIP(4, CDSPDIFMUTE); 1772b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_SPDIF_CD_L), M_IN1_FRONT_L, C_FRONT_L, 0); 1773b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_SPDIF_CD_R), M_IN1_FRONT_R, C_FRONT_R, 0); 1774b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_SPDIF_CD_L), M_IN1_REC_L, C_REC_L, 0); 1775b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_SPDIF_CD_R), M_IN1_REC_R, C_REC_R, 0); 1776b28624fdSAriff Abdullah 1777b28624fdSAriff Abdullah if (sc->dbg_level > 0) { 1778d056fa04SAlexander Leidinger /* in2, ZoomVide (???) */ 1779d056fa04SAlexander Leidinger EFX_ROUTE("zoom_front_l", INP(IN_ZOOM_L), M_IN2_FRONT_L, C_FRONT_L, 0); 1780d056fa04SAlexander Leidinger EFX_ROUTE("zoom_front_r", INP(IN_ZOOM_R), M_IN2_FRONT_R, C_FRONT_R, 0); 1781d056fa04SAlexander Leidinger EFX_ROUTE("zoom_rec_l", INP(IN_ZOOM_L), M_IN2_REC_L, C_REC_L, 0); 1782d056fa04SAlexander Leidinger EFX_ROUTE("zoom_rec_r", INP(IN_ZOOM_R), M_IN2_REC_R, C_REC_R, 0); 1783b28624fdSAriff Abdullah } 1784b28624fdSAriff Abdullah 1785b28624fdSAriff Abdullah /* in3, TOSLink */ 1786b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_TOSLINK_L), M_IN3_FRONT_L, C_FRONT_L, 0); 1787b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_TOSLINK_R), M_IN3_FRONT_R, C_FRONT_R, 0); 1788b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_TOSLINK_L), M_IN3_REC_L, C_REC_L, 0); 1789b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_TOSLINK_R), M_IN3_REC_R, C_REC_R, 0); 1790d056fa04SAlexander Leidinger /* in4, LineIn */ 1791b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_LINE1_L), M_IN4_FRONT_L, C_FRONT_L, 0); 1792b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_LINE1_R), M_IN4_FRONT_R, C_FRONT_R, 0); 1793b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_LINE1_L), M_IN4_REC_L, C_REC_L, 0); 1794b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_LINE1_R), M_IN4_REC_R, C_REC_R, 0); 1795d056fa04SAlexander Leidinger 1796d056fa04SAlexander Leidinger /* in5, on-card S/PDIF */ 1797b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_L), M_IN5_FRONT_L, C_FRONT_L, 0); 1798b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_R), M_IN5_FRONT_R, C_FRONT_R, 0); 1799b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_L), M_IN5_REC_L, C_REC_L, 0); 1800b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_R), M_IN5_REC_R, C_REC_R, 0); 1801d056fa04SAlexander Leidinger 1802d056fa04SAlexander Leidinger /* in6, Line2 on Live!Drive */ 1803b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_LINE2_L), M_IN6_FRONT_L, C_FRONT_L, 0); 1804b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_LINE2_R), M_IN6_FRONT_R, C_FRONT_R, 0); 1805b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_LINE2_L), M_IN6_REC_L, C_REC_L, 0); 1806b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(IN_LINE2_R), M_IN6_REC_R, C_REC_R, 0); 1807b28624fdSAriff Abdullah 1808b28624fdSAriff Abdullah if (sc->dbg_level > 0) { 1809d056fa04SAlexander Leidinger /* in7, unknown */ 1810d056fa04SAlexander Leidinger EFX_ROUTE("in7_front_l", INP(0xE), M_IN7_FRONT_L, C_FRONT_L, 0); 1811d056fa04SAlexander Leidinger EFX_ROUTE("in7_front_r", INP(0xF), M_IN7_FRONT_R, C_FRONT_R, 0); 1812d056fa04SAlexander Leidinger EFX_ROUTE("in7_rec_l", INP(0xE), M_IN7_REC_L, C_REC_L, 0); 1813d056fa04SAlexander Leidinger EFX_ROUTE("in7_rec_r", INP(0xF), M_IN7_REC_R, C_REC_R, 0); 1814b28624fdSAriff Abdullah } 1815b28624fdSAriff Abdullah 1816b28624fdSAriff Abdullah /* analog and digital */ 1817d056fa04SAlexander Leidinger EFX_OUTPUT("master_front_l", C_FRONT_L, M_MASTER_FRONT_L, OUT_AC97_L, 100); 1818d056fa04SAlexander Leidinger EFX_OUTPUT("master_front_r", C_FRONT_R, M_MASTER_FRONT_R, OUT_AC97_R, 100); 1819b28624fdSAriff Abdullah /* S/PDIF */ 1820b28624fdSAriff Abdullah EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, OUT_TOSLINK_L); 1821b28624fdSAriff Abdullah EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, OUT_TOSLINK_R); 1822b28624fdSAriff Abdullah /* Headphones */ 1823f856af04SAlexander Leidinger EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, OUT_HEADPHONE_L); 1824f856af04SAlexander Leidinger EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, OUT_HEADPHONE_R); 1825d056fa04SAlexander Leidinger 1826d056fa04SAlexander Leidinger /* rec output to "ADC" */ 1827d056fa04SAlexander Leidinger EFX_OUTPUT("master_rec_l", C_REC_L, M_MASTER_REC_L, OUT_ADC_REC_L, 100); 1828d056fa04SAlexander Leidinger EFX_OUTPUT("master_rec_r", C_REC_R, M_MASTER_REC_R, OUT_ADC_REC_R, 100); 1829b28624fdSAriff Abdullah 1830b28624fdSAriff Abdullah if (!(sc->mch_disabled)) { 1831d056fa04SAlexander Leidinger /* 1832d056fa04SAlexander Leidinger * Additional channel volume is controlled by mixer in 1833d056fa04SAlexander Leidinger * emu_dspmixer_set() in -pcm.c 1834d056fa04SAlexander Leidinger */ 1835d056fa04SAlexander Leidinger 1836d056fa04SAlexander Leidinger /* fx2/3 (pcm1) to rear */ 1837d056fa04SAlexander Leidinger EFX_CACHE(C_REAR_L); 1838d056fa04SAlexander Leidinger EFX_CACHE(C_REAR_R); 1839d056fa04SAlexander Leidinger EFX_ROUTE(NULL, FX(2), M_FX2_REAR_L, C_REAR_L, 100); 1840d056fa04SAlexander Leidinger EFX_ROUTE(NULL, FX(3), M_FX3_REAR_R, C_REAR_R, 100); 1841d056fa04SAlexander Leidinger 1842d056fa04SAlexander Leidinger EFX_OUTPUT(NULL, C_REAR_L, M_MASTER_REAR_L, OUT_REAR_L, 100); 1843d056fa04SAlexander Leidinger EFX_OUTPUT(NULL, C_REAR_R, M_MASTER_REAR_R, OUT_REAR_R, 100); 1844f856af04SAlexander Leidinger if (sc->has_51) { 1845f856af04SAlexander Leidinger /* fx4 (pcm2) to center */ 1846f856af04SAlexander Leidinger EFX_CACHE(C_CENTER); 1847f856af04SAlexander Leidinger EFX_ROUTE(NULL, FX(4), M_FX4_CENTER, C_CENTER, 100); 1848f856af04SAlexander Leidinger EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, OUT_D_CENTER, 100); 1849b28624fdSAriff Abdullah 1850f856af04SAlexander Leidinger /* XXX in digital mode (default) this should be muted because 1851f856af04SAlexander Leidinger this output is shared with digital out */ 1852b28624fdSAriff Abdullah EFX_SKIP(1, ANALOGMUTE); 1853f856af04SAlexander Leidinger EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, OUT_A_CENTER); 1854b28624fdSAriff Abdullah 1855f856af04SAlexander Leidinger /* fx5 (pcm3) to sub */ 1856f856af04SAlexander Leidinger EFX_CACHE(C_SUB); 1857f856af04SAlexander Leidinger EFX_ROUTE(NULL, FX(5), M_FX5_SUBWOOFER, C_SUB, 100); 1858f856af04SAlexander Leidinger EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, OUT_D_SUB, 100); 1859b28624fdSAriff Abdullah 1860f856af04SAlexander Leidinger /* XXX in digital mode (default) this should be muted because 1861f856af04SAlexander Leidinger this output is shared with digital out */ 1862b28624fdSAriff Abdullah EFX_SKIP(1, ANALOGMUTE); 1863f856af04SAlexander Leidinger EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, OUT_A_SUB); 1864f856af04SAlexander Leidinger 1865f856af04SAlexander Leidinger } 1866b28624fdSAriff Abdullah } else { 1867b28624fdSAriff Abdullah /* SND_EMU10KX_MULTICHANNEL_DISABLED */ 1868b28624fdSAriff Abdullah EFX_OUTPUT(NULL, C_FRONT_L, M_MASTER_REAR_L, OUT_REAR_L, 57); /* 75%*75% */ 1869b28624fdSAriff Abdullah EFX_OUTPUT(NULL, C_FRONT_R, M_MASTER_REAR_R, OUT_REAR_R, 57); /* 75%*75% */ 1870b28624fdSAriff Abdullah 1871b28624fdSAriff Abdullah #if 0 1872b28624fdSAriff Abdullah /* XXX 5.1 does not work */ 1873b28624fdSAriff Abdullah 1874b28624fdSAriff Abdullah if (sc->has_51) { 1875b28624fdSAriff Abdullah /* (fx0+fx1)/2 to center */ 1876b28624fdSAriff Abdullah EFX_CACHE(C_CENTER); 1877b28624fdSAriff Abdullah emu_addefxop(sc, MACS, 1878b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_CENTER]), 1879b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_CENTER]), 1880b28624fdSAriff Abdullah DSP_CONST(0xd), /* = 1/2 */ 1881b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_FRONT_L]), 1882b28624fdSAriff Abdullah &pc); 1883b28624fdSAriff Abdullah emu_addefxop(sc, MACS, 1884b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_CENTER]), 1885b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_CENTER]), 1886b28624fdSAriff Abdullah DSP_CONST(0xd), /* = 1/2 */ 1887b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_FRONT_R]), 1888b28624fdSAriff Abdullah &pc); 1889b28624fdSAriff Abdullah EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, OUT_D_CENTER, 100); 1890b28624fdSAriff Abdullah 1891b28624fdSAriff Abdullah /* XXX in digital mode (default) this should be muted because 1892b28624fdSAriff Abdullah this output is shared with digital out */ 1893b28624fdSAriff Abdullah EFX_SKIP(1, ANALOGMUTE); 1894b28624fdSAriff Abdullah EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, OUT_A_CENTER); 1895b28624fdSAriff Abdullah 1896b28624fdSAriff Abdullah /* (fx0+fx1)/2 to sub */ 1897b28624fdSAriff Abdullah EFX_CACHE(C_SUB); 1898b28624fdSAriff Abdullah emu_addefxop(sc, MACS, 1899b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_CENTER]), 1900b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_CENTER]), 1901b28624fdSAriff Abdullah DSP_CONST(0xd), /* = 1/2 */ 1902b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_FRONT_L]), 1903b28624fdSAriff Abdullah &pc); 1904b28624fdSAriff Abdullah emu_addefxop(sc, MACS, 1905b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_CENTER]), 1906b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_CENTER]), 1907b28624fdSAriff Abdullah DSP_CONST(0xd), /* = 1/2 */ 1908b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_FRONT_R]), 1909b28624fdSAriff Abdullah &pc); 1910b28624fdSAriff Abdullah /* XXX add lowpass filter here */ 1911b28624fdSAriff Abdullah 1912b28624fdSAriff Abdullah EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, OUT_D_SUB, 100); 1913b28624fdSAriff Abdullah 1914b28624fdSAriff Abdullah /* XXX in digital mode (default) this should be muted because 1915b28624fdSAriff Abdullah this output is shared with digital out */ 1916b28624fdSAriff Abdullah EFX_SKIP(1, ANALOGMUTE); 1917b28624fdSAriff Abdullah EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, OUT_A_SUB); 1918b28624fdSAriff Abdullah } 1919f856af04SAlexander Leidinger #endif 1920b28624fdSAriff Abdullah } /* !mch_disabled */ 1921b28624fdSAriff Abdullah if (sc->mch_rec) { 1922b28624fdSAriff Abdullah /* 1923b28624fdSAriff Abdullah * MCH RECORDING , hight 16 slots. On 5.1 cards first 4 slots 1924b28624fdSAriff Abdullah * are used as outputs and already filled with data 1925b28624fdSAriff Abdullah */ 1926b28624fdSAriff Abdullah /* 1927b28624fdSAriff Abdullah * XXX On Live! cards stream does not begin at zero offset. 1928b28624fdSAriff Abdullah * It can be HW, driver or sound buffering problem. 1929b28624fdSAriff Abdullah * Use sync substream (offset 0x3E) to let userland find 1930b28624fdSAriff Abdullah * correct data. 1931b28624fdSAriff Abdullah */ 1932b28624fdSAriff Abdullah 1933b28624fdSAriff Abdullah /* 1934b28624fdSAriff Abdullah * Substream map (in byte offsets, each substream is 2 bytes): 1935b28624fdSAriff Abdullah * 0x00..0x1E - outputs 193684a17a97SGabor Kovesdan * 0x20..0x3E - FX, inputs and sync stream 1937b28624fdSAriff Abdullah */ 1938b28624fdSAriff Abdullah 1939b28624fdSAriff Abdullah /* First 2 channels (offset 0x20,0x22) are empty */ 1940b28624fdSAriff Abdullah for(i = (sc->has_51 ? 2 : 0); i < 2; i++) 1941b28624fdSAriff Abdullah EFX_COPY(FX2(i), DSP_CONST(0)); 1942b28624fdSAriff Abdullah 1943b28624fdSAriff Abdullah /* PCM Playback monitoring, offset 0x24..0x2A */ 1944b28624fdSAriff Abdullah for(i = 0; i < 4; i++) 1945b28624fdSAriff Abdullah EFX_COPY(FX2(i+2), FX(i)); 1946b28624fdSAriff Abdullah 1947b28624fdSAriff Abdullah /* Copy of some inputs, offset 0x2C..0x3C */ 1948b28624fdSAriff Abdullah for(i = 0; i < 9; i++) 1949b28624fdSAriff Abdullah EFX_COPY(FX2(i+8), INP(i)); 1950b28624fdSAriff Abdullah 1951b28624fdSAriff Abdullah /* sync data (0xc0de, offset 0x3E) */ 1952b28624fdSAriff Abdullah sc->dummy_gpr = emu_rm_gpr_alloc(sc->rm, 1); 1953b28624fdSAriff Abdullah emumix_set_gpr(sc, sc->dummy_gpr, 0xc0de0000); 1954b28624fdSAriff Abdullah 1955b28624fdSAriff Abdullah EFX_COPY(FX2(15), GPR(sc->dummy_gpr)); 1956b28624fdSAriff Abdullah } /* mch_rec */ 1957d056fa04SAlexander Leidinger } else /* emu10k2 and later */ { 1958d056fa04SAlexander Leidinger EFX_CACHE(C_FRONT_L); 1959d056fa04SAlexander Leidinger EFX_CACHE(C_FRONT_R); 1960d056fa04SAlexander Leidinger EFX_CACHE(C_REC_L); 1961d056fa04SAlexander Leidinger EFX_CACHE(C_REC_R); 1962d056fa04SAlexander Leidinger 1963d056fa04SAlexander Leidinger /* fx0 to front/record, 100%/muted by default */ 1964d056fa04SAlexander Leidinger /* 1965d056fa04SAlexander Leidinger * FRONT_[L|R] is controlled by AC97 emulation in 1966d056fa04SAlexander Leidinger * emu_ac97_[read|write]_emulation in -pcm.c 1967d056fa04SAlexander Leidinger */ 1968d056fa04SAlexander Leidinger EFX_ROUTE(NULL, FX(0), M_FX0_FRONT_L, C_FRONT_L, 100); 1969d056fa04SAlexander Leidinger EFX_ROUTE(NULL, FX(1), M_FX1_FRONT_R, C_FRONT_R, 100); 1970b28624fdSAriff Abdullah EFX_ROUTE(NULL, FX(0), M_FX0_REC_L, C_REC_L, 0); 1971b28624fdSAriff Abdullah EFX_ROUTE(NULL, FX(1), M_FX1_REC_R, C_REC_R, 0); 1972d056fa04SAlexander Leidinger 1973d056fa04SAlexander Leidinger /* in0, from AC97 codec output */ 1974b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_AC97_L), M_IN0_FRONT_L, C_FRONT_L, 100); 1975b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_AC97_R), M_IN0_FRONT_R, C_FRONT_R, 100); 1976b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_AC97_L), M_IN0_REC_L, C_REC_L, 0); 1977b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_AC97_R), M_IN0_REC_R, C_REC_R, 0); 1978d056fa04SAlexander Leidinger 1979d056fa04SAlexander Leidinger /* in1, from CD S/PDIF */ 1980b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_L), M_IN1_FRONT_L, C_FRONT_L, 0); 1981b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_R), M_IN1_FRONT_R, C_FRONT_R, 0); 1982b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_L), M_IN1_REC_L, C_REC_L, 0); 1983b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_R), M_IN1_REC_R, C_REC_R, 0); 1984d056fa04SAlexander Leidinger 1985d056fa04SAlexander Leidinger /* in2, optical & coax S/PDIF on AudigyDrive*/ 1986f856af04SAlexander Leidinger /* XXX Should be muted when GPRSCS valid stream == 0 */ 1987b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_L), M_IN2_FRONT_L, C_FRONT_L, 0); 1988b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_R), M_IN2_FRONT_R, C_FRONT_R, 0); 1989b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_L), M_IN2_REC_L, C_REC_L, 0); 1990b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_R), M_IN2_REC_R, C_REC_R, 0); 1991b28624fdSAriff Abdullah 1992b28624fdSAriff Abdullah if (sc->dbg_level > 0) { 1993d056fa04SAlexander Leidinger /* in3, unknown */ 1994d056fa04SAlexander Leidinger EFX_ROUTE("in3_front_l", INP(0x6), M_IN3_FRONT_L, C_FRONT_L, 0); 1995d056fa04SAlexander Leidinger EFX_ROUTE("in3_front_r", INP(0x7), M_IN3_FRONT_R, C_FRONT_R, 0); 1996d056fa04SAlexander Leidinger EFX_ROUTE("in3_rec_l", INP(0x6), M_IN3_REC_L, C_REC_L, 0); 1997d056fa04SAlexander Leidinger EFX_ROUTE("in3_rec_r", INP(0x7), M_IN3_REC_R, C_REC_R, 0); 1998b28624fdSAriff Abdullah } 1999b28624fdSAriff Abdullah 2000d056fa04SAlexander Leidinger /* in4, LineIn 2 on AudigyDrive */ 2001b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_LINE2_L), M_IN4_FRONT_L, C_FRONT_L, 0); 2002b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_LINE2_R), M_IN4_FRONT_R, C_FRONT_R, 0); 2003b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_LINE2_L), M_IN4_REC_L, C_REC_L, 0); 2004b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_LINE2_R), M_IN4_REC_R, C_REC_R, 0); 2005d056fa04SAlexander Leidinger 2006d056fa04SAlexander Leidinger /* in5, on-card S/PDIF */ 2007b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_L), M_IN5_FRONT_L, C_FRONT_L, 0); 2008b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_R), M_IN5_FRONT_R, C_FRONT_R, 0); 2009b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_L), M_IN5_REC_L, C_REC_L, 0); 2010b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_R), M_IN5_REC_R, C_REC_R, 0); 2011d056fa04SAlexander Leidinger 2012d056fa04SAlexander Leidinger /* in6, AUX2 on AudigyDrive */ 2013b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_AUX2_L), M_IN6_FRONT_L, C_FRONT_L, 0); 2014b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_AUX2_R), M_IN6_FRONT_R, C_FRONT_R, 0); 2015b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_AUX2_L), M_IN6_REC_L, C_REC_L, 0); 2016b28624fdSAriff Abdullah EFX_ROUTE(NULL, INP(A_IN_AUX2_R), M_IN6_REC_R, C_REC_R, 0); 2017b28624fdSAriff Abdullah 2018b28624fdSAriff Abdullah if (sc->dbg_level > 0) { 2019d056fa04SAlexander Leidinger /* in7, unknown */ 2020d056fa04SAlexander Leidinger EFX_ROUTE("in7_front_l", INP(0xE), M_IN7_FRONT_L, C_FRONT_L, 0); 2021d056fa04SAlexander Leidinger EFX_ROUTE("in7_front_r", INP(0xF), M_IN7_FRONT_R, C_FRONT_R, 0); 2022d056fa04SAlexander Leidinger EFX_ROUTE("in7_rec_l", INP(0xE), M_IN7_REC_L, C_REC_L, 0); 2023d056fa04SAlexander Leidinger EFX_ROUTE("in7_rec_r", INP(0xF), M_IN7_REC_R, C_REC_R, 0); 2024b28624fdSAriff Abdullah } 2025b28624fdSAriff Abdullah 2026d056fa04SAlexander Leidinger /* front output to headphones and alog and digital *front */ 2027d056fa04SAlexander Leidinger /* volume controlled by AC97 emulation */ 2028d056fa04SAlexander Leidinger EFX_OUTPUT(NULL, C_FRONT_L, M_MASTER_FRONT_L, A_OUT_A_FRONT_L, 100); 2029d056fa04SAlexander Leidinger EFX_OUTPUT(NULL, C_FRONT_R, M_MASTER_FRONT_R, A_OUT_A_FRONT_R, 100); 2030d056fa04SAlexander Leidinger EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_D_FRONT_L); 2031d056fa04SAlexander Leidinger EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_D_FRONT_R); 2032d056fa04SAlexander Leidinger EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_HPHONE_L); 2033d056fa04SAlexander Leidinger EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_HPHONE_R); 2034d056fa04SAlexander Leidinger 2035d056fa04SAlexander Leidinger /* rec output to "ADC" */ 2036d056fa04SAlexander Leidinger /* volume controlled by AC97 emulation */ 2037d056fa04SAlexander Leidinger EFX_OUTPUT(NULL, C_REC_L, M_MASTER_REC_L, A_OUT_ADC_REC_L, 100); 2038507ec6d5SAlexander Leidinger EFX_OUTPUT(NULL, C_REC_R, M_MASTER_REC_R, A_OUT_ADC_REC_R, 100); 2039b28624fdSAriff Abdullah 2040b28624fdSAriff Abdullah if (!(sc->mch_disabled)) { 2041d056fa04SAlexander Leidinger /* 2042d056fa04SAlexander Leidinger * Additional channel volume is controlled by mixer in 2043d056fa04SAlexander Leidinger * emu_dspmixer_set() in -pcm.c 2044d056fa04SAlexander Leidinger */ 2045d056fa04SAlexander Leidinger 2046d056fa04SAlexander Leidinger /* fx2/3 (pcm1) to rear */ 2047d056fa04SAlexander Leidinger EFX_CACHE(C_REAR_L); 2048d056fa04SAlexander Leidinger EFX_CACHE(C_REAR_R); 2049d056fa04SAlexander Leidinger EFX_ROUTE(NULL, FX(2), M_FX2_REAR_L, C_REAR_L, 100); 2050d056fa04SAlexander Leidinger EFX_ROUTE(NULL, FX(3), M_FX3_REAR_R, C_REAR_R, 100); 2051d056fa04SAlexander Leidinger 2052d056fa04SAlexander Leidinger EFX_OUTPUT(NULL, C_REAR_L, M_MASTER_REAR_L, A_OUT_A_REAR_L, 100); 2053d056fa04SAlexander Leidinger EFX_OUTPUT(NULL, C_REAR_R, M_MASTER_REAR_R, A_OUT_A_REAR_R, 100); 2054d056fa04SAlexander Leidinger EFX_OUTPUTD(C_REAR_L, M_MASTER_REAR_L, A_OUT_D_REAR_L); 2055507ec6d5SAlexander Leidinger EFX_OUTPUTD(C_REAR_R, M_MASTER_REAR_R, A_OUT_D_REAR_R); 2056d056fa04SAlexander Leidinger 2057d056fa04SAlexander Leidinger /* fx4 (pcm2) to center */ 2058d056fa04SAlexander Leidinger EFX_CACHE(C_CENTER); 2059d056fa04SAlexander Leidinger EFX_ROUTE(NULL, FX(4), M_FX4_CENTER, C_CENTER, 100); 2060d056fa04SAlexander Leidinger EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, A_OUT_D_CENTER, 100); 2061d056fa04SAlexander Leidinger #if 0 2062b28624fdSAriff Abdullah /* 2063b28624fdSAriff Abdullah * XXX in digital mode (default) this should be muted 2064b28624fdSAriff Abdullah * because this output is shared with digital out 2065b28624fdSAriff Abdullah */ 2066d056fa04SAlexander Leidinger EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, A_OUT_A_CENTER); 2067d056fa04SAlexander Leidinger #endif 2068d056fa04SAlexander Leidinger /* fx5 (pcm3) to sub */ 2069d056fa04SAlexander Leidinger EFX_CACHE(C_SUB); 2070d056fa04SAlexander Leidinger EFX_ROUTE(NULL, FX(5), M_FX5_SUBWOOFER, C_SUB, 100); 2071d056fa04SAlexander Leidinger EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, A_OUT_D_SUB, 100); 2072d056fa04SAlexander Leidinger #if 0 2073b28624fdSAriff Abdullah /* 2074b28624fdSAriff Abdullah * XXX in digital mode (default) this should be muted 2075b28624fdSAriff Abdullah * because this output is shared with digital out 2076b28624fdSAriff Abdullah */ 2077d056fa04SAlexander Leidinger EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, A_OUT_A_SUB); 2078d056fa04SAlexander Leidinger #endif 2079d056fa04SAlexander Leidinger if (sc->has_71) { 2080d056fa04SAlexander Leidinger /* XXX this will broke headphones on AudigyDrive */ 2081d056fa04SAlexander Leidinger /* fx6/7 (pcm4) to side */ 2082d056fa04SAlexander Leidinger EFX_CACHE(C_SIDE_L); 2083d056fa04SAlexander Leidinger EFX_CACHE(C_SIDE_R); 2084d056fa04SAlexander Leidinger EFX_ROUTE(NULL, FX(6), M_FX6_SIDE_L, C_SIDE_L, 100); 2085d056fa04SAlexander Leidinger EFX_ROUTE(NULL, FX(7), M_FX7_SIDE_R, C_SIDE_R, 100); 2086d056fa04SAlexander Leidinger EFX_OUTPUT(NULL, C_SIDE_L, M_MASTER_SIDE_L, A_OUT_A_SIDE_L, 100); 2087d056fa04SAlexander Leidinger EFX_OUTPUT(NULL, C_SIDE_R, M_MASTER_SIDE_R, A_OUT_A_SIDE_R, 100); 2088d056fa04SAlexander Leidinger EFX_OUTPUTD(C_SIDE_L, M_MASTER_SIDE_L, A_OUT_D_SIDE_L); 2089d056fa04SAlexander Leidinger EFX_OUTPUTD(C_SIDE_R, M_MASTER_SIDE_R, A_OUT_D_SIDE_R); 2090d056fa04SAlexander Leidinger } 2091b28624fdSAriff Abdullah } else { /* mch_disabled */ 2092d056fa04SAlexander Leidinger EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_A_REAR_L); 2093d056fa04SAlexander Leidinger EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_A_REAR_R); 2094d056fa04SAlexander Leidinger 2095d056fa04SAlexander Leidinger EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_D_REAR_L); 2096d056fa04SAlexander Leidinger EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_D_REAR_R); 2097b28624fdSAriff Abdullah 2098b28624fdSAriff Abdullah if (sc->has_51) { 2099b28624fdSAriff Abdullah /* (fx0+fx1)/2 to center */ 2100b28624fdSAriff Abdullah EFX_CACHE(C_CENTER); 2101b28624fdSAriff Abdullah emu_addefxop(sc, MACS, 2102b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_CENTER]), 2103b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_CENTER]), 2104b28624fdSAriff Abdullah DSP_CONST(0xd), /* = 1/2 */ 2105b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_FRONT_L]), 2106b28624fdSAriff Abdullah &pc); 2107b28624fdSAriff Abdullah emu_addefxop(sc, MACS, 2108b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_CENTER]), 2109b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_CENTER]), 2110b28624fdSAriff Abdullah DSP_CONST(0xd), /* = 1/2 */ 2111b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_FRONT_R]), 2112b28624fdSAriff Abdullah &pc); 2113b28624fdSAriff Abdullah EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, A_OUT_D_CENTER, 100); 2114b28624fdSAriff Abdullah 2115b28624fdSAriff Abdullah /* XXX in digital mode (default) this should be muted because 2116b28624fdSAriff Abdullah this output is shared with digital out */ 2117b28624fdSAriff Abdullah EFX_SKIP(1, ANALOGMUTE); 2118b28624fdSAriff Abdullah EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, A_OUT_A_CENTER); 2119b28624fdSAriff Abdullah 2120b28624fdSAriff Abdullah /* (fx0+fx1)/2 to sub */ 2121b28624fdSAriff Abdullah EFX_CACHE(C_SUB); 2122b28624fdSAriff Abdullah emu_addefxop(sc, MACS, 2123b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_SUB]), 2124b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_SUB]), 2125b28624fdSAriff Abdullah DSP_CONST(0xd), /* = 1/2 */ 2126b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_FRONT_L]), 2127b28624fdSAriff Abdullah &pc); 2128b28624fdSAriff Abdullah emu_addefxop(sc, MACS, 2129b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_SUB]), 2130b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_SUB]), 2131b28624fdSAriff Abdullah DSP_CONST(0xd), /* = 1/2 */ 2132b28624fdSAriff Abdullah GPR(sc->cache_gpr[C_FRONT_R]), 2133b28624fdSAriff Abdullah &pc); 2134b28624fdSAriff Abdullah /* XXX add lowpass filter here */ 2135b28624fdSAriff Abdullah 2136b28624fdSAriff Abdullah EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, A_OUT_D_SUB, 100); 2137b28624fdSAriff Abdullah 2138b28624fdSAriff Abdullah /* XXX in digital mode (default) this should be muted because 2139b28624fdSAriff Abdullah this output is shared with digital out */ 2140b28624fdSAriff Abdullah EFX_SKIP(1, ANALOGMUTE); 2141b28624fdSAriff Abdullah EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, A_OUT_A_SUB); 2142b28624fdSAriff Abdullah } 2143b28624fdSAriff Abdullah } /* mch_disabled */ 2144b28624fdSAriff Abdullah if (sc->mch_rec) { 2145b28624fdSAriff Abdullah /* MCH RECORDING, high 32 slots */ 2146b28624fdSAriff Abdullah 2147b28624fdSAriff Abdullah /* 2148b28624fdSAriff Abdullah * Stream map (in byte offsets): 2149b28624fdSAriff Abdullah * 0x00..0x3E - outputs 2150b28624fdSAriff Abdullah * 0x40..0x7E - FX, inputs 2151b28624fdSAriff Abdullah * each substream is 2 bytes. 2152b28624fdSAriff Abdullah */ 2153b28624fdSAriff Abdullah /* 2154b28624fdSAriff Abdullah * XXX Audigy 2 Value cards (and, possibly, 2155b28624fdSAriff Abdullah * Audigy 4) write some unknown data in place of 2156b28624fdSAriff Abdullah * some outputs (offsets 0x20..0x3F) and one 2157b28624fdSAriff Abdullah * input (offset 0x7E). 2158b28624fdSAriff Abdullah */ 2159b28624fdSAriff Abdullah 2160b28624fdSAriff Abdullah /* PCM Playback monitoring, offsets 0x40..0x5E */ 2161b28624fdSAriff Abdullah for(i = 0; i < 16; i++) 2162b28624fdSAriff Abdullah EFX_COPY(FX2(i), FX(i)); 2163b28624fdSAriff Abdullah 2164b28624fdSAriff Abdullah /* Copy of all inputs, offsets 0x60..0x7E */ 2165b28624fdSAriff Abdullah for(i = 0; i < 16; i++) 2166b28624fdSAriff Abdullah EFX_COPY(FX2(i+16), INP(i)); 2167b28624fdSAriff Abdullah #if 0 2168b28624fdSAriff Abdullah /* XXX Audigy seems to work correct and does not need this */ 2169b28624fdSAriff Abdullah /* sync data (0xc0de), offset 0x7E */ 2170b28624fdSAriff Abdullah sc->dummy_gpr = emu_rm_gpr_alloc(sc->rm, 1); 2171b28624fdSAriff Abdullah emumix_set_gpr(sc, sc->dummy_gpr, 0xc0de0000); 2172b28624fdSAriff Abdullah EFX_COPY(FX2(31), GPR(sc->dummy_gpr)); 2173d056fa04SAlexander Leidinger #endif 2174b28624fdSAriff Abdullah } /* mch_rec */ 2175d056fa04SAlexander Leidinger } 2176d056fa04SAlexander Leidinger 2177d056fa04SAlexander Leidinger sc->routing_code_end = pc; 2178d056fa04SAlexander Leidinger 2179d056fa04SAlexander Leidinger /* start DSP */ 2180d056fa04SAlexander Leidinger if (sc->is_emu10k1) { 218170e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_DBG, 0); 2182d056fa04SAlexander Leidinger } else { 218370e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_A_DBG, 0); 2184d056fa04SAlexander Leidinger } 2185d056fa04SAlexander Leidinger } 2186d056fa04SAlexander Leidinger 2187d056fa04SAlexander Leidinger /* /dev/em10kx */ 2188d056fa04SAlexander Leidinger static d_open_t emu10kx_open; 2189d056fa04SAlexander Leidinger static d_close_t emu10kx_close; 2190d056fa04SAlexander Leidinger static d_read_t emu10kx_read; 2191d056fa04SAlexander Leidinger 2192d056fa04SAlexander Leidinger static struct cdevsw emu10kx_cdevsw = { 2193d056fa04SAlexander Leidinger .d_open = emu10kx_open, 2194d056fa04SAlexander Leidinger .d_close = emu10kx_close, 2195d056fa04SAlexander Leidinger .d_read = emu10kx_read, 2196d056fa04SAlexander Leidinger .d_name = "emu10kx", 2197d056fa04SAlexander Leidinger .d_version = D_VERSION, 2198d056fa04SAlexander Leidinger }; 2199d056fa04SAlexander Leidinger 2200d056fa04SAlexander Leidinger 2201d056fa04SAlexander Leidinger static int 2202d056fa04SAlexander Leidinger emu10kx_open(struct cdev *i_dev, int flags __unused, int mode __unused, struct thread *td __unused) 2203d056fa04SAlexander Leidinger { 2204d056fa04SAlexander Leidinger int error; 2205d056fa04SAlexander Leidinger struct emu_sc_info *sc; 2206d056fa04SAlexander Leidinger 2207d056fa04SAlexander Leidinger sc = i_dev->si_drv1; 2208d056fa04SAlexander Leidinger mtx_lock(&sc->emu10kx_lock); 2209d056fa04SAlexander Leidinger if (sc->emu10kx_isopen) { 2210d056fa04SAlexander Leidinger mtx_unlock(&sc->emu10kx_lock); 2211d056fa04SAlexander Leidinger return (EBUSY); 2212d056fa04SAlexander Leidinger } 2213d056fa04SAlexander Leidinger sc->emu10kx_isopen = 1; 2214d056fa04SAlexander Leidinger mtx_unlock(&sc->emu10kx_lock); 2215d056fa04SAlexander Leidinger if (sbuf_new(&sc->emu10kx_sbuf, NULL, 4096, 0) == NULL) { 2216d056fa04SAlexander Leidinger error = ENXIO; 2217d056fa04SAlexander Leidinger goto out; 2218d056fa04SAlexander Leidinger } 2219d056fa04SAlexander Leidinger sc->emu10kx_bufptr = 0; 2220d056fa04SAlexander Leidinger error = (emu10kx_prepare(sc, &sc->emu10kx_sbuf) > 0) ? 0 : ENOMEM; 2221d056fa04SAlexander Leidinger out: 2222d056fa04SAlexander Leidinger if (error) { 2223d056fa04SAlexander Leidinger mtx_lock(&sc->emu10kx_lock); 2224d056fa04SAlexander Leidinger sc->emu10kx_isopen = 0; 2225d056fa04SAlexander Leidinger mtx_unlock(&sc->emu10kx_lock); 2226d056fa04SAlexander Leidinger } 2227d056fa04SAlexander Leidinger return (error); 2228d056fa04SAlexander Leidinger } 2229d056fa04SAlexander Leidinger 2230d056fa04SAlexander Leidinger static int 2231d056fa04SAlexander Leidinger emu10kx_close(struct cdev *i_dev, int flags __unused, int mode __unused, struct thread *td __unused) 2232d056fa04SAlexander Leidinger { 2233d056fa04SAlexander Leidinger struct emu_sc_info *sc; 2234d056fa04SAlexander Leidinger 2235d056fa04SAlexander Leidinger sc = i_dev->si_drv1; 2236d056fa04SAlexander Leidinger 2237d056fa04SAlexander Leidinger mtx_lock(&sc->emu10kx_lock); 2238d056fa04SAlexander Leidinger if (!(sc->emu10kx_isopen)) { 2239d056fa04SAlexander Leidinger mtx_unlock(&sc->emu10kx_lock); 2240d056fa04SAlexander Leidinger return (EBADF); 2241d056fa04SAlexander Leidinger } 2242d056fa04SAlexander Leidinger sbuf_delete(&sc->emu10kx_sbuf); 2243d056fa04SAlexander Leidinger sc->emu10kx_isopen = 0; 2244d056fa04SAlexander Leidinger mtx_unlock(&sc->emu10kx_lock); 2245d056fa04SAlexander Leidinger 2246d056fa04SAlexander Leidinger return (0); 2247d056fa04SAlexander Leidinger } 2248d056fa04SAlexander Leidinger 2249d056fa04SAlexander Leidinger static int 2250d056fa04SAlexander Leidinger emu10kx_read(struct cdev *i_dev, struct uio *buf, int flag __unused) 2251d056fa04SAlexander Leidinger { 2252d056fa04SAlexander Leidinger int l, err; 2253d056fa04SAlexander Leidinger struct emu_sc_info *sc; 2254d056fa04SAlexander Leidinger 2255d056fa04SAlexander Leidinger sc = i_dev->si_drv1; 2256d056fa04SAlexander Leidinger mtx_lock(&sc->emu10kx_lock); 2257d056fa04SAlexander Leidinger if (!(sc->emu10kx_isopen)) { 2258d056fa04SAlexander Leidinger mtx_unlock(&sc->emu10kx_lock); 2259d056fa04SAlexander Leidinger return (EBADF); 2260d056fa04SAlexander Leidinger } 2261d056fa04SAlexander Leidinger mtx_unlock(&sc->emu10kx_lock); 2262d056fa04SAlexander Leidinger 2263d056fa04SAlexander Leidinger l = min(buf->uio_resid, sbuf_len(&sc->emu10kx_sbuf) - sc->emu10kx_bufptr); 2264d056fa04SAlexander Leidinger err = (l > 0) ? uiomove(sbuf_data(&sc->emu10kx_sbuf) + sc->emu10kx_bufptr, l, buf) : 0; 2265d056fa04SAlexander Leidinger sc->emu10kx_bufptr += l; 2266d056fa04SAlexander Leidinger 2267d056fa04SAlexander Leidinger return (err); 2268d056fa04SAlexander Leidinger } 2269d056fa04SAlexander Leidinger 2270d056fa04SAlexander Leidinger static int 2271d056fa04SAlexander Leidinger emu10kx_prepare(struct emu_sc_info *sc, struct sbuf *s) 2272d056fa04SAlexander Leidinger { 2273d056fa04SAlexander Leidinger int i; 2274d056fa04SAlexander Leidinger 2275d056fa04SAlexander Leidinger sbuf_printf(s, "FreeBSD EMU10Kx Audio Driver\n"); 2276d056fa04SAlexander Leidinger sbuf_printf(s, "\nHardware resource usage:\n"); 2277d056fa04SAlexander Leidinger sbuf_printf(s, "DSP General Purpose Registers: %d used, %d total\n", sc->rm->num_used, sc->rm->num_gprs); 2278d056fa04SAlexander Leidinger sbuf_printf(s, "DSP Instruction Registers: %d used, %d total\n", sc->routing_code_end, sc->code_size); 2279d056fa04SAlexander Leidinger sbuf_printf(s, "Card supports"); 2280d056fa04SAlexander Leidinger if (sc->has_ac97) { 2281d056fa04SAlexander Leidinger sbuf_printf(s, " AC97 codec"); 2282d056fa04SAlexander Leidinger } else { 2283d056fa04SAlexander Leidinger sbuf_printf(s, " NO AC97 codec"); 2284d056fa04SAlexander Leidinger } 2285d056fa04SAlexander Leidinger if (sc->has_51) { 2286d056fa04SAlexander Leidinger if (sc->has_71) 2287d056fa04SAlexander Leidinger sbuf_printf(s, " and 7.1 output"); 2288d056fa04SAlexander Leidinger else 2289d056fa04SAlexander Leidinger sbuf_printf(s, " and 5.1 output"); 2290d056fa04SAlexander Leidinger } 2291d056fa04SAlexander Leidinger if (sc->is_emu10k1) 2292d056fa04SAlexander Leidinger sbuf_printf(s, ", SBLive! DSP code"); 2293d056fa04SAlexander Leidinger if (sc->is_emu10k2) 2294d056fa04SAlexander Leidinger sbuf_printf(s, ", Audigy DSP code"); 2295d056fa04SAlexander Leidinger if (sc->is_ca0102) 2296d056fa04SAlexander Leidinger sbuf_printf(s, ", Audigy DSP code with Audigy2 hacks"); 2297d056fa04SAlexander Leidinger if (sc->is_ca0108) 2298d056fa04SAlexander Leidinger sbuf_printf(s, ", Audigy DSP code with Audigy2Value hacks"); 2299d056fa04SAlexander Leidinger sbuf_printf(s, "\n"); 2300d056fa04SAlexander Leidinger if (sc->broken_digital) 2301d056fa04SAlexander Leidinger sbuf_printf(s, "Digital mode unsupported\n"); 2302d056fa04SAlexander Leidinger sbuf_printf(s, "\nInstalled devices:\n"); 2303f856af04SAlexander Leidinger for (i = 0; i < RT_COUNT; i++) 2304d056fa04SAlexander Leidinger if (sc->pcm[i] != NULL) 2305d056fa04SAlexander Leidinger if (device_is_attached(sc->pcm[i])) { 2306d056fa04SAlexander Leidinger sbuf_printf(s, "%s on %s\n", device_get_desc(sc->pcm[i]), device_get_nameunit(sc->pcm[i])); 2307d056fa04SAlexander Leidinger } 2308d056fa04SAlexander Leidinger if (sc->midi[0] != NULL) 2309d056fa04SAlexander Leidinger if (device_is_attached(sc->midi[0])) { 2310d056fa04SAlexander Leidinger sbuf_printf(s, "EMU10Kx MIDI Interface\n"); 2311d056fa04SAlexander Leidinger sbuf_printf(s, "\tOn-card connector on %s\n", device_get_nameunit(sc->midi[0])); 2312d056fa04SAlexander Leidinger } 2313d056fa04SAlexander Leidinger if (sc->midi[1] != NULL) 2314d056fa04SAlexander Leidinger if (device_is_attached(sc->midi[1])) { 2315d056fa04SAlexander Leidinger sbuf_printf(s, "\tOn-Drive connector on %s\n", device_get_nameunit(sc->midi[1])); 2316d056fa04SAlexander Leidinger } 2317d056fa04SAlexander Leidinger if (sc->midi[0] != NULL) 2318d056fa04SAlexander Leidinger if (device_is_attached(sc->midi[0])) { 2319d056fa04SAlexander Leidinger sbuf_printf(s, "\tIR reciever MIDI events %s\n", sc->enable_ir ? "enabled" : "disabled"); 2320d056fa04SAlexander Leidinger } 2321b28624fdSAriff Abdullah sbuf_printf(s, "Card is in %s mode\n", (sc->mode == MODE_ANALOG) ? "analog" : "digital"); 2322b28624fdSAriff Abdullah 2323d056fa04SAlexander Leidinger sbuf_finish(s); 2324d056fa04SAlexander Leidinger return (sbuf_len(s)); 2325d056fa04SAlexander Leidinger } 2326d056fa04SAlexander Leidinger 2327d056fa04SAlexander Leidinger /* INIT & UNINIT */ 2328d056fa04SAlexander Leidinger static int 2329d056fa04SAlexander Leidinger emu10kx_dev_init(struct emu_sc_info *sc) 2330d056fa04SAlexander Leidinger { 2331d056fa04SAlexander Leidinger int unit; 2332d056fa04SAlexander Leidinger 2333b28624fdSAriff Abdullah mtx_init(&sc->emu10kx_lock, device_get_nameunit(sc->dev), "kxdevlock", 0); 2334d056fa04SAlexander Leidinger unit = device_get_unit(sc->dev); 2335d056fa04SAlexander Leidinger 233690da2b28SAriff Abdullah sc->cdev = make_dev(&emu10kx_cdevsw, PCMMINOR(unit), UID_ROOT, GID_WHEEL, 0640, "emu10kx%d", unit); 2337d056fa04SAlexander Leidinger if (sc->cdev != NULL) { 2338d056fa04SAlexander Leidinger sc->cdev->si_drv1 = sc; 2339d056fa04SAlexander Leidinger return (0); 2340d056fa04SAlexander Leidinger } 2341d056fa04SAlexander Leidinger return (ENXIO); 2342d056fa04SAlexander Leidinger } 2343d056fa04SAlexander Leidinger 2344d056fa04SAlexander Leidinger static int 2345d056fa04SAlexander Leidinger emu10kx_dev_uninit(struct emu_sc_info *sc) 2346d056fa04SAlexander Leidinger { 2347d056fa04SAlexander Leidinger mtx_lock(&sc->emu10kx_lock); 2348d056fa04SAlexander Leidinger if (sc->emu10kx_isopen) { 2349d056fa04SAlexander Leidinger mtx_unlock(&sc->emu10kx_lock); 2350d056fa04SAlexander Leidinger return (EBUSY); 2351d056fa04SAlexander Leidinger } 2352d056fa04SAlexander Leidinger if (sc->cdev) 2353d056fa04SAlexander Leidinger destroy_dev(sc->cdev); 2354d056fa04SAlexander Leidinger sc->cdev = 0; 2355d056fa04SAlexander Leidinger 2356d056fa04SAlexander Leidinger mtx_destroy(&sc->emu10kx_lock); 2357d056fa04SAlexander Leidinger return (0); 2358d056fa04SAlexander Leidinger } 2359d056fa04SAlexander Leidinger 2360d056fa04SAlexander Leidinger /* resource manager */ 2361d056fa04SAlexander Leidinger int 2362d056fa04SAlexander Leidinger emu_rm_init(struct emu_sc_info *sc) 2363d056fa04SAlexander Leidinger { 2364d056fa04SAlexander Leidinger int i; 2365d056fa04SAlexander Leidinger int maxcount; 2366d056fa04SAlexander Leidinger struct emu_rm *rm; 2367d056fa04SAlexander Leidinger 2368d056fa04SAlexander Leidinger rm = malloc(sizeof(struct emu_rm), M_DEVBUF, M_NOWAIT | M_ZERO); 2369d056fa04SAlexander Leidinger if (rm == NULL) { 2370d056fa04SAlexander Leidinger return (ENOMEM); 2371d056fa04SAlexander Leidinger } 2372d056fa04SAlexander Leidinger sc->rm = rm; 2373d056fa04SAlexander Leidinger rm->card = sc; 2374d056fa04SAlexander Leidinger maxcount = sc->num_gprs; 2375d056fa04SAlexander Leidinger rm->num_used = 0; 2376b28624fdSAriff Abdullah mtx_init(&(rm->gpr_lock), device_get_nameunit(sc->dev), "gpr alloc", MTX_DEF); 2377d056fa04SAlexander Leidinger rm->num_gprs = (maxcount < EMU_MAX_GPR ? maxcount : EMU_MAX_GPR); 2378d056fa04SAlexander Leidinger for (i = 0; i < rm->num_gprs; i++) 2379d056fa04SAlexander Leidinger rm->allocmap[i] = 0; 2380b28624fdSAriff Abdullah /* pre-allocate gpr[0] */ 2381b28624fdSAriff Abdullah rm->allocmap[0] = 1; 2382b28624fdSAriff Abdullah rm->last_free_gpr = 1; 2383d056fa04SAlexander Leidinger 2384d056fa04SAlexander Leidinger return (0); 2385d056fa04SAlexander Leidinger } 2386d056fa04SAlexander Leidinger 2387d056fa04SAlexander Leidinger int 2388d056fa04SAlexander Leidinger emu_rm_uninit(struct emu_sc_info *sc) 2389d056fa04SAlexander Leidinger { 2390d056fa04SAlexander Leidinger int i; 2391d056fa04SAlexander Leidinger 2392b28624fdSAriff Abdullah if (sc->dbg_level > 1) { 2393d056fa04SAlexander Leidinger mtx_lock(&(sc->rm->gpr_lock)); 2394b28624fdSAriff Abdullah for (i = 1; i < sc->rm->last_free_gpr; i++) 2395d056fa04SAlexander Leidinger if (sc->rm->allocmap[i] > 0) 2396d056fa04SAlexander Leidinger device_printf(sc->dev, "rm: gpr %d not free before uninit\n", i); 2397d056fa04SAlexander Leidinger mtx_unlock(&(sc->rm->gpr_lock)); 2398b28624fdSAriff Abdullah } 2399b28624fdSAriff Abdullah 2400d056fa04SAlexander Leidinger mtx_destroy(&(sc->rm->gpr_lock)); 2401d056fa04SAlexander Leidinger free(sc->rm, M_DEVBUF); 2402d056fa04SAlexander Leidinger return (0); 2403d056fa04SAlexander Leidinger } 2404d056fa04SAlexander Leidinger 2405d056fa04SAlexander Leidinger static int 2406d056fa04SAlexander Leidinger emu_rm_gpr_alloc(struct emu_rm *rm, int count) 2407d056fa04SAlexander Leidinger { 2408d056fa04SAlexander Leidinger int i, j; 2409d056fa04SAlexander Leidinger int allocated_gpr; 2410d056fa04SAlexander Leidinger 2411d056fa04SAlexander Leidinger allocated_gpr = rm->num_gprs; 2412d056fa04SAlexander Leidinger /* try fast way first */ 2413d056fa04SAlexander Leidinger mtx_lock(&(rm->gpr_lock)); 2414d056fa04SAlexander Leidinger if (rm->last_free_gpr + count <= rm->num_gprs) { 2415d056fa04SAlexander Leidinger allocated_gpr = rm->last_free_gpr; 2416d056fa04SAlexander Leidinger rm->last_free_gpr += count; 2417d056fa04SAlexander Leidinger rm->allocmap[allocated_gpr] = count; 2418d056fa04SAlexander Leidinger for (i = 1; i < count; i++) 2419d056fa04SAlexander Leidinger rm->allocmap[allocated_gpr + i] = -(count - i); 2420d056fa04SAlexander Leidinger } else { 2421d056fa04SAlexander Leidinger /* longer */ 2422d056fa04SAlexander Leidinger i = 0; 2423d056fa04SAlexander Leidinger allocated_gpr = rm->num_gprs; 2424d056fa04SAlexander Leidinger while (i < rm->last_free_gpr - count) { 2425d056fa04SAlexander Leidinger if (rm->allocmap[i] > 0) { 2426d056fa04SAlexander Leidinger i += rm->allocmap[i]; 2427d056fa04SAlexander Leidinger } else { 2428d056fa04SAlexander Leidinger allocated_gpr = i; 2429d056fa04SAlexander Leidinger for (j = 1; j < count; j++) { 2430d056fa04SAlexander Leidinger if (rm->allocmap[i + j] != 0) 2431d056fa04SAlexander Leidinger allocated_gpr = rm->num_gprs; 2432d056fa04SAlexander Leidinger } 2433d056fa04SAlexander Leidinger if (allocated_gpr == i) 2434d056fa04SAlexander Leidinger break; 2435d056fa04SAlexander Leidinger } 2436d056fa04SAlexander Leidinger } 2437d056fa04SAlexander Leidinger if (allocated_gpr + count < rm->last_free_gpr) { 2438d056fa04SAlexander Leidinger rm->allocmap[allocated_gpr] = count; 2439d056fa04SAlexander Leidinger for (i = 1; i < count; i++) 2440d056fa04SAlexander Leidinger rm->allocmap[allocated_gpr + i] = -(count - i); 2441d056fa04SAlexander Leidinger 2442d056fa04SAlexander Leidinger } 2443d056fa04SAlexander Leidinger } 2444d056fa04SAlexander Leidinger if (allocated_gpr == rm->num_gprs) 2445d056fa04SAlexander Leidinger allocated_gpr = (-1); 2446d056fa04SAlexander Leidinger if (allocated_gpr >= 0) 2447d056fa04SAlexander Leidinger rm->num_used += count; 2448d056fa04SAlexander Leidinger mtx_unlock(&(rm->gpr_lock)); 2449d056fa04SAlexander Leidinger return (allocated_gpr); 2450d056fa04SAlexander Leidinger } 2451d056fa04SAlexander Leidinger 2452d056fa04SAlexander Leidinger /* mixer */ 2453d056fa04SAlexander Leidinger void 2454d056fa04SAlexander Leidinger emumix_set_mode(struct emu_sc_info *sc, int mode) 2455d056fa04SAlexander Leidinger { 2456d056fa04SAlexander Leidinger uint32_t a_iocfg; 2457d056fa04SAlexander Leidinger uint32_t hcfg; 2458d056fa04SAlexander Leidinger uint32_t tmp; 2459d056fa04SAlexander Leidinger 2460d056fa04SAlexander Leidinger switch (mode) { 2461d056fa04SAlexander Leidinger case MODE_DIGITAL: 2462d056fa04SAlexander Leidinger /* FALLTHROUGH */ 2463d056fa04SAlexander Leidinger case MODE_ANALOG: 2464d056fa04SAlexander Leidinger break; 2465d056fa04SAlexander Leidinger default: 2466d056fa04SAlexander Leidinger return; 2467d056fa04SAlexander Leidinger } 2468d056fa04SAlexander Leidinger 246970e0bbedSPedro F. Giffuni hcfg = EMU_HCFG_AUDIOENABLE | EMU_HCFG_AUTOMUTE; 2470d056fa04SAlexander Leidinger a_iocfg = 0; 2471d056fa04SAlexander Leidinger 2472d056fa04SAlexander Leidinger if (sc->rev >= 6) 247370e0bbedSPedro F. Giffuni hcfg |= EMU_HCFG_JOYENABLE; 2474d056fa04SAlexander Leidinger 2475d056fa04SAlexander Leidinger if (sc->is_emu10k1) 247670e0bbedSPedro F. Giffuni hcfg |= EMU_HCFG_LOCKTANKCACHE_MASK; 2477d056fa04SAlexander Leidinger else 247870e0bbedSPedro F. Giffuni hcfg |= EMU_HCFG_CODECFMT_I2S | EMU_HCFG_JOYENABLE; 2479d056fa04SAlexander Leidinger 2480d056fa04SAlexander Leidinger 2481d056fa04SAlexander Leidinger if (mode == MODE_DIGITAL) { 2482d056fa04SAlexander Leidinger if (sc->broken_digital) { 2483b28624fdSAriff Abdullah device_printf(sc->dev, "Digital mode is reported as broken on this card.\n"); 2484d056fa04SAlexander Leidinger } 248570e0bbedSPedro F. Giffuni a_iocfg |= EMU_A_IOCFG_GPOUT1; 248670e0bbedSPedro F. Giffuni hcfg |= EMU_HCFG_GPOUT0; 2487d056fa04SAlexander Leidinger } 2488d056fa04SAlexander Leidinger 2489d056fa04SAlexander Leidinger if (mode == MODE_ANALOG) 2490d056fa04SAlexander Leidinger emumix_set_spdif_mode(sc, SPDIF_MODE_PCM); 2491d056fa04SAlexander Leidinger 2492d056fa04SAlexander Leidinger if (sc->is_emu10k2) 2493d056fa04SAlexander Leidinger a_iocfg |= 0x80; /* XXX */ 2494d056fa04SAlexander Leidinger 2495d056fa04SAlexander Leidinger if ((sc->is_ca0102) || (sc->is_ca0108)) 2496b28624fdSAriff Abdullah /* 249770e0bbedSPedro F. Giffuni * Setting EMU_A_IOCFG_DISABLE_ANALOG will do opposite things 2498b28624fdSAriff Abdullah * on diffrerent cards. 2499b28624fdSAriff Abdullah * "don't disable analog outs" on Audigy 2 (ca0102/ca0108) 2500b28624fdSAriff Abdullah * "disable analog outs" on Audigy (emu10k2) 2501b28624fdSAriff Abdullah */ 250270e0bbedSPedro F. Giffuni a_iocfg |= EMU_A_IOCFG_DISABLE_ANALOG; 2503d056fa04SAlexander Leidinger 2504d056fa04SAlexander Leidinger if (sc->is_ca0108) 2505d056fa04SAlexander Leidinger a_iocfg |= 0x20; /* XXX */ 2506d056fa04SAlexander Leidinger 2507b28624fdSAriff Abdullah /* Mute analog center & subwoofer before mode change */ 2508b28624fdSAriff Abdullah if (mode == MODE_DIGITAL) 2509b28624fdSAriff Abdullah emumix_set_gpr(sc, sc->mute_gpr[ANALOGMUTE], 1); 2510b28624fdSAriff Abdullah 251170e0bbedSPedro F. Giffuni emu_wr(sc, EMU_HCFG, hcfg, 4); 2512d056fa04SAlexander Leidinger 2513d056fa04SAlexander Leidinger if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) { 251470e0bbedSPedro F. Giffuni tmp = emu_rd(sc, EMU_A_IOCFG, 2); 2515d056fa04SAlexander Leidinger tmp = a_iocfg; 251670e0bbedSPedro F. Giffuni emu_wr(sc, EMU_A_IOCFG, tmp, 2); 2517d056fa04SAlexander Leidinger } 2518d056fa04SAlexander Leidinger 2519b28624fdSAriff Abdullah /* Unmute if we have changed mode to analog. */ 2520b28624fdSAriff Abdullah 2521b28624fdSAriff Abdullah if (mode == MODE_ANALOG) 2522b28624fdSAriff Abdullah emumix_set_gpr(sc, sc->mute_gpr[ANALOGMUTE], 0); 2523b28624fdSAriff Abdullah 2524b28624fdSAriff Abdullah sc->mode = mode; 2525d056fa04SAlexander Leidinger } 2526d056fa04SAlexander Leidinger 2527d056fa04SAlexander Leidinger void 2528d056fa04SAlexander Leidinger emumix_set_spdif_mode(struct emu_sc_info *sc, int mode) 2529d056fa04SAlexander Leidinger { 2530d056fa04SAlexander Leidinger uint32_t spcs; 2531d056fa04SAlexander Leidinger 2532d056fa04SAlexander Leidinger switch (mode) { 2533d056fa04SAlexander Leidinger case SPDIF_MODE_PCM: 2534d056fa04SAlexander Leidinger break; 2535d056fa04SAlexander Leidinger case SPDIF_MODE_AC3: 2536d056fa04SAlexander Leidinger device_printf(sc->dev, "AC3 mode does not work and disabled\n"); 2537d056fa04SAlexander Leidinger return; 2538d056fa04SAlexander Leidinger default: 2539d056fa04SAlexander Leidinger return; 2540d056fa04SAlexander Leidinger } 2541d056fa04SAlexander Leidinger 254270e0bbedSPedro F. Giffuni spcs = EMU_SPCS_CLKACCY_1000PPM | EMU_SPCS_SAMPLERATE_48 | 254370e0bbedSPedro F. Giffuni EMU_SPCS_CHANNELNUM_LEFT | EMU_SPCS_SOURCENUM_UNSPEC | 254470e0bbedSPedro F. Giffuni EMU_SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | 254570e0bbedSPedro F. Giffuni EMU_SPCS_EMPHASIS_NONE | EMU_SPCS_COPYRIGHT; 2546d056fa04SAlexander Leidinger 2547d056fa04SAlexander Leidinger mode = SPDIF_MODE_PCM; 2548d056fa04SAlexander Leidinger 254970e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SPCS0, spcs); 255070e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SPCS1, spcs); 255170e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SPCS2, spcs); 2552d056fa04SAlexander Leidinger } 2553d056fa04SAlexander Leidinger 2554d056fa04SAlexander Leidinger #define L2L_POINTS 10 2555d056fa04SAlexander Leidinger 2556d056fa04SAlexander Leidinger static int l2l_df[L2L_POINTS] = { 2557d056fa04SAlexander Leidinger 0x572C5CA, /* 100..90 */ 2558d056fa04SAlexander Leidinger 0x3211625, /* 90..80 */ 2559d056fa04SAlexander Leidinger 0x1CC1A76, /* 80..70 */ 2560d056fa04SAlexander Leidinger 0x108428F, /* 70..60 */ 2561d056fa04SAlexander Leidinger 0x097C70A, /* 60..50 */ 2562d056fa04SAlexander Leidinger 0x0572C5C, /* 50..40 */ 2563d056fa04SAlexander Leidinger 0x0321162, /* 40..30 */ 2564d056fa04SAlexander Leidinger 0x01CC1A7, /* 30..20 */ 2565d056fa04SAlexander Leidinger 0x0108428, /* 20..10 */ 2566d056fa04SAlexander Leidinger 0x016493D /* 10..0 */ 2567d056fa04SAlexander Leidinger }; 2568d056fa04SAlexander Leidinger 2569d056fa04SAlexander Leidinger static int l2l_f[L2L_POINTS] = { 2570d056fa04SAlexander Leidinger 0x4984461A, /* 90 */ 2571d056fa04SAlexander Leidinger 0x2A3968A7, /* 80 */ 2572d056fa04SAlexander Leidinger 0x18406003, /* 70 */ 2573d056fa04SAlexander Leidinger 0x0DEDC66D, /* 60 */ 2574d056fa04SAlexander Leidinger 0x07FFFFFF, /* 50 */ 2575d056fa04SAlexander Leidinger 0x04984461, /* 40 */ 2576d056fa04SAlexander Leidinger 0x02A3968A, /* 30 */ 2577d056fa04SAlexander Leidinger 0x01840600, /* 20 */ 2578d056fa04SAlexander Leidinger 0x00DEDC66, /* 10 */ 2579d056fa04SAlexander Leidinger 0x00000000 /* 0 */ 2580d056fa04SAlexander Leidinger }; 2581d056fa04SAlexander Leidinger 2582d056fa04SAlexander Leidinger 2583d056fa04SAlexander Leidinger static int 2584d056fa04SAlexander Leidinger log2lin(int log_t) 2585d056fa04SAlexander Leidinger { 2586d056fa04SAlexander Leidinger int lin_t; 2587d056fa04SAlexander Leidinger int idx, lin; 2588d056fa04SAlexander Leidinger 2589d056fa04SAlexander Leidinger if (log_t <= 0) { 2590d056fa04SAlexander Leidinger lin_t = 0x00000000; 2591d056fa04SAlexander Leidinger return (lin_t); 2592d056fa04SAlexander Leidinger } 2593d056fa04SAlexander Leidinger 2594d056fa04SAlexander Leidinger if (log_t >= 100) { 2595d056fa04SAlexander Leidinger lin_t = 0x7fffffff; 2596d056fa04SAlexander Leidinger return (lin_t); 2597d056fa04SAlexander Leidinger } 2598d056fa04SAlexander Leidinger 2599d056fa04SAlexander Leidinger idx = (L2L_POINTS - 1) - log_t / (L2L_POINTS); 2600d056fa04SAlexander Leidinger lin = log_t % (L2L_POINTS); 2601d056fa04SAlexander Leidinger lin_t = l2l_df[idx] * lin + l2l_f[idx]; 2602d056fa04SAlexander Leidinger return (lin_t); 2603d056fa04SAlexander Leidinger } 2604d056fa04SAlexander Leidinger 2605d056fa04SAlexander Leidinger 2606d056fa04SAlexander Leidinger void 2607d056fa04SAlexander Leidinger emumix_set_fxvol(struct emu_sc_info *sc, unsigned gpr, int32_t vol) 2608d056fa04SAlexander Leidinger { 2609d056fa04SAlexander Leidinger 2610d056fa04SAlexander Leidinger vol = log2lin(vol); 2611d056fa04SAlexander Leidinger emumix_set_gpr(sc, gpr, vol); 2612d056fa04SAlexander Leidinger } 2613d056fa04SAlexander Leidinger 2614d056fa04SAlexander Leidinger void 2615d056fa04SAlexander Leidinger emumix_set_gpr(struct emu_sc_info *sc, unsigned gpr, int32_t val) 2616d056fa04SAlexander Leidinger { 2617b28624fdSAriff Abdullah if (sc->dbg_level > 1) 2618b28624fdSAriff Abdullah if (gpr == 0) { 2619b28624fdSAriff Abdullah device_printf(sc->dev, "Zero gpr write access\n"); 2620b28624fdSAriff Abdullah #ifdef KDB 2621b28624fdSAriff Abdullah kdb_backtrace(); 2622b28624fdSAriff Abdullah #endif 2623b28624fdSAriff Abdullah return; 2624b28624fdSAriff Abdullah } 2625d056fa04SAlexander Leidinger 2626d056fa04SAlexander Leidinger emu_wrptr(sc, 0, GPR(gpr), val); 2627d056fa04SAlexander Leidinger } 2628d056fa04SAlexander Leidinger 2629d056fa04SAlexander Leidinger void 2630d056fa04SAlexander Leidinger emumix_set_volume(struct emu_sc_info *sc, int mixer_idx, int volume) 2631d056fa04SAlexander Leidinger { 2632d056fa04SAlexander Leidinger 2633d056fa04SAlexander Leidinger RANGE(volume, 0, 100); 2634d056fa04SAlexander Leidinger if (mixer_idx < NUM_MIXERS) { 2635d056fa04SAlexander Leidinger sc->mixer_volcache[mixer_idx] = volume; 2636d056fa04SAlexander Leidinger emumix_set_fxvol(sc, sc->mixer_gpr[mixer_idx], volume); 2637d056fa04SAlexander Leidinger } 2638d056fa04SAlexander Leidinger } 2639d056fa04SAlexander Leidinger 2640d056fa04SAlexander Leidinger int 2641d056fa04SAlexander Leidinger emumix_get_volume(struct emu_sc_info *sc, int mixer_idx) 2642d056fa04SAlexander Leidinger { 2643d056fa04SAlexander Leidinger if ((mixer_idx < NUM_MIXERS) && (mixer_idx >= 0)) 2644d056fa04SAlexander Leidinger return (sc->mixer_volcache[mixer_idx]); 2645d056fa04SAlexander Leidinger return (-1); 2646d056fa04SAlexander Leidinger } 2647d056fa04SAlexander Leidinger 2648d056fa04SAlexander Leidinger /* Init CardBus part */ 2649d056fa04SAlexander Leidinger static int 2650d056fa04SAlexander Leidinger emu_cardbus_init(struct emu_sc_info *sc) 2651d056fa04SAlexander Leidinger { 2652d056fa04SAlexander Leidinger 2653d056fa04SAlexander Leidinger /* 265470e0bbedSPedro F. Giffuni * XXX May not need this if we have EMU_IPR3 handler. 265570e0bbedSPedro F. Giffuni * Is it a real init calls, or EMU_IPR3 interrupt acknowledgments? 2656d056fa04SAlexander Leidinger * Looks much like "(data << 16) | register". 2657d056fa04SAlexander Leidinger */ 2658d056fa04SAlexander Leidinger emu_wr_cbptr(sc, (0x00d0 << 16) | 0x0000); 2659d056fa04SAlexander Leidinger emu_wr_cbptr(sc, (0x00d0 << 16) | 0x0001); 2660d056fa04SAlexander Leidinger emu_wr_cbptr(sc, (0x00d0 << 16) | 0x005f); 2661d056fa04SAlexander Leidinger emu_wr_cbptr(sc, (0x00d0 << 16) | 0x007f); 2662d056fa04SAlexander Leidinger 2663d056fa04SAlexander Leidinger emu_wr_cbptr(sc, (0x0090 << 16) | 0x007f); 2664d056fa04SAlexander Leidinger 2665d056fa04SAlexander Leidinger return (0); 2666d056fa04SAlexander Leidinger } 2667d056fa04SAlexander Leidinger 2668d056fa04SAlexander Leidinger /* Probe and attach the card */ 2669d056fa04SAlexander Leidinger static int 267055837609SAriff Abdullah emu_init(struct emu_sc_info *sc) 2671d056fa04SAlexander Leidinger { 2672d056fa04SAlexander Leidinger uint32_t ch, tmp; 2673d056fa04SAlexander Leidinger uint32_t spdif_sr; 2674d056fa04SAlexander Leidinger uint32_t ac97slot; 2675d056fa04SAlexander Leidinger int def_mode; 2676d056fa04SAlexander Leidinger int i; 2677d056fa04SAlexander Leidinger 2678d056fa04SAlexander Leidinger /* disable audio and lock cache */ 267970e0bbedSPedro F. Giffuni emu_wr(sc, EMU_HCFG, EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_MUTEBUTTONENABLE, 4); 2680d056fa04SAlexander Leidinger 2681d056fa04SAlexander Leidinger /* reset recording buffers */ 268270e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE); 268370e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_MICBA, 0); 268470e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE); 268570e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_FXBA, 0); 268670e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE); 268770e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_ADCBA, 0); 2688d056fa04SAlexander Leidinger 2689d056fa04SAlexander Leidinger /* disable channel interrupt */ 269070e0bbedSPedro F. Giffuni emu_wr(sc, EMU_INTE, EMU_INTE_INTERTIMERENB | EMU_INTE_SAMPLERATER | EMU_INTE_PCIERRENABLE, 4); 269170e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_CLIEL, 0); 269270e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_CLIEH, 0); 269370e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SOLEL, 0); 269470e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SOLEH, 0); 2695d056fa04SAlexander Leidinger 2696d056fa04SAlexander Leidinger /* disable P16V and S/PDIF interrupts */ 2697d056fa04SAlexander Leidinger if ((sc->is_ca0102) || (sc->is_ca0108)) 269870e0bbedSPedro F. Giffuni emu_wr(sc, EMU_INTE2, 0, 4); 2699d056fa04SAlexander Leidinger 2700d056fa04SAlexander Leidinger if (sc->is_ca0102) 270170e0bbedSPedro F. Giffuni emu_wr(sc, EMU_INTE3, 0, 4); 2702d056fa04SAlexander Leidinger 2703d056fa04SAlexander Leidinger /* init phys inputs and outputs */ 2704d056fa04SAlexander Leidinger ac97slot = 0; 2705d056fa04SAlexander Leidinger if (sc->has_51) 270670e0bbedSPedro F. Giffuni ac97slot = EMU_AC97SLOT_CENTER | EMU_AC97SLOT_LFE; 2707d056fa04SAlexander Leidinger if (sc->has_71) 270870e0bbedSPedro F. Giffuni ac97slot = EMU_AC97SLOT_CENTER | EMU_AC97SLOT_LFE | EMU_AC97SLOT_REAR_LEFT | EMU_AC97SLOT_REAR_RIGHT; 2709d056fa04SAlexander Leidinger if (sc->is_emu10k2) 2710d056fa04SAlexander Leidinger ac97slot |= 0x40; 271170e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_AC97SLOT, ac97slot); 2712d056fa04SAlexander Leidinger 2713d056fa04SAlexander Leidinger if (sc->is_emu10k2) /* XXX for later cards? */ 271470e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SPBYPASS, 0xf00); /* What will happen if 2715d056fa04SAlexander Leidinger * we write 1 here? */ 2716d056fa04SAlexander Leidinger 271755837609SAriff Abdullah if (bus_dma_tag_create( /* parent */ bus_get_dma_tag(sc->dev), 27180b989078SAlexander Leidinger /* alignment */ 2, /* boundary */ 0, 27191115e138SMarius Strobl /* lowaddr */ (1U << 31) - 1, /* can only access 0-2gb */ 2720d056fa04SAlexander Leidinger /* highaddr */ BUS_SPACE_MAXADDR, 2721d056fa04SAlexander Leidinger /* filter */ NULL, /* filterarg */ NULL, 2722e4c87b14SAlexander Leidinger /* maxsize */ EMU_MAX_BUFSZ, /* nsegments */ 1, /* maxsegz */ 0x3ffff, 2723d056fa04SAlexander Leidinger /* flags */ 0, /* lockfunc */ busdma_lock_mutex, 2724d056fa04SAlexander Leidinger /* lockarg */ &Giant, &(sc->mem.dmat)) != 0) { 2725d056fa04SAlexander Leidinger device_printf(sc->dev, "unable to create dma tag\n"); 2726d056fa04SAlexander Leidinger bus_dma_tag_destroy(sc->mem.dmat); 2727d056fa04SAlexander Leidinger return (ENOMEM); 2728d056fa04SAlexander Leidinger } 2729d056fa04SAlexander Leidinger 2730b28624fdSAriff Abdullah sc->mem.card = sc; 2731d056fa04SAlexander Leidinger SLIST_INIT(&sc->mem.blocks); 273286843ea8SJohn Baldwin sc->mem.ptb_pages = emu_malloc(&sc->mem, EMU_MAXPAGES * sizeof(uint32_t), &sc->mem.ptb_pages_addr, &sc->mem.ptb_map); 2733d056fa04SAlexander Leidinger if (sc->mem.ptb_pages == NULL) 2734d056fa04SAlexander Leidinger return (ENOMEM); 2735d056fa04SAlexander Leidinger 273686843ea8SJohn Baldwin sc->mem.silent_page = emu_malloc(&sc->mem, EMUPAGESIZE, &sc->mem.silent_page_addr, &sc->mem.silent_map); 2737d056fa04SAlexander Leidinger if (sc->mem.silent_page == NULL) { 273886843ea8SJohn Baldwin emu_free(&sc->mem, sc->mem.ptb_pages, sc->mem.ptb_map); 2739d056fa04SAlexander Leidinger return (ENOMEM); 2740d056fa04SAlexander Leidinger } 2741d056fa04SAlexander Leidinger /* Clear page with silence & setup all pointers to this page */ 2742d056fa04SAlexander Leidinger bzero(sc->mem.silent_page, EMUPAGESIZE); 2743d056fa04SAlexander Leidinger tmp = (uint32_t) (sc->mem.silent_page_addr) << 1; 2744e4c87b14SAlexander Leidinger for (i = 0; i < EMU_MAXPAGES; i++) 2745d056fa04SAlexander Leidinger sc->mem.ptb_pages[i] = tmp | i; 2746d056fa04SAlexander Leidinger 2747d056fa04SAlexander Leidinger for (ch = 0; ch < NUM_G; ch++) { 274870e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_MAPA, tmp | EMU_CHAN_MAP_PTI_MASK); 274970e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_MAPB, tmp | EMU_CHAN_MAP_PTI_MASK); 2750d056fa04SAlexander Leidinger } 275170e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_PTB, (sc->mem.ptb_pages_addr)); 275270e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_TCB, 0); /* taken from original driver */ 275370e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_TCBS, 0); /* taken from original driver */ 2754d056fa04SAlexander Leidinger 2755d056fa04SAlexander Leidinger /* init envelope engine */ 2756d056fa04SAlexander Leidinger for (ch = 0; ch < NUM_G; ch++) { 275770e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_DCYSUSV, 0); 275870e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_IP, 0); 275970e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_VTFT, 0xffff); 276070e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_CVCF, 0xffff); 276170e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_PTRX, 0); 276270e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_CPF, 0); 276370e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_CCR, 0); 2764d056fa04SAlexander Leidinger 276570e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_PSST, 0); 276670e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_DSL, 0x10); 276770e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_CCCA, 0); 276870e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_Z1, 0); 276970e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_Z2, 0); 277070e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_FXRT, 0xd01c0000); 2771d056fa04SAlexander Leidinger 277270e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_ATKHLDM, 0); 277370e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_DCYSUSM, 0); 277470e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_IFATN, 0xffff); 277570e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_PEFE, 0); 277670e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_FMMOD, 0); 277770e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_TREMFRQ, 24); /* 1 Hz */ 277870e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_FM2FRQ2, 24); /* 1 Hz */ 277970e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_TEMPENV, 0); 2780d056fa04SAlexander Leidinger 2781d056fa04SAlexander Leidinger /*** these are last so OFF prevents writing ***/ 278270e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_LFOVAL2, 0); 278370e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_LFOVAL1, 0); 278470e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_ATKHLDV, 0); 278570e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_ENVVOL, 0); 278670e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_ENVVAL, 0); 2787d056fa04SAlexander Leidinger 2788d056fa04SAlexander Leidinger if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) { 2789d056fa04SAlexander Leidinger emu_wrptr(sc, ch, 0x4c, 0x0); 2790d056fa04SAlexander Leidinger emu_wrptr(sc, ch, 0x4d, 0x0); 2791d056fa04SAlexander Leidinger emu_wrptr(sc, ch, 0x4e, 0x0); 2792d056fa04SAlexander Leidinger emu_wrptr(sc, ch, 0x4f, 0x0); 279370e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_A_CHAN_FXRT1, 0x3f3f3f3f); 279470e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_A_CHAN_FXRT2, 0x3f3f3f3f); 279570e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_A_CHAN_SENDAMOUNTS, 0x0); 2796d056fa04SAlexander Leidinger } 2797d056fa04SAlexander Leidinger } 2798d056fa04SAlexander Leidinger 2799d056fa04SAlexander Leidinger emumix_set_spdif_mode(sc, SPDIF_MODE_PCM); 2800d056fa04SAlexander Leidinger 2801d056fa04SAlexander Leidinger if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) 280270e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_A_SPDIF_SAMPLERATE, EMU_A_SPDIF_48000); 2803d056fa04SAlexander Leidinger 2804d056fa04SAlexander Leidinger /* 2805d056fa04SAlexander Leidinger * CAxxxx cards needs additional setup: 2806d056fa04SAlexander Leidinger * 1. Set I2S capture sample rate to 96000 2807d056fa04SAlexander Leidinger * 2. Disable P16v / P17v proceesing 2808d056fa04SAlexander Leidinger * 3. Allow EMU10K DSP inputs 2809d056fa04SAlexander Leidinger */ 2810d056fa04SAlexander Leidinger if ((sc->is_ca0102) || (sc->is_ca0108)) { 2811d056fa04SAlexander Leidinger 281270e0bbedSPedro F. Giffuni spdif_sr = emu_rdptr(sc, 0, EMU_A_SPDIF_SAMPLERATE); 2813d056fa04SAlexander Leidinger spdif_sr &= 0xfffff1ff; 281470e0bbedSPedro F. Giffuni spdif_sr |= EMU_A_I2S_CAPTURE_96000; 281570e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_A_SPDIF_SAMPLERATE, spdif_sr); 2816d056fa04SAlexander Leidinger 2817d056fa04SAlexander Leidinger /* Disable P16v processing */ 281870e0bbedSPedro F. Giffuni emu_wr_p16vptr(sc, 0, EMU_A2_SRCSel, 0x14); 2819d056fa04SAlexander Leidinger 2820d056fa04SAlexander Leidinger /* Setup P16v/P17v sound routing */ 2821d056fa04SAlexander Leidinger if (sc->is_ca0102) 282270e0bbedSPedro F. Giffuni emu_wr_p16vptr(sc, 0, EMU_A2_SRCMULTI_ENABLE, 0xFF00FF00); 2823d056fa04SAlexander Leidinger else { 282470e0bbedSPedro F. Giffuni emu_wr_p16vptr(sc, 0, EMU_A2_MIXER_I2S_ENABLE, 0xFF000000); 282570e0bbedSPedro F. Giffuni emu_wr_p16vptr(sc, 0, EMU_A2_MIXER_SPDIF_ENABLE, 0xFF000000); 2826d056fa04SAlexander Leidinger 282770e0bbedSPedro F. Giffuni tmp = emu_rd(sc, EMU_A_IOCFG, 2); 282870e0bbedSPedro F. Giffuni emu_wr(sc, EMU_A_IOCFG, tmp & ~0x8, 2); 2829d056fa04SAlexander Leidinger } 2830d056fa04SAlexander Leidinger } 2831d056fa04SAlexander Leidinger emu_initefx(sc); 2832d056fa04SAlexander Leidinger 2833d056fa04SAlexander Leidinger def_mode = MODE_ANALOG; 2834d056fa04SAlexander Leidinger if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) 2835d056fa04SAlexander Leidinger def_mode = MODE_DIGITAL; 2836d056fa04SAlexander Leidinger if (((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) && (sc->broken_digital)) { 2837d056fa04SAlexander Leidinger device_printf(sc->dev, "Audigy card initialized in analog mode.\n"); 2838d056fa04SAlexander Leidinger def_mode = MODE_ANALOG; 2839d056fa04SAlexander Leidinger } 2840d056fa04SAlexander Leidinger emumix_set_mode(sc, def_mode); 2841d056fa04SAlexander Leidinger 2842d056fa04SAlexander Leidinger if (bootverbose) { 284370e0bbedSPedro F. Giffuni tmp = emu_rd(sc, EMU_HCFG, 4); 2844d056fa04SAlexander Leidinger device_printf(sc->dev, "Card Configuration ( 0x%08x )\n", tmp); 2845d056fa04SAlexander Leidinger device_printf(sc->dev, "Card Configuration ( & 0xff000000 ) : %s%s%s%s%s%s%s%s\n", 2846d056fa04SAlexander Leidinger (tmp & 0x80000000 ? "[Legacy MPIC] " : ""), 2847d056fa04SAlexander Leidinger (tmp & 0x40000000 ? "[0x40] " : ""), 2848d056fa04SAlexander Leidinger (tmp & 0x20000000 ? "[0x20] " : ""), 2849d056fa04SAlexander Leidinger (tmp & 0x10000000 ? "[0x10] " : ""), 2850d056fa04SAlexander Leidinger (tmp & 0x08000000 ? "[0x08] " : ""), 2851d056fa04SAlexander Leidinger (tmp & 0x04000000 ? "[0x04] " : ""), 2852d056fa04SAlexander Leidinger (tmp & 0x02000000 ? "[0x02] " : ""), 2853d056fa04SAlexander Leidinger (tmp & 0x01000000 ? "[0x01]" : " ")); 2854d056fa04SAlexander Leidinger device_printf(sc->dev, "Card Configuration ( & 0x00ff0000 ) : %s%s%s%s%s%s%s%s\n", 2855d056fa04SAlexander Leidinger (tmp & 0x00800000 ? "[0x80] " : ""), 2856d056fa04SAlexander Leidinger (tmp & 0x00400000 ? "[0x40] " : ""), 2857d056fa04SAlexander Leidinger (tmp & 0x00200000 ? "[Legacy INT] " : ""), 2858d056fa04SAlexander Leidinger (tmp & 0x00100000 ? "[0x10] " : ""), 2859d056fa04SAlexander Leidinger (tmp & 0x00080000 ? "[0x08] " : ""), 2860d056fa04SAlexander Leidinger (tmp & 0x00040000 ? "[Codec4] " : ""), 2861d056fa04SAlexander Leidinger (tmp & 0x00020000 ? "[Codec2] " : ""), 2862d056fa04SAlexander Leidinger (tmp & 0x00010000 ? "[I2S Codec]" : " ")); 2863d056fa04SAlexander Leidinger device_printf(sc->dev, "Card Configuration ( & 0x0000ff00 ) : %s%s%s%s%s%s%s%s\n", 2864d056fa04SAlexander Leidinger (tmp & 0x00008000 ? "[0x80] " : ""), 2865d056fa04SAlexander Leidinger (tmp & 0x00004000 ? "[GPINPUT0] " : ""), 2866d056fa04SAlexander Leidinger (tmp & 0x00002000 ? "[GPINPUT1] " : ""), 2867d056fa04SAlexander Leidinger (tmp & 0x00001000 ? "[GPOUT0] " : ""), 2868d056fa04SAlexander Leidinger (tmp & 0x00000800 ? "[GPOUT1] " : ""), 2869d056fa04SAlexander Leidinger (tmp & 0x00000400 ? "[GPOUT2] " : ""), 2870d056fa04SAlexander Leidinger (tmp & 0x00000200 ? "[Joystick] " : ""), 2871d056fa04SAlexander Leidinger (tmp & 0x00000100 ? "[0x01]" : " ")); 2872d056fa04SAlexander Leidinger device_printf(sc->dev, "Card Configuration ( & 0x000000ff ) : %s%s%s%s%s%s%s%s\n", 2873d056fa04SAlexander Leidinger (tmp & 0x00000080 ? "[0x80] " : ""), 2874d056fa04SAlexander Leidinger (tmp & 0x00000040 ? "[0x40] " : ""), 2875d056fa04SAlexander Leidinger (tmp & 0x00000020 ? "[0x20] " : ""), 2876d056fa04SAlexander Leidinger (tmp & 0x00000010 ? "[AUTOMUTE] " : ""), 2877d056fa04SAlexander Leidinger (tmp & 0x00000008 ? "[LOCKSOUNDCACHE] " : ""), 2878d056fa04SAlexander Leidinger (tmp & 0x00000004 ? "[LOCKTANKCACHE] " : ""), 2879d056fa04SAlexander Leidinger (tmp & 0x00000002 ? "[MUTEBUTTONENABLE] " : ""), 2880d056fa04SAlexander Leidinger (tmp & 0x00000001 ? "[AUDIOENABLE]" : " ")); 2881d056fa04SAlexander Leidinger 2882d056fa04SAlexander Leidinger if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) { 288370e0bbedSPedro F. Giffuni tmp = emu_rd(sc, EMU_A_IOCFG, 2); 2884d056fa04SAlexander Leidinger device_printf(sc->dev, "Audigy Card Configuration ( 0x%04x )\n", tmp); 2885d056fa04SAlexander Leidinger device_printf(sc->dev, "Audigy Card Configuration ( & 0xff00 )"); 2886d056fa04SAlexander Leidinger printf(" : %s%s%s%s%s%s%s%s\n", 2887d056fa04SAlexander Leidinger (tmp & 0x8000 ? "[Rear Speakers] " : ""), 2888d056fa04SAlexander Leidinger (tmp & 0x4000 ? "[Front Speakers] " : ""), 2889d056fa04SAlexander Leidinger (tmp & 0x2000 ? "[0x20] " : ""), 2890d056fa04SAlexander Leidinger (tmp & 0x1000 ? "[0x10] " : ""), 2891d056fa04SAlexander Leidinger (tmp & 0x0800 ? "[0x08] " : ""), 2892d056fa04SAlexander Leidinger (tmp & 0x0400 ? "[0x04] " : ""), 2893d056fa04SAlexander Leidinger (tmp & 0x0200 ? "[0x02] " : ""), 2894d056fa04SAlexander Leidinger (tmp & 0x0100 ? "[AudigyDrive Phones]" : " ")); 2895d056fa04SAlexander Leidinger device_printf(sc->dev, "Audigy Card Configuration ( & 0x00ff )"); 2896d056fa04SAlexander Leidinger printf(" : %s%s%s%s%s%s%s%s\n", 2897d056fa04SAlexander Leidinger (tmp & 0x0080 ? "[0x80] " : ""), 2898d056fa04SAlexander Leidinger (tmp & 0x0040 ? "[Mute AnalogOut] " : ""), 2899d056fa04SAlexander Leidinger (tmp & 0x0020 ? "[0x20] " : ""), 2900d056fa04SAlexander Leidinger (tmp & 0x0010 ? "[0x10] " : ""), 2901d056fa04SAlexander Leidinger (tmp & 0x0008 ? "[0x08] " : ""), 2902d056fa04SAlexander Leidinger (tmp & 0x0004 ? "[GPOUT0] " : ""), 2903d056fa04SAlexander Leidinger (tmp & 0x0002 ? "[GPOUT1] " : ""), 2904d056fa04SAlexander Leidinger (tmp & 0x0001 ? "[GPOUT2]" : " ")); 2905d056fa04SAlexander Leidinger } /* is_emu10k2 or ca* */ 2906d056fa04SAlexander Leidinger } /* bootverbose */ 2907d056fa04SAlexander Leidinger return (0); 2908d056fa04SAlexander Leidinger } 2909d056fa04SAlexander Leidinger 2910d056fa04SAlexander Leidinger static int 2911d056fa04SAlexander Leidinger emu_uninit(struct emu_sc_info *sc) 2912d056fa04SAlexander Leidinger { 2913d056fa04SAlexander Leidinger uint32_t ch; 2914d056fa04SAlexander Leidinger struct emu_memblk *blk; 2915d056fa04SAlexander Leidinger 291670e0bbedSPedro F. Giffuni emu_wr(sc, EMU_INTE, 0, 4); 2917d056fa04SAlexander Leidinger for (ch = 0; ch < NUM_G; ch++) 291870e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_DCYSUSV, 0); 2919d056fa04SAlexander Leidinger for (ch = 0; ch < NUM_G; ch++) { 292070e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_VTFT, 0); 292170e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_CVCF, 0); 292270e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_PTRX, 0); 292370e0bbedSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_CPF, 0); 2924d056fa04SAlexander Leidinger } 2925d056fa04SAlexander Leidinger 2926d056fa04SAlexander Leidinger /* disable audio and lock cache */ 292770e0bbedSPedro F. Giffuni emu_wr(sc, EMU_HCFG, EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_MUTEBUTTONENABLE, 4); 2928d056fa04SAlexander Leidinger 292970e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_PTB, 0); 2930d056fa04SAlexander Leidinger /* reset recording buffers */ 293170e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE); 293270e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_MICBA, 0); 293370e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE); 293470e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_FXBA, 0); 293570e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_FXWC, 0); 293670e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE); 293770e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_ADCBA, 0); 293870e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_TCB, 0); 293970e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_TCBS, 0); 2940d056fa04SAlexander Leidinger 2941d056fa04SAlexander Leidinger /* disable channel interrupt */ 294270e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_CLIEL, 0); 294370e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_CLIEH, 0); 294470e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SOLEL, 0); 294570e0bbedSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SOLEH, 0); 2946d056fa04SAlexander Leidinger 2947d056fa04SAlexander Leidinger if (!SLIST_EMPTY(&sc->mem.blocks)) 2948d056fa04SAlexander Leidinger device_printf(sc->dev, "warning: memblock list not empty\n"); 2949d056fa04SAlexander Leidinger 2950d056fa04SAlexander Leidinger SLIST_FOREACH(blk, &sc->mem.blocks, link) 2951d056fa04SAlexander Leidinger if (blk != NULL) 2952d056fa04SAlexander Leidinger device_printf(sc->dev, "lost %d for %s\n", blk->pte_size, blk->owner); 2953d056fa04SAlexander Leidinger 295486843ea8SJohn Baldwin emu_free(&sc->mem, sc->mem.ptb_pages, sc->mem.ptb_map); 295586843ea8SJohn Baldwin emu_free(&sc->mem, sc->mem.silent_page, sc->mem.silent_map); 2956d056fa04SAlexander Leidinger 2957d056fa04SAlexander Leidinger return (0); 2958d056fa04SAlexander Leidinger } 2959d056fa04SAlexander Leidinger 2960d056fa04SAlexander Leidinger static int 2961d056fa04SAlexander Leidinger emu_read_ivar(device_t bus, device_t dev, int ivar_index, uintptr_t * result) 2962d056fa04SAlexander Leidinger { 2963d056fa04SAlexander Leidinger struct sndcard_func *func = device_get_ivars(dev); 2964d056fa04SAlexander Leidinger struct emu_sc_info *sc = device_get_softc(bus); 2965d056fa04SAlexander Leidinger 2966b28624fdSAriff Abdullah if (func==NULL) 2967b28624fdSAriff Abdullah return (ENOMEM); 2968b28624fdSAriff Abdullah if (sc == NULL) 2969b28624fdSAriff Abdullah return (ENOMEM); 2970b28624fdSAriff Abdullah 2971d056fa04SAlexander Leidinger switch (ivar_index) { 2972d056fa04SAlexander Leidinger case EMU_VAR_FUNC: 2973d056fa04SAlexander Leidinger *result = func->func; 2974d056fa04SAlexander Leidinger break; 2975d056fa04SAlexander Leidinger case EMU_VAR_ROUTE: 2976b28624fdSAriff Abdullah if (func->varinfo == NULL) 2977b28624fdSAriff Abdullah return (ENOMEM); 2978d056fa04SAlexander Leidinger *result = ((struct emu_pcminfo *)func->varinfo)->route; 2979d056fa04SAlexander Leidinger break; 2980d056fa04SAlexander Leidinger case EMU_VAR_ISEMU10K1: 2981d056fa04SAlexander Leidinger *result = sc->is_emu10k1; 2982d056fa04SAlexander Leidinger break; 2983b28624fdSAriff Abdullah case EMU_VAR_MCH_DISABLED: 2984b28624fdSAriff Abdullah *result = sc->mch_disabled; 2985b28624fdSAriff Abdullah break; 2986b28624fdSAriff Abdullah case EMU_VAR_MCH_REC: 2987b28624fdSAriff Abdullah *result = sc->mch_rec; 2988b28624fdSAriff Abdullah break; 2989d056fa04SAlexander Leidinger default: 2990d056fa04SAlexander Leidinger return (ENOENT); 2991d056fa04SAlexander Leidinger } 2992d056fa04SAlexander Leidinger 2993d056fa04SAlexander Leidinger return (0); 2994d056fa04SAlexander Leidinger } 2995d056fa04SAlexander Leidinger 2996d056fa04SAlexander Leidinger static int 2997d056fa04SAlexander Leidinger emu_write_ivar(device_t bus __unused, device_t dev __unused, 2998d056fa04SAlexander Leidinger int ivar_index, uintptr_t value __unused) 2999d056fa04SAlexander Leidinger { 3000d056fa04SAlexander Leidinger 3001d056fa04SAlexander Leidinger switch (ivar_index) { 3002d056fa04SAlexander Leidinger case 0: 3003d056fa04SAlexander Leidinger return (EINVAL); 3004d056fa04SAlexander Leidinger 3005d056fa04SAlexander Leidinger default: 3006d056fa04SAlexander Leidinger return (ENOENT); 3007d056fa04SAlexander Leidinger } 3008d056fa04SAlexander Leidinger } 3009d056fa04SAlexander Leidinger 3010d056fa04SAlexander Leidinger static int 3011d056fa04SAlexander Leidinger emu_pci_probe(device_t dev) 3012d056fa04SAlexander Leidinger { 3013d056fa04SAlexander Leidinger struct sbuf *s; 3014f856af04SAlexander Leidinger unsigned int thiscard = 0; 3015d056fa04SAlexander Leidinger uint16_t vendor; 3016d056fa04SAlexander Leidinger 3017d056fa04SAlexander Leidinger vendor = pci_read_config(dev, PCIR_DEVVENDOR, /* bytes */ 2); 3018d056fa04SAlexander Leidinger if (vendor != 0x1102) 3019d056fa04SAlexander Leidinger return (ENXIO); /* Not Creative */ 3020d056fa04SAlexander Leidinger 3021d056fa04SAlexander Leidinger thiscard = emu_getcard(dev); 3022f856af04SAlexander Leidinger if (thiscard == 0) 3023d056fa04SAlexander Leidinger return (ENXIO); 3024d056fa04SAlexander Leidinger 3025d056fa04SAlexander Leidinger s = sbuf_new(NULL, NULL, 4096, 0); 3026d056fa04SAlexander Leidinger if (s == NULL) 3027d056fa04SAlexander Leidinger return (ENOMEM); 3028d056fa04SAlexander Leidinger sbuf_printf(s, "Creative %s [%s]", emu_cards[thiscard].desc, emu_cards[thiscard].SBcode); 3029d056fa04SAlexander Leidinger sbuf_finish(s); 3030d056fa04SAlexander Leidinger 3031d056fa04SAlexander Leidinger device_set_desc_copy(dev, sbuf_data(s)); 3032b28624fdSAriff Abdullah 3033b28624fdSAriff Abdullah sbuf_delete(s); 3034b28624fdSAriff Abdullah 3035d056fa04SAlexander Leidinger return (BUS_PROBE_DEFAULT); 3036d056fa04SAlexander Leidinger } 3037d056fa04SAlexander Leidinger 3038d056fa04SAlexander Leidinger 3039d056fa04SAlexander Leidinger static int 3040d056fa04SAlexander Leidinger emu_pci_attach(device_t dev) 3041d056fa04SAlexander Leidinger { 3042d056fa04SAlexander Leidinger struct sndcard_func *func; 3043d056fa04SAlexander Leidinger struct emu_sc_info *sc; 3044d056fa04SAlexander Leidinger struct emu_pcminfo *pcminfo; 3045b28624fdSAriff Abdullah #if 0 3046b28624fdSAriff Abdullah struct emu_midiinfo *midiinfo; 3047b28624fdSAriff Abdullah #endif 3048d056fa04SAlexander Leidinger int i; 3049d056fa04SAlexander Leidinger int device_flags; 3050d056fa04SAlexander Leidinger char status[255]; 3051d056fa04SAlexander Leidinger int error = ENXIO; 3052b28624fdSAriff Abdullah int unit; 3053d056fa04SAlexander Leidinger 3054d056fa04SAlexander Leidinger sc = device_get_softc(dev); 3055b28624fdSAriff Abdullah unit = device_get_unit(dev); 3056b28624fdSAriff Abdullah 3057b28624fdSAriff Abdullah /* Get configuration */ 3058b28624fdSAriff Abdullah 3059b28624fdSAriff Abdullah sc->ctx = device_get_sysctl_ctx(dev); 3060b28624fdSAriff Abdullah if (sc->ctx == NULL) 3061b28624fdSAriff Abdullah goto bad; 3062b28624fdSAriff Abdullah sc->root = device_get_sysctl_tree(dev); 3063b28624fdSAriff Abdullah if (sc->root == NULL) 3064b28624fdSAriff Abdullah goto bad; 3065b28624fdSAriff Abdullah 3066b28624fdSAriff Abdullah if (resource_int_value("emu10kx", unit, "multichannel_disabled", &(sc->mch_disabled))) 3067b28624fdSAriff Abdullah RANGE(sc->mch_disabled, 0, 1); 3068b28624fdSAriff Abdullah SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 3069b28624fdSAriff Abdullah SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 3070b28624fdSAriff Abdullah OID_AUTO, "multichannel_disabled", CTLFLAG_RD, &(sc->mch_disabled), 0, "Multichannel playback setting"); 3071b28624fdSAriff Abdullah 3072b28624fdSAriff Abdullah if (resource_int_value("emu10kx", unit, "multichannel_recording", &(sc->mch_rec))) 3073b28624fdSAriff Abdullah RANGE(sc->mch_rec, 0, 1); 3074b28624fdSAriff Abdullah SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 3075b28624fdSAriff Abdullah SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 3076b28624fdSAriff Abdullah OID_AUTO, "multichannel_recording", CTLFLAG_RD, &(sc->mch_rec), 0, "Multichannel recording setting"); 3077b28624fdSAriff Abdullah 3078b28624fdSAriff Abdullah if (resource_int_value("emu10kx", unit, "debug", &(sc->dbg_level))) 3079b28624fdSAriff Abdullah RANGE(sc->mch_rec, 0, 2); 3080b28624fdSAriff Abdullah SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 3081b28624fdSAriff Abdullah SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 3082b28624fdSAriff Abdullah OID_AUTO, "debug", CTLFLAG_RW, &(sc->dbg_level), 0, "Debug level"); 3083d056fa04SAlexander Leidinger 3084d056fa04SAlexander Leidinger /* Fill in the softc. */ 3085b28624fdSAriff Abdullah mtx_init(&sc->lock, device_get_nameunit(dev), "bridge conf", MTX_DEF); 3086b28624fdSAriff Abdullah mtx_init(&sc->rw, device_get_nameunit(dev), "exclusive io", MTX_DEF); 3087d056fa04SAlexander Leidinger sc->dev = dev; 3088d056fa04SAlexander Leidinger sc->type = pci_get_devid(dev); 3089d056fa04SAlexander Leidinger sc->rev = pci_get_revid(dev); 3090d056fa04SAlexander Leidinger sc->enable_ir = 0; 3091d056fa04SAlexander Leidinger sc->has_ac97 = 0; 3092d056fa04SAlexander Leidinger sc->has_51 = 0; 3093d056fa04SAlexander Leidinger sc->has_71 = 0; 3094d056fa04SAlexander Leidinger sc->broken_digital = 0; 3095d056fa04SAlexander Leidinger sc->is_emu10k1 = 0; 3096d056fa04SAlexander Leidinger sc->is_emu10k2 = 0; 3097d056fa04SAlexander Leidinger sc->is_ca0102 = 0; 3098d056fa04SAlexander Leidinger sc->is_ca0108 = 0; 3099d056fa04SAlexander Leidinger sc->is_cardbus = 0; 3100d056fa04SAlexander Leidinger 3101d056fa04SAlexander Leidinger device_flags = emu_cards[emu_getcard(dev)].flags; 3102d056fa04SAlexander Leidinger if (device_flags & HAS_51) 3103d056fa04SAlexander Leidinger sc->has_51 = 1; 3104d056fa04SAlexander Leidinger if (device_flags & HAS_71) { 3105d056fa04SAlexander Leidinger sc->has_51 = 1; 3106d056fa04SAlexander Leidinger sc->has_71 = 1; 3107d056fa04SAlexander Leidinger } 3108d056fa04SAlexander Leidinger if (device_flags & IS_EMU10K1) 3109d056fa04SAlexander Leidinger sc->is_emu10k1 = 1; 3110d056fa04SAlexander Leidinger if (device_flags & IS_EMU10K2) 3111d056fa04SAlexander Leidinger sc->is_emu10k2 = 1; 3112d056fa04SAlexander Leidinger if (device_flags & IS_CA0102) 3113d056fa04SAlexander Leidinger sc->is_ca0102 = 1; 3114d056fa04SAlexander Leidinger if (device_flags & IS_CA0108) 3115d056fa04SAlexander Leidinger sc->is_ca0108 = 1; 3116d056fa04SAlexander Leidinger if ((sc->is_emu10k2) && (sc->rev == 4)) { 3117d056fa04SAlexander Leidinger sc->is_emu10k2 = 0; 3118d056fa04SAlexander Leidinger sc->is_ca0102 = 1; /* for unknown Audigy 2 cards */ 3119d056fa04SAlexander Leidinger } 3120d056fa04SAlexander Leidinger if ((sc->is_ca0102 == 1) || (sc->is_ca0108 == 1)) 3121d056fa04SAlexander Leidinger if (device_flags & IS_CARDBUS) 3122d056fa04SAlexander Leidinger sc->is_cardbus = 1; 3123d056fa04SAlexander Leidinger 3124d056fa04SAlexander Leidinger if ((sc->is_emu10k1 + sc->is_emu10k2 + sc->is_ca0102 + sc->is_ca0108) != 1) { 3125d056fa04SAlexander Leidinger device_printf(sc->dev, "Unable to detect HW chipset\n"); 3126d056fa04SAlexander Leidinger goto bad; 3127d056fa04SAlexander Leidinger } 3128d056fa04SAlexander Leidinger if (device_flags & BROKEN_DIGITAL) 3129d056fa04SAlexander Leidinger sc->broken_digital = 1; 3130d056fa04SAlexander Leidinger if (device_flags & HAS_AC97) 3131d056fa04SAlexander Leidinger sc->has_ac97 = 1; 3132d056fa04SAlexander Leidinger 3133d056fa04SAlexander Leidinger sc->opcode_shift = 0; 3134d056fa04SAlexander Leidinger if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) { 3135d056fa04SAlexander Leidinger sc->opcode_shift = 24; 3136d056fa04SAlexander Leidinger sc->high_operand_shift = 12; 3137f856af04SAlexander Leidinger 3138f856af04SAlexander Leidinger /* DSP map */ 3139f856af04SAlexander Leidinger /* sc->fx_base = 0x0 */ 3140d056fa04SAlexander Leidinger sc->input_base = 0x40; 3141d056fa04SAlexander Leidinger /* sc->p16vinput_base = 0x50; */ 3142d056fa04SAlexander Leidinger sc->output_base = 0x60; 3143d056fa04SAlexander Leidinger sc->efxc_base = 0x80; 3144d056fa04SAlexander Leidinger /* sc->output32h_base = 0xa0; */ 3145d056fa04SAlexander Leidinger /* sc->output32l_base = 0xb0; */ 3146d056fa04SAlexander Leidinger sc->dsp_zero = 0xc0; 3147f856af04SAlexander Leidinger /* 0xe0...0x100 are unknown */ 3148f856af04SAlexander Leidinger /* sc->tram_base = 0x200 */ 3149f856af04SAlexander Leidinger /* sc->tram_addr_base = 0x300 */ 315070e0bbedSPedro F. Giffuni sc->gpr_base = EMU_A_FXGPREGBASE; 3151f856af04SAlexander Leidinger sc->num_gprs = 0x200; 315270e0bbedSPedro F. Giffuni sc->code_base = EMU_A_MICROCODEBASE; 3153f856af04SAlexander Leidinger sc->code_size = 0x800 / 2; /* 0x600-0xdff, 2048 words, 3154f856af04SAlexander Leidinger * 1024 instructions */ 3155f856af04SAlexander Leidinger 3156d056fa04SAlexander Leidinger sc->mchannel_fx = 8; 3157d056fa04SAlexander Leidinger sc->num_fxbuses = 16; 3158d056fa04SAlexander Leidinger sc->num_inputs = 8; 3159d056fa04SAlexander Leidinger sc->num_outputs = 16; 316070e0bbedSPedro F. Giffuni sc->address_mask = EMU_A_PTR_ADDR_MASK; 3161d056fa04SAlexander Leidinger } 3162d056fa04SAlexander Leidinger if (sc->is_emu10k1) { 3163b28624fdSAriff Abdullah sc->has_51 = 0; /* We don't support 5.1 sound on SB Live! 5.1 */ 3164d056fa04SAlexander Leidinger sc->opcode_shift = 20; 3165d056fa04SAlexander Leidinger sc->high_operand_shift = 10; 316670e0bbedSPedro F. Giffuni sc->code_base = EMU_MICROCODEBASE; 3167d056fa04SAlexander Leidinger sc->code_size = 0x400 / 2; /* 0x400-0x7ff, 1024 words, 3168d056fa04SAlexander Leidinger * 512 instructions */ 316970e0bbedSPedro F. Giffuni sc->gpr_base = EMU_FXGPREGBASE; 3170d056fa04SAlexander Leidinger sc->num_gprs = 0x100; 3171d056fa04SAlexander Leidinger sc->input_base = 0x10; 3172d056fa04SAlexander Leidinger sc->output_base = 0x20; 3173f856af04SAlexander Leidinger /* 3174f856af04SAlexander Leidinger * XXX 5.1 Analog outputs are inside efxc address space! 31750f5e7edcSKevin Lo * They use output+0x11/+0x12 (=efxc+1/+2). 3176f856af04SAlexander Leidinger * Don't use this efx registers for recording on SB Live! 5.1! 3177f856af04SAlexander Leidinger */ 3178d056fa04SAlexander Leidinger sc->efxc_base = 0x30; 3179d056fa04SAlexander Leidinger sc->dsp_zero = 0x40; 3180d056fa04SAlexander Leidinger sc->mchannel_fx = 0; 3181d056fa04SAlexander Leidinger sc->num_fxbuses = 8; 3182d056fa04SAlexander Leidinger sc->num_inputs = 8; 3183d056fa04SAlexander Leidinger sc->num_outputs = 16; 318470e0bbedSPedro F. Giffuni sc->address_mask = EMU_PTR_ADDR_MASK; 3185d056fa04SAlexander Leidinger } 3186d056fa04SAlexander Leidinger if (sc->opcode_shift == 0) 3187d056fa04SAlexander Leidinger goto bad; 3188d056fa04SAlexander Leidinger 3189d056fa04SAlexander Leidinger pci_enable_busmaster(dev); 3190d056fa04SAlexander Leidinger 3191d056fa04SAlexander Leidinger i = PCIR_BAR(0); 3192d056fa04SAlexander Leidinger sc->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &i, RF_ACTIVE); 3193d056fa04SAlexander Leidinger if (sc->reg == NULL) { 3194d056fa04SAlexander Leidinger device_printf(dev, "unable to map register space\n"); 3195d056fa04SAlexander Leidinger goto bad; 3196d056fa04SAlexander Leidinger } 3197d056fa04SAlexander Leidinger sc->st = rman_get_bustag(sc->reg); 3198d056fa04SAlexander Leidinger sc->sh = rman_get_bushandle(sc->reg); 3199d056fa04SAlexander Leidinger 3200d056fa04SAlexander Leidinger for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) 3201d056fa04SAlexander Leidinger sc->timer[i] = 0; /* disable it */ 3202d056fa04SAlexander Leidinger 3203d056fa04SAlexander Leidinger i = 0; 3204d056fa04SAlexander Leidinger sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, RF_ACTIVE | RF_SHAREABLE); 320590da2b28SAriff Abdullah if ((sc->irq == NULL) || bus_setup_intr(dev, sc->irq, INTR_MPSAFE | INTR_TYPE_AV, 320690da2b28SAriff Abdullah #if __FreeBSD_version >= 700031 320790da2b28SAriff Abdullah NULL, 320890da2b28SAriff Abdullah #endif 320990da2b28SAriff Abdullah emu_intr, sc, &sc->ih)) { 3210d056fa04SAlexander Leidinger device_printf(dev, "unable to map interrupt\n"); 3211d056fa04SAlexander Leidinger goto bad; 3212d056fa04SAlexander Leidinger } 3213d056fa04SAlexander Leidinger if (emu_rm_init(sc) != 0) { 3214d056fa04SAlexander Leidinger device_printf(dev, "unable to create resource manager\n"); 3215d056fa04SAlexander Leidinger goto bad; 3216d056fa04SAlexander Leidinger } 3217d056fa04SAlexander Leidinger if (sc->is_cardbus) 3218d056fa04SAlexander Leidinger if (emu_cardbus_init(sc) != 0) { 3219d056fa04SAlexander Leidinger device_printf(dev, "unable to initialize CardBus interface\n"); 3220d056fa04SAlexander Leidinger goto bad; 3221d056fa04SAlexander Leidinger } 3222b28624fdSAriff Abdullah if (emu_init(sc) != 0) { 3223d056fa04SAlexander Leidinger device_printf(dev, "unable to initialize the card\n"); 3224d056fa04SAlexander Leidinger goto bad; 3225d056fa04SAlexander Leidinger } 3226b28624fdSAriff Abdullah if (emu10kx_dev_init(sc) != 0) { 3227d056fa04SAlexander Leidinger device_printf(dev, "unable to create control device\n"); 3228d056fa04SAlexander Leidinger goto bad; 3229d056fa04SAlexander Leidinger } 3230d056fa04SAlexander Leidinger snprintf(status, 255, "rev %d at io 0x%lx irq %ld", sc->rev, rman_get_start(sc->reg), rman_get_start(sc->irq)); 3231d056fa04SAlexander Leidinger 3232d056fa04SAlexander Leidinger /* Voices */ 3233d056fa04SAlexander Leidinger for (i = 0; i < NUM_G; i++) { 3234d056fa04SAlexander Leidinger sc->voice[i].vnum = i; 3235d056fa04SAlexander Leidinger sc->voice[i].slave = NULL; 3236d056fa04SAlexander Leidinger sc->voice[i].busy = 0; 3237d056fa04SAlexander Leidinger sc->voice[i].ismaster = 0; 3238d056fa04SAlexander Leidinger sc->voice[i].running = 0; 3239d056fa04SAlexander Leidinger sc->voice[i].b16 = 0; 3240d056fa04SAlexander Leidinger sc->voice[i].stereo = 0; 3241d056fa04SAlexander Leidinger sc->voice[i].speed = 0; 3242d056fa04SAlexander Leidinger sc->voice[i].start = 0; 3243d056fa04SAlexander Leidinger sc->voice[i].end = 0; 3244d056fa04SAlexander Leidinger } 3245d056fa04SAlexander Leidinger 3246d056fa04SAlexander Leidinger /* PCM Audio */ 3247b28624fdSAriff Abdullah for (i = 0; i < RT_COUNT; i++) 3248b28624fdSAriff Abdullah sc->pcm[i] = NULL; 3249b28624fdSAriff Abdullah 3250d056fa04SAlexander Leidinger /* FRONT */ 3251d056fa04SAlexander Leidinger func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); 3252d056fa04SAlexander Leidinger if (func == NULL) { 3253d056fa04SAlexander Leidinger error = ENOMEM; 3254d056fa04SAlexander Leidinger goto bad; 3255d056fa04SAlexander Leidinger } 3256d056fa04SAlexander Leidinger pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); 3257d056fa04SAlexander Leidinger if (pcminfo == NULL) { 3258d056fa04SAlexander Leidinger error = ENOMEM; 3259d056fa04SAlexander Leidinger goto bad; 3260d056fa04SAlexander Leidinger } 3261d056fa04SAlexander Leidinger pcminfo->card = sc; 3262d056fa04SAlexander Leidinger pcminfo->route = RT_FRONT; 3263d056fa04SAlexander Leidinger 3264d056fa04SAlexander Leidinger func->func = SCF_PCM; 3265d056fa04SAlexander Leidinger func->varinfo = pcminfo; 3266d056fa04SAlexander Leidinger sc->pcm[RT_FRONT] = device_add_child(dev, "pcm", -1); 3267d056fa04SAlexander Leidinger device_set_ivars(sc->pcm[RT_FRONT], func); 3268f856af04SAlexander Leidinger 3269b28624fdSAriff Abdullah if (!(sc->mch_disabled)) { 3270d056fa04SAlexander Leidinger /* REAR */ 3271d056fa04SAlexander Leidinger func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); 3272d056fa04SAlexander Leidinger if (func == NULL) { 3273d056fa04SAlexander Leidinger error = ENOMEM; 3274d056fa04SAlexander Leidinger goto bad; 3275d056fa04SAlexander Leidinger } 3276d056fa04SAlexander Leidinger pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); 3277d056fa04SAlexander Leidinger if (pcminfo == NULL) { 3278d056fa04SAlexander Leidinger error = ENOMEM; 3279d056fa04SAlexander Leidinger goto bad; 3280d056fa04SAlexander Leidinger } 3281d056fa04SAlexander Leidinger pcminfo->card = sc; 3282d056fa04SAlexander Leidinger pcminfo->route = RT_REAR; 3283d056fa04SAlexander Leidinger 3284d056fa04SAlexander Leidinger func->func = SCF_PCM; 3285d056fa04SAlexander Leidinger func->varinfo = pcminfo; 3286d056fa04SAlexander Leidinger sc->pcm[RT_REAR] = device_add_child(dev, "pcm", -1); 3287d056fa04SAlexander Leidinger device_set_ivars(sc->pcm[RT_REAR], func); 3288d056fa04SAlexander Leidinger if (sc->has_51) { 3289d056fa04SAlexander Leidinger /* CENTER */ 3290d056fa04SAlexander Leidinger func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); 3291d056fa04SAlexander Leidinger if (func == NULL) { 3292d056fa04SAlexander Leidinger error = ENOMEM; 3293d056fa04SAlexander Leidinger goto bad; 3294d056fa04SAlexander Leidinger } 3295d056fa04SAlexander Leidinger pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); 3296d056fa04SAlexander Leidinger if (pcminfo == NULL) { 3297d056fa04SAlexander Leidinger error = ENOMEM; 3298d056fa04SAlexander Leidinger goto bad; 3299d056fa04SAlexander Leidinger } 3300d056fa04SAlexander Leidinger pcminfo->card = sc; 3301d056fa04SAlexander Leidinger pcminfo->route = RT_CENTER; 3302d056fa04SAlexander Leidinger 3303d056fa04SAlexander Leidinger func->func = SCF_PCM; 3304d056fa04SAlexander Leidinger func->varinfo = pcminfo; 3305d056fa04SAlexander Leidinger sc->pcm[RT_CENTER] = device_add_child(dev, "pcm", -1); 3306d056fa04SAlexander Leidinger device_set_ivars(sc->pcm[RT_CENTER], func); 3307d056fa04SAlexander Leidinger /* SUB */ 3308d056fa04SAlexander Leidinger func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); 3309d056fa04SAlexander Leidinger if (func == NULL) { 3310d056fa04SAlexander Leidinger error = ENOMEM; 3311d056fa04SAlexander Leidinger goto bad; 3312d056fa04SAlexander Leidinger } 3313d056fa04SAlexander Leidinger pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); 3314d056fa04SAlexander Leidinger if (pcminfo == NULL) { 3315d056fa04SAlexander Leidinger error = ENOMEM; 3316d056fa04SAlexander Leidinger goto bad; 3317d056fa04SAlexander Leidinger } 3318d056fa04SAlexander Leidinger pcminfo->card = sc; 3319d056fa04SAlexander Leidinger pcminfo->route = RT_SUB; 3320d056fa04SAlexander Leidinger 3321d056fa04SAlexander Leidinger func->func = SCF_PCM; 3322d056fa04SAlexander Leidinger func->varinfo = pcminfo; 3323d056fa04SAlexander Leidinger sc->pcm[RT_SUB] = device_add_child(dev, "pcm", -1); 3324d056fa04SAlexander Leidinger device_set_ivars(sc->pcm[RT_SUB], func); 3325d056fa04SAlexander Leidinger } 3326d056fa04SAlexander Leidinger if (sc->has_71) { 3327d056fa04SAlexander Leidinger /* SIDE */ 3328d056fa04SAlexander Leidinger func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); 3329d056fa04SAlexander Leidinger if (func == NULL) { 3330d056fa04SAlexander Leidinger error = ENOMEM; 3331d056fa04SAlexander Leidinger goto bad; 3332d056fa04SAlexander Leidinger } 3333d056fa04SAlexander Leidinger pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); 3334d056fa04SAlexander Leidinger if (pcminfo == NULL) { 3335d056fa04SAlexander Leidinger error = ENOMEM; 3336d056fa04SAlexander Leidinger goto bad; 3337d056fa04SAlexander Leidinger } 3338d056fa04SAlexander Leidinger pcminfo->card = sc; 3339d056fa04SAlexander Leidinger pcminfo->route = RT_SIDE; 3340d056fa04SAlexander Leidinger 3341d056fa04SAlexander Leidinger func->func = SCF_PCM; 3342d056fa04SAlexander Leidinger func->varinfo = pcminfo; 3343d056fa04SAlexander Leidinger sc->pcm[RT_SIDE] = device_add_child(dev, "pcm", -1); 3344d056fa04SAlexander Leidinger device_set_ivars(sc->pcm[RT_SIDE], func); 3345b28624fdSAriff Abdullah } 3346b28624fdSAriff Abdullah } /* mch_disabled */ 3347b28624fdSAriff Abdullah 3348b28624fdSAriff Abdullah if (sc->mch_rec) { 3349f856af04SAlexander Leidinger func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); 3350f856af04SAlexander Leidinger if (func == NULL) { 3351f856af04SAlexander Leidinger error = ENOMEM; 3352f856af04SAlexander Leidinger goto bad; 3353f856af04SAlexander Leidinger } 3354f856af04SAlexander Leidinger pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); 3355f856af04SAlexander Leidinger if (pcminfo == NULL) { 3356f856af04SAlexander Leidinger error = ENOMEM; 3357f856af04SAlexander Leidinger goto bad; 3358f856af04SAlexander Leidinger } 3359f856af04SAlexander Leidinger pcminfo->card = sc; 3360f856af04SAlexander Leidinger pcminfo->route = RT_MCHRECORD; 3361f856af04SAlexander Leidinger 3362f856af04SAlexander Leidinger func->func = SCF_PCM; 3363f856af04SAlexander Leidinger func->varinfo = pcminfo; 3364f856af04SAlexander Leidinger sc->pcm[RT_MCHRECORD] = device_add_child(dev, "pcm", -1); 3365f856af04SAlexander Leidinger device_set_ivars(sc->pcm[RT_MCHRECORD], func); 3366b28624fdSAriff Abdullah } /*mch_rec */ 3367f856af04SAlexander Leidinger 3368b28624fdSAriff Abdullah for (i = 0; i < 2; i++) 3369b28624fdSAriff Abdullah sc->midi[i] = NULL; 3370d056fa04SAlexander Leidinger 3371b28624fdSAriff Abdullah /* MIDI has some memory mangament and (possible) locking problems */ 3372b28624fdSAriff Abdullah #if 0 3373d056fa04SAlexander Leidinger /* Midi Interface 1: Live!, Audigy, Audigy 2 */ 3374d056fa04SAlexander Leidinger if ((sc->is_emu10k1) || (sc->is_emu10k2) || (sc->is_ca0102)) { 3375d056fa04SAlexander Leidinger func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); 3376d056fa04SAlexander Leidinger if (func == NULL) { 3377d056fa04SAlexander Leidinger error = ENOMEM; 3378d056fa04SAlexander Leidinger goto bad; 3379d056fa04SAlexander Leidinger } 3380b28624fdSAriff Abdullah midiinfo = malloc(sizeof(struct emu_midiinfo), M_DEVBUF, M_NOWAIT | M_ZERO); 3381b28624fdSAriff Abdullah if (midiinfo == NULL) { 3382d056fa04SAlexander Leidinger error = ENOMEM; 3383d056fa04SAlexander Leidinger goto bad; 3384d056fa04SAlexander Leidinger } 3385b28624fdSAriff Abdullah midiinfo->card = sc; 3386d056fa04SAlexander Leidinger if (sc->is_emu10k2 || (sc->is_ca0102)) { 338770e0bbedSPedro F. Giffuni midiinfo->port = EMU_A_MUDATA1; 3388b28624fdSAriff Abdullah midiinfo->portnr = 1; 3389d056fa04SAlexander Leidinger } 3390d056fa04SAlexander Leidinger if (sc->is_emu10k1) { 3391b28624fdSAriff Abdullah midiinfo->port = MUDATA; 3392b28624fdSAriff Abdullah midiinfo->portnr = 1; 3393d056fa04SAlexander Leidinger } 3394d056fa04SAlexander Leidinger func->func = SCF_MIDI; 3395b28624fdSAriff Abdullah func->varinfo = midiinfo; 3396d056fa04SAlexander Leidinger sc->midi[0] = device_add_child(dev, "midi", -1); 3397d056fa04SAlexander Leidinger device_set_ivars(sc->midi[0], func); 3398d056fa04SAlexander Leidinger } 3399d056fa04SAlexander Leidinger /* Midi Interface 2: Audigy, Audigy 2 (on AudigyDrive) */ 3400d056fa04SAlexander Leidinger if (sc->is_emu10k2 || (sc->is_ca0102)) { 3401d056fa04SAlexander Leidinger func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); 3402d056fa04SAlexander Leidinger if (func == NULL) { 3403d056fa04SAlexander Leidinger error = ENOMEM; 3404d056fa04SAlexander Leidinger goto bad; 3405d056fa04SAlexander Leidinger } 3406b28624fdSAriff Abdullah midiinfo = malloc(sizeof(struct emu_midiinfo), M_DEVBUF, M_NOWAIT | M_ZERO); 3407b28624fdSAriff Abdullah if (midiinfo == NULL) { 3408d056fa04SAlexander Leidinger error = ENOMEM; 3409d056fa04SAlexander Leidinger goto bad; 3410d056fa04SAlexander Leidinger } 3411b28624fdSAriff Abdullah midiinfo->card = sc; 3412d056fa04SAlexander Leidinger 341370e0bbedSPedro F. Giffuni midiinfo->port = EMU_A_MUDATA2; 3414b28624fdSAriff Abdullah midiinfo->portnr = 2; 3415d056fa04SAlexander Leidinger 3416d056fa04SAlexander Leidinger func->func = SCF_MIDI; 3417b28624fdSAriff Abdullah func->varinfo = midiinfo; 3418d056fa04SAlexander Leidinger sc->midi[1] = device_add_child(dev, "midi", -1); 3419d056fa04SAlexander Leidinger device_set_ivars(sc->midi[1], func); 3420d056fa04SAlexander Leidinger } 3421b28624fdSAriff Abdullah #endif 3422d056fa04SAlexander Leidinger return (bus_generic_attach(dev)); 3423d056fa04SAlexander Leidinger 3424d056fa04SAlexander Leidinger bad: 3425d056fa04SAlexander Leidinger /* XXX can we just call emu_pci_detach here? */ 3426d056fa04SAlexander Leidinger if (sc->cdev) 3427d056fa04SAlexander Leidinger emu10kx_dev_uninit(sc); 3428d056fa04SAlexander Leidinger if (sc->rm != NULL) 3429d056fa04SAlexander Leidinger emu_rm_uninit(sc); 3430d056fa04SAlexander Leidinger if (sc->reg) 3431d056fa04SAlexander Leidinger bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->reg); 3432d056fa04SAlexander Leidinger if (sc->ih) 3433d056fa04SAlexander Leidinger bus_teardown_intr(dev, sc->irq, sc->ih); 3434d056fa04SAlexander Leidinger if (sc->irq) 3435d056fa04SAlexander Leidinger bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 3436d056fa04SAlexander Leidinger mtx_destroy(&sc->rw); 3437b28624fdSAriff Abdullah mtx_destroy(&sc->lock); 3438d056fa04SAlexander Leidinger return (error); 3439d056fa04SAlexander Leidinger } 3440d056fa04SAlexander Leidinger 3441d056fa04SAlexander Leidinger static int 3442d056fa04SAlexander Leidinger emu_pci_detach(device_t dev) 3443d056fa04SAlexander Leidinger { 3444d056fa04SAlexander Leidinger struct emu_sc_info *sc; 3445b28624fdSAriff Abdullah struct sndcard_func *func; 3446d056fa04SAlexander Leidinger int devcount, i; 3447d056fa04SAlexander Leidinger device_t *childlist; 3448d056fa04SAlexander Leidinger int r = 0; 3449d056fa04SAlexander Leidinger 3450d056fa04SAlexander Leidinger sc = device_get_softc(dev); 3451d056fa04SAlexander Leidinger 3452f856af04SAlexander Leidinger for (i = 0; i < RT_COUNT; i++) { 3453b28624fdSAriff Abdullah if (sc->pcm[i] != NULL) { 3454b28624fdSAriff Abdullah func = device_get_ivars(sc->pcm[i]); 3455b28624fdSAriff Abdullah if (func != NULL && func->func == SCF_PCM) { 3456b28624fdSAriff Abdullah device_set_ivars(sc->pcm[i], NULL); 3457b28624fdSAriff Abdullah free(func->varinfo, M_DEVBUF); 3458b28624fdSAriff Abdullah free(func, M_DEVBUF); 3459d056fa04SAlexander Leidinger } 3460b28624fdSAriff Abdullah r = device_delete_child(dev, sc->pcm[i]); 3461b28624fdSAriff Abdullah if (r) return (r); 3462b28624fdSAriff Abdullah } 3463b28624fdSAriff Abdullah } 3464b28624fdSAriff Abdullah 3465b28624fdSAriff Abdullah if (sc->midi[0] != NULL) { 3466b28624fdSAriff Abdullah func = device_get_ivars(sc->midi[0]); 3467b28624fdSAriff Abdullah if (func != NULL && func->func == SCF_MIDI) { 3468b28624fdSAriff Abdullah device_set_ivars(sc->midi[0], NULL); 3469b28624fdSAriff Abdullah free(func->varinfo, M_DEVBUF); 3470b28624fdSAriff Abdullah free(func, M_DEVBUF); 3471b28624fdSAriff Abdullah } 3472d056fa04SAlexander Leidinger r = device_delete_child(dev, sc->midi[0]); 3473b28624fdSAriff Abdullah if (r) return (r); 3474b28624fdSAriff Abdullah } 3475b28624fdSAriff Abdullah 3476b28624fdSAriff Abdullah if (sc->midi[1] != NULL) { 3477b28624fdSAriff Abdullah func = device_get_ivars(sc->midi[1]); 3478b28624fdSAriff Abdullah if (func != NULL && func->func == SCF_MIDI) { 3479b28624fdSAriff Abdullah device_set_ivars(sc->midi[1], NULL); 3480b28624fdSAriff Abdullah free(func->varinfo, M_DEVBUF); 3481b28624fdSAriff Abdullah free(func, M_DEVBUF); 3482b28624fdSAriff Abdullah } 3483d056fa04SAlexander Leidinger r = device_delete_child(dev, sc->midi[1]); 3484b28624fdSAriff Abdullah if (r) return (r); 3485b28624fdSAriff Abdullah } 3486b28624fdSAriff Abdullah 3487b28624fdSAriff Abdullah if (device_get_children(dev, &childlist, &devcount) == 0) 3488d056fa04SAlexander Leidinger for (i = 0; i < devcount - 1; i++) { 3489d056fa04SAlexander Leidinger device_printf(dev, "removing stale child %d (unit %d)\n", i, device_get_unit(childlist[i])); 3490b28624fdSAriff Abdullah func = device_get_ivars(childlist[i]); 3491b28624fdSAriff Abdullah if (func != NULL && (func->func == SCF_MIDI || func->func == SCF_PCM)) { 3492b28624fdSAriff Abdullah device_set_ivars(childlist[i], NULL); 3493b28624fdSAriff Abdullah free(func->varinfo, M_DEVBUF); 3494b28624fdSAriff Abdullah free(func, M_DEVBUF); 3495b28624fdSAriff Abdullah } 3496d056fa04SAlexander Leidinger device_delete_child(dev, childlist[i]); 3497d056fa04SAlexander Leidinger } 3498b28624fdSAriff Abdullah if (childlist != NULL) 3499d056fa04SAlexander Leidinger free(childlist, M_TEMP); 3500d056fa04SAlexander Leidinger 3501d056fa04SAlexander Leidinger r = emu10kx_dev_uninit(sc); 3502d056fa04SAlexander Leidinger if (r) 3503d056fa04SAlexander Leidinger return (r); 3504b28624fdSAriff Abdullah 3505b28624fdSAriff Abdullah /* shutdown chip */ 3506b28624fdSAriff Abdullah emu_uninit(sc); 3507d056fa04SAlexander Leidinger emu_rm_uninit(sc); 350853bc1d83SAriff Abdullah 350953bc1d83SAriff Abdullah if (sc->mem.dmat) 351053bc1d83SAriff Abdullah bus_dma_tag_destroy(sc->mem.dmat); 351153bc1d83SAriff Abdullah 3512d056fa04SAlexander Leidinger if (sc->reg) 3513d056fa04SAlexander Leidinger bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->reg); 3514d056fa04SAlexander Leidinger bus_teardown_intr(dev, sc->irq, sc->ih); 3515d056fa04SAlexander Leidinger bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 3516d056fa04SAlexander Leidinger mtx_destroy(&sc->rw); 3517b28624fdSAriff Abdullah mtx_destroy(&sc->lock); 3518b28624fdSAriff Abdullah 3519d056fa04SAlexander Leidinger return (bus_generic_detach(dev)); 3520d056fa04SAlexander Leidinger } 3521d056fa04SAlexander Leidinger /* add suspend, resume */ 3522d056fa04SAlexander Leidinger static device_method_t emu_methods[] = { 3523d056fa04SAlexander Leidinger /* Device interface */ 3524d056fa04SAlexander Leidinger DEVMETHOD(device_probe, emu_pci_probe), 3525d056fa04SAlexander Leidinger DEVMETHOD(device_attach, emu_pci_attach), 3526d056fa04SAlexander Leidinger DEVMETHOD(device_detach, emu_pci_detach), 3527d056fa04SAlexander Leidinger /* Bus methods */ 3528d056fa04SAlexander Leidinger DEVMETHOD(bus_read_ivar, emu_read_ivar), 3529d056fa04SAlexander Leidinger DEVMETHOD(bus_write_ivar, emu_write_ivar), 3530d056fa04SAlexander Leidinger 353161bfd867SSofian Brabez DEVMETHOD_END 3532d056fa04SAlexander Leidinger }; 3533d056fa04SAlexander Leidinger 3534d056fa04SAlexander Leidinger 3535d056fa04SAlexander Leidinger static driver_t emu_driver = { 3536d056fa04SAlexander Leidinger "emu10kx", 3537d056fa04SAlexander Leidinger emu_methods, 3538d056fa04SAlexander Leidinger sizeof(struct emu_sc_info), 3539d056fa04SAlexander Leidinger NULL, 3540d056fa04SAlexander Leidinger 0, 3541d056fa04SAlexander Leidinger NULL 3542d056fa04SAlexander Leidinger }; 3543d056fa04SAlexander Leidinger 3544d056fa04SAlexander Leidinger static int 3545d056fa04SAlexander Leidinger emu_modevent(module_t mod __unused, int cmd, void *data __unused) 3546d056fa04SAlexander Leidinger { 3547d056fa04SAlexander Leidinger int err = 0; 3548d056fa04SAlexander Leidinger 3549d056fa04SAlexander Leidinger switch (cmd) { 3550d056fa04SAlexander Leidinger case MOD_LOAD: 3551d056fa04SAlexander Leidinger break; /* Success */ 3552d056fa04SAlexander Leidinger 3553d056fa04SAlexander Leidinger case MOD_UNLOAD: 3554d056fa04SAlexander Leidinger case MOD_SHUTDOWN: 3555d056fa04SAlexander Leidinger 3556d056fa04SAlexander Leidinger /* XXX Should we check state of pcm & midi subdevices here? */ 3557d056fa04SAlexander Leidinger 3558d056fa04SAlexander Leidinger break; /* Success */ 3559d056fa04SAlexander Leidinger 3560d056fa04SAlexander Leidinger default: 3561d056fa04SAlexander Leidinger err = EINVAL; 3562d056fa04SAlexander Leidinger break; 3563d056fa04SAlexander Leidinger } 3564d056fa04SAlexander Leidinger 3565d056fa04SAlexander Leidinger return (err); 3566d056fa04SAlexander Leidinger 3567d056fa04SAlexander Leidinger } 3568d056fa04SAlexander Leidinger 3569d056fa04SAlexander Leidinger static devclass_t emu_devclass; 3570d056fa04SAlexander Leidinger 3571d056fa04SAlexander Leidinger DRIVER_MODULE(snd_emu10kx, pci, emu_driver, emu_devclass, emu_modevent, NULL); 3572d056fa04SAlexander Leidinger MODULE_VERSION(snd_emu10kx, SND_EMU10KX_PREFVER); 3573