1 1.63 andvar /* $NetBSD: sv.c,v 1.63 2024/02/09 22:08:36 andvar Exp $ */ 2 1.1 augustss /* $OpenBSD: sv.c,v 1.2 1998/07/13 01:50:15 csapuntz Exp $ */ 3 1.1 augustss 4 1.1 augustss /* 5 1.45 jmcneill * Copyright (c) 1999, 2008 The NetBSD Foundation, Inc. 6 1.3 mycroft * All rights reserved. 7 1.3 mycroft * 8 1.3 mycroft * This code is derived from software contributed to The NetBSD Foundation 9 1.3 mycroft * by Charles M. Hannum. 10 1.3 mycroft * 11 1.3 mycroft * Redistribution and use in source and binary forms, with or without 12 1.3 mycroft * modification, are permitted provided that the following conditions 13 1.3 mycroft * are met: 14 1.3 mycroft * 1. Redistributions of source code must retain the above copyright 15 1.3 mycroft * notice, this list of conditions and the following disclaimer. 16 1.3 mycroft * 2. Redistributions in binary form must reproduce the above copyright 17 1.3 mycroft * notice, this list of conditions and the following disclaimer in the 18 1.3 mycroft * documentation and/or other materials provided with the distribution. 19 1.3 mycroft * 20 1.3 mycroft * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.3 mycroft * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.3 mycroft * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.3 mycroft * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.3 mycroft * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.3 mycroft * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.3 mycroft * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.3 mycroft * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.3 mycroft * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.3 mycroft * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.3 mycroft * POSSIBILITY OF SUCH DAMAGE. 31 1.3 mycroft */ 32 1.3 mycroft 33 1.3 mycroft /* 34 1.1 augustss * Copyright (c) 1998 Constantine Paul Sapuntzakis 35 1.1 augustss * All rights reserved 36 1.1 augustss * 37 1.1 augustss * Author: Constantine Paul Sapuntzakis (csapuntz (at) cvs.openbsd.org) 38 1.1 augustss * 39 1.1 augustss * Redistribution and use in source and binary forms, with or without 40 1.1 augustss * modification, are permitted provided that the following conditions 41 1.1 augustss * are met: 42 1.1 augustss * 1. Redistributions of source code must retain the above copyright 43 1.1 augustss * notice, this list of conditions and the following disclaimer. 44 1.1 augustss * 2. Redistributions in binary form must reproduce the above copyright 45 1.1 augustss * notice, this list of conditions and the following disclaimer in the 46 1.1 augustss * documentation and/or other materials provided with the distribution. 47 1.1 augustss * 3. The author's name or those of the contributors may be used to 48 1.28 perry * endorse or promote products derived from this software without 49 1.1 augustss * specific prior written permission. 50 1.1 augustss * 51 1.1 augustss * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS 52 1.1 augustss * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 53 1.1 augustss * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 54 1.1 augustss * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 55 1.1 augustss * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 56 1.1 augustss * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 57 1.1 augustss * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 58 1.1 augustss * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 59 1.1 augustss * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 60 1.1 augustss * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 61 1.1 augustss * POSSIBILITY OF SUCH DAMAGE. 62 1.1 augustss */ 63 1.1 augustss 64 1.1 augustss /* 65 1.1 augustss * S3 SonicVibes driver 66 1.1 augustss * Heavily based on the eap driver by Lennart Augustsson 67 1.1 augustss */ 68 1.15 lukem 69 1.15 lukem #include <sys/cdefs.h> 70 1.63 andvar __KERNEL_RCSID(0, "$NetBSD: sv.c,v 1.63 2024/02/09 22:08:36 andvar Exp $"); 71 1.1 augustss 72 1.1 augustss #include <sys/param.h> 73 1.1 augustss #include <sys/systm.h> 74 1.1 augustss #include <sys/kernel.h> 75 1.45 jmcneill #include <sys/kmem.h> 76 1.1 augustss #include <sys/device.h> 77 1.1 augustss 78 1.1 augustss #include <dev/pci/pcireg.h> 79 1.1 augustss #include <dev/pci/pcivar.h> 80 1.1 augustss #include <dev/pci/pcidevs.h> 81 1.1 augustss 82 1.1 augustss #include <sys/audioio.h> 83 1.55 isaki #include <dev/audio/audio_if.h> 84 1.1 augustss 85 1.1 augustss #include <dev/ic/i8237reg.h> 86 1.1 augustss #include <dev/pci/svreg.h> 87 1.1 augustss #include <dev/pci/svvar.h> 88 1.1 augustss 89 1.37 ad #include <sys/bus.h> 90 1.1 augustss 91 1.20 hannken /* XXX 92 1.20 hannken * The SonicVibes DMA is broken and only works on 24-bit addresses. 93 1.20 hannken * As long as bus_dmamem_alloc_range() is missing we use the ISA 94 1.22 wiz * DMA tag on i386. 95 1.20 hannken */ 96 1.48 soren #if defined(amd64) || defined(i386) 97 1.20 hannken #include <dev/isa/isavar.h> 98 1.20 hannken #endif 99 1.20 hannken 100 1.1 augustss #ifdef AUDIO_DEBUG 101 1.1 augustss #define DPRINTF(x) if (svdebug) printf x 102 1.1 augustss #define DPRINTFN(n,x) if (svdebug>(n)) printf x 103 1.1 augustss int svdebug = 0; 104 1.1 augustss #else 105 1.1 augustss #define DPRINTF(x) 106 1.1 augustss #define DPRINTFN(n,x) 107 1.1 augustss #endif 108 1.1 augustss 109 1.41 cegger static int sv_match(device_t, cfdata_t, void *); 110 1.41 cegger static void sv_attach(device_t, device_t, void *); 111 1.30 thorpej static int sv_intr(void *); 112 1.1 augustss 113 1.1 augustss struct sv_dma { 114 1.1 augustss bus_dmamap_t map; 115 1.36 christos void *addr; 116 1.4 mycroft bus_dma_segment_t segs[1]; 117 1.4 mycroft int nsegs; 118 1.4 mycroft size_t size; 119 1.4 mycroft struct sv_dma *next; 120 1.1 augustss }; 121 1.5 mycroft #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr) 122 1.5 mycroft #define KERNADDR(p) ((void *)((p)->addr)) 123 1.1 augustss 124 1.47 chs CFATTACH_DECL_NEW(sv, sizeof(struct sv_softc), 125 1.18 thorpej sv_match, sv_attach, NULL, NULL); 126 1.1 augustss 127 1.30 thorpej static struct audio_device sv_device = { 128 1.1 augustss "S3 SonicVibes", 129 1.1 augustss "", 130 1.1 augustss "sv" 131 1.1 augustss }; 132 1.1 augustss 133 1.1 augustss #define ARRAY_SIZE(foo) ((sizeof(foo)) / sizeof(foo[0])) 134 1.1 augustss 135 1.30 thorpej static int sv_allocmem(struct sv_softc *, size_t, size_t, int, 136 1.30 thorpej struct sv_dma *); 137 1.30 thorpej static int sv_freemem(struct sv_softc *, struct sv_dma *); 138 1.30 thorpej 139 1.30 thorpej static void sv_init_mixer(struct sv_softc *); 140 1.30 thorpej 141 1.30 thorpej static int sv_open(void *, int); 142 1.55 isaki static int sv_query_format(void *, audio_format_query_t *); 143 1.55 isaki static int sv_set_format(void *, int, 144 1.55 isaki const audio_params_t *, const audio_params_t *, 145 1.55 isaki audio_filter_reg_t *, audio_filter_reg_t *); 146 1.30 thorpej static int sv_round_blocksize(void *, int, int, const audio_params_t *); 147 1.30 thorpej static int sv_trigger_output(void *, void *, void *, int, void (*)(void *), 148 1.30 thorpej void *, const audio_params_t *); 149 1.30 thorpej static int sv_trigger_input(void *, void *, void *, int, void (*)(void *), 150 1.30 thorpej void *, const audio_params_t *); 151 1.30 thorpej static int sv_halt_output(void *); 152 1.30 thorpej static int sv_halt_input(void *); 153 1.30 thorpej static int sv_getdev(void *, struct audio_device *); 154 1.30 thorpej static int sv_mixer_set_port(void *, mixer_ctrl_t *); 155 1.30 thorpej static int sv_mixer_get_port(void *, mixer_ctrl_t *); 156 1.30 thorpej static int sv_query_devinfo(void *, mixer_devinfo_t *); 157 1.45 jmcneill static void * sv_malloc(void *, int, size_t); 158 1.45 jmcneill static void sv_free(void *, void *, size_t); 159 1.30 thorpej static int sv_get_props(void *); 160 1.45 jmcneill static void sv_get_locks(void *, kmutex_t **, kmutex_t **); 161 1.1 augustss 162 1.1 augustss #ifdef AUDIO_DEBUG 163 1.27 kent void sv_dumpregs(struct sv_softc *sc); 164 1.1 augustss #endif 165 1.1 augustss 166 1.30 thorpej static const struct audio_hw_if sv_hw_if = { 167 1.54 isaki .open = sv_open, 168 1.55 isaki .query_format = sv_query_format, 169 1.55 isaki .set_format = sv_set_format, 170 1.54 isaki .round_blocksize = sv_round_blocksize, 171 1.54 isaki .halt_output = sv_halt_output, 172 1.54 isaki .halt_input = sv_halt_input, 173 1.54 isaki .getdev = sv_getdev, 174 1.54 isaki .set_port = sv_mixer_set_port, 175 1.54 isaki .get_port = sv_mixer_get_port, 176 1.54 isaki .query_devinfo = sv_query_devinfo, 177 1.54 isaki .allocm = sv_malloc, 178 1.54 isaki .freem = sv_free, 179 1.54 isaki .get_props = sv_get_props, 180 1.54 isaki .trigger_output = sv_trigger_output, 181 1.54 isaki .trigger_input = sv_trigger_input, 182 1.54 isaki .get_locks = sv_get_locks, 183 1.1 augustss }; 184 1.1 augustss 185 1.55 isaki static const struct audio_format sv_formats[] = { 186 1.55 isaki { 187 1.55 isaki .mode = AUMODE_PLAY | AUMODE_RECORD, 188 1.55 isaki .encoding = AUDIO_ENCODING_SLINEAR_LE, 189 1.55 isaki .validbits = 16, 190 1.55 isaki .precision = 16, 191 1.55 isaki .channels = 2, 192 1.55 isaki .channel_mask = AUFMT_STEREO, 193 1.55 isaki .frequency_type = 0, 194 1.55 isaki .frequency = { 2000, 48000 }, 195 1.55 isaki }, 196 1.26 kent }; 197 1.55 isaki #define SV_NFORMATS __arraycount(sv_formats) 198 1.26 kent 199 1.1 augustss 200 1.1 augustss static void 201 1.27 kent sv_write(struct sv_softc *sc, uint8_t reg, uint8_t val) 202 1.1 augustss { 203 1.27 kent 204 1.1 augustss DPRINTFN(8,("sv_write(0x%x, 0x%x)\n", reg, val)); 205 1.1 augustss bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, val); 206 1.1 augustss } 207 1.1 augustss 208 1.27 kent static uint8_t 209 1.27 kent sv_read(struct sv_softc *sc, uint8_t reg) 210 1.1 augustss { 211 1.27 kent uint8_t val; 212 1.1 augustss 213 1.1 augustss val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg); 214 1.1 augustss DPRINTFN(8,("sv_read(0x%x) = 0x%x\n", reg, val)); 215 1.1 augustss return val; 216 1.1 augustss } 217 1.1 augustss 218 1.27 kent static uint8_t 219 1.27 kent sv_read_indirect(struct sv_softc *sc, uint8_t reg) 220 1.1 augustss { 221 1.27 kent uint8_t val; 222 1.1 augustss 223 1.1 augustss sv_write(sc, SV_CODEC_IADDR, reg & SV_IADDR_MASK); 224 1.1 augustss val = sv_read(sc, SV_CODEC_IDATA); 225 1.27 kent return val; 226 1.1 augustss } 227 1.1 augustss 228 1.1 augustss static void 229 1.27 kent sv_write_indirect(struct sv_softc *sc, uint8_t reg, uint8_t val) 230 1.1 augustss { 231 1.27 kent uint8_t iaddr; 232 1.1 augustss 233 1.27 kent iaddr = reg & SV_IADDR_MASK; 234 1.1 augustss if (reg == SV_DMA_DATA_FORMAT) 235 1.1 augustss iaddr |= SV_IADDR_MCE; 236 1.1 augustss 237 1.1 augustss sv_write(sc, SV_CODEC_IADDR, iaddr); 238 1.1 augustss sv_write(sc, SV_CODEC_IDATA, val); 239 1.1 augustss } 240 1.1 augustss 241 1.30 thorpej static int 242 1.41 cegger sv_match(device_t parent, cfdata_t match, void *aux) 243 1.1 augustss { 244 1.27 kent struct pci_attach_args *pa; 245 1.1 augustss 246 1.27 kent pa = aux; 247 1.1 augustss if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_S3 && 248 1.1 augustss PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_S3_SONICVIBES) 249 1.27 kent return 1; 250 1.27 kent 251 1.27 kent return 0; 252 1.1 augustss } 253 1.1 augustss 254 1.20 hannken static pcireg_t pci_io_alloc_low, pci_io_alloc_high; 255 1.20 hannken 256 1.30 thorpej static int 257 1.27 kent pci_alloc_io(pci_chipset_tag_t pc, pcitag_t pt, int pcioffs, 258 1.27 kent bus_space_tag_t iot, bus_size_t size, bus_size_t align, 259 1.27 kent bus_size_t bound, int flags, bus_space_handle_t *ioh) 260 1.1 augustss { 261 1.1 augustss bus_addr_t addr; 262 1.1 augustss int error; 263 1.1 augustss 264 1.20 hannken error = bus_space_alloc(iot, pci_io_alloc_low, pci_io_alloc_high, 265 1.1 augustss size, align, bound, flags, &addr, ioh); 266 1.1 augustss if (error) 267 1.27 kent return error; 268 1.1 augustss 269 1.1 augustss pci_conf_write(pc, pt, pcioffs, addr); 270 1.27 kent return 0; 271 1.1 augustss } 272 1.1 augustss 273 1.1 augustss /* 274 1.1 augustss * Allocate IO addresses when all other configuration is done. 275 1.1 augustss */ 276 1.30 thorpej static void 277 1.41 cegger sv_defer(device_t self) 278 1.1 augustss { 279 1.27 kent struct sv_softc *sc; 280 1.27 kent pci_chipset_tag_t pc; 281 1.27 kent pcitag_t pt; 282 1.1 augustss pcireg_t dmaio; 283 1.1 augustss 284 1.42 cegger sc = device_private(self); 285 1.27 kent pc = sc->sc_pa.pa_pc; 286 1.27 kent pt = sc->sc_pa.pa_tag; 287 1.1 augustss DPRINTF(("sv_defer: %p\n", sc)); 288 1.20 hannken 289 1.20 hannken /* XXX 290 1.20 hannken * Get a reasonable default for the I/O range. 291 1.20 hannken * Assume the range around SB_PORTBASE is valid on this PCI bus. 292 1.20 hannken */ 293 1.20 hannken pci_io_alloc_low = pci_conf_read(pc, pt, SV_SB_PORTBASE_SLOT); 294 1.20 hannken pci_io_alloc_high = pci_io_alloc_low + 0x1000; 295 1.20 hannken 296 1.27 kent if (pci_alloc_io(pc, pt, SV_DMAA_CONFIG_OFF, 297 1.1 augustss sc->sc_iot, SV_DMAA_SIZE, SV_DMAA_ALIGN, 0, 298 1.1 augustss 0, &sc->sc_dmaa_ioh)) { 299 1.1 augustss printf("sv_attach: cannot allocate DMA A range\n"); 300 1.1 augustss return; 301 1.1 augustss } 302 1.1 augustss dmaio = pci_conf_read(pc, pt, SV_DMAA_CONFIG_OFF); 303 1.1 augustss DPRINTF(("sv_attach: addr a dmaio=0x%lx\n", (u_long)dmaio)); 304 1.27 kent pci_conf_write(pc, pt, SV_DMAA_CONFIG_OFF, 305 1.1 augustss dmaio | SV_DMA_CHANNEL_ENABLE | SV_DMAA_EXTENDED_ADDR); 306 1.1 augustss 307 1.27 kent if (pci_alloc_io(pc, pt, SV_DMAC_CONFIG_OFF, 308 1.5 mycroft sc->sc_iot, SV_DMAC_SIZE, SV_DMAC_ALIGN, 0, 309 1.1 augustss 0, &sc->sc_dmac_ioh)) { 310 1.1 augustss printf("sv_attach: cannot allocate DMA C range\n"); 311 1.1 augustss return; 312 1.1 augustss } 313 1.1 augustss dmaio = pci_conf_read(pc, pt, SV_DMAC_CONFIG_OFF); 314 1.1 augustss DPRINTF(("sv_attach: addr c dmaio=0x%lx\n", (u_long)dmaio)); 315 1.27 kent pci_conf_write(pc, pt, SV_DMAC_CONFIG_OFF, 316 1.1 augustss dmaio | SV_DMA_CHANNEL_ENABLE); 317 1.1 augustss 318 1.1 augustss sc->sc_dmaset = 1; 319 1.1 augustss } 320 1.1 augustss 321 1.30 thorpej static void 322 1.41 cegger sv_attach(device_t parent, device_t self, void *aux) 323 1.27 kent { 324 1.27 kent struct sv_softc *sc; 325 1.27 kent struct pci_attach_args *pa; 326 1.27 kent pci_chipset_tag_t pc; 327 1.27 kent pcitag_t pt; 328 1.1 augustss pci_intr_handle_t ih; 329 1.1 augustss pcireg_t csr; 330 1.1 augustss char const *intrstr; 331 1.27 kent uint8_t reg; 332 1.1 augustss struct audio_attach_args arg; 333 1.50 christos char intrbuf[PCI_INTRSTR_LEN]; 334 1.27 kent 335 1.42 cegger sc = device_private(self); 336 1.27 kent pa = aux; 337 1.27 kent pc = pa->pa_pc; 338 1.27 kent pt = pa->pa_tag; 339 1.51 msaitoh aprint_naive("\n"); 340 1.51 msaitoh aprint_normal("\n"); 341 1.27 kent 342 1.1 augustss /* Map I/O registers */ 343 1.1 augustss if (pci_mapreg_map(pa, SV_ENHANCED_PORTBASE_SLOT, 344 1.1 augustss PCI_MAPREG_TYPE_IO, 0, 345 1.1 augustss &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) { 346 1.47 chs aprint_error_dev(self, "can't map enhanced i/o space\n"); 347 1.1 augustss return; 348 1.1 augustss } 349 1.1 augustss if (pci_mapreg_map(pa, SV_FM_PORTBASE_SLOT, 350 1.1 augustss PCI_MAPREG_TYPE_IO, 0, 351 1.1 augustss &sc->sc_opliot, &sc->sc_oplioh, NULL, NULL)) { 352 1.47 chs aprint_error_dev(self, "can't map FM i/o space\n"); 353 1.1 augustss return; 354 1.1 augustss } 355 1.1 augustss if (pci_mapreg_map(pa, SV_MIDI_PORTBASE_SLOT, 356 1.1 augustss PCI_MAPREG_TYPE_IO, 0, 357 1.1 augustss &sc->sc_midiiot, &sc->sc_midiioh, NULL, NULL)) { 358 1.47 chs aprint_error_dev(self, "can't map MIDI i/o space\n"); 359 1.1 augustss return; 360 1.1 augustss } 361 1.1 augustss DPRINTF(("sv: IO ports: enhanced=0x%x, OPL=0x%x, MIDI=0x%x\n", 362 1.1 augustss (int)sc->sc_ioh, (int)sc->sc_oplioh, (int)sc->sc_midiioh)); 363 1.1 augustss 364 1.20 hannken #if defined(alpha) 365 1.6 mycroft /* XXX Force allocation through the SGMAP. */ 366 1.6 mycroft sc->sc_dmatag = alphabus_dma_get_tag(pa->pa_dmat, ALPHA_BUS_ISA); 367 1.48 soren #elif defined(amd64) || defined(i386) 368 1.20 hannken /* XXX 369 1.20 hannken * The SonicVibes DMA is broken and only works on 24-bit addresses. 370 1.20 hannken * As long as bus_dmamem_alloc_range() is missing we use the ISA 371 1.22 wiz * DMA tag on i386. 372 1.20 hannken */ 373 1.20 hannken sc->sc_dmatag = &isa_bus_dma_tag; 374 1.6 mycroft #else 375 1.1 augustss sc->sc_dmatag = pa->pa_dmat; 376 1.6 mycroft #endif 377 1.1 augustss 378 1.5 mycroft pci_conf_write(pc, pt, SV_DMAA_CONFIG_OFF, SV_DMAA_EXTENDED_ADDR); 379 1.1 augustss pci_conf_write(pc, pt, SV_DMAC_CONFIG_OFF, 0); 380 1.1 augustss 381 1.1 augustss /* Enable the device. */ 382 1.1 augustss csr = pci_conf_read(pc, pt, PCI_COMMAND_STATUS_REG); 383 1.1 augustss pci_conf_write(pc, pt, PCI_COMMAND_STATUS_REG, 384 1.1 augustss csr | PCI_COMMAND_MASTER_ENABLE); 385 1.1 augustss 386 1.1 augustss sv_write_indirect(sc, SV_ANALOG_POWER_DOWN_CONTROL, 0); 387 1.1 augustss sv_write_indirect(sc, SV_DIGITAL_POWER_DOWN_CONTROL, 0); 388 1.27 kent 389 1.1 augustss /* initialize codec registers */ 390 1.1 augustss reg = sv_read(sc, SV_CODEC_CONTROL); 391 1.1 augustss reg |= SV_CTL_RESET; 392 1.1 augustss sv_write(sc, SV_CODEC_CONTROL, reg); 393 1.1 augustss delay(50); 394 1.1 augustss 395 1.1 augustss reg = sv_read(sc, SV_CODEC_CONTROL); 396 1.1 augustss reg &= ~SV_CTL_RESET; 397 1.1 augustss reg |= SV_CTL_INTA | SV_CTL_ENHANCED; 398 1.1 augustss 399 1.1 augustss /* This write clears the reset */ 400 1.1 augustss sv_write(sc, SV_CODEC_CONTROL, reg); 401 1.1 augustss delay(50); 402 1.1 augustss 403 1.1 augustss /* This write actually shoves the new values in */ 404 1.1 augustss sv_write(sc, SV_CODEC_CONTROL, reg); 405 1.1 augustss 406 1.1 augustss DPRINTF(("sv_attach: control=0x%x\n", sv_read(sc, SV_CODEC_CONTROL))); 407 1.1 augustss 408 1.1 augustss /* Map and establish the interrupt. */ 409 1.12 sommerfe if (pci_intr_map(pa, &ih)) { 410 1.47 chs aprint_error_dev(self, "couldn't map interrupt\n"); 411 1.1 augustss return; 412 1.1 augustss } 413 1.45 jmcneill 414 1.45 jmcneill mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 415 1.46 mrg mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); 416 1.45 jmcneill 417 1.50 christos intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); 418 1.53 jdolecek sc->sc_ih = pci_intr_establish_xname(pc, ih, IPL_AUDIO, sv_intr, sc, 419 1.53 jdolecek device_xname(self)); 420 1.1 augustss if (sc->sc_ih == NULL) { 421 1.47 chs aprint_error_dev(self, "couldn't establish interrupt"); 422 1.1 augustss if (intrstr != NULL) 423 1.44 njoly aprint_error(" at %s", intrstr); 424 1.44 njoly aprint_error("\n"); 425 1.45 jmcneill mutex_destroy(&sc->sc_lock); 426 1.45 jmcneill mutex_destroy(&sc->sc_intr_lock); 427 1.1 augustss return; 428 1.1 augustss } 429 1.51 msaitoh aprint_normal_dev(self, "interrupting at %s\n", intrstr); 430 1.51 msaitoh aprint_normal_dev(self, "rev %d", 431 1.51 msaitoh sv_read_indirect(sc, SV_REVISION_LEVEL)); 432 1.1 augustss if (sv_read(sc, SV_CODEC_CONTROL) & SV_CTL_MD1) 433 1.51 msaitoh aprint_normal(", reverb SRAM present"); 434 1.1 augustss if (!(sv_read_indirect(sc, SV_WAVETABLE_SOURCE_SELECT) & SV_WSS_WT0)) 435 1.51 msaitoh aprint_normal(", wavetable ROM present"); 436 1.51 msaitoh aprint_normal("\n"); 437 1.27 kent 438 1.45 jmcneill /* Enable DMA interrupts */ 439 1.45 jmcneill reg = sv_read(sc, SV_CODEC_INTMASK); 440 1.45 jmcneill reg &= ~(SV_INTMASK_DMAA | SV_INTMASK_DMAC); 441 1.45 jmcneill reg |= SV_INTMASK_UD | SV_INTMASK_SINT | SV_INTMASK_MIDI; 442 1.45 jmcneill sv_write(sc, SV_CODEC_INTMASK, reg); 443 1.45 jmcneill sv_read(sc, SV_CODEC_STATUS); 444 1.45 jmcneill 445 1.1 augustss sv_init_mixer(sc); 446 1.27 kent 447 1.47 chs audio_attach_mi(&sv_hw_if, sc, self); 448 1.1 augustss 449 1.1 augustss arg.type = AUDIODEV_TYPE_OPL; 450 1.1 augustss arg.hwif = 0; 451 1.1 augustss arg.hdl = 0; 452 1.62 chs (void)config_found(self, &arg, audioprint, CFARGS(.iattr = "sv")); 453 1.1 augustss 454 1.1 augustss sc->sc_pa = *pa; /* for deferred setup */ 455 1.1 augustss config_defer(self, sv_defer); 456 1.1 augustss } 457 1.1 augustss 458 1.1 augustss #ifdef AUDIO_DEBUG 459 1.1 augustss void 460 1.27 kent sv_dumpregs(struct sv_softc *sc) 461 1.1 augustss { 462 1.1 augustss int idx; 463 1.1 augustss 464 1.1 augustss #if 0 465 1.1 augustss for (idx = 0; idx < 0x50; idx += 4) 466 1.27 kent printf ("%02x = %x\n", idx, 467 1.1 augustss pci_conf_read(pa->pa_pc, pa->pa_tag, idx)); 468 1.1 augustss #endif 469 1.1 augustss 470 1.1 augustss for (idx = 0; idx < 6; idx++) 471 1.1 augustss printf ("REG %02x = %02x\n", idx, sv_read(sc, idx)); 472 1.27 kent 473 1.1 augustss for (idx = 0; idx < 0x32; idx++) 474 1.1 augustss printf ("IREG %02x = %02x\n", idx, sv_read_indirect(sc, idx)); 475 1.1 augustss 476 1.1 augustss for (idx = 0; idx < 0x10; idx++) 477 1.27 kent printf ("DMA %02x = %02x\n", idx, 478 1.1 augustss bus_space_read_1(sc->sc_iot, sc->sc_dmaa_ioh, idx)); 479 1.1 augustss } 480 1.1 augustss #endif 481 1.1 augustss 482 1.30 thorpej static int 483 1.27 kent sv_intr(void *p) 484 1.1 augustss { 485 1.27 kent struct sv_softc *sc; 486 1.27 kent uint8_t intr; 487 1.1 augustss 488 1.27 kent sc = p; 489 1.45 jmcneill 490 1.45 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 491 1.45 jmcneill 492 1.1 augustss intr = sv_read(sc, SV_CODEC_STATUS); 493 1.1 augustss DPRINTFN(5,("sv_intr: intr=0x%x\n", intr)); 494 1.1 augustss 495 1.1 augustss if (intr & SV_INTSTATUS_DMAA) { 496 1.1 augustss if (sc->sc_pintr) 497 1.1 augustss sc->sc_pintr(sc->sc_parg); 498 1.1 augustss } 499 1.1 augustss 500 1.1 augustss if (intr & SV_INTSTATUS_DMAC) { 501 1.1 augustss if (sc->sc_rintr) 502 1.1 augustss sc->sc_rintr(sc->sc_rarg); 503 1.1 augustss } 504 1.27 kent 505 1.45 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 506 1.45 jmcneill 507 1.45 jmcneill return (intr & (SV_INTSTATUS_DMAA | SV_INTSTATUS_DMAC)) != 0; 508 1.1 augustss } 509 1.1 augustss 510 1.30 thorpej static int 511 1.27 kent sv_allocmem(struct sv_softc *sc, size_t size, size_t align, 512 1.27 kent int direction, struct sv_dma *p) 513 1.1 augustss { 514 1.1 augustss int error; 515 1.1 augustss 516 1.1 augustss p->size = size; 517 1.1 augustss error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0, 518 1.45 jmcneill p->segs, ARRAY_SIZE(p->segs), &p->nsegs, BUS_DMA_WAITOK); 519 1.1 augustss if (error) 520 1.27 kent return error; 521 1.1 augustss 522 1.27 kent error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size, 523 1.45 jmcneill &p->addr, BUS_DMA_WAITOK|BUS_DMA_COHERENT); 524 1.1 augustss if (error) 525 1.1 augustss goto free; 526 1.1 augustss 527 1.1 augustss error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size, 528 1.45 jmcneill 0, BUS_DMA_WAITOK, &p->map); 529 1.1 augustss if (error) 530 1.1 augustss goto unmap; 531 1.1 augustss 532 1.27 kent error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL, 533 1.57 joerg BUS_DMA_WAITOK | ((direction == AUMODE_RECORD) ? BUS_DMA_READ : BUS_DMA_WRITE)); 534 1.1 augustss if (error) 535 1.1 augustss goto destroy; 536 1.5 mycroft DPRINTF(("sv_allocmem: pa=%lx va=%lx pba=%lx\n", 537 1.5 mycroft (long)p->segs[0].ds_addr, (long)KERNADDR(p), (long)DMAADDR(p))); 538 1.27 kent return 0; 539 1.1 augustss 540 1.1 augustss destroy: 541 1.1 augustss bus_dmamap_destroy(sc->sc_dmatag, p->map); 542 1.1 augustss unmap: 543 1.1 augustss bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size); 544 1.1 augustss free: 545 1.1 augustss bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs); 546 1.27 kent return error; 547 1.1 augustss } 548 1.1 augustss 549 1.30 thorpej static int 550 1.27 kent sv_freemem(struct sv_softc *sc, struct sv_dma *p) 551 1.1 augustss { 552 1.27 kent 553 1.1 augustss bus_dmamap_unload(sc->sc_dmatag, p->map); 554 1.1 augustss bus_dmamap_destroy(sc->sc_dmatag, p->map); 555 1.1 augustss bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size); 556 1.1 augustss bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs); 557 1.27 kent return 0; 558 1.1 augustss } 559 1.1 augustss 560 1.30 thorpej static int 561 1.35 christos sv_open(void *addr, int flags) 562 1.1 augustss { 563 1.27 kent struct sv_softc *sc; 564 1.1 augustss 565 1.27 kent sc = addr; 566 1.1 augustss DPRINTF(("sv_open\n")); 567 1.1 augustss if (!sc->sc_dmaset) 568 1.27 kent return ENXIO; 569 1.1 augustss 570 1.27 kent return 0; 571 1.1 augustss } 572 1.1 augustss 573 1.30 thorpej static int 574 1.55 isaki sv_query_format(void *addr, audio_format_query_t *afp) 575 1.1 augustss { 576 1.27 kent 577 1.55 isaki return audio_query_format(sv_formats, SV_NFORMATS, afp); 578 1.1 augustss } 579 1.1 augustss 580 1.30 thorpej static int 581 1.55 isaki sv_set_format(void *addr, int setmode, 582 1.55 isaki const audio_params_t *play, const audio_params_t *rec, 583 1.55 isaki audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 584 1.27 kent { 585 1.27 kent struct sv_softc *sc; 586 1.27 kent uint32_t val; 587 1.26 kent 588 1.27 kent sc = addr; 589 1.1 augustss 590 1.55 isaki /* *play and *rec are the identical because !AUDIO_PROP_INDEPENDENT. */ 591 1.29 hannken 592 1.55 isaki val = play->sample_rate * 65536 / 48000; 593 1.7 mycroft /* 594 1.32 lukem * If the sample rate is exactly 48 kHz, the fraction would overflow the 595 1.7 mycroft * register, so we have to bias it. This causes a little clock drift. 596 1.7 mycroft * The drift is below normal crystal tolerance (.0001%), so although 597 1.7 mycroft * this seems a little silly, we can pretty much ignore it. 598 1.7 mycroft * (I tested the output speed with values of 1-20, just to be sure this 599 1.7 mycroft * register isn't *supposed* to have a bias. It isn't.) 600 1.7 mycroft * - mycroft 601 1.7 mycroft */ 602 1.7 mycroft if (val > 65535) 603 1.7 mycroft val = 65535; 604 1.1 augustss 605 1.45 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 606 1.3 mycroft sv_write_indirect(sc, SV_PCM_SAMPLE_RATE_0, val & 0xff); 607 1.3 mycroft sv_write_indirect(sc, SV_PCM_SAMPLE_RATE_1, val >> 8); 608 1.45 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 609 1.1 augustss 610 1.1 augustss #define F_REF 24576000 611 1.1 augustss 612 1.1 augustss #define ABS(x) (((x) < 0) ? (-x) : (x)) 613 1.1 augustss 614 1.1 augustss if (setmode & AUMODE_RECORD) { 615 1.1 augustss /* The ADC reference frequency (f_out) is 512 * sample rate */ 616 1.1 augustss 617 1.63 andvar /* f_out is derived from the 24.576MHz crystal by three values: 618 1.1 augustss M & N & R. The equation is as follows: 619 1.1 augustss 620 1.1 augustss f_out = (m + 2) * f_ref / ((n + 2) * (2 ^ a)) 621 1.1 augustss 622 1.1 augustss with the constraint that: 623 1.1 augustss 624 1.21 tsutsui 80 MHz < (m + 2) / (n + 2) * f_ref <= 150MHz 625 1.1 augustss and n, m >= 1 626 1.1 augustss */ 627 1.1 augustss 628 1.27 kent int goal_f_out; 629 1.27 kent int a, n, m, best_n, best_m, best_error; 630 1.1 augustss int pll_sample; 631 1.1 augustss int error; 632 1.1 augustss 633 1.27 kent goal_f_out = 512 * rec->sample_rate; 634 1.27 kent best_n = 0; 635 1.27 kent best_m = 0; 636 1.27 kent best_error = 10000000; 637 1.1 augustss for (a = 0; a < 8; a++) { 638 1.1 augustss if ((goal_f_out * (1 << a)) >= 80000000) 639 1.1 augustss break; 640 1.1 augustss } 641 1.27 kent 642 1.1 augustss /* a != 8 because sample_rate >= 2000 */ 643 1.1 augustss 644 1.1 augustss for (n = 33; n > 2; n--) { 645 1.1 augustss m = (goal_f_out * n * (1 << a)) / F_REF; 646 1.3 mycroft if ((m > 257) || (m < 3)) 647 1.3 mycroft continue; 648 1.27 kent 649 1.1 augustss pll_sample = (m * F_REF) / (n * (1 << a)); 650 1.1 augustss pll_sample /= 512; 651 1.1 augustss 652 1.1 augustss /* Threshold might be good here */ 653 1.3 mycroft error = pll_sample - rec->sample_rate; 654 1.1 augustss error = ABS(error); 655 1.27 kent 656 1.1 augustss if (error < best_error) { 657 1.1 augustss best_error = error; 658 1.1 augustss best_n = n; 659 1.1 augustss best_m = m; 660 1.1 augustss if (error == 0) break; 661 1.1 augustss } 662 1.1 augustss } 663 1.1 augustss 664 1.1 augustss best_n -= 2; 665 1.1 augustss best_m -= 2; 666 1.27 kent 667 1.45 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 668 1.1 augustss sv_write_indirect(sc, SV_ADC_PLL_M, best_m); 669 1.27 kent sv_write_indirect(sc, SV_ADC_PLL_N, 670 1.1 augustss best_n | (a << SV_PLL_R_SHIFT)); 671 1.45 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 672 1.1 augustss } 673 1.3 mycroft 674 1.27 kent return 0; 675 1.1 augustss } 676 1.1 augustss 677 1.30 thorpej static int 678 1.35 christos sv_round_blocksize(void *addr, int blk, int mode, 679 1.35 christos const audio_params_t *param) 680 1.1 augustss { 681 1.27 kent 682 1.58 isaki blk = blk & -32; /* keep good alignment */ 683 1.58 isaki if (blk < 32) 684 1.58 isaki blk = 32; 685 1.58 isaki return blk; 686 1.1 augustss } 687 1.1 augustss 688 1.30 thorpej static int 689 1.27 kent sv_trigger_output(void *addr, void *start, void *end, int blksize, 690 1.27 kent void (*intr)(void *), void *arg, const audio_params_t *param) 691 1.1 augustss { 692 1.27 kent struct sv_softc *sc; 693 1.1 augustss struct sv_dma *p; 694 1.27 kent uint8_t mode; 695 1.1 augustss int dma_count; 696 1.1 augustss 697 1.27 kent DPRINTFN(1, ("sv_trigger_output: sc=%p start=%p end=%p blksize=%d " 698 1.27 kent "intr=%p(%p)\n", addr, start, end, blksize, intr, arg)); 699 1.27 kent sc = addr; 700 1.3 mycroft sc->sc_pintr = intr; 701 1.3 mycroft sc->sc_parg = arg; 702 1.1 augustss 703 1.3 mycroft mode = sv_read_indirect(sc, SV_DMA_DATA_FORMAT); 704 1.3 mycroft mode &= ~(SV_DMAA_FORMAT16 | SV_DMAA_STEREO); 705 1.26 kent if (param->precision == 16) 706 1.3 mycroft mode |= SV_DMAA_FORMAT16; 707 1.3 mycroft if (param->channels == 2) 708 1.3 mycroft mode |= SV_DMAA_STEREO; 709 1.3 mycroft sv_write_indirect(sc, SV_DMA_DATA_FORMAT, mode); 710 1.1 augustss 711 1.4 mycroft for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) 712 1.27 kent continue; 713 1.27 kent if (p == NULL) { 714 1.3 mycroft printf("sv_trigger_output: bad addr %p\n", start); 715 1.27 kent return EINVAL; 716 1.1 augustss } 717 1.1 augustss 718 1.3 mycroft dma_count = ((char *)end - (char *)start) - 1; 719 1.27 kent DPRINTF(("sv_trigger_output: DMA start loop input addr=%x cc=%d\n", 720 1.5 mycroft (int)DMAADDR(p), dma_count)); 721 1.1 augustss 722 1.1 augustss bus_space_write_4(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_ADDR0, 723 1.1 augustss DMAADDR(p)); 724 1.1 augustss bus_space_write_4(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_COUNT0, 725 1.1 augustss dma_count); 726 1.1 augustss bus_space_write_1(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_MODE, 727 1.1 augustss DMA37MD_READ | DMA37MD_LOOP); 728 1.1 augustss 729 1.5 mycroft DPRINTF(("sv_trigger_output: current addr=%x\n", 730 1.5 mycroft bus_space_read_4(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_ADDR0))); 731 1.5 mycroft 732 1.3 mycroft dma_count = blksize - 1; 733 1.3 mycroft 734 1.3 mycroft sv_write_indirect(sc, SV_DMAA_COUNT1, dma_count >> 8); 735 1.3 mycroft sv_write_indirect(sc, SV_DMAA_COUNT0, dma_count & 0xFF); 736 1.3 mycroft 737 1.3 mycroft mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE); 738 1.3 mycroft sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode | SV_PLAY_ENABLE); 739 1.3 mycroft 740 1.27 kent return 0; 741 1.1 augustss } 742 1.1 augustss 743 1.30 thorpej static int 744 1.27 kent sv_trigger_input(void *addr, void *start, void *end, int blksize, 745 1.27 kent void (*intr)(void *), void *arg, const audio_params_t *param) 746 1.1 augustss { 747 1.27 kent struct sv_softc *sc; 748 1.3 mycroft struct sv_dma *p; 749 1.27 kent uint8_t mode; 750 1.3 mycroft int dma_count; 751 1.1 augustss 752 1.27 kent DPRINTFN(1, ("sv_trigger_input: sc=%p start=%p end=%p blksize=%d " 753 1.27 kent "intr=%p(%p)\n", addr, start, end, blksize, intr, arg)); 754 1.27 kent sc = addr; 755 1.3 mycroft sc->sc_rintr = intr; 756 1.3 mycroft sc->sc_rarg = arg; 757 1.1 augustss 758 1.3 mycroft mode = sv_read_indirect(sc, SV_DMA_DATA_FORMAT); 759 1.3 mycroft mode &= ~(SV_DMAC_FORMAT16 | SV_DMAC_STEREO); 760 1.26 kent if (param->precision == 16) 761 1.3 mycroft mode |= SV_DMAC_FORMAT16; 762 1.3 mycroft if (param->channels == 2) 763 1.3 mycroft mode |= SV_DMAC_STEREO; 764 1.3 mycroft sv_write_indirect(sc, SV_DMA_DATA_FORMAT, mode); 765 1.1 augustss 766 1.4 mycroft for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) 767 1.27 kent continue; 768 1.3 mycroft if (!p) { 769 1.3 mycroft printf("sv_trigger_input: bad addr %p\n", start); 770 1.27 kent return EINVAL; 771 1.1 augustss } 772 1.1 augustss 773 1.3 mycroft dma_count = (((char *)end - (char *)start) >> 1) - 1; 774 1.27 kent DPRINTF(("sv_trigger_input: DMA start loop input addr=%x cc=%d\n", 775 1.5 mycroft (int)DMAADDR(p), dma_count)); 776 1.3 mycroft 777 1.3 mycroft bus_space_write_4(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_ADDR0, 778 1.3 mycroft DMAADDR(p)); 779 1.3 mycroft bus_space_write_4(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_COUNT0, 780 1.3 mycroft dma_count); 781 1.3 mycroft bus_space_write_1(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_MODE, 782 1.3 mycroft DMA37MD_WRITE | DMA37MD_LOOP); 783 1.5 mycroft 784 1.5 mycroft DPRINTF(("sv_trigger_input: current addr=%x\n", 785 1.5 mycroft bus_space_read_4(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_ADDR0))); 786 1.3 mycroft 787 1.3 mycroft dma_count = (blksize >> 1) - 1; 788 1.1 augustss 789 1.3 mycroft sv_write_indirect(sc, SV_DMAC_COUNT1, dma_count >> 8); 790 1.3 mycroft sv_write_indirect(sc, SV_DMAC_COUNT0, dma_count & 0xFF); 791 1.1 augustss 792 1.3 mycroft mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE); 793 1.3 mycroft sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode | SV_RECORD_ENABLE); 794 1.1 augustss 795 1.27 kent return 0; 796 1.1 augustss } 797 1.1 augustss 798 1.30 thorpej static int 799 1.27 kent sv_halt_output(void *addr) 800 1.1 augustss { 801 1.27 kent struct sv_softc *sc; 802 1.27 kent uint8_t mode; 803 1.27 kent 804 1.4 mycroft DPRINTF(("sv: sv_halt_output\n")); 805 1.27 kent sc = addr; 806 1.1 augustss mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE); 807 1.3 mycroft sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode & ~SV_PLAY_ENABLE); 808 1.24 mycroft sc->sc_pintr = 0; 809 1.1 augustss 810 1.27 kent return 0; 811 1.1 augustss } 812 1.1 augustss 813 1.30 thorpej static int 814 1.27 kent sv_halt_input(void *addr) 815 1.1 augustss { 816 1.27 kent struct sv_softc *sc; 817 1.27 kent uint8_t mode; 818 1.27 kent 819 1.4 mycroft DPRINTF(("sv: sv_halt_input\n")); 820 1.27 kent sc = addr; 821 1.1 augustss mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE); 822 1.3 mycroft sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode & ~SV_RECORD_ENABLE); 823 1.24 mycroft sc->sc_rintr = 0; 824 1.1 augustss 825 1.27 kent return 0; 826 1.1 augustss } 827 1.1 augustss 828 1.30 thorpej static int 829 1.35 christos sv_getdev(void *addr, struct audio_device *retp) 830 1.1 augustss { 831 1.27 kent 832 1.1 augustss *retp = sv_device; 833 1.27 kent return 0; 834 1.1 augustss } 835 1.1 augustss 836 1.1 augustss 837 1.1 augustss /* 838 1.1 augustss * Mixer related code is here 839 1.1 augustss * 840 1.1 augustss */ 841 1.1 augustss 842 1.1 augustss #define SV_INPUT_CLASS 0 843 1.1 augustss #define SV_OUTPUT_CLASS 1 844 1.1 augustss #define SV_RECORD_CLASS 2 845 1.1 augustss 846 1.1 augustss #define SV_LAST_CLASS 2 847 1.1 augustss 848 1.27 kent static const char *mixer_classes[] = 849 1.1 augustss { AudioCinputs, AudioCoutputs, AudioCrecord }; 850 1.1 augustss 851 1.1 augustss static const struct { 852 1.27 kent uint8_t l_port; 853 1.27 kent uint8_t r_port; 854 1.27 kent uint8_t mask; 855 1.27 kent uint8_t class; 856 1.1 augustss const char *audio; 857 1.1 augustss } ports[] = { 858 1.1 augustss { SV_LEFT_AUX1_INPUT_CONTROL, SV_RIGHT_AUX1_INPUT_CONTROL, SV_AUX1_MASK, 859 1.1 augustss SV_INPUT_CLASS, "aux1" }, 860 1.27 kent { SV_LEFT_CD_INPUT_CONTROL, SV_RIGHT_CD_INPUT_CONTROL, SV_CD_MASK, 861 1.1 augustss SV_INPUT_CLASS, AudioNcd }, 862 1.1 augustss { SV_LEFT_LINE_IN_INPUT_CONTROL, SV_RIGHT_LINE_IN_INPUT_CONTROL, SV_LINE_IN_MASK, 863 1.1 augustss SV_INPUT_CLASS, AudioNline }, 864 1.1 augustss { SV_MIC_INPUT_CONTROL, 0, SV_MIC_MASK, SV_INPUT_CLASS, AudioNmicrophone }, 865 1.27 kent { SV_LEFT_SYNTH_INPUT_CONTROL, SV_RIGHT_SYNTH_INPUT_CONTROL, 866 1.1 augustss SV_SYNTH_MASK, SV_INPUT_CLASS, AudioNfmsynth }, 867 1.1 augustss { SV_LEFT_AUX2_INPUT_CONTROL, SV_RIGHT_AUX2_INPUT_CONTROL, SV_AUX2_MASK, 868 1.1 augustss SV_INPUT_CLASS, "aux2" }, 869 1.1 augustss { SV_LEFT_PCM_INPUT_CONTROL, SV_RIGHT_PCM_INPUT_CONTROL, SV_PCM_MASK, 870 1.1 augustss SV_INPUT_CLASS, AudioNdac }, 871 1.27 kent { SV_LEFT_MIXER_OUTPUT_CONTROL, SV_RIGHT_MIXER_OUTPUT_CONTROL, 872 1.1 augustss SV_MIXER_OUT_MASK, SV_OUTPUT_CLASS, AudioNmaster } 873 1.1 augustss }; 874 1.1 augustss 875 1.1 augustss 876 1.1 augustss static const struct { 877 1.1 augustss int idx; 878 1.1 augustss const char *name; 879 1.1 augustss } record_sources[] = { 880 1.1 augustss { SV_REC_CD, AudioNcd }, 881 1.1 augustss { SV_REC_DAC, AudioNdac }, 882 1.1 augustss { SV_REC_AUX2, "aux2" }, 883 1.1 augustss { SV_REC_LINE, AudioNline }, 884 1.1 augustss { SV_REC_AUX1, "aux1" }, 885 1.1 augustss { SV_REC_MIC, AudioNmicrophone }, 886 1.1 augustss { SV_REC_MIXER, AudioNmixerout } 887 1.1 augustss }; 888 1.1 augustss 889 1.1 augustss 890 1.1 augustss #define SV_DEVICES_PER_PORT 2 891 1.1 augustss #define SV_FIRST_MIXER (SV_LAST_CLASS + 1) 892 1.1 augustss #define SV_LAST_MIXER (SV_DEVICES_PER_PORT * (ARRAY_SIZE(ports)) + SV_LAST_CLASS) 893 1.1 augustss #define SV_RECORD_SOURCE (SV_LAST_MIXER + 1) 894 1.1 augustss #define SV_MIC_BOOST (SV_LAST_MIXER + 2) 895 1.1 augustss #define SV_RECORD_GAIN (SV_LAST_MIXER + 3) 896 1.1 augustss #define SV_SRS_MODE (SV_LAST_MIXER + 4) 897 1.1 augustss 898 1.30 thorpej static int 899 1.35 christos sv_query_devinfo(void *addr, mixer_devinfo_t *dip) 900 1.1 augustss { 901 1.1 augustss int i; 902 1.1 augustss 903 1.1 augustss /* It's a class */ 904 1.1 augustss if (dip->index <= SV_LAST_CLASS) { 905 1.1 augustss dip->type = AUDIO_MIXER_CLASS; 906 1.1 augustss dip->mixer_class = dip->index; 907 1.1 augustss dip->next = dip->prev = AUDIO_MIXER_LAST; 908 1.27 kent strcpy(dip->label.name, mixer_classes[dip->index]); 909 1.27 kent return 0; 910 1.1 augustss } 911 1.1 augustss 912 1.1 augustss if (dip->index >= SV_FIRST_MIXER && 913 1.1 augustss dip->index <= SV_LAST_MIXER) { 914 1.27 kent int off, mute ,idx; 915 1.27 kent 916 1.27 kent off = dip->index - SV_FIRST_MIXER; 917 1.27 kent mute = (off % SV_DEVICES_PER_PORT); 918 1.27 kent idx = off / SV_DEVICES_PER_PORT; 919 1.1 augustss dip->mixer_class = ports[idx].class; 920 1.1 augustss strcpy(dip->label.name, ports[idx].audio); 921 1.27 kent 922 1.1 augustss if (!mute) { 923 1.1 augustss dip->type = AUDIO_MIXER_VALUE; 924 1.1 augustss dip->prev = AUDIO_MIXER_LAST; 925 1.1 augustss dip->next = dip->index + 1; 926 1.1 augustss 927 1.1 augustss if (ports[idx].r_port != 0) 928 1.1 augustss dip->un.v.num_channels = 2; 929 1.1 augustss else 930 1.1 augustss dip->un.v.num_channels = 1; 931 1.27 kent 932 1.1 augustss strcpy(dip->un.v.units.name, AudioNvolume); 933 1.1 augustss } else { 934 1.1 augustss dip->type = AUDIO_MIXER_ENUM; 935 1.1 augustss dip->prev = dip->index - 1; 936 1.1 augustss dip->next = AUDIO_MIXER_LAST; 937 1.27 kent 938 1.1 augustss strcpy(dip->label.name, AudioNmute); 939 1.1 augustss dip->un.e.num_mem = 2; 940 1.1 augustss strcpy(dip->un.e.member[0].label.name, AudioNoff); 941 1.1 augustss dip->un.e.member[0].ord = 0; 942 1.1 augustss strcpy(dip->un.e.member[1].label.name, AudioNon); 943 1.1 augustss dip->un.e.member[1].ord = 1; 944 1.1 augustss } 945 1.27 kent 946 1.27 kent return 0; 947 1.1 augustss } 948 1.1 augustss 949 1.1 augustss switch (dip->index) { 950 1.1 augustss case SV_RECORD_SOURCE: 951 1.1 augustss dip->mixer_class = SV_RECORD_CLASS; 952 1.1 augustss dip->prev = AUDIO_MIXER_LAST; 953 1.1 augustss dip->next = SV_RECORD_GAIN; 954 1.1 augustss strcpy(dip->label.name, AudioNsource); 955 1.1 augustss dip->type = AUDIO_MIXER_ENUM; 956 1.27 kent 957 1.1 augustss dip->un.e.num_mem = ARRAY_SIZE(record_sources); 958 1.1 augustss for (i = 0; i < ARRAY_SIZE(record_sources); i++) { 959 1.27 kent strcpy(dip->un.e.member[i].label.name, 960 1.1 augustss record_sources[i].name); 961 1.1 augustss dip->un.e.member[i].ord = record_sources[i].idx; 962 1.1 augustss } 963 1.27 kent return 0; 964 1.1 augustss 965 1.1 augustss case SV_RECORD_GAIN: 966 1.1 augustss dip->mixer_class = SV_RECORD_CLASS; 967 1.1 augustss dip->prev = SV_RECORD_SOURCE; 968 1.1 augustss dip->next = AUDIO_MIXER_LAST; 969 1.1 augustss strcpy(dip->label.name, "gain"); 970 1.1 augustss dip->type = AUDIO_MIXER_VALUE; 971 1.1 augustss dip->un.v.num_channels = 1; 972 1.1 augustss strcpy(dip->un.v.units.name, AudioNvolume); 973 1.27 kent return 0; 974 1.27 kent 975 1.1 augustss case SV_MIC_BOOST: 976 1.1 augustss dip->mixer_class = SV_RECORD_CLASS; 977 1.1 augustss dip->prev = AUDIO_MIXER_LAST; 978 1.1 augustss dip->next = AUDIO_MIXER_LAST; 979 1.1 augustss strcpy(dip->label.name, "micboost"); 980 1.1 augustss goto on_off; 981 1.27 kent 982 1.1 augustss case SV_SRS_MODE: 983 1.1 augustss dip->mixer_class = SV_OUTPUT_CLASS; 984 1.1 augustss dip->prev = dip->next = AUDIO_MIXER_LAST; 985 1.1 augustss strcpy(dip->label.name, AudioNspatial); 986 1.27 kent 987 1.1 augustss on_off: 988 1.1 augustss dip->type = AUDIO_MIXER_ENUM; 989 1.1 augustss dip->un.e.num_mem = 2; 990 1.1 augustss strcpy(dip->un.e.member[0].label.name, AudioNoff); 991 1.1 augustss dip->un.e.member[0].ord = 0; 992 1.1 augustss strcpy(dip->un.e.member[1].label.name, AudioNon); 993 1.1 augustss dip->un.e.member[1].ord = 1; 994 1.27 kent return 0; 995 1.1 augustss } 996 1.27 kent 997 1.27 kent return ENXIO; 998 1.1 augustss } 999 1.1 augustss 1000 1.30 thorpej static int 1001 1.27 kent sv_mixer_set_port(void *addr, mixer_ctrl_t *cp) 1002 1.1 augustss { 1003 1.27 kent struct sv_softc *sc; 1004 1.27 kent uint8_t reg; 1005 1.1 augustss int idx; 1006 1.1 augustss 1007 1.27 kent sc = addr; 1008 1.1 augustss if (cp->dev >= SV_FIRST_MIXER && 1009 1.1 augustss cp->dev <= SV_LAST_MIXER) { 1010 1.27 kent int off, mute; 1011 1.27 kent 1012 1.27 kent off = cp->dev - SV_FIRST_MIXER; 1013 1.27 kent mute = (off % SV_DEVICES_PER_PORT); 1014 1.1 augustss idx = off / SV_DEVICES_PER_PORT; 1015 1.27 kent 1016 1.1 augustss if (mute) { 1017 1.27 kent if (cp->type != AUDIO_MIXER_ENUM) 1018 1.27 kent return EINVAL; 1019 1.1 augustss 1020 1.45 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 1021 1.1 augustss reg = sv_read_indirect(sc, ports[idx].l_port); 1022 1.27 kent if (cp->un.ord) 1023 1.1 augustss reg |= SV_MUTE_BIT; 1024 1.1 augustss else 1025 1.1 augustss reg &= ~SV_MUTE_BIT; 1026 1.1 augustss sv_write_indirect(sc, ports[idx].l_port, reg); 1027 1.27 kent 1028 1.1 augustss if (ports[idx].r_port) { 1029 1.1 augustss reg = sv_read_indirect(sc, ports[idx].r_port); 1030 1.27 kent if (cp->un.ord) 1031 1.1 augustss reg |= SV_MUTE_BIT; 1032 1.1 augustss else 1033 1.1 augustss reg &= ~SV_MUTE_BIT; 1034 1.1 augustss sv_write_indirect(sc, ports[idx].r_port, reg); 1035 1.1 augustss } 1036 1.45 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 1037 1.1 augustss } else { 1038 1.1 augustss int lval, rval; 1039 1.27 kent 1040 1.1 augustss if (cp->type != AUDIO_MIXER_VALUE) 1041 1.27 kent return EINVAL; 1042 1.27 kent 1043 1.1 augustss if (cp->un.value.num_channels != 1 && 1044 1.1 augustss cp->un.value.num_channels != 2) 1045 1.1 augustss return (EINVAL); 1046 1.27 kent 1047 1.1 augustss if (ports[idx].r_port == 0) { 1048 1.1 augustss if (cp->un.value.num_channels != 1) 1049 1.1 augustss return (EINVAL); 1050 1.1 augustss lval = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 1051 1.1 augustss rval = 0; /* shut up GCC */ 1052 1.1 augustss } else { 1053 1.1 augustss if (cp->un.value.num_channels != 2) 1054 1.1 augustss return (EINVAL); 1055 1.27 kent 1056 1.1 augustss lval = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 1057 1.1 augustss rval = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 1058 1.27 kent } 1059 1.1 augustss 1060 1.45 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 1061 1.1 augustss reg = sv_read_indirect(sc, ports[idx].l_port); 1062 1.1 augustss reg &= ~(ports[idx].mask); 1063 1.27 kent lval = (AUDIO_MAX_GAIN - lval) * ports[idx].mask / 1064 1.1 augustss AUDIO_MAX_GAIN; 1065 1.1 augustss reg |= lval; 1066 1.1 augustss sv_write_indirect(sc, ports[idx].l_port, reg); 1067 1.1 augustss 1068 1.1 augustss if (ports[idx].r_port != 0) { 1069 1.1 augustss reg = sv_read_indirect(sc, ports[idx].r_port); 1070 1.1 augustss reg &= ~(ports[idx].mask); 1071 1.27 kent 1072 1.1 augustss rval = (AUDIO_MAX_GAIN - rval) * ports[idx].mask / 1073 1.1 augustss AUDIO_MAX_GAIN; 1074 1.1 augustss reg |= rval; 1075 1.1 augustss 1076 1.1 augustss sv_write_indirect(sc, ports[idx].r_port, reg); 1077 1.1 augustss } 1078 1.1 augustss 1079 1.1 augustss sv_read_indirect(sc, ports[idx].l_port); 1080 1.45 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 1081 1.1 augustss } 1082 1.1 augustss 1083 1.27 kent return 0; 1084 1.1 augustss } 1085 1.1 augustss 1086 1.1 augustss 1087 1.1 augustss switch (cp->dev) { 1088 1.1 augustss case SV_RECORD_SOURCE: 1089 1.1 augustss if (cp->type != AUDIO_MIXER_ENUM) 1090 1.27 kent return EINVAL; 1091 1.27 kent 1092 1.1 augustss for (idx = 0; idx < ARRAY_SIZE(record_sources); idx++) { 1093 1.1 augustss if (record_sources[idx].idx == cp->un.ord) 1094 1.1 augustss goto found; 1095 1.1 augustss } 1096 1.27 kent 1097 1.27 kent return EINVAL; 1098 1.1 augustss 1099 1.1 augustss found: 1100 1.45 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 1101 1.1 augustss reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL); 1102 1.1 augustss reg &= ~SV_REC_SOURCE_MASK; 1103 1.1 augustss reg |= (((cp->un.ord) << SV_REC_SOURCE_SHIFT) & SV_REC_SOURCE_MASK); 1104 1.1 augustss sv_write_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL, reg); 1105 1.27 kent 1106 1.1 augustss reg = sv_read_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL); 1107 1.1 augustss reg &= ~SV_REC_SOURCE_MASK; 1108 1.1 augustss reg |= (((cp->un.ord) << SV_REC_SOURCE_SHIFT) & SV_REC_SOURCE_MASK); 1109 1.1 augustss sv_write_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL, reg); 1110 1.45 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 1111 1.27 kent return 0; 1112 1.27 kent 1113 1.1 augustss case SV_RECORD_GAIN: 1114 1.1 augustss { 1115 1.1 augustss int val; 1116 1.27 kent 1117 1.1 augustss if (cp->type != AUDIO_MIXER_VALUE) 1118 1.27 kent return EINVAL; 1119 1.27 kent 1120 1.1 augustss if (cp->un.value.num_channels != 1) 1121 1.27 kent return EINVAL; 1122 1.27 kent 1123 1.27 kent val = (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] 1124 1.27 kent * SV_REC_GAIN_MASK) / AUDIO_MAX_GAIN; 1125 1.27 kent 1126 1.45 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 1127 1.1 augustss reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL); 1128 1.1 augustss reg &= ~SV_REC_GAIN_MASK; 1129 1.1 augustss reg |= val; 1130 1.1 augustss sv_write_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL, reg); 1131 1.27 kent 1132 1.1 augustss reg = sv_read_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL); 1133 1.1 augustss reg &= ~SV_REC_GAIN_MASK; 1134 1.1 augustss reg |= val; 1135 1.1 augustss sv_write_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL, reg); 1136 1.45 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 1137 1.1 augustss } 1138 1.1 augustss return (0); 1139 1.1 augustss 1140 1.1 augustss case SV_MIC_BOOST: 1141 1.1 augustss if (cp->type != AUDIO_MIXER_ENUM) 1142 1.27 kent return EINVAL; 1143 1.27 kent 1144 1.45 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 1145 1.1 augustss reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL); 1146 1.1 augustss if (cp->un.ord) { 1147 1.1 augustss reg |= SV_MIC_BOOST_BIT; 1148 1.1 augustss } else { 1149 1.1 augustss reg &= ~SV_MIC_BOOST_BIT; 1150 1.1 augustss } 1151 1.27 kent 1152 1.1 augustss sv_write_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL, reg); 1153 1.45 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 1154 1.27 kent return 0; 1155 1.27 kent 1156 1.1 augustss case SV_SRS_MODE: 1157 1.1 augustss if (cp->type != AUDIO_MIXER_ENUM) 1158 1.27 kent return EINVAL; 1159 1.27 kent 1160 1.45 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 1161 1.1 augustss reg = sv_read_indirect(sc, SV_SRS_SPACE_CONTROL); 1162 1.1 augustss if (cp->un.ord) { 1163 1.1 augustss reg &= ~SV_SRS_SPACE_ONOFF; 1164 1.1 augustss } else { 1165 1.1 augustss reg |= SV_SRS_SPACE_ONOFF; 1166 1.1 augustss } 1167 1.27 kent 1168 1.1 augustss sv_write_indirect(sc, SV_SRS_SPACE_CONTROL, reg); 1169 1.45 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 1170 1.27 kent return 0; 1171 1.1 augustss } 1172 1.27 kent 1173 1.27 kent return EINVAL; 1174 1.1 augustss } 1175 1.1 augustss 1176 1.30 thorpej static int 1177 1.27 kent sv_mixer_get_port(void *addr, mixer_ctrl_t *cp) 1178 1.1 augustss { 1179 1.27 kent struct sv_softc *sc; 1180 1.45 jmcneill int val, error; 1181 1.27 kent uint8_t reg; 1182 1.27 kent 1183 1.27 kent sc = addr; 1184 1.45 jmcneill error = 0; 1185 1.45 jmcneill 1186 1.45 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 1187 1.45 jmcneill 1188 1.1 augustss if (cp->dev >= SV_FIRST_MIXER && 1189 1.1 augustss cp->dev <= SV_LAST_MIXER) { 1190 1.1 augustss int off = cp->dev - SV_FIRST_MIXER; 1191 1.1 augustss int mute = (off % 2); 1192 1.1 augustss int idx = off / 2; 1193 1.27 kent 1194 1.27 kent off = cp->dev - SV_FIRST_MIXER; 1195 1.27 kent mute = (off % 2); 1196 1.27 kent idx = off / 2; 1197 1.1 augustss if (mute) { 1198 1.27 kent if (cp->type != AUDIO_MIXER_ENUM) 1199 1.45 jmcneill error = EINVAL; 1200 1.45 jmcneill else { 1201 1.45 jmcneill reg = sv_read_indirect(sc, ports[idx].l_port); 1202 1.45 jmcneill cp->un.ord = ((reg & SV_MUTE_BIT) ? 1 : 0); 1203 1.45 jmcneill } 1204 1.1 augustss } else { 1205 1.45 jmcneill if (cp->type != AUDIO_MIXER_VALUE || 1206 1.45 jmcneill (cp->un.value.num_channels != 1 && 1207 1.45 jmcneill cp->un.value.num_channels != 2) || 1208 1.45 jmcneill ((ports[idx].r_port == 0 && 1209 1.1 augustss cp->un.value.num_channels != 1) || 1210 1.1 augustss (ports[idx].r_port != 0 && 1211 1.45 jmcneill cp->un.value.num_channels != 2))) 1212 1.45 jmcneill error = EINVAL; 1213 1.45 jmcneill else { 1214 1.45 jmcneill reg = sv_read_indirect(sc, ports[idx].l_port); 1215 1.45 jmcneill reg &= ports[idx].mask; 1216 1.27 kent 1217 1.45 jmcneill val = AUDIO_MAX_GAIN - 1218 1.45 jmcneill ((reg * AUDIO_MAX_GAIN) / ports[idx].mask); 1219 1.27 kent 1220 1.45 jmcneill if (ports[idx].r_port != 0) { 1221 1.45 jmcneill cp->un.value.level 1222 1.45 jmcneill [AUDIO_MIXER_LEVEL_LEFT] = val; 1223 1.45 jmcneill 1224 1.45 jmcneill reg = sv_read_indirect(sc, 1225 1.45 jmcneill ports[idx].r_port); 1226 1.45 jmcneill reg &= ports[idx].mask; 1227 1.45 jmcneill 1228 1.45 jmcneill val = AUDIO_MAX_GAIN - 1229 1.45 jmcneill ((reg * AUDIO_MAX_GAIN) 1230 1.45 jmcneill / ports[idx].mask); 1231 1.45 jmcneill cp->un.value.level 1232 1.45 jmcneill [AUDIO_MIXER_LEVEL_RIGHT] = val; 1233 1.45 jmcneill } else 1234 1.45 jmcneill cp->un.value.level 1235 1.45 jmcneill [AUDIO_MIXER_LEVEL_MONO] = val; 1236 1.45 jmcneill } 1237 1.1 augustss } 1238 1.1 augustss 1239 1.59 isaki mutex_spin_exit(&sc->sc_intr_lock); 1240 1.45 jmcneill return error; 1241 1.27 kent } 1242 1.1 augustss 1243 1.1 augustss switch (cp->dev) { 1244 1.1 augustss case SV_RECORD_SOURCE: 1245 1.45 jmcneill if (cp->type != AUDIO_MIXER_ENUM) { 1246 1.45 jmcneill error = EINVAL; 1247 1.45 jmcneill break; 1248 1.45 jmcneill } 1249 1.27 kent 1250 1.1 augustss reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL); 1251 1.1 augustss cp->un.ord = ((reg & SV_REC_SOURCE_MASK) >> SV_REC_SOURCE_SHIFT); 1252 1.27 kent 1253 1.45 jmcneill break; 1254 1.27 kent 1255 1.1 augustss case SV_RECORD_GAIN: 1256 1.45 jmcneill if (cp->type != AUDIO_MIXER_VALUE) { 1257 1.45 jmcneill error = EINVAL; 1258 1.45 jmcneill break; 1259 1.45 jmcneill } 1260 1.45 jmcneill if (cp->un.value.num_channels != 1) { 1261 1.45 jmcneill error = EINVAL; 1262 1.45 jmcneill break; 1263 1.45 jmcneill } 1264 1.27 kent 1265 1.1 augustss reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL) & SV_REC_GAIN_MASK; 1266 1.27 kent cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 1267 1.1 augustss (((unsigned int)reg) * AUDIO_MAX_GAIN) / SV_REC_GAIN_MASK; 1268 1.27 kent 1269 1.45 jmcneill break; 1270 1.27 kent 1271 1.1 augustss case SV_MIC_BOOST: 1272 1.45 jmcneill if (cp->type != AUDIO_MIXER_ENUM) { 1273 1.45 jmcneill error = EINVAL; 1274 1.45 jmcneill break; 1275 1.45 jmcneill } 1276 1.1 augustss reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL); 1277 1.1 augustss cp->un.ord = ((reg & SV_MIC_BOOST_BIT) ? 1 : 0); 1278 1.45 jmcneill break; 1279 1.27 kent 1280 1.1 augustss case SV_SRS_MODE: 1281 1.45 jmcneill if (cp->type != AUDIO_MIXER_ENUM) { 1282 1.45 jmcneill error = EINVAL; 1283 1.45 jmcneill break; 1284 1.45 jmcneill } 1285 1.1 augustss reg = sv_read_indirect(sc, SV_SRS_SPACE_CONTROL); 1286 1.1 augustss cp->un.ord = ((reg & SV_SRS_SPACE_ONOFF) ? 0 : 1); 1287 1.45 jmcneill break; 1288 1.45 jmcneill default: 1289 1.45 jmcneill error = EINVAL; 1290 1.45 jmcneill break; 1291 1.1 augustss } 1292 1.27 kent 1293 1.45 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 1294 1.45 jmcneill return error; 1295 1.1 augustss } 1296 1.1 augustss 1297 1.1 augustss static void 1298 1.27 kent sv_init_mixer(struct sv_softc *sc) 1299 1.1 augustss { 1300 1.1 augustss mixer_ctrl_t cp; 1301 1.1 augustss int i; 1302 1.27 kent 1303 1.1 augustss cp.type = AUDIO_MIXER_ENUM; 1304 1.1 augustss cp.dev = SV_SRS_MODE; 1305 1.1 augustss cp.un.ord = 0; 1306 1.1 augustss 1307 1.1 augustss sv_mixer_set_port(sc, &cp); 1308 1.1 augustss 1309 1.1 augustss for (i = 0; i < ARRAY_SIZE(ports); i++) { 1310 1.43 drochner if (!strcmp(ports[i].audio, AudioNdac)) { 1311 1.1 augustss cp.type = AUDIO_MIXER_ENUM; 1312 1.1 augustss cp.dev = SV_FIRST_MIXER + i * SV_DEVICES_PER_PORT + 1; 1313 1.1 augustss cp.un.ord = 0; 1314 1.1 augustss sv_mixer_set_port(sc, &cp); 1315 1.1 augustss break; 1316 1.1 augustss } 1317 1.1 augustss } 1318 1.1 augustss } 1319 1.1 augustss 1320 1.30 thorpej static void * 1321 1.45 jmcneill sv_malloc(void *addr, int direction, size_t size) 1322 1.1 augustss { 1323 1.27 kent struct sv_softc *sc; 1324 1.4 mycroft struct sv_dma *p; 1325 1.4 mycroft int error; 1326 1.1 augustss 1327 1.27 kent sc = addr; 1328 1.45 jmcneill p = kmem_alloc(sizeof(*p), KM_SLEEP); 1329 1.13 kleink error = sv_allocmem(sc, size, 16, direction, p); 1330 1.4 mycroft if (error) { 1331 1.45 jmcneill kmem_free(p, sizeof(*p)); 1332 1.27 kent return 0; 1333 1.4 mycroft } 1334 1.4 mycroft p->next = sc->sc_dmas; 1335 1.4 mycroft sc->sc_dmas = p; 1336 1.27 kent return KERNADDR(p); 1337 1.1 augustss } 1338 1.1 augustss 1339 1.30 thorpej static void 1340 1.45 jmcneill sv_free(void *addr, void *ptr, size_t size) 1341 1.1 augustss { 1342 1.27 kent struct sv_softc *sc; 1343 1.9 kleink struct sv_dma **pp, *p; 1344 1.1 augustss 1345 1.27 kent sc = addr; 1346 1.9 kleink for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) { 1347 1.9 kleink if (KERNADDR(p) == ptr) { 1348 1.9 kleink sv_freemem(sc, p); 1349 1.9 kleink *pp = p->next; 1350 1.45 jmcneill kmem_free(p, sizeof(*p)); 1351 1.4 mycroft return; 1352 1.4 mycroft } 1353 1.4 mycroft } 1354 1.1 augustss } 1355 1.1 augustss 1356 1.30 thorpej static int 1357 1.35 christos sv_get_props(void *addr) 1358 1.1 augustss { 1359 1.56 isaki 1360 1.56 isaki return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE | 1361 1.56 isaki AUDIO_PROP_FULLDUPLEX; 1362 1.1 augustss } 1363 1.45 jmcneill 1364 1.45 jmcneill static void 1365 1.45 jmcneill sv_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread) 1366 1.45 jmcneill { 1367 1.45 jmcneill struct sv_softc *sc; 1368 1.45 jmcneill 1369 1.45 jmcneill sc = addr; 1370 1.45 jmcneill *intr = &sc->sc_intr_lock; 1371 1.45 jmcneill *thread = &sc->sc_lock; 1372 1.45 jmcneill } 1373