1 /* $NetBSD: sbdsp.c,v 1.122 2006/05/14 21:42:27 elad Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Copyright (c) 1991-1993 Regents of the University of California. 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the Computer Systems 54 * Engineering Group at Lawrence Berkeley Laboratory. 55 * 4. Neither the name of the University nor of the Laboratory may be used 56 * to endorse or promote products derived from this software without 57 * specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 */ 72 73 /* 74 * SoundBlaster Pro code provided by John Kohl, based on lots of 75 * information he gleaned from Steve Haehnichen <steve@vigra.com>'s 76 * SBlast driver for 386BSD and DOS driver code from Daniel Sachs 77 * <sachs@meibm15.cen.uiuc.edu>. 78 * Lots of rewrites by Lennart Augustsson <augustss@cs.chalmers.se> 79 * with information from SB "Hardware Programming Guide" and the 80 * Linux drivers. 81 */ 82 83 #include <sys/cdefs.h> 84 __KERNEL_RCSID(0, "$NetBSD: sbdsp.c,v 1.122 2006/05/14 21:42:27 elad Exp $"); 85 86 #include "midi.h" 87 #include "mpu.h" 88 89 #include <sys/param.h> 90 #include <sys/systm.h> 91 #include <sys/kernel.h> 92 #include <sys/errno.h> 93 #include <sys/ioctl.h> 94 #include <sys/syslog.h> 95 #include <sys/device.h> 96 #include <sys/proc.h> 97 #include <sys/buf.h> 98 99 #include <machine/cpu.h> 100 #include <machine/intr.h> 101 #include <machine/bus.h> 102 103 #include <sys/audioio.h> 104 #include <dev/audio_if.h> 105 #include <dev/midi_if.h> 106 #include <dev/mulaw.h> 107 #include <dev/auconv.h> 108 109 #include <dev/isa/isavar.h> 110 #include <dev/isa/isadmavar.h> 111 112 #include <dev/isa/sbreg.h> 113 #include <dev/isa/sbdspvar.h> 114 115 116 #ifdef AUDIO_DEBUG 117 #define DPRINTF(x) if (sbdspdebug) printf x 118 #define DPRINTFN(n,x) if (sbdspdebug >= (n)) printf x 119 int sbdspdebug = 0; 120 #else 121 #define DPRINTF(x) 122 #define DPRINTFN(n,x) 123 #endif 124 125 #ifndef SBDSP_NPOLL 126 #define SBDSP_NPOLL 3000 127 #endif 128 129 struct { 130 int wdsp; 131 int rdsp; 132 int wmidi; 133 } sberr; 134 135 /* 136 * Time constant routines follow. See SBK, section 12. 137 * Although they don't come out and say it (in the docs), 138 * the card clearly uses a 1MHz countdown timer, as the 139 * low-speed formula (p. 12-4) is: 140 * tc = 256 - 10^6 / sr 141 * In high-speed mode, the constant is the upper byte of a 16-bit counter, 142 * and a 256MHz clock is used: 143 * tc = 65536 - 256 * 10^ 6 / sr 144 * Since we can only use the upper byte of the HS TC, the two formulae 145 * are equivalent. (Why didn't they say so?) E.g., 146 * (65536 - 256 * 10 ^ 6 / x) >> 8 = 256 - 10^6 / x 147 * 148 * The crossover point (from low- to high-speed modes) is different 149 * for the SBPRO and SB20. The table on p. 12-5 gives the following data: 150 * 151 * SBPRO SB20 152 * ----- -------- 153 * input ls min 4 kHz 4 kHz 154 * input ls max 23 kHz 13 kHz 155 * input hs max 44.1 kHz 15 kHz 156 * output ls min 4 kHz 4 kHz 157 * output ls max 23 kHz 23 kHz 158 * output hs max 44.1 kHz 44.1 kHz 159 */ 160 /* XXX Should we round the tc? 161 #define SB_RATE_TO_TC(x) (((65536 - 256 * 1000000 / (x)) + 128) >> 8) 162 */ 163 #define SB_RATE_TO_TC(x) (256 - 1000000 / (x)) 164 #define SB_TC_TO_RATE(tc) (1000000 / (256 - (tc))) 165 166 struct sbmode { 167 short model; 168 u_char channels; 169 u_char precision; 170 u_short lowrate, highrate; 171 u_char cmd; 172 u_char halt, cont; 173 u_char cmdchan; 174 }; 175 static struct sbmode sbpmodes[] = { 176 { SB_1, 1, 8, 4000,22727,SB_DSP_WDMA ,SB_DSP_HALT ,SB_DSP_CONT }, 177 { SB_20, 1, 8, 4000,22727,SB_DSP_WDMA_LOOP,SB_DSP_HALT ,SB_DSP_CONT }, 178 { SB_2x, 1, 8,22727,45454,SB_DSP_HS_OUTPUT,SB_DSP_HALT ,SB_DSP_CONT }, 179 { SB_2x, 1, 8, 4000,22727,SB_DSP_WDMA_LOOP,SB_DSP_HALT ,SB_DSP_CONT }, 180 { SB_PRO, 1, 8,22727,45454,SB_DSP_HS_OUTPUT,SB_DSP_HALT ,SB_DSP_CONT }, 181 { SB_PRO, 1, 8, 4000,22727,SB_DSP_WDMA_LOOP,SB_DSP_HALT ,SB_DSP_CONT }, 182 { SB_PRO, 2, 8,11025,22727,SB_DSP_HS_OUTPUT,SB_DSP_HALT ,SB_DSP_CONT }, 183 /* Yes, we write the record mode to set 16-bit playback mode. weird, huh? */ 184 { SB_JAZZ,1, 8,22727,45454,SB_DSP_HS_OUTPUT,SB_DSP_HALT ,SB_DSP_CONT ,SB_DSP_RECORD_MONO }, 185 { SB_JAZZ,1, 8, 4000,22727,SB_DSP_WDMA_LOOP,SB_DSP_HALT ,SB_DSP_CONT ,SB_DSP_RECORD_MONO }, 186 { SB_JAZZ,2, 8,11025,22727,SB_DSP_HS_OUTPUT,SB_DSP_HALT ,SB_DSP_CONT ,SB_DSP_RECORD_STEREO }, 187 { SB_JAZZ,1,16,22727,45454,SB_DSP_HS_OUTPUT,SB_DSP_HALT ,SB_DSP_CONT ,JAZZ16_RECORD_MONO }, 188 { SB_JAZZ,1,16, 4000,22727,SB_DSP_WDMA_LOOP,SB_DSP_HALT ,SB_DSP_CONT ,JAZZ16_RECORD_MONO }, 189 { SB_JAZZ,2,16,11025,22727,SB_DSP_HS_OUTPUT,SB_DSP_HALT ,SB_DSP_CONT ,JAZZ16_RECORD_STEREO }, 190 { SB_16, 1, 8, 5000,49000,SB_DSP16_WDMA_8 ,SB_DSP_HALT ,SB_DSP_CONT }, 191 { SB_16, 2, 8, 5000,49000,SB_DSP16_WDMA_8 ,SB_DSP_HALT ,SB_DSP_CONT }, 192 #define PLAY16 15 /* must be the index of the next entry in the table */ 193 { SB_16, 1,16, 5000,49000,SB_DSP16_WDMA_16,SB_DSP16_HALT,SB_DSP16_CONT}, 194 { SB_16, 2,16, 5000,49000,SB_DSP16_WDMA_16,SB_DSP16_HALT,SB_DSP16_CONT}, 195 { -1 } 196 }; 197 static struct sbmode sbrmodes[] = { 198 { SB_1, 1, 8, 4000,12987,SB_DSP_RDMA ,SB_DSP_HALT ,SB_DSP_CONT }, 199 { SB_20, 1, 8, 4000,12987,SB_DSP_RDMA_LOOP,SB_DSP_HALT ,SB_DSP_CONT }, 200 { SB_2x, 1, 8,12987,14925,SB_DSP_HS_INPUT ,SB_DSP_HALT ,SB_DSP_CONT }, 201 { SB_2x, 1, 8, 4000,12987,SB_DSP_RDMA_LOOP,SB_DSP_HALT ,SB_DSP_CONT }, 202 { SB_PRO, 1, 8,22727,45454,SB_DSP_HS_INPUT ,SB_DSP_HALT ,SB_DSP_CONT ,SB_DSP_RECORD_MONO }, 203 { SB_PRO, 1, 8, 4000,22727,SB_DSP_RDMA_LOOP,SB_DSP_HALT ,SB_DSP_CONT ,SB_DSP_RECORD_MONO }, 204 { SB_PRO, 2, 8,11025,22727,SB_DSP_HS_INPUT ,SB_DSP_HALT ,SB_DSP_CONT ,SB_DSP_RECORD_STEREO }, 205 { SB_JAZZ,1, 8,22727,45454,SB_DSP_HS_INPUT ,SB_DSP_HALT ,SB_DSP_CONT ,SB_DSP_RECORD_MONO }, 206 { SB_JAZZ,1, 8, 4000,22727,SB_DSP_RDMA_LOOP,SB_DSP_HALT ,SB_DSP_CONT ,SB_DSP_RECORD_MONO }, 207 { SB_JAZZ,2, 8,11025,22727,SB_DSP_HS_INPUT ,SB_DSP_HALT ,SB_DSP_CONT ,SB_DSP_RECORD_STEREO }, 208 { SB_JAZZ,1,16,22727,45454,SB_DSP_HS_INPUT ,SB_DSP_HALT ,SB_DSP_CONT ,JAZZ16_RECORD_MONO }, 209 { SB_JAZZ,1,16, 4000,22727,SB_DSP_RDMA_LOOP,SB_DSP_HALT ,SB_DSP_CONT ,JAZZ16_RECORD_MONO }, 210 { SB_JAZZ,2,16,11025,22727,SB_DSP_HS_INPUT ,SB_DSP_HALT ,SB_DSP_CONT ,JAZZ16_RECORD_STEREO }, 211 { SB_16, 1, 8, 5000,49000,SB_DSP16_RDMA_8 ,SB_DSP_HALT ,SB_DSP_CONT }, 212 { SB_16, 2, 8, 5000,49000,SB_DSP16_RDMA_8 ,SB_DSP_HALT ,SB_DSP_CONT }, 213 { SB_16, 1,16, 5000,49000,SB_DSP16_RDMA_16,SB_DSP16_HALT,SB_DSP16_CONT}, 214 { SB_16, 2,16, 5000,49000,SB_DSP16_RDMA_16,SB_DSP16_HALT,SB_DSP16_CONT}, 215 { -1 } 216 }; 217 218 void sbversion(struct sbdsp_softc *); 219 void sbdsp_jazz16_probe(struct sbdsp_softc *); 220 void sbdsp_set_mixer_gain(struct sbdsp_softc *, int); 221 void sbdsp_pause(struct sbdsp_softc *); 222 int sbdsp_set_timeconst(struct sbdsp_softc *, int); 223 int sbdsp16_set_rate(struct sbdsp_softc *, int, int); 224 int sbdsp_set_in_ports(struct sbdsp_softc *, int); 225 void sbdsp_set_ifilter(void *, int); 226 int sbdsp_get_ifilter(void *); 227 228 int sbdsp_block_output(void *); 229 int sbdsp_block_input(void *); 230 static int sbdsp_adjust(int, int); 231 232 int sbdsp_midi_intr(void *); 233 234 static void sbdsp_powerhook(int, void*); 235 236 #ifdef AUDIO_DEBUG 237 void sb_printsc(struct sbdsp_softc *); 238 239 void 240 sb_printsc(struct sbdsp_softc *sc) 241 { 242 int i; 243 244 printf("open %d DMA chan %d/%d %d/%d iobase 0x%x irq %d\n", 245 (int)sc->sc_open, sc->sc_i.run, sc->sc_o.run, 246 sc->sc_drq8, sc->sc_drq16, 247 sc->sc_iobase, sc->sc_irq); 248 printf("irate %d itc %x orate %d otc %x\n", 249 sc->sc_i.rate, sc->sc_i.tc, 250 sc->sc_o.rate, sc->sc_o.tc); 251 printf("spkron %u nintr %lu\n", 252 sc->spkr_state, sc->sc_interrupts); 253 printf("intr8 %p intr16 %p\n", 254 sc->sc_intr8, sc->sc_intr16); 255 printf("gain:"); 256 for (i = 0; i < SB_NDEVS; i++) 257 printf(" %u,%u", sc->gain[i][SB_LEFT], sc->gain[i][SB_RIGHT]); 258 printf("\n"); 259 } 260 #endif /* AUDIO_DEBUG */ 261 262 /* 263 * Probe / attach routines. 264 */ 265 266 /* 267 * Probe for the soundblaster hardware. 268 */ 269 int 270 sbdsp_probe(struct sbdsp_softc *sc) 271 { 272 273 if (sbdsp_reset(sc) < 0) { 274 DPRINTF(("sbdsp: couldn't reset card\n")); 275 return 0; 276 } 277 /* if flags set, go and probe the jazz16 stuff */ 278 if (device_cfdata(&sc->sc_dev)->cf_flags & 1) 279 sbdsp_jazz16_probe(sc); 280 else 281 sbversion(sc); 282 if (sc->sc_model == SB_UNK) { 283 /* Unknown SB model found. */ 284 DPRINTF(("sbdsp: unknown SB model found\n")); 285 return 0; 286 } 287 return 1; 288 } 289 290 /* 291 * Try add-on stuff for Jazz16. 292 */ 293 void 294 sbdsp_jazz16_probe(struct sbdsp_softc *sc) 295 { 296 static u_char jazz16_irq_conf[16] = { 297 -1, -1, 0x02, 0x03, 298 -1, 0x01, -1, 0x04, 299 -1, 0x02, 0x05, -1, 300 -1, -1, -1, 0x06}; 301 static u_char jazz16_drq_conf[8] = { 302 -1, 0x01, -1, 0x02, 303 -1, 0x03, -1, 0x04}; 304 305 bus_space_tag_t iot; 306 bus_space_handle_t ioh; 307 308 iot = sc->sc_iot; 309 sbversion(sc); 310 311 DPRINTF(("jazz16 probe\n")); 312 313 if (bus_space_map(iot, JAZZ16_CONFIG_PORT, 1, 0, &ioh)) { 314 DPRINTF(("bus map failed\n")); 315 return; 316 } 317 318 if (jazz16_drq_conf[sc->sc_drq8] == (u_char)-1 || 319 jazz16_irq_conf[sc->sc_irq] == (u_char)-1) { 320 DPRINTF(("drq/irq check failed\n")); 321 goto done; /* give up, we can't do it. */ 322 } 323 324 bus_space_write_1(iot, ioh, 0, JAZZ16_WAKEUP); 325 delay(10000); /* delay 10 ms */ 326 bus_space_write_1(iot, ioh, 0, JAZZ16_SETBASE); 327 bus_space_write_1(iot, ioh, 0, sc->sc_iobase & 0x70); 328 329 if (sbdsp_reset(sc) < 0) { 330 DPRINTF(("sbdsp_reset check failed\n")); 331 goto done; /* XXX? what else could we do? */ 332 } 333 334 if (sbdsp_wdsp(sc, JAZZ16_READ_VER)) { 335 DPRINTF(("read16 setup failed\n")); 336 goto done; 337 } 338 339 if (sbdsp_rdsp(sc) != JAZZ16_VER_JAZZ) { 340 DPRINTF(("read16 failed\n")); 341 goto done; 342 } 343 344 /* XXX set both 8 & 16-bit drq to same channel, it works fine. */ 345 sc->sc_drq16 = sc->sc_drq8; 346 if (sbdsp_wdsp(sc, JAZZ16_SET_DMAINTR) || 347 (sc->sc_drq16 >= 0 && 348 sbdsp_wdsp(sc, (jazz16_drq_conf[sc->sc_drq16] << 4) | 349 jazz16_drq_conf[sc->sc_drq8])) || 350 sbdsp_wdsp(sc, jazz16_irq_conf[sc->sc_irq])) { 351 DPRINTF(("sbdsp: can't write jazz16 probe stuff\n")); 352 } else { 353 DPRINTF(("jazz16 detected!\n")); 354 sc->sc_model = SB_JAZZ; 355 sc->sc_mixer_model = SBM_CT1345; /* XXX really? */ 356 } 357 358 done: 359 bus_space_unmap(iot, ioh, 1); 360 } 361 362 /* 363 * Attach hardware to driver, attach hardware driver to audio 364 * pseudo-device driver . 365 */ 366 void 367 sbdsp_attach(struct sbdsp_softc *sc) 368 { 369 int i, error; 370 u_int v; 371 372 sbdsp_set_in_ports(sc, 1 << SB_MIC_VOL); 373 374 if (sc->sc_mixer_model != SBM_NONE) { 375 /* Reset the mixer.*/ 376 sbdsp_mix_write(sc, SBP_MIX_RESET, SBP_MIX_RESET); 377 /* And set our own default values */ 378 for (i = 0; i < SB_NDEVS; i++) { 379 switch(i) { 380 case SB_MIC_VOL: 381 case SB_LINE_IN_VOL: 382 v = 0; 383 break; 384 case SB_BASS: 385 case SB_TREBLE: 386 v = SB_ADJUST_GAIN(sc, AUDIO_MAX_GAIN / 2); 387 break; 388 case SB_CD_IN_MUTE: 389 case SB_MIC_IN_MUTE: 390 case SB_LINE_IN_MUTE: 391 case SB_MIDI_IN_MUTE: 392 case SB_CD_SWAP: 393 case SB_MIC_SWAP: 394 case SB_LINE_SWAP: 395 case SB_MIDI_SWAP: 396 case SB_CD_OUT_MUTE: 397 case SB_MIC_OUT_MUTE: 398 case SB_LINE_OUT_MUTE: 399 v = 0; 400 break; 401 default: 402 v = SB_ADJUST_GAIN(sc, AUDIO_MAX_GAIN / 2); 403 break; 404 } 405 sc->gain[i][SB_LEFT] = sc->gain[i][SB_RIGHT] = v; 406 sbdsp_set_mixer_gain(sc, i); 407 } 408 sc->in_filter = 0; /* no filters turned on, please */ 409 } 410 411 printf(": dsp v%d.%02d%s\n", 412 SBVER_MAJOR(sc->sc_version), SBVER_MINOR(sc->sc_version), 413 sc->sc_model == SB_JAZZ ? ": <Jazz16>" : ""); 414 415 sc->sc_fullduplex = ISSB16CLASS(sc) && 416 sc->sc_drq8 != -1 && sc->sc_drq16 != -1 && 417 sc->sc_drq8 != sc->sc_drq16; 418 419 if (sc->sc_drq8 != -1) { 420 sc->sc_drq8_maxsize = isa_dmamaxsize(sc->sc_ic, 421 sc->sc_drq8); 422 error = isa_dmamap_create(sc->sc_ic, sc->sc_drq8, 423 sc->sc_drq8_maxsize, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW); 424 if (error) { 425 printf("%s: can't create map for drq %d\n", 426 sc->sc_dev.dv_xname, sc->sc_drq8); 427 return; 428 } 429 } 430 431 if (sc->sc_drq16 != -1 && sc->sc_drq16 != sc->sc_drq8) { 432 sc->sc_drq16_maxsize = isa_dmamaxsize(sc->sc_ic, 433 sc->sc_drq16); 434 error = isa_dmamap_create(sc->sc_ic, sc->sc_drq16, 435 sc->sc_drq16_maxsize, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW); 436 if (error) { 437 printf("%s: can't create map for drq %d\n", 438 sc->sc_dev.dv_xname, sc->sc_drq16); 439 isa_dmamap_destroy(sc->sc_ic, sc->sc_drq8); 440 return; 441 } 442 } 443 444 powerhook_establish (sbdsp_powerhook, sc); 445 } 446 447 static void 448 sbdsp_powerhook(int why, void *arg) 449 { 450 struct sbdsp_softc *sc; 451 int i; 452 453 sc = arg; 454 if (!sc || why != PWR_RESUME) 455 return; 456 457 /* Reset the mixer. */ 458 sbdsp_mix_write(sc, SBP_MIX_RESET, SBP_MIX_RESET); 459 for (i = 0; i < SB_NDEVS; i++) 460 sbdsp_set_mixer_gain (sc, i); 461 } 462 463 void 464 sbdsp_mix_write(struct sbdsp_softc *sc, int mixerport, int val) 465 { 466 bus_space_tag_t iot; 467 bus_space_handle_t ioh; 468 int s; 469 470 iot = sc->sc_iot; 471 ioh = sc->sc_ioh; 472 s = splaudio(); 473 bus_space_write_1(iot, ioh, SBP_MIXER_ADDR, mixerport); 474 delay(20); 475 bus_space_write_1(iot, ioh, SBP_MIXER_DATA, val); 476 delay(30); 477 splx(s); 478 } 479 480 int 481 sbdsp_mix_read(struct sbdsp_softc *sc, int mixerport) 482 { 483 bus_space_tag_t iot; 484 bus_space_handle_t ioh; 485 int val; 486 int s; 487 488 iot = sc->sc_iot; 489 ioh = sc->sc_ioh; 490 s = splaudio(); 491 bus_space_write_1(iot, ioh, SBP_MIXER_ADDR, mixerport); 492 delay(20); 493 val = bus_space_read_1(iot, ioh, SBP_MIXER_DATA); 494 delay(30); 495 splx(s); 496 return val; 497 } 498 499 /* 500 * Various routines to interface to higher level audio driver 501 */ 502 503 int 504 sbdsp_query_encoding(void *addr, struct audio_encoding *fp) 505 { 506 struct sbdsp_softc *sc; 507 int emul; 508 509 sc = addr; 510 emul = ISSB16CLASS(sc) ? 0 : AUDIO_ENCODINGFLAG_EMULATED; 511 512 switch (fp->index) { 513 case 0: 514 strcpy(fp->name, AudioEulinear); 515 fp->encoding = AUDIO_ENCODING_ULINEAR; 516 fp->precision = 8; 517 fp->flags = 0; 518 return 0; 519 case 1: 520 strcpy(fp->name, AudioEmulaw); 521 fp->encoding = AUDIO_ENCODING_ULAW; 522 fp->precision = 8; 523 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 524 return 0; 525 case 2: 526 strcpy(fp->name, AudioEalaw); 527 fp->encoding = AUDIO_ENCODING_ALAW; 528 fp->precision = 8; 529 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 530 return 0; 531 case 3: 532 strcpy(fp->name, AudioEslinear); 533 fp->encoding = AUDIO_ENCODING_SLINEAR; 534 fp->precision = 8; 535 fp->flags = emul; 536 return 0; 537 } 538 if (!ISSB16CLASS(sc) && sc->sc_model != SB_JAZZ) 539 return EINVAL; 540 541 switch(fp->index) { 542 case 4: 543 strcpy(fp->name, AudioEslinear_le); 544 fp->encoding = AUDIO_ENCODING_SLINEAR_LE; 545 fp->precision = 16; 546 fp->flags = 0; 547 return 0; 548 case 5: 549 strcpy(fp->name, AudioEulinear_le); 550 fp->encoding = AUDIO_ENCODING_ULINEAR_LE; 551 fp->precision = 16; 552 fp->flags = emul; 553 return 0; 554 case 6: 555 strcpy(fp->name, AudioEslinear_be); 556 fp->encoding = AUDIO_ENCODING_SLINEAR_BE; 557 fp->precision = 16; 558 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 559 return 0; 560 case 7: 561 strcpy(fp->name, AudioEulinear_be); 562 fp->encoding = AUDIO_ENCODING_ULINEAR_BE; 563 fp->precision = 16; 564 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 565 return 0; 566 default: 567 return EINVAL; 568 } 569 return 0; 570 } 571 572 int 573 sbdsp_set_params( 574 void *addr, 575 int setmode, int usemode, 576 audio_params_t *play, audio_params_t *rec, 577 stream_filter_list_t *pfil, stream_filter_list_t *rfil) 578 { 579 struct sbdsp_softc *sc; 580 struct sbmode *m; 581 u_int rate, tc, bmode; 582 stream_filter_factory_t *swcode; 583 int model; 584 int chan; 585 struct audio_params *p; 586 audio_params_t hw; 587 stream_filter_list_t *fil; 588 int mode; 589 590 sc = addr; 591 if (sc->sc_open == SB_OPEN_MIDI) 592 return EBUSY; 593 594 /* Later models work like SB16. */ 595 model = min(sc->sc_model, SB_16); 596 597 /* 598 * Prior to the SB16, we have only one clock, so make the sample 599 * rates match. 600 */ 601 if (!ISSB16CLASS(sc) && 602 play->sample_rate != rec->sample_rate && 603 usemode == (AUMODE_PLAY | AUMODE_RECORD)) { 604 if (setmode == AUMODE_PLAY) { 605 rec->sample_rate = play->sample_rate; 606 setmode |= AUMODE_RECORD; 607 } else if (setmode == AUMODE_RECORD) { 608 play->sample_rate = rec->sample_rate; 609 setmode |= AUMODE_PLAY; 610 } else 611 return EINVAL; 612 } 613 614 /* Set first record info, then play info */ 615 for (mode = AUMODE_RECORD; mode != -1; 616 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 617 if ((setmode & mode) == 0) 618 continue; 619 620 p = mode == AUMODE_PLAY ? play : rec; 621 /* Locate proper commands */ 622 for (m = mode == AUMODE_PLAY ? sbpmodes : sbrmodes; 623 m->model != -1; m++) { 624 if (model == m->model && 625 p->channels == m->channels && 626 p->precision == m->precision && 627 p->sample_rate >= m->lowrate && 628 p->sample_rate <= m->highrate) 629 break; 630 } 631 if (m->model == -1) 632 return EINVAL; 633 rate = p->sample_rate; 634 swcode = NULL; 635 fil = mode == AUMODE_PLAY ? pfil : rfil; 636 hw = *p; 637 tc = 1; 638 bmode = -1; 639 if (model == SB_16) { 640 switch (p->encoding) { 641 case AUDIO_ENCODING_SLINEAR_BE: 642 if (p->precision == 16) { 643 hw.encoding = AUDIO_ENCODING_SLINEAR_LE; 644 swcode = swap_bytes; 645 } 646 /* fall into */ 647 case AUDIO_ENCODING_SLINEAR_LE: 648 bmode = SB_BMODE_SIGNED; 649 break; 650 651 case AUDIO_ENCODING_ULINEAR_BE: 652 if (p->precision == 16) { 653 hw.encoding = AUDIO_ENCODING_ULINEAR_LE; 654 swcode = swap_bytes; 655 } 656 /* fall into */ 657 case AUDIO_ENCODING_ULINEAR_LE: 658 bmode = SB_BMODE_UNSIGNED; 659 break; 660 661 case AUDIO_ENCODING_ULAW: 662 hw.encoding = AUDIO_ENCODING_ULINEAR_LE; 663 if (mode == AUMODE_PLAY) { 664 hw.precision = hw.validbits = 16; 665 swcode = mulaw_to_linear16; 666 m = &sbpmodes[PLAY16]; 667 } else 668 swcode = linear8_to_mulaw; 669 bmode = SB_BMODE_UNSIGNED; 670 break; 671 672 case AUDIO_ENCODING_ALAW: 673 hw.encoding = AUDIO_ENCODING_ULINEAR_LE; 674 if (mode == AUMODE_PLAY) { 675 hw.precision = hw.validbits = 16; 676 swcode = alaw_to_linear16; 677 m = &sbpmodes[PLAY16]; 678 } else 679 swcode = linear8_to_alaw; 680 bmode = SB_BMODE_UNSIGNED; 681 break; 682 default: 683 return EINVAL; 684 } 685 if (p->channels == 2) 686 bmode |= SB_BMODE_STEREO; 687 } else if (m->model == SB_JAZZ && m->precision == 16) { 688 switch (p->encoding) { 689 case AUDIO_ENCODING_SLINEAR_LE: 690 break; 691 case AUDIO_ENCODING_ULINEAR_LE: 692 hw.encoding = AUDIO_ENCODING_SLINEAR_LE; 693 swcode = change_sign16; 694 break; 695 case AUDIO_ENCODING_SLINEAR_BE: 696 hw.encoding = AUDIO_ENCODING_SLINEAR_LE; 697 swcode = swap_bytes; 698 break; 699 case AUDIO_ENCODING_ULINEAR_BE: 700 hw.encoding = AUDIO_ENCODING_SLINEAR_LE; 701 swcode = swap_bytes_change_sign16; 702 break; 703 case AUDIO_ENCODING_ULAW: 704 hw.encoding = AUDIO_ENCODING_ULINEAR_LE; 705 swcode = mode == AUMODE_PLAY ? 706 mulaw_to_linear8 : linear8_to_mulaw; 707 break; 708 case AUDIO_ENCODING_ALAW: 709 hw.encoding = AUDIO_ENCODING_ULINEAR_LE; 710 swcode = mode == AUMODE_PLAY ? 711 alaw_to_linear8 : linear8_to_alaw; 712 break; 713 default: 714 return EINVAL; 715 } 716 tc = SB_RATE_TO_TC(p->sample_rate * p->channels); 717 p->sample_rate = SB_TC_TO_RATE(tc) / p->channels; 718 hw.sample_rate = p->sample_rate; 719 } else { 720 switch (p->encoding) { 721 case AUDIO_ENCODING_SLINEAR_BE: 722 case AUDIO_ENCODING_SLINEAR_LE: 723 hw.encoding = AUDIO_ENCODING_ULINEAR_LE; 724 swcode = change_sign8; 725 break; 726 case AUDIO_ENCODING_ULINEAR_BE: 727 case AUDIO_ENCODING_ULINEAR_LE: 728 break; 729 case AUDIO_ENCODING_ULAW: 730 hw.encoding = AUDIO_ENCODING_ULINEAR_LE; 731 swcode = mode == AUMODE_PLAY ? 732 mulaw_to_linear8 : linear8_to_mulaw; 733 break; 734 case AUDIO_ENCODING_ALAW: 735 hw.encoding = AUDIO_ENCODING_ULINEAR_LE; 736 swcode = mode == AUMODE_PLAY ? 737 alaw_to_linear8 : linear8_to_alaw; 738 break; 739 default: 740 return EINVAL; 741 } 742 tc = SB_RATE_TO_TC(p->sample_rate * p->channels); 743 p->sample_rate = SB_TC_TO_RATE(tc) / p->channels; 744 hw.sample_rate = p->sample_rate; 745 } 746 747 chan = m->precision == 16 ? sc->sc_drq16 : sc->sc_drq8; 748 if (mode == AUMODE_PLAY) { 749 sc->sc_o.rate = rate; 750 sc->sc_o.tc = tc; 751 sc->sc_o.modep = m; 752 sc->sc_o.bmode = bmode; 753 sc->sc_o.dmachan = chan; 754 } else { 755 sc->sc_i.rate = rate; 756 sc->sc_i.tc = tc; 757 sc->sc_i.modep = m; 758 sc->sc_i.bmode = bmode; 759 sc->sc_i.dmachan = chan; 760 } 761 762 if (swcode != NULL) 763 fil->append(fil, swcode, &hw); 764 DPRINTF(("sbdsp_set_params: model=%d, mode=%d, rate=%u, " 765 "prec=%d, chan=%d, enc=%d -> tc=%02x, cmd=%02x, " 766 "bmode=%02x, cmdchan=%02x\n", sc->sc_model, mode, 767 p->sample_rate, p->precision, p->channels, 768 p->encoding, tc, m->cmd, bmode, m->cmdchan)); 769 770 } 771 772 if (sc->sc_fullduplex && 773 usemode == (AUMODE_PLAY | AUMODE_RECORD) && 774 sc->sc_i.dmachan == sc->sc_o.dmachan) { 775 DPRINTF(("sbdsp_set_params: fd=%d, usemode=%d, idma=%d, " 776 "odma=%d\n", sc->sc_fullduplex, usemode, 777 sc->sc_i.dmachan, sc->sc_o.dmachan)); 778 if (sc->sc_o.dmachan == sc->sc_drq8) { 779 /* Use 16 bit DMA for playing by expanding the samples. */ 780 hw.precision = hw.validbits = 16; 781 pfil->append(pfil, linear8_to_linear16, &hw); 782 sc->sc_o.modep = &sbpmodes[PLAY16]; 783 sc->sc_o.dmachan = sc->sc_drq16; 784 } else { 785 return EINVAL; 786 } 787 } 788 DPRINTF(("sbdsp_set_params ichan=%d, ochan=%d\n", 789 sc->sc_i.dmachan, sc->sc_o.dmachan)); 790 791 return 0; 792 } 793 794 void 795 sbdsp_set_ifilter(void *addr, int which) 796 { 797 struct sbdsp_softc *sc; 798 int mixval; 799 800 sc = addr; 801 mixval = sbdsp_mix_read(sc, SBP_INFILTER) & ~SBP_IFILTER_MASK; 802 switch (which) { 803 case 0: 804 mixval |= SBP_FILTER_OFF; 805 break; 806 case SB_TREBLE: 807 mixval |= SBP_FILTER_ON | SBP_IFILTER_HIGH; 808 break; 809 case SB_BASS: 810 mixval |= SBP_FILTER_ON | SBP_IFILTER_LOW; 811 break; 812 default: 813 return; 814 } 815 sc->in_filter = mixval & SBP_IFILTER_MASK; 816 sbdsp_mix_write(sc, SBP_INFILTER, mixval); 817 } 818 819 int 820 sbdsp_get_ifilter(void *addr) 821 { 822 struct sbdsp_softc *sc; 823 824 sc = addr; 825 sc->in_filter = 826 sbdsp_mix_read(sc, SBP_INFILTER) & SBP_IFILTER_MASK; 827 switch (sc->in_filter) { 828 case SBP_FILTER_ON|SBP_IFILTER_HIGH: 829 return SB_TREBLE; 830 case SBP_FILTER_ON|SBP_IFILTER_LOW: 831 return SB_BASS; 832 default: 833 return 0; 834 } 835 } 836 837 int 838 sbdsp_set_in_ports(struct sbdsp_softc *sc, int mask) 839 { 840 int bitsl, bitsr; 841 int sbport; 842 843 if (sc->sc_open == SB_OPEN_MIDI) 844 return EBUSY; 845 846 DPRINTF(("sbdsp_set_in_ports: model=%d, mask=%x\n", 847 sc->sc_mixer_model, mask)); 848 849 switch(sc->sc_mixer_model) { 850 case SBM_NONE: 851 return EINVAL; 852 case SBM_CT1335: 853 if (mask != (1 << SB_MIC_VOL)) 854 return EINVAL; 855 break; 856 case SBM_CT1345: 857 switch (mask) { 858 case 1 << SB_MIC_VOL: 859 sbport = SBP_FROM_MIC; 860 break; 861 case 1 << SB_LINE_IN_VOL: 862 sbport = SBP_FROM_LINE; 863 break; 864 case 1 << SB_CD_VOL: 865 sbport = SBP_FROM_CD; 866 break; 867 default: 868 return EINVAL; 869 } 870 sbdsp_mix_write(sc, SBP_RECORD_SOURCE, sbport | sc->in_filter); 871 break; 872 case SBM_CT1XX5: 873 case SBM_CT1745: 874 if (mask & ~((1<<SB_MIDI_VOL) | (1<<SB_LINE_IN_VOL) | 875 (1<<SB_CD_VOL) | (1<<SB_MIC_VOL))) 876 return EINVAL; 877 bitsr = 0; 878 if (mask & (1<<SB_MIDI_VOL)) bitsr |= SBP_MIDI_SRC_R; 879 if (mask & (1<<SB_LINE_IN_VOL)) bitsr |= SBP_LINE_SRC_R; 880 if (mask & (1<<SB_CD_VOL)) bitsr |= SBP_CD_SRC_R; 881 bitsl = SB_SRC_R_TO_L(bitsr); 882 if (mask & (1<<SB_MIC_VOL)) { 883 bitsl |= SBP_MIC_SRC; 884 bitsr |= SBP_MIC_SRC; 885 } 886 sbdsp_mix_write(sc, SBP_RECORD_SOURCE_L, bitsl); 887 sbdsp_mix_write(sc, SBP_RECORD_SOURCE_R, bitsr); 888 break; 889 } 890 sc->in_mask = mask; 891 892 return 0; 893 } 894 895 int 896 sbdsp_speaker_ctl(void *addr, int newstate) 897 { 898 struct sbdsp_softc *sc; 899 900 sc = addr; 901 if (sc->sc_open == SB_OPEN_MIDI) 902 return EBUSY; 903 904 if ((newstate == SPKR_ON) && 905 (sc->spkr_state == SPKR_OFF)) { 906 sbdsp_spkron(sc); 907 sc->spkr_state = SPKR_ON; 908 } 909 if ((newstate == SPKR_OFF) && 910 (sc->spkr_state == SPKR_ON)) { 911 sbdsp_spkroff(sc); 912 sc->spkr_state = SPKR_OFF; 913 } 914 return 0; 915 } 916 917 int 918 sbdsp_round_blocksize( 919 void *addr, 920 int blk, 921 int mode, 922 const audio_params_t *param) 923 { 924 return blk & -4; /* round to biggest sample size */ 925 } 926 927 int 928 sbdsp_open(void *addr, int flags) 929 { 930 struct sbdsp_softc *sc; 931 int error, state; 932 933 sc = addr; 934 DPRINTF(("sbdsp_open: sc=%p\n", sc)); 935 936 if (sc->sc_open != SB_CLOSED) 937 return EBUSY; 938 sc->sc_open = SB_OPEN_AUDIO; 939 state = 0; 940 941 if (sc->sc_drq8 != -1) { 942 error = isa_drq_alloc(sc->sc_ic, sc->sc_drq8); 943 if (error != 0) 944 goto bad; 945 state |= 1; 946 } 947 948 if (sc->sc_drq16 != -1 && sc->sc_drq16 != sc->sc_drq8) { 949 error = isa_drq_alloc(sc->sc_ic, sc->sc_drq16); 950 if (error != 0) 951 goto bad; 952 state |= 2; 953 } 954 955 956 if (sbdsp_reset(sc) != 0) { 957 error = EIO; 958 goto bad; 959 } 960 961 if (ISSBPRO(sc) && 962 sbdsp_wdsp(sc, SB_DSP_RECORD_MONO) < 0) { 963 DPRINTF(("sbdsp_open: can't set mono mode\n")); 964 /* we'll readjust when it's time for DMA. */ 965 } 966 967 /* 968 * Leave most things as they were; users must change things if 969 * the previous process didn't leave it they way they wanted. 970 * Looked at another way, it's easy to set up a configuration 971 * in one program and leave it for another to inherit. 972 */ 973 DPRINTF(("sbdsp_open: opened\n")); 974 975 return 0; 976 977 bad: 978 if (state & 1) 979 isa_drq_free(sc->sc_ic, sc->sc_drq8); 980 if (state & 2) 981 isa_drq_free(sc->sc_ic, sc->sc_drq16); 982 983 sc->sc_open = SB_CLOSED; 984 return error; 985 } 986 987 void 988 sbdsp_close(void *addr) 989 { 990 struct sbdsp_softc *sc; 991 992 sc = addr; 993 DPRINTF(("sbdsp_close: sc=%p\n", sc)); 994 995 sbdsp_spkroff(sc); 996 sc->spkr_state = SPKR_OFF; 997 998 sc->sc_intr8 = 0; 999 sc->sc_intr16 = 0; 1000 1001 if (sc->sc_drq8 != -1) 1002 isa_drq_free(sc->sc_ic, sc->sc_drq8); 1003 if (sc->sc_drq16 != -1 && sc->sc_drq16 != sc->sc_drq8) 1004 isa_drq_free(sc->sc_ic, sc->sc_drq16); 1005 1006 sc->sc_open = SB_CLOSED; 1007 DPRINTF(("sbdsp_close: closed\n")); 1008 } 1009 1010 /* 1011 * Lower-level routines 1012 */ 1013 1014 /* 1015 * Reset the card. 1016 * Return non-zero if the card isn't detected. 1017 */ 1018 int 1019 sbdsp_reset(struct sbdsp_softc *sc) 1020 { 1021 bus_space_tag_t iot; 1022 bus_space_handle_t ioh; 1023 1024 iot = sc->sc_iot; 1025 ioh = sc->sc_ioh; 1026 sc->sc_intr8 = 0; 1027 sc->sc_intr16 = 0; 1028 sc->sc_intrm = 0; 1029 1030 /* 1031 * See SBK, section 11.3. 1032 * We pulse a reset signal into the card. 1033 * Gee, what a brilliant hardware design. 1034 */ 1035 bus_space_write_1(iot, ioh, SBP_DSP_RESET, 1); 1036 delay(10); 1037 bus_space_write_1(iot, ioh, SBP_DSP_RESET, 0); 1038 delay(30); 1039 if (sbdsp_rdsp(sc) != SB_MAGIC) 1040 return -1; 1041 1042 return 0; 1043 } 1044 1045 /* 1046 * Write a byte to the dsp. 1047 * We are at the mercy of the card as we use a 1048 * polling loop and wait until it can take the byte. 1049 */ 1050 int 1051 sbdsp_wdsp(struct sbdsp_softc *sc, int v) 1052 { 1053 bus_space_tag_t iot; 1054 bus_space_handle_t ioh; 1055 int i; 1056 u_char x; 1057 1058 iot = sc->sc_iot; 1059 ioh = sc->sc_ioh; 1060 for (i = SBDSP_NPOLL; --i >= 0; ) { 1061 x = bus_space_read_1(iot, ioh, SBP_DSP_WSTAT); 1062 delay(10); 1063 if ((x & SB_DSP_BUSY) == 0) { 1064 bus_space_write_1(iot, ioh, SBP_DSP_WRITE, v); 1065 delay(10); 1066 return 0; 1067 } 1068 } 1069 ++sberr.wdsp; 1070 return -1; 1071 } 1072 1073 /* 1074 * Read a byte from the DSP, using polling. 1075 */ 1076 int 1077 sbdsp_rdsp(struct sbdsp_softc *sc) 1078 { 1079 bus_space_tag_t iot; 1080 bus_space_handle_t ioh; 1081 int i; 1082 u_char x; 1083 1084 iot = sc->sc_iot; 1085 ioh = sc->sc_ioh; 1086 for (i = SBDSP_NPOLL; --i >= 0; ) { 1087 x = bus_space_read_1(iot, ioh, SBP_DSP_RSTAT); 1088 delay(10); 1089 if (x & SB_DSP_READY) { 1090 x = bus_space_read_1(iot, ioh, SBP_DSP_READ); 1091 delay(10); 1092 return x; 1093 } 1094 } 1095 ++sberr.rdsp; 1096 return -1; 1097 } 1098 1099 void 1100 sbdsp_pause(struct sbdsp_softc *sc) 1101 { 1102 1103 (void) tsleep(sbdsp_pause, PWAIT, "sbpause", hz / 8); 1104 } 1105 1106 /* 1107 * Turn on the speaker. The SBK documention says this operation 1108 * can take up to 1/10 of a second. Higher level layers should 1109 * probably let the task sleep for this amount of time after 1110 * calling here. Otherwise, things might not work (because 1111 * sbdsp_wdsp() and sbdsp_rdsp() will probably timeout.) 1112 * 1113 * These engineers had their heads up their ass when 1114 * they designed this card. 1115 */ 1116 void 1117 sbdsp_spkron(struct sbdsp_softc *sc) 1118 { 1119 1120 (void)sbdsp_wdsp(sc, SB_DSP_SPKR_ON); 1121 sbdsp_pause(sc); 1122 } 1123 1124 /* 1125 * Turn off the speaker; see comment above. 1126 */ 1127 void 1128 sbdsp_spkroff(struct sbdsp_softc *sc) 1129 { 1130 1131 (void)sbdsp_wdsp(sc, SB_DSP_SPKR_OFF); 1132 sbdsp_pause(sc); 1133 } 1134 1135 /* 1136 * Read the version number out of the card. 1137 * Store version information in the softc. 1138 */ 1139 void 1140 sbversion(struct sbdsp_softc *sc) 1141 { 1142 int v; 1143 1144 sc->sc_model = SB_UNK; 1145 sc->sc_version = 0; 1146 if (sbdsp_wdsp(sc, SB_DSP_VERSION) < 0) 1147 return; 1148 v = sbdsp_rdsp(sc) << 8; 1149 v |= sbdsp_rdsp(sc); 1150 if (v < 0) 1151 return; 1152 sc->sc_version = v; 1153 switch(SBVER_MAJOR(v)) { 1154 case 1: 1155 sc->sc_mixer_model = SBM_NONE; 1156 sc->sc_model = SB_1; 1157 break; 1158 case 2: 1159 /* Some SB2 have a mixer, some don't. */ 1160 sbdsp_mix_write(sc, SBP_1335_MASTER_VOL, 0x04); 1161 sbdsp_mix_write(sc, SBP_1335_MIDI_VOL, 0x06); 1162 /* Check if we can read back the mixer values. */ 1163 if ((sbdsp_mix_read(sc, SBP_1335_MASTER_VOL) & 0x0e) == 0x04 && 1164 (sbdsp_mix_read(sc, SBP_1335_MIDI_VOL) & 0x0e) == 0x06) 1165 sc->sc_mixer_model = SBM_CT1335; 1166 else 1167 sc->sc_mixer_model = SBM_NONE; 1168 if (SBVER_MINOR(v) == 0) 1169 sc->sc_model = SB_20; 1170 else 1171 sc->sc_model = SB_2x; 1172 break; 1173 case 3: 1174 sc->sc_mixer_model = SBM_CT1345; 1175 sc->sc_model = SB_PRO; 1176 break; 1177 case 4: 1178 #if 0 1179 /* XXX This does not work */ 1180 /* Most SB16 have a tone controls, but some don't. */ 1181 sbdsp_mix_write(sc, SB16P_TREBLE_L, 0x80); 1182 /* Check if we can read back the mixer value. */ 1183 if ((sbdsp_mix_read(sc, SB16P_TREBLE_L) & 0xf0) == 0x80) 1184 sc->sc_mixer_model = SBM_CT1745; 1185 else 1186 sc->sc_mixer_model = SBM_CT1XX5; 1187 #else 1188 sc->sc_mixer_model = SBM_CT1745; 1189 #endif 1190 #if 0 1191 /* XXX figure out a good way of determining the model */ 1192 /* XXX what about SB_32 */ 1193 if (SBVER_MINOR(v) == 16) 1194 sc->sc_model = SB_64; 1195 else 1196 #endif 1197 sc->sc_model = SB_16; 1198 break; 1199 } 1200 } 1201 1202 int 1203 sbdsp_set_timeconst(struct sbdsp_softc *sc, int tc) 1204 { 1205 1206 DPRINTF(("sbdsp_set_timeconst: sc=%p tc=%d\n", sc, tc)); 1207 if (sbdsp_wdsp(sc, SB_DSP_TIMECONST) < 0 || 1208 sbdsp_wdsp(sc, tc) < 0) 1209 return EIO; 1210 return 0; 1211 } 1212 1213 int 1214 sbdsp16_set_rate(struct sbdsp_softc *sc, int cmd, int rate) 1215 { 1216 1217 DPRINTF(("sbdsp16_set_rate: sc=%p cmd=0x%02x rate=%d\n", sc, cmd, rate)); 1218 if (sbdsp_wdsp(sc, cmd) < 0 || 1219 sbdsp_wdsp(sc, rate >> 8) < 0 || 1220 sbdsp_wdsp(sc, rate) < 0) 1221 return EIO; 1222 return 0; 1223 } 1224 1225 int 1226 sbdsp_trigger_input( 1227 void *addr, 1228 void *start, void *end, 1229 int blksize, 1230 void (*intr)(void *), 1231 void *arg, 1232 const audio_params_t *param) 1233 { 1234 struct sbdsp_softc *sc; 1235 int stereo; 1236 int width; 1237 int filter; 1238 1239 sc = addr; 1240 stereo = param->channels == 2; 1241 width = param->precision; 1242 #ifdef DIAGNOSTIC 1243 if (stereo && (blksize & 1)) { 1244 DPRINTF(("stereo record odd bytes (%d)\n", blksize)); 1245 return EIO; 1246 } 1247 if (sc->sc_i.run != SB_NOTRUNNING) 1248 printf("sbdsp_trigger_input: already running\n"); 1249 #endif 1250 1251 sc->sc_intrr = intr; 1252 sc->sc_argr = arg; 1253 1254 if (width == 8) { 1255 #ifdef DIAGNOSTIC 1256 if (sc->sc_i.dmachan != sc->sc_drq8) { 1257 printf("sbdsp_trigger_input: width=%d bad chan %d\n", 1258 width, sc->sc_i.dmachan); 1259 return EIO; 1260 } 1261 #endif 1262 sc->sc_intr8 = sbdsp_block_input; 1263 } else { 1264 #ifdef DIAGNOSTIC 1265 if (sc->sc_i.dmachan != sc->sc_drq16) { 1266 printf("sbdsp_trigger_input: width=%d bad chan %d\n", 1267 width, sc->sc_i.dmachan); 1268 return EIO; 1269 } 1270 #endif 1271 sc->sc_intr16 = sbdsp_block_input; 1272 } 1273 1274 if ((sc->sc_model == SB_JAZZ) ? (sc->sc_i.dmachan > 3) : (width == 16)) 1275 blksize >>= 1; 1276 --blksize; 1277 sc->sc_i.blksize = blksize; 1278 1279 if (ISSBPRO(sc)) { 1280 if (sbdsp_wdsp(sc, sc->sc_i.modep->cmdchan) < 0) 1281 return EIO; 1282 filter = stereo ? SBP_FILTER_OFF : sc->in_filter; 1283 sbdsp_mix_write(sc, SBP_INFILTER, 1284 (sbdsp_mix_read(sc, SBP_INFILTER) & ~SBP_IFILTER_MASK) | 1285 filter); 1286 } 1287 1288 if (ISSB16CLASS(sc)) { 1289 if (sbdsp16_set_rate(sc, SB_DSP16_INPUTRATE, sc->sc_i.rate)) { 1290 DPRINTF(("sbdsp_trigger_input: rate=%d set failed\n", 1291 sc->sc_i.rate)); 1292 return EIO; 1293 } 1294 } else { 1295 if (sbdsp_set_timeconst(sc, sc->sc_i.tc)) { 1296 DPRINTF(("sbdsp_trigger_input: tc=%d set failed\n", 1297 sc->sc_i.rate)); 1298 return EIO; 1299 } 1300 } 1301 1302 DPRINTF(("sbdsp: DMA start loop input start=%p end=%p chan=%d\n", 1303 start, end, sc->sc_i.dmachan)); 1304 isa_dmastart(sc->sc_ic, sc->sc_i.dmachan, start, 1305 (char *)end - (char *)start, NULL, 1306 DMAMODE_READ | DMAMODE_LOOPDEMAND, BUS_DMA_NOWAIT); 1307 1308 return sbdsp_block_input(addr); 1309 } 1310 1311 int 1312 sbdsp_block_input(void *addr) 1313 { 1314 struct sbdsp_softc *sc; 1315 int cc; 1316 1317 sc = addr; 1318 cc = sc->sc_i.blksize; 1319 DPRINTFN(2, ("sbdsp_block_input: sc=%p cc=%d\n", addr, cc)); 1320 1321 if (sc->sc_i.run != SB_NOTRUNNING) 1322 sc->sc_intrr(sc->sc_argr); 1323 1324 if (sc->sc_model == SB_1) { 1325 /* Non-looping mode, start DMA */ 1326 if (sbdsp_wdsp(sc, sc->sc_i.modep->cmd) < 0 || 1327 sbdsp_wdsp(sc, cc) < 0 || 1328 sbdsp_wdsp(sc, cc >> 8) < 0) { 1329 DPRINTF(("sbdsp_block_input: SB1 DMA start failed\n")); 1330 return EIO; 1331 } 1332 sc->sc_i.run = SB_RUNNING; 1333 } else if (sc->sc_i.run == SB_NOTRUNNING) { 1334 /* Initialize looping PCM */ 1335 if (ISSB16CLASS(sc)) { 1336 DPRINTFN(3, ("sbdsp16 input command cmd=0x%02x bmode=0x%02x cc=%d\n", 1337 sc->sc_i.modep->cmd, sc->sc_i.bmode, cc)); 1338 if (sbdsp_wdsp(sc, sc->sc_i.modep->cmd) < 0 || 1339 sbdsp_wdsp(sc, sc->sc_i.bmode) < 0 || 1340 sbdsp_wdsp(sc, cc) < 0 || 1341 sbdsp_wdsp(sc, cc >> 8) < 0) { 1342 DPRINTF(("sbdsp_block_input: SB16 DMA start failed\n")); 1343 return EIO; 1344 } 1345 } else { 1346 DPRINTF(("sbdsp_block_input: set blocksize=%d\n", cc)); 1347 if (sbdsp_wdsp(sc, SB_DSP_BLOCKSIZE) < 0 || 1348 sbdsp_wdsp(sc, cc) < 0 || 1349 sbdsp_wdsp(sc, cc >> 8) < 0) { 1350 DPRINTF(("sbdsp_block_input: SB2 DMA blocksize failed\n")); 1351 return EIO; 1352 } 1353 if (sbdsp_wdsp(sc, sc->sc_i.modep->cmd) < 0) { 1354 DPRINTF(("sbdsp_block_input: SB2 DMA start failed\n")); 1355 return EIO; 1356 } 1357 } 1358 sc->sc_i.run = SB_LOOPING; 1359 } 1360 1361 return 0; 1362 } 1363 1364 int 1365 sbdsp_trigger_output( 1366 void *addr, 1367 void *start, void *end, 1368 int blksize, 1369 void (*intr)(void *), 1370 void *arg, 1371 const audio_params_t *param) 1372 { 1373 struct sbdsp_softc *sc; 1374 int stereo; 1375 int width; 1376 int cmd; 1377 1378 sc = addr; 1379 stereo = param->channels == 2; 1380 width = param->precision; 1381 #ifdef DIAGNOSTIC 1382 if (stereo && (blksize & 1)) { 1383 DPRINTF(("stereo playback odd bytes (%d)\n", blksize)); 1384 return EIO; 1385 } 1386 if (sc->sc_o.run != SB_NOTRUNNING) 1387 printf("sbdsp_trigger_output: already running\n"); 1388 #endif 1389 1390 sc->sc_intrp = intr; 1391 sc->sc_argp = arg; 1392 1393 if (width == 8) { 1394 #ifdef DIAGNOSTIC 1395 if (sc->sc_o.dmachan != sc->sc_drq8) { 1396 printf("sbdsp_trigger_output: width=%d bad chan %d\n", 1397 width, sc->sc_o.dmachan); 1398 return EIO; 1399 } 1400 #endif 1401 sc->sc_intr8 = sbdsp_block_output; 1402 } else { 1403 #ifdef DIAGNOSTIC 1404 if (sc->sc_o.dmachan != sc->sc_drq16) { 1405 printf("sbdsp_trigger_output: width=%d bad chan %d\n", 1406 width, sc->sc_o.dmachan); 1407 return EIO; 1408 } 1409 #endif 1410 sc->sc_intr16 = sbdsp_block_output; 1411 } 1412 1413 if ((sc->sc_model == SB_JAZZ) ? (sc->sc_o.dmachan > 3) : (width == 16)) 1414 blksize >>= 1; 1415 --blksize; 1416 sc->sc_o.blksize = blksize; 1417 1418 if (ISSBPRO(sc)) { 1419 /* make sure we re-set stereo mixer bit when we start output. */ 1420 sbdsp_mix_write(sc, SBP_STEREO, 1421 (sbdsp_mix_read(sc, SBP_STEREO) & ~SBP_PLAYMODE_MASK) | 1422 (stereo ? SBP_PLAYMODE_STEREO : SBP_PLAYMODE_MONO)); 1423 cmd = sc->sc_o.modep->cmdchan; 1424 if (cmd && sbdsp_wdsp(sc, cmd) < 0) 1425 return EIO; 1426 } 1427 1428 if (ISSB16CLASS(sc)) { 1429 if (sbdsp16_set_rate(sc, SB_DSP16_OUTPUTRATE, sc->sc_o.rate)) { 1430 DPRINTF(("sbdsp_trigger_output: rate=%d set failed\n", 1431 sc->sc_o.rate)); 1432 return EIO; 1433 } 1434 } else { 1435 if (sbdsp_set_timeconst(sc, sc->sc_o.tc)) { 1436 DPRINTF(("sbdsp_trigger_output: tc=%d set failed\n", 1437 sc->sc_o.rate)); 1438 return EIO; 1439 } 1440 } 1441 1442 DPRINTF(("sbdsp: DMA start loop output start=%p end=%p chan=%d\n", 1443 start, end, sc->sc_o.dmachan)); 1444 isa_dmastart(sc->sc_ic, sc->sc_o.dmachan, start, 1445 (char *)end - (char *)start, NULL, 1446 DMAMODE_WRITE | DMAMODE_LOOPDEMAND, BUS_DMA_NOWAIT); 1447 1448 return sbdsp_block_output(addr); 1449 } 1450 1451 int 1452 sbdsp_block_output(void *addr) 1453 { 1454 struct sbdsp_softc *sc; 1455 int cc; 1456 1457 sc = addr; 1458 cc = sc->sc_o.blksize; 1459 DPRINTFN(2, ("sbdsp_block_output: sc=%p cc=%d\n", addr, cc)); 1460 1461 if (sc->sc_o.run != SB_NOTRUNNING) 1462 sc->sc_intrp(sc->sc_argp); 1463 1464 if (sc->sc_model == SB_1) { 1465 /* Non-looping mode, initialized. Start DMA and PCM */ 1466 if (sbdsp_wdsp(sc, sc->sc_o.modep->cmd) < 0 || 1467 sbdsp_wdsp(sc, cc) < 0 || 1468 sbdsp_wdsp(sc, cc >> 8) < 0) { 1469 DPRINTF(("sbdsp_block_output: SB1 DMA start failed\n")); 1470 return EIO; 1471 } 1472 sc->sc_o.run = SB_RUNNING; 1473 } else if (sc->sc_o.run == SB_NOTRUNNING) { 1474 /* Initialize looping PCM */ 1475 if (ISSB16CLASS(sc)) { 1476 DPRINTF(("sbdsp_block_output: SB16 cmd=0x%02x bmode=0x%02x cc=%d\n", 1477 sc->sc_o.modep->cmd,sc->sc_o.bmode, cc)); 1478 if (sbdsp_wdsp(sc, sc->sc_o.modep->cmd) < 0 || 1479 sbdsp_wdsp(sc, sc->sc_o.bmode) < 0 || 1480 sbdsp_wdsp(sc, cc) < 0 || 1481 sbdsp_wdsp(sc, cc >> 8) < 0) { 1482 DPRINTF(("sbdsp_block_output: SB16 DMA start failed\n")); 1483 return EIO; 1484 } 1485 } else { 1486 DPRINTF(("sbdsp_block_output: set blocksize=%d\n", cc)); 1487 if (sbdsp_wdsp(sc, SB_DSP_BLOCKSIZE) < 0 || 1488 sbdsp_wdsp(sc, cc) < 0 || 1489 sbdsp_wdsp(sc, cc >> 8) < 0) { 1490 DPRINTF(("sbdsp_block_output: SB2 DMA blocksize failed\n")); 1491 return EIO; 1492 } 1493 if (sbdsp_wdsp(sc, sc->sc_o.modep->cmd) < 0) { 1494 DPRINTF(("sbdsp_block_output: SB2 DMA start failed\n")); 1495 return EIO; 1496 } 1497 } 1498 sc->sc_o.run = SB_LOOPING; 1499 } 1500 1501 return 0; 1502 } 1503 1504 int 1505 sbdsp_halt_output(void *addr) 1506 { 1507 struct sbdsp_softc *sc; 1508 1509 sc = addr; 1510 if (sc->sc_o.run != SB_NOTRUNNING) { 1511 if (sbdsp_wdsp(sc, sc->sc_o.modep->halt) < 0) 1512 printf("sbdsp_halt_output: failed to halt\n"); 1513 isa_dmaabort(sc->sc_ic, sc->sc_o.dmachan); 1514 sc->sc_o.run = SB_NOTRUNNING; 1515 } 1516 return 0; 1517 } 1518 1519 int 1520 sbdsp_halt_input(void *addr) 1521 { 1522 struct sbdsp_softc *sc; 1523 1524 sc = addr; 1525 if (sc->sc_i.run != SB_NOTRUNNING) { 1526 if (sbdsp_wdsp(sc, sc->sc_i.modep->halt) < 0) 1527 printf("sbdsp_halt_input: failed to halt\n"); 1528 isa_dmaabort(sc->sc_ic, sc->sc_i.dmachan); 1529 sc->sc_i.run = SB_NOTRUNNING; 1530 } 1531 return 0; 1532 } 1533 1534 /* 1535 * Only the DSP unit on the sound blaster generates interrupts. 1536 * There are three cases of interrupt: reception of a midi byte 1537 * (when mode is enabled), completion of DMA transmission, or 1538 * completion of a DMA reception. 1539 * 1540 * If there is interrupt sharing or a spurious interrupt occurs 1541 * there is no way to distinguish this on an SB2. So if you have 1542 * an SB2 and experience problems, buy an SB16 (it's only $40). 1543 */ 1544 int 1545 sbdsp_intr(void *arg) 1546 { 1547 struct sbdsp_softc *sc; 1548 u_char irq; 1549 1550 sc = arg; 1551 DPRINTFN(2, ("sbdsp_intr: intr8=%p, intr16=%p\n", 1552 sc->sc_intr8, sc->sc_intr16)); 1553 if (ISSB16CLASS(sc)) { 1554 irq = sbdsp_mix_read(sc, SBP_IRQ_STATUS); 1555 if ((irq & (SBP_IRQ_DMA8 | SBP_IRQ_DMA16 | SBP_IRQ_MPU401)) == 0) { 1556 DPRINTF(("sbdsp_intr: Spurious interrupt 0x%x\n", irq)); 1557 return 0; 1558 } 1559 } else { 1560 /* XXXX CHECK FOR INTERRUPT */ 1561 irq = SBP_IRQ_DMA8; 1562 } 1563 1564 sc->sc_interrupts++; 1565 delay(10); /* XXX why? */ 1566 1567 /* clear interrupt */ 1568 if (irq & SBP_IRQ_DMA8) { 1569 bus_space_read_1(sc->sc_iot, sc->sc_ioh, SBP_DSP_IRQACK8); 1570 if (sc->sc_intr8) 1571 sc->sc_intr8(arg); 1572 } 1573 if (irq & SBP_IRQ_DMA16) { 1574 bus_space_read_1(sc->sc_iot, sc->sc_ioh, SBP_DSP_IRQACK16); 1575 if (sc->sc_intr16) 1576 sc->sc_intr16(arg); 1577 } 1578 #if NMPU > 0 1579 if ((irq & SBP_IRQ_MPU401) && sc->sc_mpudev) { 1580 mpu_intr(sc->sc_mpudev); 1581 } 1582 #endif 1583 return 1; 1584 } 1585 1586 /* Like val & mask, but make sure the result is correctly rounded. */ 1587 #define MAXVAL 256 1588 static int 1589 sbdsp_adjust(int val, int mask) 1590 { 1591 1592 val += (MAXVAL - mask) >> 1; 1593 if (val >= MAXVAL) 1594 val = MAXVAL-1; 1595 return val & mask; 1596 } 1597 1598 void 1599 sbdsp_set_mixer_gain(struct sbdsp_softc *sc, int port) 1600 { 1601 int src, gain; 1602 1603 switch(sc->sc_mixer_model) { 1604 case SBM_NONE: 1605 return; 1606 case SBM_CT1335: 1607 gain = SB_1335_GAIN(sc->gain[port][SB_LEFT]); 1608 switch(port) { 1609 case SB_MASTER_VOL: 1610 src = SBP_1335_MASTER_VOL; 1611 break; 1612 case SB_MIDI_VOL: 1613 src = SBP_1335_MIDI_VOL; 1614 break; 1615 case SB_CD_VOL: 1616 src = SBP_1335_CD_VOL; 1617 break; 1618 case SB_VOICE_VOL: 1619 src = SBP_1335_VOICE_VOL; 1620 gain = SB_1335_MASTER_GAIN(sc->gain[port][SB_LEFT]); 1621 break; 1622 default: 1623 return; 1624 } 1625 sbdsp_mix_write(sc, src, gain); 1626 break; 1627 case SBM_CT1345: 1628 gain = SB_STEREO_GAIN(sc->gain[port][SB_LEFT], 1629 sc->gain[port][SB_RIGHT]); 1630 switch (port) { 1631 case SB_MIC_VOL: 1632 src = SBP_MIC_VOL; 1633 gain = SB_MIC_GAIN(sc->gain[port][SB_LEFT]); 1634 break; 1635 case SB_MASTER_VOL: 1636 src = SBP_MASTER_VOL; 1637 break; 1638 case SB_LINE_IN_VOL: 1639 src = SBP_LINE_VOL; 1640 break; 1641 case SB_VOICE_VOL: 1642 src = SBP_VOICE_VOL; 1643 break; 1644 case SB_MIDI_VOL: 1645 src = SBP_MIDI_VOL; 1646 break; 1647 case SB_CD_VOL: 1648 src = SBP_CD_VOL; 1649 break; 1650 default: 1651 return; 1652 } 1653 sbdsp_mix_write(sc, src, gain); 1654 break; 1655 case SBM_CT1XX5: 1656 case SBM_CT1745: 1657 switch (port) { 1658 case SB_MIC_VOL: 1659 src = SB16P_MIC_L; 1660 break; 1661 case SB_MASTER_VOL: 1662 src = SB16P_MASTER_L; 1663 break; 1664 case SB_LINE_IN_VOL: 1665 src = SB16P_LINE_L; 1666 break; 1667 case SB_VOICE_VOL: 1668 src = SB16P_VOICE_L; 1669 break; 1670 case SB_MIDI_VOL: 1671 src = SB16P_MIDI_L; 1672 break; 1673 case SB_CD_VOL: 1674 src = SB16P_CD_L; 1675 break; 1676 case SB_INPUT_GAIN: 1677 src = SB16P_INPUT_GAIN_L; 1678 break; 1679 case SB_OUTPUT_GAIN: 1680 src = SB16P_OUTPUT_GAIN_L; 1681 break; 1682 case SB_TREBLE: 1683 src = SB16P_TREBLE_L; 1684 break; 1685 case SB_BASS: 1686 src = SB16P_BASS_L; 1687 break; 1688 case SB_PCSPEAKER: 1689 sbdsp_mix_write(sc, SB16P_PCSPEAKER, sc->gain[port][SB_LEFT]); 1690 return; 1691 default: 1692 return; 1693 } 1694 sbdsp_mix_write(sc, src, sc->gain[port][SB_LEFT]); 1695 sbdsp_mix_write(sc, SB16P_L_TO_R(src), sc->gain[port][SB_RIGHT]); 1696 break; 1697 } 1698 } 1699 1700 int 1701 sbdsp_mixer_set_port(void *addr, mixer_ctrl_t *cp) 1702 { 1703 struct sbdsp_softc *sc; 1704 int lgain, rgain; 1705 int mask, bits; 1706 int lmask, rmask, lbits, rbits; 1707 int mute, swap; 1708 1709 sc = addr; 1710 if (sc->sc_open == SB_OPEN_MIDI) 1711 return EBUSY; 1712 1713 DPRINTF(("sbdsp_mixer_set_port: port=%d num_channels=%d\n", cp->dev, 1714 cp->un.value.num_channels)); 1715 1716 if (sc->sc_mixer_model == SBM_NONE) 1717 return EINVAL; 1718 1719 switch (cp->dev) { 1720 case SB_TREBLE: 1721 case SB_BASS: 1722 if (sc->sc_mixer_model == SBM_CT1345 || 1723 sc->sc_mixer_model == SBM_CT1XX5) { 1724 if (cp->type != AUDIO_MIXER_ENUM) 1725 return EINVAL; 1726 switch (cp->dev) { 1727 case SB_TREBLE: 1728 sbdsp_set_ifilter(addr, cp->un.ord ? SB_TREBLE : 0); 1729 return 0; 1730 case SB_BASS: 1731 sbdsp_set_ifilter(addr, cp->un.ord ? SB_BASS : 0); 1732 return 0; 1733 } 1734 } 1735 case SB_PCSPEAKER: 1736 case SB_INPUT_GAIN: 1737 case SB_OUTPUT_GAIN: 1738 if (!ISSBM1745(sc)) 1739 return EINVAL; 1740 case SB_MIC_VOL: 1741 case SB_LINE_IN_VOL: 1742 if (sc->sc_mixer_model == SBM_CT1335) 1743 return EINVAL; 1744 case SB_VOICE_VOL: 1745 case SB_MIDI_VOL: 1746 case SB_CD_VOL: 1747 case SB_MASTER_VOL: 1748 if (cp->type != AUDIO_MIXER_VALUE) 1749 return EINVAL; 1750 1751 /* 1752 * All the mixer ports are stereo except for the microphone. 1753 * If we get a single-channel gain value passed in, then we 1754 * duplicate it to both left and right channels. 1755 */ 1756 1757 switch (cp->dev) { 1758 case SB_MIC_VOL: 1759 if (cp->un.value.num_channels != 1) 1760 return EINVAL; 1761 1762 lgain = rgain = SB_ADJUST_MIC_GAIN(sc, 1763 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); 1764 break; 1765 case SB_PCSPEAKER: 1766 if (cp->un.value.num_channels != 1) 1767 return EINVAL; 1768 /* fall into */ 1769 case SB_INPUT_GAIN: 1770 case SB_OUTPUT_GAIN: 1771 lgain = rgain = SB_ADJUST_2_GAIN(sc, 1772 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); 1773 break; 1774 default: 1775 switch (cp->un.value.num_channels) { 1776 case 1: 1777 lgain = rgain = SB_ADJUST_GAIN(sc, 1778 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); 1779 break; 1780 case 2: 1781 if (sc->sc_mixer_model == SBM_CT1335) 1782 return EINVAL; 1783 lgain = SB_ADJUST_GAIN(sc, 1784 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]); 1785 rgain = SB_ADJUST_GAIN(sc, 1786 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]); 1787 break; 1788 default: 1789 return EINVAL; 1790 } 1791 break; 1792 } 1793 sc->gain[cp->dev][SB_LEFT] = lgain; 1794 sc->gain[cp->dev][SB_RIGHT] = rgain; 1795 1796 sbdsp_set_mixer_gain(sc, cp->dev); 1797 break; 1798 1799 case SB_RECORD_SOURCE: 1800 if (ISSBM1745(sc)) { 1801 if (cp->type != AUDIO_MIXER_SET) 1802 return EINVAL; 1803 return sbdsp_set_in_ports(sc, cp->un.mask); 1804 } else { 1805 if (cp->type != AUDIO_MIXER_ENUM) 1806 return EINVAL; 1807 sc->in_port = cp->un.ord; 1808 return sbdsp_set_in_ports(sc, 1 << cp->un.ord); 1809 } 1810 break; 1811 1812 case SB_AGC: 1813 if (!ISSBM1745(sc) || cp->type != AUDIO_MIXER_ENUM) 1814 return EINVAL; 1815 sbdsp_mix_write(sc, SB16P_AGC, cp->un.ord & 1); 1816 break; 1817 1818 case SB_CD_OUT_MUTE: 1819 mask = SB16P_SW_CD; 1820 goto omute; 1821 case SB_MIC_OUT_MUTE: 1822 mask = SB16P_SW_MIC; 1823 goto omute; 1824 case SB_LINE_OUT_MUTE: 1825 mask = SB16P_SW_LINE; 1826 omute: 1827 if (cp->type != AUDIO_MIXER_ENUM) 1828 return EINVAL; 1829 bits = sbdsp_mix_read(sc, SB16P_OSWITCH); 1830 sc->gain[cp->dev][SB_LR] = cp->un.ord != 0; 1831 if (cp->un.ord) 1832 bits = bits & ~mask; 1833 else 1834 bits = bits | mask; 1835 sbdsp_mix_write(sc, SB16P_OSWITCH, bits); 1836 break; 1837 1838 case SB_MIC_IN_MUTE: 1839 case SB_MIC_SWAP: 1840 lmask = rmask = SB16P_SW_MIC; 1841 goto imute; 1842 case SB_CD_IN_MUTE: 1843 case SB_CD_SWAP: 1844 lmask = SB16P_SW_CD_L; 1845 rmask = SB16P_SW_CD_R; 1846 goto imute; 1847 case SB_LINE_IN_MUTE: 1848 case SB_LINE_SWAP: 1849 lmask = SB16P_SW_LINE_L; 1850 rmask = SB16P_SW_LINE_R; 1851 goto imute; 1852 case SB_MIDI_IN_MUTE: 1853 case SB_MIDI_SWAP: 1854 lmask = SB16P_SW_MIDI_L; 1855 rmask = SB16P_SW_MIDI_R; 1856 imute: 1857 if (cp->type != AUDIO_MIXER_ENUM) 1858 return EINVAL; 1859 mask = lmask | rmask; 1860 lbits = sbdsp_mix_read(sc, SB16P_ISWITCH_L) & ~mask; 1861 rbits = sbdsp_mix_read(sc, SB16P_ISWITCH_R) & ~mask; 1862 sc->gain[cp->dev][SB_LR] = cp->un.ord != 0; 1863 if (SB_IS_IN_MUTE(cp->dev)) { 1864 mute = cp->dev; 1865 swap = mute - SB_CD_IN_MUTE + SB_CD_SWAP; 1866 } else { 1867 swap = cp->dev; 1868 mute = swap + SB_CD_IN_MUTE - SB_CD_SWAP; 1869 } 1870 if (sc->gain[swap][SB_LR]) { 1871 mask = lmask; 1872 lmask = rmask; 1873 rmask = mask; 1874 } 1875 if (!sc->gain[mute][SB_LR]) { 1876 lbits = lbits | lmask; 1877 rbits = rbits | rmask; 1878 } 1879 sbdsp_mix_write(sc, SB16P_ISWITCH_L, lbits); 1880 sbdsp_mix_write(sc, SB16P_ISWITCH_L, rbits); 1881 break; 1882 1883 default: 1884 return EINVAL; 1885 } 1886 1887 return 0; 1888 } 1889 1890 int 1891 sbdsp_mixer_get_port(void *addr, mixer_ctrl_t *cp) 1892 { 1893 struct sbdsp_softc *sc; 1894 1895 sc = addr; 1896 if (sc->sc_open == SB_OPEN_MIDI) 1897 return EBUSY; 1898 1899 DPRINTF(("sbdsp_mixer_get_port: port=%d\n", cp->dev)); 1900 1901 if (sc->sc_mixer_model == SBM_NONE) 1902 return EINVAL; 1903 1904 switch (cp->dev) { 1905 case SB_TREBLE: 1906 case SB_BASS: 1907 if (sc->sc_mixer_model == SBM_CT1345 || 1908 sc->sc_mixer_model == SBM_CT1XX5) { 1909 switch (cp->dev) { 1910 case SB_TREBLE: 1911 cp->un.ord = sbdsp_get_ifilter(addr) == SB_TREBLE; 1912 return 0; 1913 case SB_BASS: 1914 cp->un.ord = sbdsp_get_ifilter(addr) == SB_BASS; 1915 return 0; 1916 } 1917 } 1918 case SB_PCSPEAKER: 1919 case SB_INPUT_GAIN: 1920 case SB_OUTPUT_GAIN: 1921 if (!ISSBM1745(sc)) 1922 return EINVAL; 1923 case SB_MIC_VOL: 1924 case SB_LINE_IN_VOL: 1925 if (sc->sc_mixer_model == SBM_CT1335) 1926 return EINVAL; 1927 case SB_VOICE_VOL: 1928 case SB_MIDI_VOL: 1929 case SB_CD_VOL: 1930 case SB_MASTER_VOL: 1931 switch (cp->dev) { 1932 case SB_MIC_VOL: 1933 case SB_PCSPEAKER: 1934 if (cp->un.value.num_channels != 1) 1935 return EINVAL; 1936 /* fall into */ 1937 default: 1938 switch (cp->un.value.num_channels) { 1939 case 1: 1940 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 1941 sc->gain[cp->dev][SB_LEFT]; 1942 break; 1943 case 2: 1944 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 1945 sc->gain[cp->dev][SB_LEFT]; 1946 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 1947 sc->gain[cp->dev][SB_RIGHT]; 1948 break; 1949 default: 1950 return EINVAL; 1951 } 1952 break; 1953 } 1954 break; 1955 1956 case SB_RECORD_SOURCE: 1957 if (ISSBM1745(sc)) 1958 cp->un.mask = sc->in_mask; 1959 else 1960 cp->un.ord = sc->in_port; 1961 break; 1962 1963 case SB_AGC: 1964 if (!ISSBM1745(sc)) 1965 return EINVAL; 1966 cp->un.ord = sbdsp_mix_read(sc, SB16P_AGC); 1967 break; 1968 1969 case SB_CD_IN_MUTE: 1970 case SB_MIC_IN_MUTE: 1971 case SB_LINE_IN_MUTE: 1972 case SB_MIDI_IN_MUTE: 1973 case SB_CD_SWAP: 1974 case SB_MIC_SWAP: 1975 case SB_LINE_SWAP: 1976 case SB_MIDI_SWAP: 1977 case SB_CD_OUT_MUTE: 1978 case SB_MIC_OUT_MUTE: 1979 case SB_LINE_OUT_MUTE: 1980 cp->un.ord = sc->gain[cp->dev][SB_LR]; 1981 break; 1982 1983 default: 1984 return EINVAL; 1985 } 1986 1987 return 0; 1988 } 1989 1990 int 1991 sbdsp_mixer_query_devinfo(void *addr, mixer_devinfo_t *dip) 1992 { 1993 struct sbdsp_softc *sc = addr; 1994 int chan, class, is1745; 1995 1996 sc = addr; 1997 DPRINTF(("sbdsp_mixer_query_devinfo: model=%d index=%d\n", 1998 sc->sc_mixer_model, dip->index)); 1999 2000 if (sc->sc_mixer_model == SBM_NONE) 2001 return ENXIO; 2002 2003 chan = sc->sc_mixer_model == SBM_CT1335 ? 1 : 2; 2004 is1745 = ISSBM1745(sc); 2005 class = is1745 ? SB_INPUT_CLASS : SB_OUTPUT_CLASS; 2006 2007 switch (dip->index) { 2008 case SB_MASTER_VOL: 2009 dip->type = AUDIO_MIXER_VALUE; 2010 dip->mixer_class = SB_OUTPUT_CLASS; 2011 dip->prev = dip->next = AUDIO_MIXER_LAST; 2012 strcpy(dip->label.name, AudioNmaster); 2013 dip->un.v.num_channels = chan; 2014 strcpy(dip->un.v.units.name, AudioNvolume); 2015 return 0; 2016 case SB_MIDI_VOL: 2017 dip->type = AUDIO_MIXER_VALUE; 2018 dip->mixer_class = class; 2019 dip->prev = AUDIO_MIXER_LAST; 2020 dip->next = is1745 ? SB_MIDI_IN_MUTE : AUDIO_MIXER_LAST; 2021 strcpy(dip->label.name, AudioNfmsynth); 2022 dip->un.v.num_channels = chan; 2023 strcpy(dip->un.v.units.name, AudioNvolume); 2024 return 0; 2025 case SB_CD_VOL: 2026 dip->type = AUDIO_MIXER_VALUE; 2027 dip->mixer_class = class; 2028 dip->prev = AUDIO_MIXER_LAST; 2029 dip->next = is1745 ? SB_CD_IN_MUTE : AUDIO_MIXER_LAST; 2030 strcpy(dip->label.name, AudioNcd); 2031 dip->un.v.num_channels = chan; 2032 strcpy(dip->un.v.units.name, AudioNvolume); 2033 return 0; 2034 case SB_VOICE_VOL: 2035 dip->type = AUDIO_MIXER_VALUE; 2036 dip->mixer_class = class; 2037 dip->prev = AUDIO_MIXER_LAST; 2038 dip->next = AUDIO_MIXER_LAST; 2039 strcpy(dip->label.name, AudioNdac); 2040 dip->un.v.num_channels = chan; 2041 strcpy(dip->un.v.units.name, AudioNvolume); 2042 return 0; 2043 case SB_OUTPUT_CLASS: 2044 dip->type = AUDIO_MIXER_CLASS; 2045 dip->mixer_class = SB_OUTPUT_CLASS; 2046 dip->next = dip->prev = AUDIO_MIXER_LAST; 2047 strcpy(dip->label.name, AudioCoutputs); 2048 return 0; 2049 } 2050 2051 if (sc->sc_mixer_model == SBM_CT1335) 2052 return ENXIO; 2053 2054 switch (dip->index) { 2055 case SB_MIC_VOL: 2056 dip->type = AUDIO_MIXER_VALUE; 2057 dip->mixer_class = class; 2058 dip->prev = AUDIO_MIXER_LAST; 2059 dip->next = is1745 ? SB_MIC_IN_MUTE : AUDIO_MIXER_LAST; 2060 strcpy(dip->label.name, AudioNmicrophone); 2061 dip->un.v.num_channels = 1; 2062 strcpy(dip->un.v.units.name, AudioNvolume); 2063 return 0; 2064 2065 case SB_LINE_IN_VOL: 2066 dip->type = AUDIO_MIXER_VALUE; 2067 dip->mixer_class = class; 2068 dip->prev = AUDIO_MIXER_LAST; 2069 dip->next = is1745 ? SB_LINE_IN_MUTE : AUDIO_MIXER_LAST; 2070 strcpy(dip->label.name, AudioNline); 2071 dip->un.v.num_channels = 2; 2072 strcpy(dip->un.v.units.name, AudioNvolume); 2073 return 0; 2074 2075 case SB_RECORD_SOURCE: 2076 dip->mixer_class = SB_RECORD_CLASS; 2077 dip->prev = dip->next = AUDIO_MIXER_LAST; 2078 strcpy(dip->label.name, AudioNsource); 2079 if (ISSBM1745(sc)) { 2080 dip->type = AUDIO_MIXER_SET; 2081 dip->un.s.num_mem = 4; 2082 strcpy(dip->un.s.member[0].label.name, AudioNmicrophone); 2083 dip->un.s.member[0].mask = 1 << SB_MIC_VOL; 2084 strcpy(dip->un.s.member[1].label.name, AudioNcd); 2085 dip->un.s.member[1].mask = 1 << SB_CD_VOL; 2086 strcpy(dip->un.s.member[2].label.name, AudioNline); 2087 dip->un.s.member[2].mask = 1 << SB_LINE_IN_VOL; 2088 strcpy(dip->un.s.member[3].label.name, AudioNfmsynth); 2089 dip->un.s.member[3].mask = 1 << SB_MIDI_VOL; 2090 } else { 2091 dip->type = AUDIO_MIXER_ENUM; 2092 dip->un.e.num_mem = 3; 2093 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone); 2094 dip->un.e.member[0].ord = SB_MIC_VOL; 2095 strcpy(dip->un.e.member[1].label.name, AudioNcd); 2096 dip->un.e.member[1].ord = SB_CD_VOL; 2097 strcpy(dip->un.e.member[2].label.name, AudioNline); 2098 dip->un.e.member[2].ord = SB_LINE_IN_VOL; 2099 } 2100 return 0; 2101 2102 case SB_BASS: 2103 dip->prev = dip->next = AUDIO_MIXER_LAST; 2104 strcpy(dip->label.name, AudioNbass); 2105 if (sc->sc_mixer_model == SBM_CT1745) { 2106 dip->type = AUDIO_MIXER_VALUE; 2107 dip->mixer_class = SB_EQUALIZATION_CLASS; 2108 dip->un.v.num_channels = 2; 2109 strcpy(dip->un.v.units.name, AudioNbass); 2110 } else { 2111 dip->type = AUDIO_MIXER_ENUM; 2112 dip->mixer_class = SB_INPUT_CLASS; 2113 dip->un.e.num_mem = 2; 2114 strcpy(dip->un.e.member[0].label.name, AudioNoff); 2115 dip->un.e.member[0].ord = 0; 2116 strcpy(dip->un.e.member[1].label.name, AudioNon); 2117 dip->un.e.member[1].ord = 1; 2118 } 2119 return 0; 2120 2121 case SB_TREBLE: 2122 dip->prev = dip->next = AUDIO_MIXER_LAST; 2123 strcpy(dip->label.name, AudioNtreble); 2124 if (sc->sc_mixer_model == SBM_CT1745) { 2125 dip->type = AUDIO_MIXER_VALUE; 2126 dip->mixer_class = SB_EQUALIZATION_CLASS; 2127 dip->un.v.num_channels = 2; 2128 strcpy(dip->un.v.units.name, AudioNtreble); 2129 } else { 2130 dip->type = AUDIO_MIXER_ENUM; 2131 dip->mixer_class = SB_INPUT_CLASS; 2132 dip->un.e.num_mem = 2; 2133 strcpy(dip->un.e.member[0].label.name, AudioNoff); 2134 dip->un.e.member[0].ord = 0; 2135 strcpy(dip->un.e.member[1].label.name, AudioNon); 2136 dip->un.e.member[1].ord = 1; 2137 } 2138 return 0; 2139 2140 case SB_RECORD_CLASS: /* record source class */ 2141 dip->type = AUDIO_MIXER_CLASS; 2142 dip->mixer_class = SB_RECORD_CLASS; 2143 dip->next = dip->prev = AUDIO_MIXER_LAST; 2144 strcpy(dip->label.name, AudioCrecord); 2145 return 0; 2146 2147 case SB_INPUT_CLASS: 2148 dip->type = AUDIO_MIXER_CLASS; 2149 dip->mixer_class = SB_INPUT_CLASS; 2150 dip->next = dip->prev = AUDIO_MIXER_LAST; 2151 strcpy(dip->label.name, AudioCinputs); 2152 return 0; 2153 2154 } 2155 2156 if (sc->sc_mixer_model == SBM_CT1345) 2157 return ENXIO; 2158 2159 switch(dip->index) { 2160 case SB_PCSPEAKER: 2161 dip->type = AUDIO_MIXER_VALUE; 2162 dip->mixer_class = SB_INPUT_CLASS; 2163 dip->prev = dip->next = AUDIO_MIXER_LAST; 2164 strcpy(dip->label.name, "pc_speaker"); 2165 dip->un.v.num_channels = 1; 2166 strcpy(dip->un.v.units.name, AudioNvolume); 2167 return 0; 2168 2169 case SB_INPUT_GAIN: 2170 dip->type = AUDIO_MIXER_VALUE; 2171 dip->mixer_class = SB_INPUT_CLASS; 2172 dip->prev = dip->next = AUDIO_MIXER_LAST; 2173 strcpy(dip->label.name, AudioNinput); 2174 dip->un.v.num_channels = 2; 2175 strcpy(dip->un.v.units.name, AudioNvolume); 2176 return 0; 2177 2178 case SB_OUTPUT_GAIN: 2179 dip->type = AUDIO_MIXER_VALUE; 2180 dip->mixer_class = SB_OUTPUT_CLASS; 2181 dip->prev = dip->next = AUDIO_MIXER_LAST; 2182 strcpy(dip->label.name, AudioNoutput); 2183 dip->un.v.num_channels = 2; 2184 strcpy(dip->un.v.units.name, AudioNvolume); 2185 return 0; 2186 2187 case SB_AGC: 2188 dip->type = AUDIO_MIXER_ENUM; 2189 dip->mixer_class = SB_INPUT_CLASS; 2190 dip->prev = dip->next = AUDIO_MIXER_LAST; 2191 strcpy(dip->label.name, "agc"); 2192 dip->un.e.num_mem = 2; 2193 strcpy(dip->un.e.member[0].label.name, AudioNoff); 2194 dip->un.e.member[0].ord = 0; 2195 strcpy(dip->un.e.member[1].label.name, AudioNon); 2196 dip->un.e.member[1].ord = 1; 2197 return 0; 2198 2199 case SB_EQUALIZATION_CLASS: 2200 dip->type = AUDIO_MIXER_CLASS; 2201 dip->mixer_class = SB_EQUALIZATION_CLASS; 2202 dip->next = dip->prev = AUDIO_MIXER_LAST; 2203 strcpy(dip->label.name, AudioCequalization); 2204 return 0; 2205 2206 case SB_CD_IN_MUTE: 2207 dip->prev = SB_CD_VOL; 2208 dip->next = SB_CD_SWAP; 2209 dip->mixer_class = SB_INPUT_CLASS; 2210 goto mute; 2211 2212 case SB_MIC_IN_MUTE: 2213 dip->prev = SB_MIC_VOL; 2214 dip->next = SB_MIC_SWAP; 2215 dip->mixer_class = SB_INPUT_CLASS; 2216 goto mute; 2217 2218 case SB_LINE_IN_MUTE: 2219 dip->prev = SB_LINE_IN_VOL; 2220 dip->next = SB_LINE_SWAP; 2221 dip->mixer_class = SB_INPUT_CLASS; 2222 goto mute; 2223 2224 case SB_MIDI_IN_MUTE: 2225 dip->prev = SB_MIDI_VOL; 2226 dip->next = SB_MIDI_SWAP; 2227 dip->mixer_class = SB_INPUT_CLASS; 2228 goto mute; 2229 2230 case SB_CD_SWAP: 2231 dip->prev = SB_CD_IN_MUTE; 2232 dip->next = SB_CD_OUT_MUTE; 2233 goto swap; 2234 2235 case SB_MIC_SWAP: 2236 dip->prev = SB_MIC_IN_MUTE; 2237 dip->next = SB_MIC_OUT_MUTE; 2238 goto swap; 2239 2240 case SB_LINE_SWAP: 2241 dip->prev = SB_LINE_IN_MUTE; 2242 dip->next = SB_LINE_OUT_MUTE; 2243 goto swap; 2244 2245 case SB_MIDI_SWAP: 2246 dip->prev = SB_MIDI_IN_MUTE; 2247 dip->next = AUDIO_MIXER_LAST; 2248 swap: 2249 dip->mixer_class = SB_INPUT_CLASS; 2250 strcpy(dip->label.name, AudioNswap); 2251 goto mute1; 2252 2253 case SB_CD_OUT_MUTE: 2254 dip->prev = SB_CD_SWAP; 2255 dip->next = AUDIO_MIXER_LAST; 2256 dip->mixer_class = SB_OUTPUT_CLASS; 2257 goto mute; 2258 2259 case SB_MIC_OUT_MUTE: 2260 dip->prev = SB_MIC_SWAP; 2261 dip->next = AUDIO_MIXER_LAST; 2262 dip->mixer_class = SB_OUTPUT_CLASS; 2263 goto mute; 2264 2265 case SB_LINE_OUT_MUTE: 2266 dip->prev = SB_LINE_SWAP; 2267 dip->next = AUDIO_MIXER_LAST; 2268 dip->mixer_class = SB_OUTPUT_CLASS; 2269 mute: 2270 strcpy(dip->label.name, AudioNmute); 2271 mute1: 2272 dip->type = AUDIO_MIXER_ENUM; 2273 dip->un.e.num_mem = 2; 2274 strcpy(dip->un.e.member[0].label.name, AudioNoff); 2275 dip->un.e.member[0].ord = 0; 2276 strcpy(dip->un.e.member[1].label.name, AudioNon); 2277 dip->un.e.member[1].ord = 1; 2278 return 0; 2279 2280 } 2281 2282 return ENXIO; 2283 } 2284 2285 void * 2286 sb_malloc(void *addr, int direction, size_t size, 2287 struct malloc_type *pool, int flags) 2288 { 2289 struct sbdsp_softc *sc; 2290 int drq; 2291 2292 sc = addr; 2293 if (sc->sc_drq8 != -1) 2294 drq = sc->sc_drq8; 2295 else 2296 drq = sc->sc_drq16; 2297 return isa_malloc(sc->sc_ic, drq, size, pool, flags); 2298 } 2299 2300 void 2301 sb_free(void *addr, void *ptr, struct malloc_type *pool) 2302 { 2303 2304 isa_free(ptr, pool); 2305 } 2306 2307 size_t 2308 sb_round_buffersize(void *addr, int direction, size_t size) 2309 { 2310 struct sbdsp_softc *sc; 2311 bus_size_t maxsize; 2312 2313 sc = addr; 2314 if (sc->sc_drq8 != -1) 2315 maxsize = sc->sc_drq8_maxsize; 2316 else 2317 maxsize = sc->sc_drq16_maxsize; 2318 2319 if (size > maxsize) 2320 size = maxsize; 2321 return size; 2322 } 2323 2324 paddr_t 2325 sb_mappage(void *addr, void *mem, off_t off, int prot) 2326 { 2327 2328 return isa_mappage(mem, off, prot); 2329 } 2330 2331 int 2332 sbdsp_get_props(void *addr) 2333 { 2334 struct sbdsp_softc *sc; 2335 2336 sc = addr; 2337 return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | 2338 (sc->sc_fullduplex ? AUDIO_PROP_FULLDUPLEX : 0); 2339 } 2340 2341 #if NMPU > 0 2342 /* 2343 * MIDI related routines. 2344 */ 2345 2346 int 2347 sbdsp_midi_open(void *addr, int flags, void (*iintr)(void *, int), 2348 void (*ointr)(void *), void *arg) 2349 { 2350 struct sbdsp_softc *sc; 2351 2352 sc = addr; 2353 DPRINTF(("sbdsp_midi_open: sc=%p\n", sc)); 2354 2355 if (sc->sc_open != SB_CLOSED) 2356 return EBUSY; 2357 if (sbdsp_reset(sc) != 0) 2358 return EIO; 2359 2360 sc->sc_open = SB_OPEN_MIDI; 2361 2362 if (sc->sc_model >= SB_20) 2363 if (sbdsp_wdsp(sc, SB_MIDI_UART_INTR)) /* enter UART mode */ 2364 return EIO; 2365 2366 sc->sc_intr8 = sbdsp_midi_intr; 2367 sc->sc_intrm = iintr; 2368 sc->sc_argm = arg; 2369 2370 return 0; 2371 } 2372 2373 void 2374 sbdsp_midi_close(void *addr) 2375 { 2376 struct sbdsp_softc *sc; 2377 2378 sc = addr; 2379 DPRINTF(("sbdsp_midi_close: sc=%p\n", sc)); 2380 2381 if (sc->sc_model >= SB_20) 2382 sbdsp_reset(sc); /* exit UART mode */ 2383 2384 sc->sc_intrm = 0; 2385 sc->sc_open = SB_CLOSED; 2386 } 2387 2388 int 2389 sbdsp_midi_output(void *addr, int d) 2390 { 2391 struct sbdsp_softc *sc; 2392 2393 sc = addr; 2394 if (sc->sc_model < SB_20 && sbdsp_wdsp(sc, SB_MIDI_WRITE)) 2395 return EIO; 2396 if (sbdsp_wdsp(sc, d)) 2397 return EIO; 2398 return 0; 2399 } 2400 2401 void 2402 sbdsp_midi_getinfo(void *addr, struct midi_info *mi) 2403 { 2404 struct sbdsp_softc *sc; 2405 2406 sc = addr; 2407 mi->name = sc->sc_model < SB_20 ? "SB MIDI cmd" : "SB MIDI UART"; 2408 mi->props = MIDI_PROP_CAN_INPUT; 2409 } 2410 2411 int 2412 sbdsp_midi_intr(void *addr) 2413 { 2414 struct sbdsp_softc *sc; 2415 2416 sc = addr; 2417 sc->sc_intrm(sc->sc_argm, sbdsp_rdsp(sc)); 2418 return (0); 2419 } 2420 2421 #endif 2422 2423