1 /* 2 * Copyright (c) 1991, 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * All advertising materials mentioning features or use of this software 10 * must display the following acknowledgement: 11 * This product includes software developed by the University of 12 * California, Lawrence Berkeley Laboratory. 13 * 14 * %sccs.include.redist.c% 15 * 16 * @(#)bsd_audio.c 8.1 (Berkeley) 06/11/93 17 * 18 * from: $Header: bsd_audio.c,v 1.18 93/04/24 16:20:35 leres Exp $ (LBL) 19 */ 20 #include "bsdaudio.h" 21 #if NBSDAUDIO > 0 22 23 #include <sys/param.h> 24 #include <sys/systm.h> 25 26 #if BSD < 199103 27 #ifndef SUNOS 28 #define SUNOS 29 #endif 30 #endif 31 32 #include <sys/errno.h> 33 #include <sys/file.h> 34 #include <sys/proc.h> 35 #include <sys/user.h> 36 #include <sys/vnode.h> 37 #include <sys/ioctl.h> 38 #include <sys/time.h> 39 #ifndef SUNOS 40 #include <sys/tty.h> 41 #endif 42 #include <sys/uio.h> 43 44 #ifdef SUNOS 45 #include <sundev/mbvar.h> 46 #include <sun4c/intreg.h> 47 #else 48 #include <sys/device.h> 49 #include <machine/autoconf.h> 50 #endif 51 #include <machine/cpu.h> 52 53 /* 54 * Avoid name clashes with SunOS so we can config either the bsd or sun 55 * streams driver in a SunOS kernel. 56 */ 57 #ifdef SUNOS 58 #include <sbusdev/bsd_audioreg.h> 59 #include <sbusdev/bsd_audiovar.h> 60 #include <sbusdev/bsd_audioio.h> 61 struct selinfo { 62 struct proc *si_proc; 63 int si_coll; 64 }; 65 #else 66 #include <sparc/dev/bsd_audioreg.h> 67 #include <sparc/dev/bsd_audiovar.h> 68 #include <machine/bsd_audioio.h> 69 #endif 70 71 #ifdef SUNOS 72 #include "bsd_audiocompat.h" 73 #endif 74 75 /* 76 * Initial/default block size is patchable. 77 */ 78 int audio_blocksize = DEFBLKSIZE; 79 int audio_backlog = 400; /* 50ms in samples */ 80 81 /* 82 * Software state, per AMD79C30 audio chip. 83 */ 84 struct audio_softc { 85 #ifndef SUNOS 86 struct device sc_dev; /* base device */ 87 struct intrhand sc_hwih; /* hardware interrupt vector */ 88 struct intrhand sc_swih; /* software interrupt vector */ 89 #endif 90 int sc_interrupts; /* number of interrupts taken */ 91 92 int sc_open; /* single use device */ 93 u_long sc_wseek; /* timestamp of last frame written */ 94 u_long sc_rseek; /* timestamp of last frame read */ 95 struct mapreg sc_map; /* current contents of map registers */ 96 struct selinfo sc_wsel; /* write selector */ 97 struct selinfo sc_rsel; /* read selector */ 98 /* 99 * keep track of levels so we don't have to convert back from 100 * MAP gain constants 101 */ 102 int sc_rlevel; /* record level */ 103 int sc_plevel; /* play level */ 104 int sc_mlevel; /* monitor level */ 105 106 /* sc_au is special in that the hardware interrupt handler uses it */ 107 struct auio sc_au; /* recv and xmit buffers, etc */ 108 109 }; 110 111 /* interrupt interfaces */ 112 #ifndef AUDIO_C_HANDLER 113 int audiohwintr __P((void *)); 114 #endif 115 int audioswintr __P((void *)); 116 117 /* forward declarations */ 118 int audio_sleep __P((struct aucb *, int)); 119 void audio_setmap __P((volatile struct amd7930 *, struct mapreg *)); 120 121 static void init_amd(); 122 123 #if !defined(AUDIO_C_HANDLER) || defined(SUNOS) 124 struct auio *audio_au; 125 extern void audio_trap(); 126 #endif 127 128 #ifdef SUNOS 129 struct audio_softc audio_softc; 130 #define SOFTC(dev) &audio_softc 131 #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio) 132 133 #define AUDIOOPEN(d, f, i, p)\ 134 audioopen(d, f, i)\ 135 dev_t d; int f, i; 136 #define AUDIOCLOSE(d, f, i, p)\ 137 audioclose(d, f, i)\ 138 dev_t d; int f, i; 139 #define AUDIOREAD(d, u, f) \ 140 audioread(d, u) dev_t d; struct uio *u; 141 #define AUDIOWRITE(d, u, f) \ 142 audiowrite(d, u) dev_t d; struct uio *u; 143 #define AUDIOIOCTL(d, c, a, f, o)\ 144 audioioctl(d, c, a, f)\ 145 dev_t d; int c; caddr_t a; int f; 146 #define AUDIOSELECT(d, r, p)\ 147 audio_select(d, r, p)\ 148 dev_t d; int r; struct proc *p; 149 150 151 #define AUDIO_SET_SWINTR set_intreg(IR_SOFT_INT4, 1) 152 153 int 154 audioselect(dev, rw) 155 register dev_t dev; 156 int rw; 157 { 158 return (audio_select(dev, rw, u.u_procp)); 159 } 160 161 static void 162 selrecord(p, si) 163 struct proc *p; 164 struct selinfo *si; 165 { 166 if (si->si_proc != 0) 167 si->si_coll = 1; 168 else 169 si->si_proc = p; 170 } 171 #define SELWAKEUP(si) \ 172 {\ 173 if ((si)->si_proc != 0) {\ 174 selwakeup((si)->si_proc, (si)->si_coll); \ 175 (si)->si_proc = 0;\ 176 (si)->si_coll = 0;\ 177 }\ 178 } 179 180 181 static int audioattach(); 182 static int audioidentify(); 183 184 struct dev_ops bsdaudio_ops = { 185 0, 186 audioidentify, 187 audioattach, 188 }; 189 190 static int 191 audioidentify(cp) 192 char *cp; 193 { 194 return (strcmp(cp, "audio") == 0); 195 } 196 197 static int 198 audioattach(dev) 199 struct dev_info *dev; 200 { 201 register struct audio_softc *sc; 202 register volatile struct amd7930 *amd; 203 struct dev_reg *reg; 204 205 sc = &audio_softc; 206 if (dev->devi_nreg != 1 || dev->devi_nintr != 1) { 207 printf("audio: bad config\n"); 208 return (-1); 209 } 210 reg = dev->devi_reg; 211 amd = (struct amd7930 *)map_regs(reg->reg_addr, reg->reg_size, 212 reg->reg_bustype); 213 sc->sc_au.au_amd = amd; 214 init_amd(amd); 215 216 audio_au = &sc->sc_au; 217 #ifndef AUDIO_C_HANDLER 218 settrap(dev->devi_intr->int_pri, audio_trap); 219 #else 220 /* XXX */ 221 addintr(dev->devi_intr->int_pri, audiohwintr, dev->devi_name, 222 dev->devi_unit); 223 #endif 224 addintr(4, audioswintr, dev->devi_name, dev->devi_unit); 225 report_dev(dev); 226 227 return (0); 228 } 229 #else 230 #define AUDIOOPEN(d, f, i, p) audioopen(dev_t d, int f, int i, struct proc *p) 231 #define AUDIOCLOSE(d, f, i, p) audioclose(dev_t d, int f, int i, \ 232 struct proc *p) 233 #define AUDIOREAD(d, u, f) audioread(dev_t d, struct uio *u, int f) 234 #define AUDIOWRITE(d, u, f) audiowrite(dev_t d, struct uio *u, int f) 235 #define AUDIOIOCTL(d, c, a, f, o)\ 236 audioioctl(dev_t dev, int c, caddr_t a, int f, struct proc *p) 237 #define AUDIOSELECT(d, r, p) audioselect(dev_t dev, int rw, struct proc *p) 238 #define SELWAKEUP selwakeup 239 240 #define AUDIO_SET_SWINTR ienab_bis(IE_L6) 241 242 /* autoconfiguration driver */ 243 void audioattach(struct device *, struct device *, void *); 244 struct cfdriver audiocd = 245 { NULL, "audio", matchbyname, audioattach, 246 DV_DULL, sizeof(struct audio_softc) }; 247 #define SOFTC(dev) audiocd.cd_devs[minor(dev)] 248 #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, uio) 249 250 /* 251 * Audio chip found. 252 */ 253 void 254 audioattach(parent, self, args) 255 struct device *parent, *self; 256 void *args; 257 { 258 register struct audio_softc *sc = (struct audio_softc *)self; 259 register struct romaux *ra = args; 260 register volatile struct amd7930 *amd; 261 register int pri; 262 263 if (ra->ra_nintr != 1) { 264 printf(": expected 1 interrupt, got %d\n", ra->ra_nintr); 265 return; 266 } 267 pri = ra->ra_intr[0].int_pri; 268 printf(" pri %d, softpri %d\n", pri, PIL_AUSOFT); 269 amd = (volatile struct amd7930 *)(ra->ra_vaddr ? 270 ra->ra_vaddr : mapiodev(ra->ra_paddr, sizeof *amd)); 271 sc->sc_au.au_amd = amd; 272 273 init_amd(amd); 274 275 #ifndef AUDIO_C_HANDLER 276 audio_au = &sc->sc_au; 277 intr_fasttrap(pri, audio_trap); 278 #else 279 sc->sc_hwih.ih_fun = audiohwintr; 280 sc->sc_hwih.ih_arg = &sc->sc_au; 281 intr_establish(pri, &sc->sc_hwih); 282 #endif 283 sc->sc_swih.ih_fun = audioswintr; 284 sc->sc_swih.ih_arg = sc; 285 intr_establish(PIL_AUSOFT, &sc->sc_swih); 286 } 287 #endif 288 289 static void 290 init_amd(amd) 291 register volatile struct amd7930 *amd; 292 { 293 /* disable interrupts */ 294 amd->cr = AMDR_INIT; 295 amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 296 297 /* 298 * Initialize the mux unit. We use MCR3 to route audio (MAP) 299 * through channel Bb. MCR1 and MCR2 are unused. 300 * Setting the INT enable bit in MCR4 will generate an interrupt 301 * on each converted audio sample. 302 */ 303 amd->cr = AMDR_MUX_1_4; 304 amd->dr = 0; 305 amd->dr = 0; 306 amd->dr = (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA; 307 amd->dr = AMD_MCR4_INT_ENABLE; 308 } 309 310 static int audio_default_level = 150; 311 static void ausetrgain __P((struct audio_softc *, int)); 312 static void ausetpgain __P((struct audio_softc *, int)); 313 static void ausetmgain __P((struct audio_softc *, int)); 314 static int audiosetinfo __P((struct audio_softc *, struct audio_info *)); 315 static int audiogetinfo __P((struct audio_softc *, struct audio_info *)); 316 struct sun_audio_info; 317 static int sunaudiosetinfo __P((struct audio_softc *, 318 struct sun_audio_info *)); 319 static int sunaudiogetinfo __P((struct audio_softc *, 320 struct sun_audio_info *)); 321 static void audio_setmmr2 __P((volatile struct amd7930 *, int)); 322 323 /* ARGSUSED */ 324 int 325 AUDIOOPEN(dev, flags, ifmt, p) 326 { 327 register struct audio_softc *sc; 328 register volatile struct amd7930 *amd; 329 int unit = minor(dev); 330 331 #ifdef SUNOS 332 if (unit > 0) 333 return (ENXIO); 334 sc = &audio_softc; 335 #else 336 if (unit >= audiocd.cd_ndevs || (sc = audiocd.cd_devs[unit]) == NULL) 337 return (ENXIO); 338 #endif 339 if (sc->sc_open) 340 return (EBUSY); 341 sc->sc_open = 1; 342 343 sc->sc_au.au_lowat = audio_blocksize; 344 sc->sc_au.au_hiwat = AUCB_SIZE - sc->sc_au.au_lowat; 345 sc->sc_au.au_blksize = audio_blocksize; 346 sc->sc_au.au_backlog = audio_backlog; 347 348 /* set up read and write blocks and `dead sound' zero value. */ 349 AUCB_INIT(&sc->sc_au.au_rb); 350 sc->sc_au.au_rb.cb_thresh = AUCB_SIZE; 351 AUCB_INIT(&sc->sc_au.au_wb); 352 sc->sc_au.au_wb.cb_thresh = -1; 353 354 /* nothing read or written yet */ 355 sc->sc_rseek = 0; 356 sc->sc_wseek = 0; 357 358 bzero((char *)&sc->sc_map, sizeof sc->sc_map); 359 /* default to speaker */ 360 sc->sc_map.mr_mmr2 = AMD_MMR2_AINB | AMD_MMR2_LS; 361 362 /* enable interrupts and set parameters established above */ 363 amd = sc->sc_au.au_amd; 364 audio_setmmr2(amd, sc->sc_map.mr_mmr2); 365 ausetrgain(sc, audio_default_level); 366 ausetpgain(sc, audio_default_level); 367 ausetmgain(sc, 0); 368 amd->cr = AMDR_INIT; 369 amd->dr = AMD_INIT_PMS_ACTIVE; 370 371 return (0); 372 } 373 374 static int 375 audio_drain(sc) 376 register struct audio_softc *sc; 377 { 378 register int error; 379 380 while (!AUCB_EMPTY(&sc->sc_au.au_wb)) 381 if ((error = audio_sleep(&sc->sc_au.au_wb, 0)) != 0) 382 return (error); 383 return (0); 384 } 385 386 /* 387 * Close an audio chip. 388 */ 389 /* ARGSUSED */ 390 int 391 AUDIOCLOSE(dev, flags, ifmt, p) 392 { 393 register struct audio_softc *sc = SOFTC(dev); 394 register volatile struct amd7930 *amd; 395 register struct aucb *cb; 396 register int s; 397 398 /* 399 * Block until output drains, but allow ^C interrupt. 400 */ 401 sc->sc_au.au_lowat = 0; /* avoid excessive wakeups */ 402 s = splaudio(); 403 /* 404 * If there is pending output, let it drain (unless 405 * the output is paused). 406 */ 407 cb = &sc->sc_au.au_wb; 408 if (!AUCB_EMPTY(cb) && !cb->cb_pause) 409 (void)audio_drain(sc); 410 /* 411 * Disable interrupts, clear open flag, and done. 412 */ 413 amd = sc->sc_au.au_amd; 414 amd->cr = AMDR_INIT; 415 amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 416 splx(s); 417 sc->sc_open = 0; 418 return (0); 419 } 420 421 int 422 audio_sleep(cb, thresh) 423 register struct aucb *cb; 424 register int thresh; 425 { 426 register int error; 427 register int s = splaudio(); 428 429 cb->cb_thresh = thresh; 430 error = tsleep((caddr_t)cb, (PZERO + 1) | PCATCH, "audio", 0); 431 splx(s); 432 return (error); 433 } 434 435 /* ARGSUSED */ 436 int 437 AUDIOREAD(dev, uio, ioflag) 438 { 439 register struct audio_softc *sc = SOFTC(dev); 440 register struct aucb *cb; 441 register int n, head, taildata, error; 442 register int blocksize = sc->sc_au.au_blksize; 443 444 if (uio->uio_resid == 0) 445 return (0); 446 cb = &sc->sc_au.au_rb; 447 error = 0; 448 cb->cb_drops = 0; 449 sc->sc_rseek = sc->sc_au.au_stamp - AUCB_LEN(cb); 450 do { 451 while (AUCB_LEN(cb) < blocksize) { 452 #ifndef SUNOS 453 if (ioflag & IO_NDELAY) { 454 error = EWOULDBLOCK; 455 return (error); 456 } 457 #endif 458 if ((error = audio_sleep(cb, blocksize)) != 0) 459 return (error); 460 } 461 /* 462 * The space calculation can only err on the short 463 * side if an interrupt occurs during processing: 464 * only cb_tail is altered in the interrupt code. 465 */ 466 head = cb->cb_head; 467 if ((n = AUCB_LEN(cb)) > uio->uio_resid) 468 n = uio->uio_resid; 469 taildata = AUCB_SIZE - head; 470 if (n > taildata) { 471 error = UIOMOVE((caddr_t)cb->cb_data + head, 472 taildata, UIO_READ, uio); 473 if (error == 0) 474 error = UIOMOVE((caddr_t)cb->cb_data, 475 n - taildata, UIO_READ, uio); 476 } else 477 error = UIOMOVE((caddr_t)cb->cb_data + head, n, 478 UIO_READ, uio); 479 if (error) 480 break; 481 head = AUCB_MOD(head + n); 482 cb->cb_head = head; 483 } while (uio->uio_resid >= blocksize); 484 485 return (error); 486 } 487 488 /* ARGSUSED */ 489 int 490 AUDIOWRITE(dev, uio, ioflag) 491 { 492 register struct audio_softc *sc = SOFTC(dev); 493 register struct aucb *cb = &sc->sc_au.au_wb; 494 register int n, tail, tailspace, error, first, watermark; 495 496 error = 0; 497 first = 1; 498 while (uio->uio_resid > 0) { 499 watermark = sc->sc_au.au_hiwat; 500 while (AUCB_LEN(cb) > watermark) { 501 #ifndef SUNOS 502 if (ioflag & IO_NDELAY) { 503 error = EWOULDBLOCK; 504 return (error); 505 } 506 #endif 507 if ((error = audio_sleep(cb, watermark)) != 0) 508 return (error); 509 watermark = sc->sc_au.au_lowat; 510 } 511 /* 512 * The only value that can change on an interrupt is 513 * cb->cb_head. We only pull that out once to decide 514 * how much to write into cb_data; if we lose a race 515 * and cb_head changes, we will merely be overly 516 * conservative. For a legitimate time stamp, 517 * however, we need to synchronize the accesses to 518 * au_stamp and cb_head at a high ipl below. 519 */ 520 tail = cb->cb_tail; 521 if ((n = (AUCB_SIZE - 1) - AUCB_LEN(cb)) > uio->uio_resid) { 522 n = uio->uio_resid; 523 if (cb->cb_head == tail && 524 n <= sc->sc_au.au_blksize && 525 sc->sc_au.au_stamp - sc->sc_wseek > 400) { 526 /* 527 * the write is 'small', the buffer is empty 528 * and we have been silent for at least 50ms 529 * so we might be dealing with an application 530 * that writes frames synchronously with 531 * reading them. If so, we need an output 532 * backlog to cover scheduling delays or 533 * there will be gaps in the sound output. 534 * Also take this opportunity to reset the 535 * buffer pointers in case we ended up on 536 * a bad boundary (odd byte, blksize bytes 537 * from end, etc.). 538 */ 539 register u_int* ip; 540 register int muzero = 0x7f7f7f7f; 541 register int i = splaudio(); 542 cb->cb_head = cb->cb_tail = 0; 543 splx(i); 544 tail = sc->sc_au.au_backlog; 545 ip = (u_int*)cb->cb_data; 546 for (i = tail >> 2; --i >= 0; ) 547 *ip++ = muzero; 548 } 549 } 550 tailspace = AUCB_SIZE - tail; 551 if (n > tailspace) { 552 /* write first part at tail and rest at head */ 553 error = UIOMOVE((caddr_t)cb->cb_data + tail, 554 tailspace, UIO_WRITE, uio); 555 if (error == 0) 556 error = UIOMOVE((caddr_t)cb->cb_data, 557 n - tailspace, UIO_WRITE, uio); 558 } else 559 error = UIOMOVE((caddr_t)cb->cb_data + tail, n, 560 UIO_WRITE, uio); 561 if (error) 562 break; 563 564 tail = AUCB_MOD(tail + n); 565 if (first) { 566 register int s = splaudio(); 567 sc->sc_wseek = AUCB_LEN(cb) + sc->sc_au.au_stamp + 1; 568 /* 569 * To guarantee that a write is contiguous in the 570 * sample space, we clear the drop count the first 571 * time through. If we later get drops, we will 572 * break out of the loop below, before writing 573 * a new frame. 574 */ 575 cb->cb_drops = 0; 576 cb->cb_tail = tail; 577 splx(s); 578 first = 0; 579 } else { 580 if (cb->cb_drops != 0) 581 break; 582 cb->cb_tail = tail; 583 } 584 } 585 return (error); 586 } 587 588 /* Sun audio compatibility */ 589 struct sun_audio_prinfo { 590 u_int sample_rate; 591 u_int channels; 592 u_int precision; 593 u_int encoding; 594 u_int gain; 595 u_int port; 596 u_int reserved0[4]; 597 u_int samples; 598 u_int eof; 599 u_char pause; 600 u_char error; 601 u_char waiting; 602 u_char reserved1[3]; 603 u_char open; 604 u_char active; 605 }; 606 struct sun_audio_info { 607 struct sun_audio_prinfo play; 608 struct sun_audio_prinfo record; 609 u_int monitor_gain; 610 u_int reserved[4]; 611 }; 612 613 #ifndef SUNOS 614 #define SUNAUDIO_GETINFO _IOR('A', 1, struct sun_audio_info) 615 #define SUNAUDIO_SETINFO _IOWR('A', 2, struct sun_audio_info) 616 #else 617 #define SUNAUDIO_GETINFO _IOR(A, 1, struct sun_audio_info) 618 #define SUNAUDIO_SETINFO _IOWR(A, 2, struct sun_audio_info) 619 #endif 620 621 /* ARGSUSED */ 622 int 623 AUDIOIOCTL(dev, cmd, addr, flag, p) 624 { 625 register struct audio_softc *sc = SOFTC(dev); 626 int error = 0, s; 627 628 switch (cmd) { 629 630 case AUDIO_GETMAP: 631 bcopy((caddr_t)&sc->sc_map, addr, sizeof(sc->sc_map)); 632 break; 633 634 case AUDIO_SETMAP: 635 bcopy(addr, (caddr_t)&sc->sc_map, sizeof(sc->sc_map)); 636 sc->sc_map.mr_mmr2 &= 0x7f; 637 audio_setmap(sc->sc_au.au_amd, &sc->sc_map); 638 break; 639 640 case AUDIO_FLUSH: 641 s = splaudio(); 642 AUCB_INIT(&sc->sc_au.au_rb); 643 AUCB_INIT(&sc->sc_au.au_wb); 644 sc->sc_au.au_stamp = 0; 645 splx(s); 646 sc->sc_wseek = 0; 647 sc->sc_rseek = 0; 648 break; 649 650 /* 651 * Number of read samples dropped. We don't know where or 652 * when they were dropped. 653 */ 654 case AUDIO_RERROR: 655 *(int *)addr = sc->sc_au.au_rb.cb_drops != 0; 656 break; 657 658 /* 659 * How many samples will elapse until mike hears the first 660 * sample of what we last wrote? 661 */ 662 case AUDIO_WSEEK: 663 s = splaudio(); 664 *(u_long *)addr = sc->sc_wseek - sc->sc_au.au_stamp 665 + AUCB_LEN(&sc->sc_au.au_rb); 666 splx(s); 667 break; 668 669 case AUDIO_SETINFO: 670 error = audiosetinfo(sc, (struct audio_info *)addr); 671 break; 672 673 case AUDIO_GETINFO: 674 error = audiogetinfo(sc, (struct audio_info *)addr); 675 break; 676 677 case SUNAUDIO_GETINFO: 678 error = sunaudiogetinfo(sc, (struct sun_audio_info *)addr); 679 break; 680 681 case SUNAUDIO_SETINFO: 682 error = sunaudiosetinfo(sc, (struct sun_audio_info *)addr); 683 break; 684 685 case AUDIO_DRAIN: 686 error = audio_drain(sc); 687 break; 688 689 default: 690 error = EINVAL; 691 break; 692 } 693 return (error); 694 } 695 696 /* ARGSUSED */ 697 int 698 AUDIOSELECT(dev, rw, p) 699 { 700 register struct audio_softc *sc = SOFTC(dev); 701 register struct aucb *cb; 702 register int s = splaudio(); 703 704 switch (rw) { 705 706 case FREAD: 707 cb = &sc->sc_au.au_rb; 708 if (AUCB_LEN(cb) >= sc->sc_au.au_blksize) { 709 splx(s); 710 return (1); 711 } 712 selrecord(p, &sc->sc_rsel); 713 cb->cb_thresh = sc->sc_au.au_blksize; 714 break; 715 716 case FWRITE: 717 cb = &sc->sc_au.au_wb; 718 if (AUCB_LEN(cb) <= sc->sc_au.au_lowat) { 719 splx(s); 720 return (1); 721 } 722 selrecord(p, &sc->sc_wsel); 723 cb->cb_thresh = sc->sc_au.au_lowat; 724 break; 725 } 726 splx(s); 727 return (0); 728 } 729 730 #ifdef AUDIO_C_HANDLER 731 int 732 audiohwintr(au0) 733 void *au0; 734 { 735 #ifdef SUNOS 736 register struct auio *au = audio_au; 737 #else 738 register struct auio *au = au0; 739 #endif 740 register volatile struct amd7930 *amd = au->au_amd; 741 register struct aucb *cb; 742 register int h, t, k; 743 744 k = amd->ir; /* clear interrupt */ 745 ++au->au_stamp; 746 747 /* receive incoming data */ 748 cb = &au->au_rb; 749 h = cb->cb_head; 750 t = cb->cb_tail; 751 k = AUCB_MOD(t + 1); 752 if (h == k) 753 cb->cb_drops++; 754 else if (cb->cb_pause != 0) 755 cb->cb_pdrops++; 756 else { 757 cb->cb_data[t] = amd->bbrb; 758 cb->cb_tail = t = k; 759 } 760 if (AUCB_MOD(t - h) >= cb->cb_thresh) { 761 cb->cb_thresh = AUCB_SIZE; 762 cb->cb_waking = 1; 763 AUDIO_SET_SWINTR; 764 } 765 /* send outgoing data */ 766 cb = &au->au_wb; 767 h = cb->cb_head; 768 t = cb->cb_tail; 769 if (h == t) 770 cb->cb_drops++; 771 else if (cb->cb_pause != 0) 772 cb->cb_pdrops++; 773 else { 774 cb->cb_head = h = AUCB_MOD(h + 1); 775 amd->bbtb = cb->cb_data[h]; 776 } 777 if (AUCB_MOD(t - h) <= cb->cb_thresh) { 778 cb->cb_thresh = -1; 779 cb->cb_waking = 1; 780 AUDIO_SET_SWINTR; 781 } 782 return (1); 783 } 784 #endif 785 786 /* ARGSUSED */ 787 int 788 audioswintr(sc0) 789 void *sc0; 790 { 791 register struct audio_softc *sc; 792 register int s, ret = 0; 793 #ifdef SUNOS 794 sc = &audio_softc; 795 #else 796 sc = sc0; 797 #endif 798 s = splaudio(); 799 if (sc->sc_au.au_rb.cb_waking != 0) { 800 sc->sc_au.au_rb.cb_waking = 0; 801 splx(s); 802 ret = 1; 803 wakeup((caddr_t)&sc->sc_au.au_rb); 804 SELWAKEUP(&sc->sc_rsel); 805 } 806 if (sc->sc_au.au_wb.cb_waking != 0) { 807 sc->sc_au.au_wb.cb_waking = 0; 808 splx(s); 809 ret = 1; 810 wakeup((caddr_t)&sc->sc_au.au_wb); 811 SELWAKEUP(&sc->sc_wsel); 812 } else 813 splx(s); 814 return (ret); 815 } 816 817 /* Write 16 bits of data from variable v to the data port of the audio chip */ 818 819 #define WAMD16(amd, v) ((amd)->dr = (v), (amd)->dr = (v) >> 8) 820 821 void 822 audio_setmap(amd, map) 823 register volatile struct amd7930 *amd; 824 register struct mapreg *map; 825 { 826 register int i, s, v; 827 828 s = splaudio(); 829 amd->cr = AMDR_MAP_1_10; 830 for (i = 0; i < 8; i++) { 831 v = map->mr_x[i]; 832 WAMD16(amd, v); 833 } 834 for (i = 0; i < 8; ++i) { 835 v = map->mr_r[i]; 836 WAMD16(amd, v); 837 } 838 v = map->mr_gx; WAMD16(amd, v); 839 v = map->mr_gr; WAMD16(amd, v); 840 v = map->mr_ger; WAMD16(amd, v); 841 v = map->mr_stgr; WAMD16(amd, v); 842 v = map->mr_ftgr; WAMD16(amd, v); 843 v = map->mr_atgr; WAMD16(amd, v); 844 amd->dr = map->mr_mmr1; 845 amd->dr = map->mr_mmr2; 846 splx(s); 847 } 848 849 /* 850 * Set the mmr1 register and one other 16 bit register in the audio chip. 851 * The other register is indicated by op and val. 852 */ 853 void 854 audio_setmmr1(amd, mmr1, op, val) 855 register volatile struct amd7930 *amd; 856 register int mmr1; 857 register int op; 858 register int val; 859 { 860 register int s = splaudio(); 861 862 amd->cr = AMDR_MAP_MMR1; 863 amd->dr = mmr1; 864 amd->cr = op; 865 WAMD16(amd, val); 866 splx(s); 867 } 868 869 /* 870 * Set the mmr2 register. 871 */ 872 static void 873 audio_setmmr2(amd, mmr2) 874 register volatile struct amd7930 *amd; 875 register int mmr2; 876 { 877 register int s = splaudio(); 878 879 amd->cr = AMDR_MAP_MMR2; 880 amd->dr = mmr2; 881 splx(s); 882 } 883 884 /* 885 * gx, gr & stg gains. this table must contain 256 elements with 886 * the 0th being "infinity" (the magic value 9008). The remaining 887 * elements match sun's gain curve (but with higher resolution): 888 * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps. 889 */ 890 static const u_short gx_coeff[256] = { 891 0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33, 892 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22, 893 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b, 894 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb, 895 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a, 896 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213, 897 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231, 898 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4, 899 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2, 900 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa, 901 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b, 902 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b, 903 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd, 904 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808, 905 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243, 906 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224, 907 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb, 908 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33, 909 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32, 910 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323, 911 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a, 912 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23, 913 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1, 914 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333, 915 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227, 916 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6, 917 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2, 918 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba, 919 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033, 920 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021, 921 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012, 922 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e, 923 }; 924 925 /* 926 * second stage play gain. 927 */ 928 static const u_short ger_coeff[] = { 929 0x431f, /* 5. dB */ 930 0x331f, /* 5.5 dB */ 931 0x40dd, /* 6. dB */ 932 0x11dd, /* 6.5 dB */ 933 0x440f, /* 7. dB */ 934 0x411f, /* 7.5 dB */ 935 0x311f, /* 8. dB */ 936 0x5520, /* 8.5 dB */ 937 0x10dd, /* 9. dB */ 938 0x4211, /* 9.5 dB */ 939 0x410f, /* 10. dB */ 940 0x111f, /* 10.5 dB */ 941 0x600b, /* 11. dB */ 942 0x00dd, /* 11.5 dB */ 943 0x4210, /* 12. dB */ 944 0x110f, /* 13. dB */ 945 0x7200, /* 14. dB */ 946 0x2110, /* 15. dB */ 947 0x2200, /* 15.9 dB */ 948 0x000b, /* 16.9 dB */ 949 0x000f /* 18. dB */ 950 #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0])) 951 }; 952 953 static void 954 ausetrgain(sc, level) 955 register struct audio_softc *sc; 956 register int level; 957 { 958 level &= 0xff; 959 sc->sc_rlevel = level; 960 sc->sc_map.mr_mmr1 |= AMD_MMR1_GX; 961 sc->sc_map.mr_gx = gx_coeff[level]; 962 audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1, 963 AMDR_MAP_GX, sc->sc_map.mr_gx); 964 } 965 966 static void 967 ausetpgain(sc, level) 968 register struct audio_softc *sc; 969 register int level; 970 { 971 register int gi, s; 972 register volatile struct amd7930 *amd; 973 974 level &= 0xff; 975 sc->sc_plevel = level; 976 sc->sc_map.mr_mmr1 |= AMD_MMR1_GER|AMD_MMR1_GR; 977 level *= 256 + NGER; 978 level >>= 8; 979 if (level >= 256) { 980 gi = level - 256; 981 level = 255; 982 } else 983 gi = 0; 984 sc->sc_map.mr_ger = ger_coeff[gi]; 985 sc->sc_map.mr_gr = gx_coeff[level]; 986 987 amd = sc->sc_au.au_amd; 988 s = splaudio(); 989 amd->cr = AMDR_MAP_MMR1; 990 amd->dr = sc->sc_map.mr_mmr1; 991 amd->cr = AMDR_MAP_GR; 992 gi = sc->sc_map.mr_gr; 993 WAMD16(amd, gi); 994 amd->cr = AMDR_MAP_GER; 995 gi = sc->sc_map.mr_ger; 996 WAMD16(amd, gi); 997 splx(s); 998 } 999 1000 static void 1001 ausetmgain(sc, level) 1002 register struct audio_softc *sc; 1003 register int level; 1004 { 1005 level &= 0xff; 1006 sc->sc_mlevel = level; 1007 sc->sc_map.mr_mmr1 |= AMD_MMR1_STG; 1008 sc->sc_map.mr_stgr = gx_coeff[level]; 1009 audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1, 1010 AMDR_MAP_STG, sc->sc_map.mr_stgr); 1011 } 1012 1013 static int 1014 audiosetinfo(sc, ai) 1015 struct audio_softc *sc; 1016 struct audio_info *ai; 1017 { 1018 struct audio_prinfo *r = &ai->record, *p = &ai->play; 1019 register int s, bsize; 1020 1021 if (p->gain != ~0) 1022 ausetpgain(sc, p->gain); 1023 if (r->gain != ~0) 1024 ausetrgain(sc, r->gain); 1025 if (ai->monitor_gain != ~0) 1026 ausetmgain(sc, ai->monitor_gain); 1027 if (p->port == AUDIO_SPEAKER) { 1028 sc->sc_map.mr_mmr2 |= AMD_MMR2_LS; 1029 audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 1030 } else if (p->port == AUDIO_HEADPHONE) { 1031 sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS; 1032 audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 1033 } 1034 if (p->pause != (u_char)~0) 1035 sc->sc_au.au_wb.cb_pause = p->pause; 1036 if (r->pause != (u_char)~0) 1037 sc->sc_au.au_rb.cb_pause = r->pause; 1038 1039 if (ai->blocksize != ~0) { 1040 if (ai->blocksize == 0) 1041 bsize = ai->blocksize = DEFBLKSIZE; 1042 else if (ai->blocksize > MAXBLKSIZE) 1043 bsize = ai->blocksize = MAXBLKSIZE; 1044 else 1045 bsize = ai->blocksize; 1046 1047 s = splaudio(); 1048 sc->sc_au.au_blksize = bsize; 1049 /* AUDIO_FLUSH */ 1050 AUCB_INIT(&sc->sc_au.au_rb); 1051 AUCB_INIT(&sc->sc_au.au_wb); 1052 splx(s); 1053 1054 } 1055 if (ai->hiwat != ~0 && (unsigned)ai->hiwat < AUCB_SIZE) 1056 sc->sc_au.au_hiwat = ai->hiwat; 1057 if (ai->lowat != ~0 && ai->lowat < AUCB_SIZE) 1058 sc->sc_au.au_lowat = ai->lowat; 1059 if (ai->backlog != ~0 && ai->backlog < (AUCB_SIZE/2)) 1060 sc->sc_au.au_backlog = ai->backlog; 1061 1062 return (0); 1063 } 1064 1065 static int 1066 sunaudiosetinfo(sc, ai) 1067 struct audio_softc *sc; 1068 struct sun_audio_info *ai; 1069 { 1070 struct sun_audio_prinfo *r = &ai->record, *p = &ai->play; 1071 1072 if (p->gain != ~0) 1073 ausetpgain(sc, p->gain); 1074 if (r->gain != ~0) 1075 ausetrgain(sc, r->gain); 1076 if (ai->monitor_gain != ~0) 1077 ausetmgain(sc, ai->monitor_gain); 1078 if (p->port == AUDIO_SPEAKER) { 1079 sc->sc_map.mr_mmr2 |= AMD_MMR2_LS; 1080 audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 1081 } else if (p->port == AUDIO_HEADPHONE) { 1082 sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS; 1083 audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 1084 } 1085 /* 1086 * The bsd driver does not distinguish between paused and active. 1087 * (In the sun driver, not active means samples are not ouput 1088 * at all, but paused means the last streams buffer is drained 1089 * and then output stops.) If either are 0, then when stop output. 1090 * Otherwise, if either are non-zero, we resume. 1091 */ 1092 if (p->pause == 0 || p->active == 0) 1093 sc->sc_au.au_wb.cb_pause = 0; 1094 else if (p->pause != (u_char)~0 || p->active != (u_char)~0) 1095 sc->sc_au.au_wb.cb_pause = 1; 1096 if (r->pause == 0 || r->active == 0) 1097 sc->sc_au.au_rb.cb_pause = 0; 1098 else if (r->pause != (u_char)~0 || r->active != (u_char)~0) 1099 sc->sc_au.au_rb.cb_pause = 1; 1100 1101 return (0); 1102 } 1103 1104 static int 1105 audiogetinfo(sc, ai) 1106 struct audio_softc *sc; 1107 struct audio_info *ai; 1108 { 1109 struct audio_prinfo *r = &ai->record, *p = &ai->play; 1110 1111 p->sample_rate = r->sample_rate = 8000; 1112 p->channels = r->channels = 1; 1113 p->precision = r->precision = 8; 1114 p->encoding = r->encoding = AUDIO_ENCODING_ULAW; 1115 1116 ai->monitor_gain = sc->sc_mlevel; 1117 r->gain = sc->sc_rlevel; 1118 p->gain = sc->sc_plevel; 1119 r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ? 1120 AUDIO_SPEAKER : AUDIO_HEADPHONE; 1121 1122 p->pause = sc->sc_au.au_wb.cb_pause; 1123 r->pause = sc->sc_au.au_rb.cb_pause; 1124 p->error = sc->sc_au.au_wb.cb_drops != 0; 1125 r->error = sc->sc_au.au_rb.cb_drops != 0; 1126 1127 p->open = sc->sc_open; 1128 r->open = sc->sc_open; 1129 1130 p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops; 1131 r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops; 1132 1133 p->seek = sc->sc_wseek; 1134 r->seek = sc->sc_rseek; 1135 1136 ai->blocksize = sc->sc_au.au_blksize; 1137 ai->hiwat = sc->sc_au.au_hiwat; 1138 ai->lowat = sc->sc_au.au_lowat; 1139 ai->backlog = sc->sc_au.au_backlog; 1140 1141 return (0); 1142 } 1143 1144 static int 1145 sunaudiogetinfo(sc, ai) 1146 struct audio_softc *sc; 1147 struct sun_audio_info *ai; 1148 { 1149 struct sun_audio_prinfo *r = &ai->record, *p = &ai->play; 1150 1151 p->sample_rate = r->sample_rate = 8000; 1152 p->channels = r->channels = 1; 1153 p->precision = r->precision = 8; 1154 p->encoding = r->encoding = AUDIO_ENCODING_ULAW; 1155 1156 ai->monitor_gain = sc->sc_mlevel; 1157 r->gain = sc->sc_rlevel; 1158 p->gain = sc->sc_plevel; 1159 r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ? 1160 AUDIO_SPEAKER : AUDIO_HEADPHONE; 1161 1162 p->active = p->pause = sc->sc_au.au_wb.cb_pause; 1163 r->active = r->pause = sc->sc_au.au_rb.cb_pause; 1164 p->error = sc->sc_au.au_wb.cb_drops != 0; 1165 r->error = sc->sc_au.au_rb.cb_drops != 0; 1166 1167 p->waiting = 0; 1168 r->waiting = 0; 1169 p->eof = 0; 1170 r->eof = 0; 1171 1172 p->open = sc->sc_open; 1173 r->open = sc->sc_open; 1174 1175 p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops; 1176 r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops; 1177 1178 return (0); 1179 } 1180 #endif 1181