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