pas.c revision 1.30
1/* $NetBSD: pas.c,v 1.30 1997/07/27 23:51:57 augustss Exp $ */ 2 3/* 4 * Copyright (c) 1991-1993 Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the Computer Systems 18 * Engineering Group at Lawrence Berkeley Laboratory. 19 * 4. Neither the name of the University nor of the Laboratory may be used 20 * to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 */ 36/* 37 * jfw 7/13/97 - The soundblaster code requires the generic bus-space 38 * structures to be set up properly. Rather than go to the effort of making 39 * code for a dead line fully generic, properly set up the SB structures and 40 * leave the rest x86/ISA/default-configuration specific. If you have a 41 * REAL computer, go buy a REAL sound card. 42 */ 43/* 44 * Todo: 45 * - look at other PAS drivers (for PAS native suport) 46 * - use common sb.c once emulation is setup 47 */ 48 49#include <sys/param.h> 50#include <sys/systm.h> 51#include <sys/errno.h> 52#include <sys/ioctl.h> 53#include <sys/syslog.h> 54#include <sys/device.h> 55#include <sys/proc.h> 56 57#include <machine/cpu.h> 58#include <machine/intr.h> 59#include <machine/bus.h> 60#include <machine/pio.h> 61 62#include <sys/audioio.h> 63#include <dev/audio_if.h> 64 65#include <dev/isa/isavar.h> 66#include <dev/isa/isadmavar.h> 67 68#include <dev/isa/sbdspvar.h> 69#include <dev/isa/sbreg.h> 70 71#define DEFINE_TRANSLATIONS 72#include <dev/isa/pasreg.h> 73 74#ifdef AUDIO_DEBUG 75#define DPRINTF(x) if (pasdebug) printf x 76int pasdebug = 0; 77#else 78#define DPRINTF(x) 79#endif 80 81/* 82 * Software state, per SoundBlaster card. 83 * The soundblaster has multiple functionality, which we must demultiplex. 84 * One approach is to have one major device number for the soundblaster card, 85 * and use different minor numbers to indicate which hardware function 86 * we want. This would make for one large driver. Instead our approach 87 * is to partition the design into a set of drivers that share an underlying 88 * piece of hardware. Most things are hard to share, for example, the audio 89 * and midi ports. For audio, we might want to mix two processes' signals, 90 * and for midi we might want to merge streams (this is hard due to 91 * running status). Moreover, we should be able to re-use the high-level 92 * modules with other kinds of hardware. In this module, we only handle the 93 * most basic communications with the sb card. 94 */ 95struct pas_softc { 96 struct sbdsp_softc sc_sbdsp; /* base device, &c. */ 97 98 int model; 99 int rev; 100}; 101 102int pasopen __P((dev_t, int)); 103int pas_getdev __P((void *, struct audio_device *)); 104void pasconf __P((int, int, int, int)); 105 106 107/* 108 * Define our interface to the higher level audio driver. 109 */ 110 111struct audio_hw_if pas_hw_if = { 112 pasopen, 113 sbdsp_close, 114 0, 115 sbdsp_query_encoding, 116 sbdsp_set_params, 117 sbdsp_round_blocksize, 118 sbdsp_set_out_port, 119 sbdsp_get_out_port, 120 sbdsp_set_in_port, 121 sbdsp_get_in_port, 122 0, 123 0, 124 0, 125 sbdsp_dma_output, 126 sbdsp_dma_input, 127 sbdsp_haltdma, 128 sbdsp_haltdma, 129 sbdsp_contdma, 130 sbdsp_contdma, 131 sbdsp_speaker_ctl, 132 pas_getdev, 133 0, 134 sbdsp_mixer_set_port, 135 sbdsp_mixer_get_port, 136 sbdsp_mixer_query_devinfo, 137 sb_malloc, 138 sb_free, 139 sb_round, 140 0, 141 0 142}; 143 144/* The Address Translation code is used to convert I/O register addresses to 145 be relative to the given base -register */ 146 147static char *pasnames[] = { 148 "", 149 "Plus", 150 "CDPC", 151 "16", 152 "16Basic" 153}; 154 155static struct audio_device pas_device = { 156 "PAS,??", 157 "", 158 "pas" 159}; 160 161/*XXX assume default I/O base address */ 162#define pasread(p) inb(p) 163#define paswrite(d, p) outb(p, d) 164 165void 166pasconf(model, sbbase, sbirq, sbdrq) 167 int model; 168 int sbbase; 169 int sbirq; 170 int sbdrq; 171{ 172 paswrite(0x00, INTERRUPT_MASK); 173 /* Local timer control register */ 174 paswrite(0x36, SAMPLE_COUNTER_CONTROL); 175 /* Sample rate timer (16 bit) */ 176 paswrite(0x36, SAMPLE_RATE_TIMER); 177 paswrite(0, SAMPLE_RATE_TIMER); 178 /* Local timer control register */ 179 paswrite(0x74, SAMPLE_COUNTER_CONTROL); 180 /* Sample count register (16 bit) */ 181 paswrite(0x74, SAMPLE_BUFFER_COUNTER); 182 paswrite(0, SAMPLE_BUFFER_COUNTER); 183 184 paswrite(P_C_PCM_MONO | P_C_PCM_DAC_MODE | 185 P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R, 186 PCM_CONTROL); 187 paswrite(S_M_PCM_RESET | S_M_FM_RESET | 188 S_M_SB_RESET | S_M_MIXER_RESET, SERIAL_MIXER); 189 190/*XXX*/ 191 paswrite(I_C_1_BOOT_RESET_ENABLE|1, IO_CONFIGURATION_1); 192 193 paswrite(I_C_2_PCM_DMA_DISABLED, IO_CONFIGURATION_2); 194 paswrite(I_C_3_PCM_IRQ_DISABLED, IO_CONFIGURATION_3); 195 196#ifdef BROKEN_BUS_CLOCK 197 paswrite(S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | 198 S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1); 199#else 200 paswrite(S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, 201 SYSTEM_CONFIGURATION_1); 202#endif 203 204 /*XXX*/ 205 paswrite(0, SYSTEM_CONFIGURATION_2); 206 paswrite(0, SYSTEM_CONFIGURATION_3); 207 208 /* Sets mute off and selects filter rate of 17.897 kHz */ 209 paswrite(F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY); 210 211 if (model == PAS_16 || model == PAS_16BASIC) 212 paswrite(8, PRESCALE_DIVIDER); 213 else 214 paswrite(0, PRESCALE_DIVIDER); 215 216 paswrite(P_M_MV508_ADDRESS | P_M_MV508_PCM, PARALLEL_MIXER); 217 paswrite(5, PARALLEL_MIXER); 218 219 /* 220 * Setup SoundBlaster emulation. 221 */ 222 paswrite((sbbase >> 4) & 0xf, EMULATION_ADDRESS); 223 paswrite(E_C_SB_IRQ_translate[sbirq] | E_C_SB_DMA_translate[sbdrq], 224 EMULATION_CONFIGURATION); 225 paswrite(C_E_SB_ENABLE, COMPATIBILITY_ENABLE); 226 227 /* 228 * Set mid-range levels. 229 */ 230 paswrite(P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER); 231 paswrite(P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_NONE, PARALLEL_MIXER); 232 233 paswrite(P_M_MV508_ADDRESS | P_M_MV508_MASTER_A, PARALLEL_MIXER); 234 paswrite(50, PARALLEL_MIXER); 235 paswrite(P_M_MV508_ADDRESS | P_M_MV508_MASTER_B, PARALLEL_MIXER); 236 paswrite(50, PARALLEL_MIXER); 237 238 paswrite(P_M_MV508_ADDRESS | P_M_MV508_MIXER | P_M_MV508_SB, PARALLEL_MIXER); 239 paswrite(P_M_MV508_OUTPUTMIX | 30, PARALLEL_MIXER); 240 241 paswrite(P_M_MV508_ADDRESS | P_M_MV508_MIXER | P_M_MV508_MIC, PARALLEL_MIXER); 242 paswrite(P_M_MV508_INPUTMIX | 30, PARALLEL_MIXER); 243} 244 245int pasprobe __P((struct device *, void *, void *)); 246void pasattach __P((struct device *, struct device *, void *)); 247 248struct cfattach pas_ca = { 249 sizeof(struct pas_softc), pasprobe, pasattach 250}; 251 252struct cfdriver pas_cd = { 253 NULL, "pas", DV_DULL 254}; 255 256/* 257 * Probe / attach routines. 258 */ 259 260/* 261 * Probe for the soundblaster hardware. 262 */ 263int 264pasprobe(parent, match, aux) 265 struct device *parent; 266 void *match, *aux; 267{ 268 register struct pas_softc *sc = match; 269 register struct isa_attach_args *ia = aux; 270 register int iobase; 271 u_char id, t; 272 273 /* ensure we can set this up as a sound blaster */ 274 if (!SB_BASE_VALID(ia->ia_iobase)) { 275 printf("pas: configured SB iobase 0x%x invalid\n", ia->ia_iobase); 276 return 0; 277 } 278 279 /* 280 * WARNING: Setting an option like W:1 or so that disables 281 * warm boot reset of the card will screw up this detect code 282 * something fierce. Adding code to handle this means possibly 283 * interfering with other cards on the bus if you have something 284 * on base port 0x388. SO be forewarned. 285 */ 286 /* Talk to first board */ 287 outb(MASTER_DECODE, 0xbc); 288 /* Set base address */ 289 290#if 0 291 /* XXX Need to setup pseudo device */ 292 /* XXX What are good io addrs ? */ 293 if (iobase != PAS_DEFAULT_BASE) { 294 printf("pas: configured iobase %d invalid\n", iobase); 295 return 0; 296 } 297#else 298 /* Start out talking to native PAS */ 299 iobase = PAS_DEFAULT_BASE; 300#endif 301 302 outb(MASTER_DECODE, iobase >> 2); 303 /* One wait-state */ 304 paswrite(1, WAIT_STATE); 305 306 id = pasread(INTERRUPT_MASK); 307 if (id == 0xff || id == 0xfe) { 308 /* sanity */ 309 DPRINTF(("pas: bogus card id\n")); 310 return 0; 311 } 312 /* 313 * We probably have a PAS-series board, now check for a 314 * PAS2-series board by trying to change the board revision 315 * bits. PAS2-series hardware won't let you do this because 316 * the bits are read-only. 317 */ 318 t = id ^ 0xe0; 319 paswrite(t, INTERRUPT_MASK); 320 t = inb(INTERRUPT_MASK); 321 paswrite(id, INTERRUPT_MASK); 322 323 if (t != id) { 324 /* Not a PAS2 */ 325 printf("pas: detected card but PAS2 test failed\n"); 326 return 0; 327 } 328 /*XXX*/ 329 t = pasread(OPERATION_MODE_1) & 0xf; 330 sc->model = O_M_1_to_card[t]; 331 if (sc->model != 0) { 332 sc->rev = pasread(BOARD_REV_ID); 333 } 334 else { 335 DPRINTF(("pas: bogus model id\n")); 336 return 0; 337 } 338 339 if (sc->model >= 0) { 340 if (ia->ia_irq == IRQUNK) { 341 printf("pas: sb emulation requires known irq\n"); 342 return (0); 343 } 344 pasconf(sc->model, ia->ia_iobase, ia->ia_irq, 1); 345 } else { 346 DPRINTF(("pas: could not probe pas\n")); 347 return (0); 348 } 349 350 /* Now a SoundBlaster, so set up proper bus-space hooks 351 * appropriately 352 */ 353 354 sc->sc_sbdsp.sc_iobase = ia->ia_iobase; 355 sc->sc_sbdsp.sc_iot = ia->ia_iot; 356 357 /* Map i/o space [we map 24 ports which is the max of the sb and pro */ 358 if (bus_space_map(sc->sc_sbdsp.sc_iot, ia->ia_iobase, SBP_NPORT, 0, 359 &sc->sc_sbdsp.sc_ioh)) { 360 printf("pas: can't map i/o space 0x%x/%d in probe\n", 361 ia->ia_iobase, SBP_NPORT); 362 return 0; 363 } 364 365 if (sbdsp_reset(&sc->sc_sbdsp) < 0) { 366 DPRINTF(("pas: couldn't reset card\n")); 367 goto unmap; 368 } 369 370 /* 371 * Cannot auto-discover DMA channel. 372 */ 373 if (!SB_DRQ_VALID(ia->ia_drq)) { 374 printf("pas: configured dma chan %d invalid\n", ia->ia_drq); 375 goto unmap; 376 } 377#ifdef NEWCONFIG 378 /* 379 * If the IRQ wasn't compiled in, auto-detect it. 380 */ 381 if (ia->ia_irq == IRQUNK) { 382 ia->ia_irq = isa_discoverintr(pasforceintr, aux); 383 sbdsp_reset(&sc->sc_sbdsp); 384 if (!SB_IRQ_VALID(ia->ia_irq)) { 385 printf("pas: couldn't auto-detect interrupt"); 386 goto unmap; 387 } 388 } else 389#endif 390 if (!SB_IRQ_VALID(ia->ia_irq)) { 391 printf("pas: configured irq chan %d invalid\n", ia->ia_irq); 392 goto unmap; 393 } 394 395 sc->sc_sbdsp.sc_irq = ia->ia_irq; 396 sc->sc_sbdsp.sc_drq8 = ia->ia_drq; 397 sc->sc_sbdsp.sc_drq16 = -1; /* XXX */ 398 399 if (sbdsp_probe(&sc->sc_sbdsp) == 0) { 400 DPRINTF(("pas: sbdsp probe failed\n")); 401 goto unmap; 402 } 403 404 ia->ia_iosize = SB_NPORT; 405 return 1; 406 407 unmap: 408 bus_space_unmap(sc->sc_sbdsp.sc_iot, sc->sc_sbdsp.sc_ioh, SBP_NPORT); 409 return 0; 410} 411 412#ifdef NEWCONFIG 413void 414pasforceintr(aux) 415 void *aux; 416{ 417 static char dmabuf; 418 struct isa_attach_args *ia = aux; 419 int iobase = ia->ia_iobase; 420 421 /* 422 * Set up a DMA read of one byte. 423 * XXX Note that at this point we haven't called 424 * at_setup_dmachan(). This is okay because it just 425 * allocates a buffer in case it needs to make a copy, 426 * and it won't need to make a copy for a 1 byte buffer. 427 * (I think that calling at_setup_dmachan() should be optional; 428 * if you don't call it, it will be called the first time 429 * it is needed (and you pay the latency). Also, you might 430 * never need the buffer anyway.) 431 */ 432 at_dma(DMAMODE_READ, &dmabuf, 1, ia->ia_drq); 433 if (pas_wdsp(iobase, SB_DSP_RDMA) == 0) { 434 (void)pas_wdsp(iobase, 0); 435 (void)pas_wdsp(iobase, 0); 436 } 437} 438#endif 439 440/* 441 * Attach hardware to driver, attach hardware driver to audio 442 * pseudo-device driver . 443 */ 444void 445pasattach(parent, self, aux) 446 struct device *parent, *self; 447 void *aux; 448{ 449 register struct pas_softc *sc = (struct pas_softc *)self; 450 struct isa_attach_args *ia = (struct isa_attach_args *)aux; 451 register int iobase = ia->ia_iobase; 452 int err; 453 454 sc->sc_sbdsp.sc_iobase = iobase; 455 sc->sc_sbdsp.sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, 456 IST_EDGE, IPL_AUDIO, sbdsp_intr, &sc->sc_sbdsp); 457 458 sc->sc_sbdsp.sc_isa = parent; 459 460 printf(" ProAudio Spectrum %s [rev %d] ", pasnames[sc->model], 461 sc->rev); 462 463 sbdsp_attach(&sc->sc_sbdsp); 464 465 sprintf(pas_device.name, "pas,%s", pasnames[sc->model]); 466 sprintf(pas_device.version, "%d", sc->rev); 467 468 if ((err = audio_hardware_attach(&pas_hw_if, &sc->sc_sbdsp)) != 0) 469 printf("pas: could not attach to audio pseudo-device driver (%d)\n", err); 470} 471 472int 473pasopen(dev, flags) 474 dev_t dev; 475 int flags; 476{ 477 struct pas_softc *sc; 478 int unit = AUDIOUNIT(dev); 479 480 if (unit >= pas_cd.cd_ndevs) 481 return ENODEV; 482 483 sc = pas_cd.cd_devs[unit]; 484 if (!sc) 485 return ENXIO; 486 487 return sbdsp_open(&sc->sc_sbdsp, dev, flags); 488} 489 490int 491pas_getdev(addr, retp) 492 void *addr; 493 struct audio_device *retp; 494{ 495 *retp = pas_device; 496 return 0; 497} 498