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