pas.c revision 1.18
1/* $NetBSD: pas.c,v 1.18 1996/10/10 22:05:10 christos 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 * Todo: 38 * - look at other PAS drivers (for PAS native suport) 39 * - use common sb.c once emulation is setup 40 */ 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/errno.h> 45#include <sys/ioctl.h> 46#include <sys/syslog.h> 47#include <sys/device.h> 48#include <sys/proc.h> 49 50#include <machine/cpu.h> 51#include <machine/intr.h> 52#include <machine/pio.h> 53 54#include <sys/audioio.h> 55#include <dev/audio_if.h> 56#include <dev/mulaw.h> 57 58#include <dev/isa/isavar.h> 59#include <dev/isa/isadmavar.h> 60 61#include <dev/isa/sbdspvar.h> 62#include <dev/isa/sbreg.h> 63 64#define DEFINE_TRANSLATIONS 65#include <dev/isa/pasreg.h> 66 67#ifdef AUDIO_DEBUG 68#define DPRINTF(x) if (pasdebug) kprintf x 69int pasdebug = 0; 70#else 71#define DPRINTF(x) 72#endif 73 74/* 75 * Software state, per SoundBlaster card. 76 * The soundblaster has multiple functionality, which we must demultiplex. 77 * One approach is to have one major device number for the soundblaster card, 78 * and use different minor numbers to indicate which hardware function 79 * we want. This would make for one large driver. Instead our approach 80 * is to partition the design into a set of drivers that share an underlying 81 * piece of hardware. Most things are hard to share, for example, the audio 82 * and midi ports. For audio, we might want to mix two processes' signals, 83 * and for midi we might want to merge streams (this is hard due to 84 * running status). Moreover, we should be able to re-use the high-level 85 * modules with other kinds of hardware. In this module, we only handle the 86 * most basic communications with the sb card. 87 */ 88struct pas_softc { 89 struct device sc_dev; /* base device */ 90 struct isadev sc_id; /* ISA device */ 91 void *sc_ih; /* interrupt vectoring */ 92 93 int sc_iobase; /* PAS iobase */ 94 int sc_irq; /* PAS irq */ 95 int sc_drq; /* PAS drq */ 96 97 int model; 98 int rev; 99 100 struct sbdsp_softc sc_sbdsp; 101}; 102 103int pasopen __P((dev_t, int)); 104int pas_getdev __P((void *, struct audio_device *)); 105void pasconf __P((int, int, int, int)); 106 107 108/* 109 * Define our interface to the higher level audio driver. 110 */ 111 112struct audio_hw_if pas_hw_if = { 113 pasopen, 114 sbdsp_close, 115 NULL, 116 sbdsp_set_in_sr, 117 sbdsp_get_in_sr, 118 sbdsp_set_out_sr, 119 sbdsp_get_out_sr, 120 sbdsp_query_encoding, 121 sbdsp_set_encoding, 122 sbdsp_get_encoding, 123 sbdsp_set_precision, 124 sbdsp_get_precision, 125 sbdsp_set_channels, 126 sbdsp_get_channels, 127 sbdsp_round_blocksize, 128 sbdsp_set_out_port, 129 sbdsp_get_out_port, 130 sbdsp_set_in_port, 131 sbdsp_get_in_port, 132 sbdsp_commit_settings, 133 sbdsp_get_silence, 134 mulaw_expand, 135 mulaw_compress, 136 sbdsp_dma_output, 137 sbdsp_dma_input, 138 sbdsp_haltdma, 139 sbdsp_haltdma, 140 sbdsp_contdma, 141 sbdsp_contdma, 142 sbdsp_speaker_ctl, 143 pas_getdev, 144 sbdsp_setfd, 145 sbdsp_mixer_set_port, 146 sbdsp_mixer_get_port, 147 sbdsp_mixer_query_devinfo, 148 0, /* not full-duplex */ 149 0 150}; 151 152/* The Address Translation code is used to convert I/O register addresses to 153 be relative to the given base -register */ 154 155static char *pasnames[] = { 156 "", 157 "Plus", 158 "CDPC", 159 "16", 160 "16Basic" 161}; 162 163static struct audio_device pas_device = { 164 "PAS,??", 165 "", 166 "pas" 167}; 168 169/*XXX assume default I/O base address */ 170#define pasread(p) inb(p) 171#define paswrite(d, p) outb(p, d) 172 173void 174pasconf(model, sbbase, sbirq, sbdrq) 175 int model; 176 int sbbase; 177 int sbirq; 178 int sbdrq; 179{ 180 paswrite(0x00, INTERRUPT_MASK); 181 /* Local timer control register */ 182 paswrite(0x36, SAMPLE_COUNTER_CONTROL); 183 /* Sample rate timer (16 bit) */ 184 paswrite(0x36, SAMPLE_RATE_TIMER); 185 paswrite(0, SAMPLE_RATE_TIMER); 186 /* Local timer control register */ 187 paswrite(0x74, SAMPLE_COUNTER_CONTROL); 188 /* Sample count register (16 bit) */ 189 paswrite(0x74, SAMPLE_BUFFER_COUNTER); 190 paswrite(0, SAMPLE_BUFFER_COUNTER); 191 192 paswrite(P_C_PCM_MONO | P_C_PCM_DAC_MODE | 193 P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R, 194 PCM_CONTROL); 195 paswrite(S_M_PCM_RESET | S_M_FM_RESET | 196 S_M_SB_RESET | S_M_MIXER_RESET, SERIAL_MIXER); 197 198/*XXX*/ 199 paswrite(I_C_1_BOOT_RESET_ENABLE|1, IO_CONFIGURATION_1); 200 201 paswrite(I_C_2_PCM_DMA_DISABLED, IO_CONFIGURATION_2); 202 paswrite(I_C_3_PCM_IRQ_DISABLED, IO_CONFIGURATION_3); 203 204#ifdef BROKEN_BUS_CLOCK 205 paswrite(S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | 206 S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1); 207#else 208 paswrite(S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, 209 SYSTEM_CONFIGURATION_1); 210#endif 211 212 /*XXX*/ 213 paswrite(0, SYSTEM_CONFIGURATION_2); 214 paswrite(0, SYSTEM_CONFIGURATION_3); 215 216 /* Sets mute off and selects filter rate of 17.897 kHz */ 217 paswrite(F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY); 218 219 if (model == PAS_16 || model == PAS_16BASIC) 220 paswrite(8, PRESCALE_DIVIDER); 221 else 222 paswrite(0, PRESCALE_DIVIDER); 223 224 paswrite(P_M_MV508_ADDRESS | P_M_MV508_PCM, PARALLEL_MIXER); 225 paswrite(5, PARALLEL_MIXER); 226 227 /* 228 * Setup SoundBlaster emulation. 229 */ 230 paswrite((sbbase >> 4) & 0xf, EMULATION_ADDRESS); 231 paswrite(E_C_SB_IRQ_translate[sbirq] | E_C_SB_DMA_translate[sbdrq], 232 EMULATION_CONFIGURATION); 233 paswrite(C_E_SB_ENABLE, COMPATIBILITY_ENABLE); 234 235 /* 236 * Set mid-range levels. 237 */ 238 paswrite(P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER); 239 paswrite(P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_NONE, PARALLEL_MIXER); 240 241 paswrite(P_M_MV508_ADDRESS | P_M_MV508_MASTER_A, PARALLEL_MIXER); 242 paswrite(50, PARALLEL_MIXER); 243 paswrite(P_M_MV508_ADDRESS | P_M_MV508_MASTER_B, PARALLEL_MIXER); 244 paswrite(50, PARALLEL_MIXER); 245 246 paswrite(P_M_MV508_ADDRESS | P_M_MV508_MIXER | P_M_MV508_SB, PARALLEL_MIXER); 247 paswrite(P_M_MV508_OUTPUTMIX | 30, PARALLEL_MIXER); 248 249 paswrite(P_M_MV508_ADDRESS | P_M_MV508_MIXER | P_M_MV508_MIC, PARALLEL_MIXER); 250 paswrite(P_M_MV508_INPUTMIX | 30, PARALLEL_MIXER); 251} 252 253int pasprobe __P((struct device *, void *, void *)); 254void pasattach __P((struct device *, struct device *, void *)); 255 256struct cfattach pas_ca = { 257 sizeof(struct pas_softc), pasprobe, pasattach 258}; 259 260struct cfdriver pas_cd = { 261 NULL, "pas", DV_DULL 262}; 263 264/* 265 * Probe / attach routines. 266 */ 267 268/* 269 * Probe for the soundblaster hardware. 270 */ 271int 272pasprobe(parent, match, aux) 273 struct device *parent; 274 void *match, *aux; 275{ 276 register struct pas_softc *sc = match; 277 register struct isa_attach_args *ia = aux; 278 register int iobase; 279 u_char id, t; 280 281 /* 282 * WARNING: Setting an option like W:1 or so that disables 283 * warm boot reset of the card will screw up this detect code 284 * something fierce. Adding code to handle this means possibly 285 * interfering with other cards on the bus if you have something 286 * on base port 0x388. SO be forewarned. 287 */ 288 /* Talk to first board */ 289 outb(MASTER_DECODE, 0xbc); 290 /* Set base address */ 291 292#if 0 293 /* XXX Need to setup pseudo device */ 294 /* XXX What are good io addrs ? */ 295 if (iobase != PAS_DEFAULT_BASE) { 296 kprintf("pas: configured iobase %d invalid\n", iobase); 297 return 0; 298 } 299#else 300 /* Start out talking to native PAS */ 301 iobase = PAS_DEFAULT_BASE; 302#endif 303 304 outb(MASTER_DECODE, iobase >> 2); 305 /* One wait-state */ 306 paswrite(1, WAIT_STATE); 307 308 id = pasread(INTERRUPT_MASK); 309 if (id == 0xff || id == 0xfe) { 310 /* sanity */ 311 DPRINTF(("pas: bogus card id\n")); 312 return 0; 313 } 314 /* 315 * We probably have a PAS-series board, now check for a 316 * PAS2-series board by trying to change the board revision 317 * bits. PAS2-series hardware won't let you do this because 318 * the bits are read-only. 319 */ 320 t = id ^ 0xe0; 321 paswrite(t, INTERRUPT_MASK); 322 t = inb(INTERRUPT_MASK); 323 paswrite(id, INTERRUPT_MASK); 324 325 if (t != id) { 326 /* Not a PAS2 */ 327 kprintf("pas: detected card but PAS2 test failed\n"); 328 return 0; 329 } 330 /*XXX*/ 331 t = pasread(OPERATION_MODE_1) & 0xf; 332 sc->model = O_M_1_to_card[t]; 333 if (sc->model != 0) { 334 sc->rev = pasread(BOARD_REV_ID); 335 } 336 else { 337 DPRINTF(("pas: bogus model id\n")); 338 return 0; 339 } 340 341 if (sc->model >= 0) { 342 if (ia->ia_irq == IRQUNK) { 343 kprintf("pas: sb emulation requires known irq\n"); 344 return (0); 345 } 346 pasconf(sc->model, ia->ia_iobase, ia->ia_irq, 1); 347 } else { 348 DPRINTF(("pas: could not probe pas\n")); 349 return (0); 350 } 351 352 /* Now a SoundBlaster */ 353 sc->sc_iobase = ia->ia_iobase; 354 /* and set the SB iobase into the DSP as well ... */ 355 sc->sc_sbdsp.sc_iobase = ia->ia_iobase; 356 if (sbdsp_reset(&sc->sc_sbdsp) < 0) { 357 DPRINTF(("pas: couldn't reset card\n")); 358 return 0; 359 } 360 361 /* 362 * Cannot auto-discover DMA channel. 363 */ 364 if (!SB_DRQ_VALID(ia->ia_drq)) { 365 kprintf("pas: configured dma chan %d invalid\n", ia->ia_drq); 366 return 0; 367 } 368#ifdef NEWCONFIG 369 /* 370 * If the IRQ wasn't compiled in, auto-detect it. 371 */ 372 if (ia->ia_irq == IRQUNK) { 373 ia->ia_irq = isa_discoverintr(pasforceintr, aux); 374 sbdsp_reset(&sc->sc_sbdsp); 375 if (!SB_IRQ_VALID(ia->ia_irq)) { 376 kprintf("pas: couldn't auto-detect interrupt"); 377 return 0; 378 } 379 } else 380#endif 381 if (!SB_IRQ_VALID(ia->ia_irq)) { 382 kprintf("pas: configured irq chan %d invalid\n", ia->ia_irq); 383 return 0; 384 } 385 386 sc->sc_sbdsp.sc_irq = ia->ia_irq; 387 sc->sc_sbdsp.sc_drq = ia->ia_drq; 388 389 if (sbdsp_probe(&sc->sc_sbdsp) == 0) { 390 DPRINTF(("pas: sbdsp probe failed\n")); 391 return 0; 392 } 393 394 ia->ia_iosize = SB_NPORT; 395 return 1; 396} 397 398#ifdef NEWCONFIG 399void 400pasforceintr(aux) 401 void *aux; 402{ 403 static char dmabuf; 404 struct isa_attach_args *ia = aux; 405 int iobase = ia->ia_iobase; 406 407 /* 408 * Set up a DMA read of one byte. 409 * XXX Note that at this point we haven't called 410 * at_setup_dmachan(). This is okay because it just 411 * allocates a buffer in case it needs to make a copy, 412 * and it won't need to make a copy for a 1 byte buffer. 413 * (I think that calling at_setup_dmachan() should be optional; 414 * if you don't call it, it will be called the first time 415 * it is needed (and you pay the latency). Also, you might 416 * never need the buffer anyway.) 417 */ 418 at_dma(DMAMODE_READ, &dmabuf, 1, ia->ia_drq); 419 if (pas_wdsp(iobase, SB_DSP_RDMA) == 0) { 420 (void)pas_wdsp(iobase, 0); 421 (void)pas_wdsp(iobase, 0); 422 } 423} 424#endif 425 426/* 427 * Attach hardware to driver, attach hardware driver to audio 428 * pseudo-device driver . 429 */ 430void 431pasattach(parent, self, aux) 432 struct device *parent, *self; 433 void *aux; 434{ 435 register struct pas_softc *sc = (struct pas_softc *)self; 436 struct isa_attach_args *ia = (struct isa_attach_args *)aux; 437 register int iobase = ia->ia_iobase; 438 int err; 439 440 sc->sc_iobase = iobase; 441 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, 442 IPL_AUDIO, sbdsp_intr, &sc->sc_sbdsp); 443 444 kprintf(" ProAudio Spectrum %s [rev %d] ", pasnames[sc->model], sc->rev); 445 446 sbdsp_attach(&sc->sc_sbdsp); 447 448 ksprintf(pas_device.name, "pas,%s", pasnames[sc->model]); 449 ksprintf(pas_device.version, "%d", sc->rev); 450 451 if ((err = audio_hardware_attach(&pas_hw_if, &sc->sc_sbdsp)) != 0) 452 kprintf("pas: could not attach to audio pseudo-device driver (%d)\n", err); 453} 454 455int 456pasopen(dev, flags) 457 dev_t dev; 458 int flags; 459{ 460 struct pas_softc *sc; 461 int unit = AUDIOUNIT(dev); 462 463 if (unit >= pas_cd.cd_ndevs) 464 return ENODEV; 465 466 sc = pas_cd.cd_devs[unit]; 467 if (!sc) 468 return ENXIO; 469 470 return sbdsp_open(&sc->sc_sbdsp, dev, flags); 471} 472 473int 474pas_getdev(addr, retp) 475 void *addr; 476 struct audio_device *retp; 477{ 478 *retp = pas_device; 479 return 0; 480} 481