1 /* 2 * Copyright (c) 1991, 1992 The Regents of the University of California. 3 * 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 Laboratories. 13 * 14 * %sccs.include.redist.c% 15 * 16 * @(#)bsd_audio.c 7.3 (Berkeley) 10/11/92 17 * 18 * from: $Header: bsd_audio.c,v 1.14 92/07/03 23:21:23 mccanne 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 80 /* 81 * Software state, per AMD79C30 audio chip. 82 */ 83 struct audio_softc { 84 #ifndef SUNOS 85 struct device sc_dev; /* base device */ 86 struct intrhand sc_hwih; /* hardware interrupt vector */ 87 struct intrhand sc_swih; /* software interrupt vector */ 88 #endif 89 int sc_interrupts; /* number of interrupts taken */ 90 91 int sc_open; /* single use device */ 92 u_long sc_wseek; /* timestamp of last frame written */ 93 u_long sc_rseek; /* timestamp of last frame read */ 94 struct mapreg sc_map; /* current contents of map registers */ 95 struct selinfo sc_wsel; /* write selector */ 96 struct selinfo sc_rsel; /* read selector */ 97 /* 98 * keep track of levels so we don't have to convert back from 99 * MAP gain constants 100 */ 101 int sc_rlevel; /* record level */ 102 int sc_plevel; /* play level */ 103 int sc_mlevel; /* monitor level */ 104 105 /* sc_au is special in that the hardware interrupt handler uses it */ 106 struct auio sc_au; /* recv and xmit buffers, etc */ 107 108 }; 109 110 /* interrupt interfaces */ 111 #ifndef AUDIO_C_HANDLER 112 int audiohwintr __P((void *)); 113 #endif 114 int audioswintr __P((void *)); 115 116 /* forward declarations */ 117 int audio_sleep __P((struct aucb *, int)); 118 void audio_setmap __P((volatile struct amd7930 *, struct mapreg *)); 119 120 static void init_amd(); 121 122 #if !defined(AUDIO_C_HANDLER) || defined(SUNOS) 123 struct auio *audio_au; 124 extern void audio_trap(); 125 #endif 126 127 #ifdef SUNOS 128 struct audio_softc audio_softc; 129 #define SOFTC(dev) &audio_softc 130 #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio) 131 132 #define AUDIOOPEN(d, f, i, p)\ 133 audioopen(d, f, i)\ 134 dev_t d; int f, i; 135 #define AUDIOCLOSE(d, f, i, p)\ 136 audioclose(d, f, i)\ 137 dev_t d; int f, i; 138 #define AUDIOREAD(d, u, f) \ 139 audioread(d, u) dev_t d; struct uio *u; 140 #define AUDIOWRITE(d, u, f) \ 141 audiowrite(d, u) dev_t d; struct uio *u; 142 #define AUDIOIOCTL(d, c, a, f, o)\ 143 audioioctl(d, c, a, f)\ 144 dev_t d; int c; caddr_t a; int f; 145 #define AUDIOSELECT(d, r, p)\ 146 audio_select(d, r, p)\ 147 dev_t d; int r; struct proc *p; 148 149 150 #define AUDIO_SET_SWINTR set_intreg(IR_SOFT_INT4, 1) 151 152 int 153 audioselect(dev, rw) 154 register dev_t dev; 155 int rw; 156 { 157 return (audio_select(dev, rw, u.u_procp)); 158 } 159 160 static void 161 selrecord(p, si) 162 struct proc *p; 163 struct selinfo *si; 164 { 165 if (si->si_proc != 0) 166 si->si_coll = 1; 167 else 168 si->si_proc = p; 169 } 170 #define SELWAKEUP(si) \ 171 {\ 172 if ((si)->si_proc != 0) {\ 173 selwakeup((si)->si_proc, (si)->si_coll); \ 174 (si)->si_proc = 0;\ 175 (si)->si_coll = 0;\ 176 }\ 177 } 178 179 180 static int audioattach(); 181 static int audioidentify(); 182 183 struct dev_ops bsdaudio_ops = { 184 0, 185 audioidentify, 186 audioattach, 187 }; 188 189 static int 190 audioidentify(cp) 191 char *cp; 192 { 193 return (strcmp(cp, "audio") == 0); 194 } 195 196 static int 197 audioattach(dev) 198 struct dev_info *dev; 199 { 200 register struct audio_softc *sc; 201 register volatile struct amd7930 *amd; 202 struct dev_reg *reg; 203 204 sc = &audio_softc; 205 if (dev->devi_nreg != 1 || dev->devi_nintr != 1) { 206 printf("audio: bad config\n"); 207 return (-1); 208 } 209 reg = dev->devi_reg; 210 amd = (struct amd7930 *)map_regs(reg->reg_addr, reg->reg_size, 211 reg->reg_bustype); 212 sc->sc_au.au_amd = amd; 213 init_amd(amd); 214 215 audio_au = &sc->sc_au; 216 #ifndef AUDIO_C_HANDLER 217 settrap(dev->devi_intr->int_pri, audio_trap); 218 #else 219 /* XXX */ 220 addintr(dev->devi_intr->int_pri, audiohwintr, dev->devi_name, 221 dev->devi_unit); 222 #endif 223 addintr(4, audioswintr, dev->devi_name, dev->devi_unit); 224 report_dev(dev); 225 226 return (0); 227 } 228 #else 229 #define AUDIOOPEN(d, f, i, p) audioopen(dev_t d, int f, int i, struct proc *p) 230 #define AUDIOCLOSE(d, f, i, p) audioclose(dev_t d, int f, int i, \ 231 struct proc *p) 232 #define AUDIOREAD(d, u, f) audioread(dev_t d, struct uio *u, int f) 233 #define AUDIOWRITE(d, u, f) audiowrite(dev_t d, struct uio *u, int f) 234 #define AUDIOIOCTL(d, c, a, f, o)\ 235 audioioctl(dev_t dev, int c, caddr_t a, int f, struct proc *p) 236 #define AUDIOSELECT(d, r, p) audioselect(dev_t dev, int rw, struct proc *p) 237 #define SELWAKEUP selwakeup 238 239 #define AUDIO_SET_SWINTR ienab_bis(IE_L6) 240 241 /* autoconfiguration driver */ 242 void audioattach(struct device *, struct device *, void *); 243 struct cfdriver audiocd = 244 { NULL, "audio", matchbyname, audioattach, 245 DV_DULL, sizeof(struct audio_softc) }; 246 #define SOFTC(dev) audiocd.cd_devs[minor(dev)] 247 #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, uio) 248 249 /* 250 * Audio chip found. 251 */ 252 void 253 audioattach(parent, self, args) 254 struct device *parent, *self; 255 void *args; 256 { 257 register struct audio_softc *sc = (struct audio_softc *)self; 258 register struct romaux *ra = args; 259 register volatile struct amd7930 *amd; 260 register int pri; 261 262 if (ra->ra_nintr != 1) { 263 printf(": expected 1 interrupt, got %d\n", ra->ra_nintr); 264 return; 265 } 266 pri = ra->ra_intr[0].int_pri; 267 printf(" pri %d, softpri %d\n", pri, PIL_AUSOFT); 268 amd = (volatile struct amd7930 *)(ra->ra_vaddr ? 269 ra->ra_vaddr : mapiodev(ra->ra_paddr, sizeof *amd)); 270 sc->sc_au.au_amd = amd; 271 272 init_amd(amd); 273 274 #ifndef AUDIO_C_HANDLER 275 audio_au = &sc->sc_au; 276 intr_fasttrap(pri, audio_trap); 277 #else 278 sc->sc_hwih.ih_fun = audiohwintr; 279 sc->sc_hwih.ih_arg = &sc->sc_au; 280 intr_establish(pri, &sc->sc_hwih); 281 #endif 282 sc->sc_swih.ih_fun = audioswintr; 283 sc->sc_swih.ih_arg = sc; 284 intr_establish(PIL_AUSOFT, &sc->sc_swih); 285 } 286 #endif 287 288 static void 289 init_amd(amd) 290 register volatile struct amd7930 *amd; 291 { 292 /* disable interrupts */ 293 amd->cr = AMDR_INIT; 294 amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 295 296 /* 297 * Initialize the mux unit. We use MCR3 to route audio (MAP) 298 * through channel Bb. MCR1 and MCR2 are unused. 299 * Setting the INT enable bit in MCR4 will generate an interrupt 300 * on each converted audio sample. 301 */ 302 amd->cr = AMDR_MUX_1_4; 303 amd->dr = 0; 304 amd->dr = 0; 305 amd->dr = (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA; 306 amd->dr = AMD_MCR4_INT_ENABLE; 307 } 308 309 static int audio_default_level = 150; 310 static void ausetrgain __P((struct audio_softc *, int)); 311 static void ausetpgain __P((struct audio_softc *, int)); 312 static int audiosetinfo __P((struct audio_softc *, struct audio_info *)); 313 static int audiogetinfo __P((struct audio_softc *, struct audio_info *)); 314 struct sun_audio_info; 315 static int sunaudiosetinfo __P((struct audio_softc *, 316 struct sun_audio_info *)); 317 static int sunaudiogetinfo __P((struct audio_softc *, 318 struct sun_audio_info *)); 319 static void audio_setmmr2 __P((volatile struct amd7930 *, int)); 320 321 int 322 AUDIOOPEN(dev, flags, ifmt, p) 323 { 324 register struct audio_softc *sc; 325 register volatile struct amd7930 *amd; 326 int unit = minor(dev), error, s; 327 328 #ifdef SUNOS 329 if (unit > 0) 330 return (ENXIO); 331 sc = &audio_softc; 332 #else 333 if (unit >= audiocd.cd_ndevs || (sc = audiocd.cd_devs[unit]) == NULL) 334 return (ENXIO); 335 #endif 336 if (sc->sc_open) 337 return (EBUSY); 338 sc->sc_open = 1; 339 340 sc->sc_au.au_lowat = audio_blocksize; 341 sc->sc_au.au_hiwat = AUCB_SIZE - sc->sc_au.au_lowat; 342 sc->sc_au.au_blksize = audio_blocksize; 343 344 /* set up read and write blocks and `dead sound' zero value. */ 345 AUCB_INIT(&sc->sc_au.au_rb); 346 sc->sc_au.au_rb.cb_thresh = AUCB_SIZE; 347 AUCB_INIT(&sc->sc_au.au_wb); 348 sc->sc_au.au_wb.cb_thresh = -1; 349 350 /* nothing read or written yet */ 351 sc->sc_rseek = 0; 352 sc->sc_wseek = 0; 353 354 bzero((char *)&sc->sc_map, sizeof sc->sc_map); 355 /* default to speaker */ 356 sc->sc_map.mr_mmr2 = AMD_MMR2_AINB | AMD_MMR2_LS; 357 358 /* enable interrupts and set parameters established above */ 359 amd = sc->sc_au.au_amd; 360 audio_setmmr2(amd, sc->sc_map.mr_mmr2); 361 ausetrgain(sc, audio_default_level); 362 ausetpgain(sc, audio_default_level); 363 amd->cr = AMDR_INIT; 364 amd->dr = AMD_INIT_PMS_ACTIVE; 365 366 return (0); 367 } 368 369 static int 370 audio_drain(sc) 371 register struct audio_softc *sc; 372 { 373 register int error; 374 375 while (!AUCB_EMPTY(&sc->sc_au.au_wb)) 376 if ((error = audio_sleep(&sc->sc_au.au_wb, 0)) != 0) 377 return (error); 378 return (0); 379 } 380 381 /* 382 * Close an audio chip. 383 */ 384 /* ARGSUSED */ 385 int 386 AUDIOCLOSE(dev, flags, ifmt, p) 387 { 388 register struct audio_softc *sc = SOFTC(dev); 389 register volatile struct amd7930 *amd; 390 register struct aucb *cb; 391 register int s; 392 393 /* 394 * Block until output drains, but allow ^C interrupt. 395 */ 396 sc->sc_au.au_lowat = 0; /* avoid excessive wakeups */ 397 s = splaudio(); 398 /* 399 * If there is pending output, let it drain (unless 400 * the output is paused). 401 */ 402 cb = &sc->sc_au.au_wb; 403 if (!AUCB_EMPTY(cb) && !cb->cb_pause) 404 (void)audio_drain(sc); 405 /* 406 * Disable interrupts, clear open flag, and done. 407 */ 408 amd = sc->sc_au.au_amd; 409 amd->cr = AMDR_INIT; 410 amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 411 splx(s); 412 sc->sc_open = 0; 413 return (0); 414 } 415 416 int 417 audio_sleep(cb, thresh) 418 register struct aucb *cb; 419 register int thresh; 420 { 421 register int error; 422 423 cb->cb_thresh = thresh; 424 error = tsleep((caddr_t)cb, (PZERO + 1) | PCATCH, "audio", 0); 425 return (error); 426 } 427 428 int 429 AUDIOREAD(dev, uio, ioflag) 430 { 431 register struct audio_softc *sc = SOFTC(dev); 432 register struct aucb *cb; 433 register int s, n, head, taildata, error; 434 register int blocksize = sc->sc_au.au_blksize; 435 436 if (uio->uio_resid == 0) 437 return (0); 438 cb = &sc->sc_au.au_rb; 439 error = 0; 440 s = splaudio(); 441 cb->cb_drops = 0; 442 sc->sc_rseek = sc->sc_au.au_stamp - AUCB_LEN(cb); 443 do { 444 while (AUCB_LEN(cb) < blocksize) { 445 #ifndef SUNOS 446 if (ioflag & IO_NDELAY) { 447 error = EWOULDBLOCK; 448 goto out; 449 } 450 #endif 451 if ((error = audio_sleep(cb, blocksize)) != 0) 452 goto out; 453 } 454 splx(s); 455 /* 456 * The space calculation can only err on the short 457 * side if an interrupt occurs during processing: 458 * only cb_tail is altered in the interrupt code. 459 */ 460 head = cb->cb_head; 461 if ((n = AUCB_LEN(cb)) > uio->uio_resid) 462 n = uio->uio_resid; 463 taildata = AUCB_SIZE - head; 464 if (n > taildata) { 465 error = UIOMOVE((caddr_t)cb->cb_data + head, 466 taildata, UIO_READ, uio); 467 if (error == 0) 468 error = UIOMOVE((caddr_t)cb->cb_data, 469 n - taildata, UIO_READ, uio); 470 } else 471 error = UIOMOVE((caddr_t)cb->cb_data + head, n, 472 UIO_READ, uio); 473 if (error) 474 return (error); 475 head = AUCB_MOD(head + n); 476 (void) splaudio(); 477 cb->cb_head = head; 478 } while (uio->uio_resid >= blocksize); 479 out: 480 splx(s); 481 return (error); 482 } 483 484 int 485 AUDIOWRITE(dev, uio, ioflag) 486 { 487 register struct audio_softc *sc = SOFTC(dev); 488 register struct aucb *cb = &sc->sc_au.au_wb; 489 register int s, n, tail, tailspace, error, first, watermark, drops; 490 491 error = 0; 492 first = 1; 493 s = splaudio(); 494 while (uio->uio_resid > 0) { 495 watermark = sc->sc_au.au_hiwat; 496 while (AUCB_LEN(cb) > watermark) { 497 #ifndef SUNOS 498 if (ioflag & IO_NDELAY) { 499 error = EWOULDBLOCK; 500 goto out; 501 } 502 #endif 503 if ((error = audio_sleep(cb, watermark)) != 0) 504 goto out; 505 watermark = sc->sc_au.au_lowat; 506 } 507 splx(s); 508 /* 509 * The only value that can change on an interrupt is 510 * cb->cb_head. We only pull that out once to decide 511 * how much to write into cb_data; if we lose a race 512 * and cb_head changes, we will merely be overly 513 * conservative. For a legitimate time stamp, 514 * however, we need to synchronize the accesses to 515 * au_stamp and cb_head at a high ipl below. 516 */ 517 if ((n = AUCB_SIZE - AUCB_LEN(cb) - 1) > uio->uio_resid) 518 n = uio->uio_resid; 519 tail = cb->cb_tail; 520 tailspace = AUCB_SIZE - tail; 521 if (n > tailspace) { 522 /* write first part at tail and rest at head */ 523 error = UIOMOVE((caddr_t)cb->cb_data + tail, 524 tailspace, UIO_WRITE, uio); 525 if (error == 0) 526 error = UIOMOVE((caddr_t)cb->cb_data, 527 n - tailspace, UIO_WRITE, uio); 528 } else 529 error = UIOMOVE((caddr_t)cb->cb_data + tail, n, 530 UIO_WRITE, uio); 531 if (error) 532 return (error); 533 /* 534 * We cannot do this outside the loop because if the 535 * buffer is empty, an indeterminate amount of time 536 * will pass before the output starts to drain. 537 */ 538 (void)splaudio(); 539 tail = AUCB_MOD(tail + n); 540 if (first) { 541 first = 0; 542 sc->sc_wseek = sc->sc_au.au_stamp + AUCB_LEN(cb) + 1; 543 /* 544 * To guarantee that a write is contiguous in the 545 * sample space, we clear the drop count the first 546 * time through. If we later get drops, we will 547 * break out of the loop below, before writing 548 * a new frame. 549 * XXX I think we're one iteration too late! 550 */ 551 cb->cb_drops = 0; 552 } 553 cb->cb_tail = tail; 554 if (cb->cb_drops != 0) 555 break; 556 } 557 out: 558 splx(s); 559 return (error); 560 } 561 562 /* Sun audio compatibility */ 563 struct sun_audio_prinfo { 564 u_int sample_rate; 565 u_int channels; 566 u_int precision; 567 u_int encoding; 568 u_int gain; 569 u_int port; 570 u_int reserved0[4]; 571 u_int samples; 572 u_int eof; 573 u_char pause; 574 u_char error; 575 u_char waiting; 576 u_char reserved1[3]; 577 u_char open; 578 u_char active; 579 }; 580 struct sun_audio_info { 581 struct sun_audio_prinfo play; 582 struct sun_audio_prinfo record; 583 u_int monitor_gain; 584 u_int reserved[4]; 585 }; 586 587 #ifndef SUNOS 588 #define SUNAUDIO_GETINFO _IOR('A', 1, struct sun_audio_info) 589 #define SUNAUDIO_SETINFO _IOWR('A', 2, struct sun_audio_info) 590 #else 591 #define SUNAUDIO_GETINFO _IOR(A, 1, struct sun_audio_info) 592 #define SUNAUDIO_SETINFO _IOWR(A, 2, struct sun_audio_info) 593 #endif 594 595 int 596 AUDIOIOCTL(dev, cmd, addr, flag, p) 597 { 598 register struct audio_softc *sc = SOFTC(dev); 599 int error = 0, i, s; 600 601 switch (cmd) { 602 603 case AUDIO_GETMAP: 604 bcopy((caddr_t)&sc->sc_map, addr, sizeof(sc->sc_map)); 605 break; 606 607 case AUDIO_SETMAP: 608 bcopy(addr, (caddr_t)&sc->sc_map, sizeof(sc->sc_map)); 609 sc->sc_map.mr_mmr2 &= 0x7f; 610 audio_setmap(sc->sc_au.au_amd, &sc->sc_map); 611 break; 612 613 case AUDIO_FLUSH: 614 s = splaudio(); 615 AUCB_INIT(&sc->sc_au.au_rb); 616 AUCB_INIT(&sc->sc_au.au_wb); 617 splx(s); 618 sc->sc_wseek = 0; 619 sc->sc_rseek = 0; 620 break; 621 622 /* 623 * Number of read samples dropped. We don't know where or 624 * when they were dropped. 625 */ 626 case AUDIO_RERROR: 627 *(int *)addr = sc->sc_au.au_rb.cb_drops != 0; 628 break; 629 630 /* 631 * Timestamp of last frame written. 632 */ 633 case AUDIO_WSEEK: 634 *(u_long *)addr = sc->sc_wseek; 635 break; 636 637 case AUDIO_SETINFO: 638 error = audiosetinfo(sc, (struct audio_info *)addr); 639 break; 640 641 case AUDIO_GETINFO: 642 error = audiogetinfo(sc, (struct audio_info *)addr); 643 break; 644 645 case SUNAUDIO_GETINFO: 646 error = sunaudiogetinfo(sc, (struct sun_audio_info *)addr); 647 break; 648 649 case SUNAUDIO_SETINFO: 650 error = sunaudiosetinfo(sc, (struct sun_audio_info *)addr); 651 break; 652 653 case AUDIO_DRAIN: 654 s = splaudio(); 655 error = audio_drain(sc); 656 splx(s); 657 break; 658 659 default: 660 error = EINVAL; 661 break; 662 } 663 return (error); 664 } 665 666 int 667 AUDIOSELECT(dev, rw, p) 668 { 669 register struct audio_softc *sc = SOFTC(dev); 670 register struct aucb *cb; 671 register int s = splaudio(); 672 673 switch (rw) { 674 675 case FREAD: 676 cb = &sc->sc_au.au_rb; 677 if (AUCB_LEN(cb) >= sc->sc_au.au_blksize) { 678 splx(s); 679 return (1); 680 } 681 selrecord(p, &sc->sc_rsel); 682 cb->cb_thresh = sc->sc_au.au_blksize; 683 break; 684 685 case FWRITE: 686 cb = &sc->sc_au.au_wb; 687 if (AUCB_LEN(cb) <= sc->sc_au.au_lowat) { 688 splx(s); 689 return (1); 690 } 691 selrecord(p, &sc->sc_wsel); 692 cb->cb_thresh = sc->sc_au.au_lowat; 693 break; 694 } 695 splx(s); 696 return (0); 697 } 698 699 #ifdef AUDIO_C_HANDLER 700 int 701 audiohwintr(au0) 702 void *au0; 703 { 704 #ifdef SUNOS 705 register struct auio *au = audio_au; 706 #else 707 register struct auio *au = au0; 708 #endif 709 register volatile struct amd7930 *amd = au->au_amd; 710 register struct aucb *cb; 711 register int h, t, k; 712 713 k = amd->ir; /* clear interrupt */ 714 ++au->au_stamp; 715 716 /* receive incoming data */ 717 cb = &au->au_rb; 718 h = cb->cb_head; 719 t = cb->cb_tail; 720 k = AUCB_MOD(t + 1); 721 if (h == k) 722 cb->cb_drops++; 723 else if (cb->cb_pause != 0) 724 cb->cb_pdrops++; 725 else { 726 cb->cb_data[t] = amd->bbrb; 727 cb->cb_tail = t = k; 728 } 729 if (AUCB_MOD(t - h) >= cb->cb_thresh) { 730 cb->cb_thresh = AUCB_SIZE; 731 cb->cb_waking = 1; 732 AUDIO_SET_SWINTR; 733 } 734 /* send outgoing data */ 735 cb = &au->au_wb; 736 h = cb->cb_head; 737 t = cb->cb_tail; 738 if (h == t) 739 cb->cb_drops++; 740 else if (cb->cb_pause != 0) 741 cb->cb_pdrops++; 742 else { 743 cb->cb_head = h = AUCB_MOD(h + 1); 744 amd->bbtb = cb->cb_data[h]; 745 } 746 if (AUCB_MOD(t - h) <= cb->cb_thresh) { 747 cb->cb_thresh = -1; 748 cb->cb_waking = 1; 749 AUDIO_SET_SWINTR; 750 } 751 return (1); 752 } 753 #endif 754 755 int 756 audioswintr(sc0) 757 void *sc0; 758 { 759 register struct audio_softc *sc; 760 register int s, ret = 0; 761 #ifdef SUNOS 762 sc = &audio_softc; 763 #else 764 sc = sc0; 765 #endif 766 s = splaudio(); 767 if (sc->sc_au.au_rb.cb_waking != 0) { 768 sc->sc_au.au_rb.cb_waking = 0; 769 splx(s); 770 ret = 1; 771 wakeup((caddr_t)&sc->sc_au.au_rb); 772 SELWAKEUP(&sc->sc_rsel); 773 (void) splaudio(); 774 } 775 if (sc->sc_au.au_wb.cb_waking != 0) { 776 sc->sc_au.au_wb.cb_waking = 0; 777 splx(s); 778 ret = 1; 779 wakeup((caddr_t)&sc->sc_au.au_wb); 780 SELWAKEUP(&sc->sc_wsel); 781 } else 782 splx(s); 783 return (ret); 784 } 785 786 /* Write 16 bits of data from variable v to the data port of the audio chip */ 787 788 #define WAMD16(amd, v) ((amd)->dr = v, (amd)->dr = v >> 8) 789 790 void 791 audio_setmap(amd, map) 792 register volatile struct amd7930 *amd; 793 register struct mapreg *map; 794 { 795 register int i, s, v; 796 797 s = splaudio(); 798 amd->cr = AMDR_MAP_1_10; 799 for (i = 0; i < 8; i++) { 800 v = map->mr_x[i]; 801 WAMD16(amd, v); 802 } 803 for (i = 0; i < 8; ++i) { 804 v = map->mr_r[i]; 805 WAMD16(amd, v); 806 } 807 v = map->mr_gx; WAMD16(amd, v); 808 v = map->mr_gr; WAMD16(amd, v); 809 v = map->mr_ger; WAMD16(amd, v); 810 v = map->mr_stgr; WAMD16(amd, v); 811 v = map->mr_ftgr; WAMD16(amd, v); 812 v = map->mr_atgr; WAMD16(amd, v); 813 amd->dr = map->mr_mmr1; 814 amd->dr = map->mr_mmr2; 815 splx(s); 816 } 817 818 /* 819 * Set the mmr1 register and one other 16 bit register in the audio chip. 820 * The other register is indicated by op and val. 821 */ 822 void 823 audio_setmmr1(amd, mmr1, op, val) 824 register volatile struct amd7930 *amd; 825 register int mmr1; 826 register int op; 827 register int val; 828 { 829 register int s = splaudio(); 830 831 amd->cr = AMDR_MAP_MMR1; 832 amd->dr = mmr1; 833 amd->cr = op; 834 WAMD16(amd, val); 835 splx(s); 836 } 837 838 /* 839 * Set only the mmr1 regsiter, and one other. 840 */ 841 static void 842 audio_setmmr2(amd, mmr2) 843 register volatile struct amd7930 *amd; 844 register int mmr2; 845 { 846 register int s = splaudio(); 847 848 amd->cr = AMDR_MAP_MMR2; 849 amd->dr = mmr2; 850 splx(s); 851 } 852 853 static u_short ger_coeff[] = { 854 0xaaaa, 0x9bbb, 0x79ac, 0x099a, 0x4199, 0x3199, 0x9cde, 0x9def, 855 0x749c, 0x549d, 0x6aae, 0xabcd, 0xabdf, 0x7429, 0x64ab, 0x6aff, 856 0x2abd, 0xbeef, 0x5cce, 0x75cd, 0x0099, 0x554c, 0x43dd, 0x33dd, 857 0x52ef, 0x771b, 0x5542, 0x41dd, 0x31dd, 0x441f, 0x431f, 0x331f, 858 0x40dd, 0x11dd, 0x440f, 0x411f, 0x311f, 0x5520, 0x10dd, 0x4211, 859 0x410f, 0x111f, 0x600b, 0x00dd, 0x4210, 0x400f, 0x110f, 0x2210, 860 0x7200, 0x4200, 0x2110, 0x100f, 0x2200, 0x1110, 0x000b, 0x2100, 861 0x000f, 862 #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0])) 863 }; 864 865 static u_short gx_coeff[] = { 866 0x0808, 0x4cb2, 0x3dac, 0x2ae5, 0x2533, 0x2222, 0x2122, 0x1fd3, 867 0x12a2, 0x121b, 0x113b, 0x0bc3, 0x10f2, 0x03ba, 0x02ca, 0x021d, 868 0x015a, 0x0122, 0x0112, 0x00ec, 0x0032, 0x0021, 0x0013, 0x0011, 869 0x000e, 870 #define NGX (sizeof(gx_coeff) / sizeof(gx_coeff[0])) 871 }; 872 873 static u_short stg_coeff[] = { 874 0x8b7c, 0x8b44, 0x8b35, 0x8b2a, 0x8b24, 0x8b22, 0x9123, 0x912e, 875 0x912a, 0x9132, 0x913b, 0x914b, 0x91f9, 0x91c5, 0x91b6, 0x9212, 876 0x91a4, 0x9222, 0x9232, 0x92fb, 0x92aa, 0x9327, 0x93b3, 0x94b3, 877 0x9f91, 0x9cea, 0x9bf9, 0x9aac, 0x9a4a, 0xa222, 0xa2a2, 0xa68d, 878 0xaaa3, 0xb242, 0xbb52, 0xcbb2, 0x0808, 879 #define NSTG (sizeof(stg_coeff) / sizeof(stg_coeff[0])) 880 }; 881 882 static void 883 ausetrgain(sc, level) 884 register struct audio_softc *sc; 885 register int level; 886 { 887 level &= 0xff; 888 sc->sc_rlevel = level; 889 if (level != 0) 890 sc->sc_map.mr_mmr1 |= AMD_MMR1_GX; 891 else 892 sc->sc_map.mr_mmr1 &=~ AMD_MMR1_GX; 893 894 sc->sc_map.mr_gx = gx_coeff[(level * NGX) / 256]; 895 audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1, 896 AMDR_MAP_GX, sc->sc_map.mr_gx); 897 } 898 899 static void 900 ausetpgain(sc, level) 901 register struct audio_softc *sc; 902 register int level; 903 { 904 level &= 0xff; 905 sc->sc_plevel = level; 906 if (level != 0) 907 sc->sc_map.mr_mmr1 |= AMD_MMR1_GER; 908 else 909 sc->sc_map.mr_mmr1 &=~ AMD_MMR1_GER; 910 911 sc->sc_map.mr_ger = ger_coeff[(level * NGER) / 256]; 912 audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1, 913 AMDR_MAP_GER, sc->sc_map.mr_ger); 914 } 915 916 static void 917 ausetmgain(sc, level) 918 register struct audio_softc *sc; 919 register int level; 920 { 921 level &= 0xff; 922 sc->sc_mlevel = level; 923 if (level != 0) 924 sc->sc_map.mr_mmr1 |= AMD_MMR1_STG; 925 else 926 sc->sc_map.mr_mmr1 &=~ AMD_MMR1_STG; 927 928 sc->sc_map.mr_stgr = stg_coeff[(level * NSTG) / 256]; 929 audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1, 930 AMDR_MAP_STG, sc->sc_map.mr_stgr); 931 } 932 933 static int 934 audiosetinfo(sc, ai) 935 struct audio_softc *sc; 936 struct audio_info *ai; 937 { 938 struct audio_prinfo *r = &ai->record, *p = &ai->play; 939 register int s, bsize; 940 941 if (p->gain != ~0) 942 ausetpgain(sc, p->gain); 943 if (r->gain != ~0) 944 ausetrgain(sc, r->gain); 945 if (ai->monitor_gain != ~0) 946 ausetmgain(sc, p->gain); 947 if (p->port == AUDIO_SPEAKER) { 948 sc->sc_map.mr_mmr2 |= AMD_MMR2_LS; 949 audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 950 } else if (p->port == AUDIO_HEADPHONE) { 951 sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS; 952 audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 953 } 954 if (p->pause != (u_char)~0) 955 sc->sc_au.au_wb.cb_pause = p->pause; 956 if (r->pause != (u_char)~0) 957 sc->sc_au.au_rb.cb_pause = r->pause; 958 959 if (ai->blocksize != ~0) { 960 if (ai->blocksize == 0) 961 bsize = ai->blocksize = DEFBLKSIZE; 962 else if (ai->blocksize > MAXBLKSIZE) 963 bsize = ai->blocksize = MAXBLKSIZE; 964 else 965 bsize = ai->blocksize; 966 967 s = splaudio(); 968 sc->sc_au.au_blksize = bsize; 969 /* AUDIO_FLUSH */ 970 AUCB_INIT(&sc->sc_au.au_rb); 971 AUCB_INIT(&sc->sc_au.au_wb); 972 splx(s); 973 974 } 975 if (ai->hiwat != ~0 && (unsigned)ai->hiwat < AUCB_SIZE) 976 sc->sc_au.au_hiwat = ai->hiwat; 977 if (ai->lowat != ~0 && ai->lowat < AUCB_SIZE) 978 sc->sc_au.au_lowat = ai->lowat; 979 980 return (0); 981 } 982 983 static int 984 sunaudiosetinfo(sc, ai) 985 struct audio_softc *sc; 986 struct sun_audio_info *ai; 987 { 988 struct sun_audio_prinfo *r = &ai->record, *p = &ai->play; 989 990 if (p->gain != ~0) 991 ausetpgain(sc, p->gain); 992 if (r->gain != ~0) 993 ausetrgain(sc, r->gain); 994 if (ai->monitor_gain != ~0) 995 ausetmgain(sc, p->gain); 996 if (p->port == AUDIO_SPEAKER) { 997 sc->sc_map.mr_mmr2 |= AMD_MMR2_LS; 998 audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 999 } else if (p->port == AUDIO_HEADPHONE) { 1000 sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS; 1001 audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 1002 } 1003 /* 1004 * The bsd driver does not distinguish between paused and active. 1005 * (In the sun driver, not active means samples are not ouput 1006 * at all, but paused means the last streams buffer is drained 1007 * and then output stops.) If either are 0, then when stop output. 1008 * Otherwise, if either are non-zero, we resume. 1009 */ 1010 if (p->pause == 0 || p->active == 0) 1011 sc->sc_au.au_wb.cb_pause = 0; 1012 else if (p->pause != (u_char)~0 || p->active != (u_char)~0) 1013 sc->sc_au.au_wb.cb_pause = 1; 1014 if (r->pause == 0 || r->active == 0) 1015 sc->sc_au.au_rb.cb_pause = 0; 1016 else if (r->pause != (u_char)~0 || r->active != (u_char)~0) 1017 sc->sc_au.au_rb.cb_pause = 1; 1018 1019 return (0); 1020 } 1021 1022 static int 1023 audiogetinfo(sc, ai) 1024 struct audio_softc *sc; 1025 struct audio_info *ai; 1026 { 1027 struct audio_prinfo *r = &ai->record, *p = &ai->play; 1028 1029 p->sample_rate = r->sample_rate = 8000; 1030 p->channels = r->channels = 1; 1031 p->precision = r->precision = 8; 1032 p->encoding = r->encoding = AUDIO_ENCODING_ULAW; 1033 1034 ai->monitor_gain = sc->sc_mlevel; 1035 r->gain = sc->sc_rlevel; 1036 p->gain = sc->sc_plevel; 1037 r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ? 1038 AUDIO_SPEAKER : AUDIO_HEADPHONE; 1039 1040 p->pause = sc->sc_au.au_wb.cb_pause; 1041 r->pause = sc->sc_au.au_rb.cb_pause; 1042 p->error = sc->sc_au.au_wb.cb_drops != 0; 1043 r->error = sc->sc_au.au_rb.cb_drops != 0; 1044 1045 p->open = sc->sc_open; 1046 r->open = sc->sc_open; 1047 1048 p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops; 1049 r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops; 1050 1051 p->seek = sc->sc_wseek; 1052 r->seek = sc->sc_rseek; 1053 1054 ai->blocksize = sc->sc_au.au_blksize; 1055 ai->hiwat = sc->sc_au.au_hiwat; 1056 ai->lowat = sc->sc_au.au_lowat; 1057 1058 return (0); 1059 } 1060 1061 static int 1062 sunaudiogetinfo(sc, ai) 1063 struct audio_softc *sc; 1064 struct sun_audio_info *ai; 1065 { 1066 struct sun_audio_prinfo *r = &ai->record, *p = &ai->play; 1067 1068 p->sample_rate = r->sample_rate = 8000; 1069 p->channels = r->channels = 1; 1070 p->precision = r->precision = 8; 1071 p->encoding = r->encoding = AUDIO_ENCODING_ULAW; 1072 1073 ai->monitor_gain = sc->sc_mlevel; 1074 r->gain = sc->sc_rlevel; 1075 p->gain = sc->sc_plevel; 1076 r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ? 1077 AUDIO_SPEAKER : AUDIO_HEADPHONE; 1078 1079 p->active = p->pause = sc->sc_au.au_wb.cb_pause; 1080 r->active = r->pause = sc->sc_au.au_rb.cb_pause; 1081 p->error = sc->sc_au.au_wb.cb_drops != 0; 1082 r->error = sc->sc_au.au_rb.cb_drops != 0; 1083 1084 p->waiting = 0; 1085 r->waiting = 0; 1086 p->eof = 0; 1087 r->eof = 0; 1088 1089 p->open = sc->sc_open; 1090 r->open = sc->sc_open; 1091 1092 p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops; 1093 r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops; 1094 1095 return (0); 1096 } 1097 #endif 1098