1 /* $NetBSD: am7930.c,v 1.14 1996/11/01 23:32:15 pk Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Rolf Grossmann 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 Rolf Grossmann. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include "audio.h" 34 #if NAUDIO > 0 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/errno.h> 39 #include <sys/ioctl.h> 40 #include <sys/device.h> 41 #include <sys/proc.h> 42 43 #include <machine/autoconf.h> 44 #include <machine/cpu.h> 45 46 #include <sys/audioio.h> 47 #include <dev/audio_if.h> 48 49 #include <dev/ic/am7930reg.h> 50 #include <sparc/dev/amd7930var.h> 51 52 #ifdef AUDIO_DEBUG 53 extern void Dprintf __P((const char *, ...)); 54 55 int amd7930debug = 0; 56 #define DPRINTF(x) if (amd7930debug) Dprintf x 57 #else 58 #define DPRINTF(x) 59 #endif 60 61 /* 62 * Software state, per AMD79C30 audio chip. 63 */ 64 struct amd7930_softc { 65 struct device sc_dev; /* base device */ 66 struct intrhand sc_hwih; /* hardware interrupt vector */ 67 struct intrhand sc_swih; /* software interrupt vector */ 68 69 int sc_open; /* single use device */ 70 int sc_locked; /* true when transfering data */ 71 struct mapreg sc_map; /* current contents of map registers */ 72 73 u_char sc_rlevel; /* record level */ 74 u_char sc_plevel; /* play level */ 75 u_char sc_mlevel; /* monitor level */ 76 u_char sc_out_port; /* output port */ 77 78 /* interfacing with the interrupt handlers */ 79 void (*sc_rintr)(void*); /* input completion intr handler */ 80 void *sc_rarg; /* arg for sc_rintr() */ 81 void (*sc_pintr)(void*); /* output completion intr handler */ 82 void *sc_parg; /* arg for sc_pintr() */ 83 84 /* sc_au is special in that the hardware interrupt handler uses it */ 85 struct auio sc_au; /* recv and xmit buffers, etc */ 86 #define sc_intrcnt sc_au.au_intrcnt /* statistics */ 87 }; 88 89 /* interrupt interfaces */ 90 #ifdef AUDIO_C_HANDLER 91 int amd7930hwintr __P((void *)); 92 #if defined(SUN4M) 93 #define AUDIO_SET_SWINTR do { \ 94 if (CPU_ISSUN4M) \ 95 raise(0, 4); \ 96 else \ 97 ienab_bis(IE_L4); \ 98 } while(0); 99 #else 100 #define AUDIO_SET_SWINTR ienab_bis(IE_L4) 101 #endif /* defined(SUN4M) */ 102 #else 103 struct auio *auiop; 104 #endif /* AUDIO_C_HANDLER */ 105 int amd7930swintr __P((void *)); 106 107 /* forward declarations */ 108 void audio_setmap __P((volatile struct amd7930 *, struct mapreg *)); 109 static void init_amd __P((volatile struct amd7930 *)); 110 111 /* autoconfiguration driver */ 112 void amd7930attach __P((struct device *, struct device *, void *)); 113 int amd7930match __P((struct device *, void *, void *)); 114 115 struct cfattach audio_ca = { 116 sizeof(struct amd7930_softc), amd7930match, amd7930attach 117 }; 118 119 struct cfdriver audio_cd = { 120 NULL, "audio", DV_DULL 121 }; 122 123 struct audio_device amd7930_device = { 124 "amd7930", 125 "x", 126 "audio" 127 }; 128 129 /* Write 16 bits of data from variable v to the data port of the audio chip */ 130 #define WAMD16(amd, v) ((amd)->dr = (v), (amd)->dr = (v) >> 8) 131 132 /* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */ 133 134 /* 135 * gx, gr & stg gains. this table must contain 256 elements with 136 * the 0th being "infinity" (the magic value 9008). The remaining 137 * elements match sun's gain curve (but with higher resolution): 138 * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps. 139 */ 140 static const u_short gx_coeff[256] = { 141 0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33, 142 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22, 143 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b, 144 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb, 145 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a, 146 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213, 147 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231, 148 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4, 149 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2, 150 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa, 151 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b, 152 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b, 153 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd, 154 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808, 155 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243, 156 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224, 157 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb, 158 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33, 159 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32, 160 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323, 161 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a, 162 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23, 163 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1, 164 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333, 165 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227, 166 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6, 167 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2, 168 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba, 169 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033, 170 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021, 171 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012, 172 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e, 173 }; 174 175 /* 176 * second stage play gain. 177 */ 178 static const u_short ger_coeff[] = { 179 0x431f, /* 5. dB */ 180 0x331f, /* 5.5 dB */ 181 0x40dd, /* 6. dB */ 182 0x11dd, /* 6.5 dB */ 183 0x440f, /* 7. dB */ 184 0x411f, /* 7.5 dB */ 185 0x311f, /* 8. dB */ 186 0x5520, /* 8.5 dB */ 187 0x10dd, /* 9. dB */ 188 0x4211, /* 9.5 dB */ 189 0x410f, /* 10. dB */ 190 0x111f, /* 10.5 dB */ 191 0x600b, /* 11. dB */ 192 0x00dd, /* 11.5 dB */ 193 0x4210, /* 12. dB */ 194 0x110f, /* 13. dB */ 195 0x7200, /* 14. dB */ 196 0x2110, /* 15. dB */ 197 0x2200, /* 15.9 dB */ 198 0x000b, /* 16.9 dB */ 199 0x000f /* 18. dB */ 200 #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0])) 201 }; 202 203 /* 204 * Define our interface to the higher level audio driver. 205 */ 206 int amd7930_open __P((dev_t, int)); 207 void amd7930_close __P((void *)); 208 int amd7930_set_in_sr __P((void *, u_long)); 209 u_long amd7930_get_in_sr __P((void *)); 210 int amd7930_set_out_sr __P((void *, u_long)); 211 u_long amd7930_get_out_sr __P((void *)); 212 int amd7930_query_encoding __P((void *, struct audio_encoding *)); 213 int amd7930_set_encoding __P((void *, u_int)); 214 int amd7930_get_encoding __P((void *)); 215 int amd7930_set_precision __P((void *, u_int)); 216 int amd7930_get_precision __P((void *)); 217 int amd7930_set_channels __P((void *, int)); 218 int amd7930_get_channels __P((void *)); 219 int amd7930_round_blocksize __P((void *, int)); 220 int amd7930_set_out_port __P((void *, int)); 221 int amd7930_get_out_port __P((void *)); 222 int amd7930_set_in_port __P((void *, int)); 223 int amd7930_get_in_port __P((void *)); 224 int amd7930_commit_settings __P((void *)); 225 u_int amd7930_get_silence __P((int)); 226 int amd7930_start_output __P((void *, void *, int, void (*)(void *), 227 void *)); 228 int amd7930_start_input __P((void *, void *, int, void (*)(void *), 229 void *)); 230 int amd7930_halt_output __P((void *)); 231 int amd7930_halt_input __P((void *)); 232 int amd7930_cont_output __P((void *)); 233 int amd7930_cont_input __P((void *)); 234 int amd7930_getdev __P((void *, struct audio_device *)); 235 int amd7930_setfd __P((void *, int)); 236 int amd7930_set_port __P((void *, mixer_ctrl_t *)); 237 int amd7930_get_port __P((void *, mixer_ctrl_t *)); 238 int amd7930_query_devinfo __P((void *, mixer_devinfo_t *)); 239 240 241 struct audio_hw_if sa_hw_if = { 242 amd7930_open, 243 amd7930_close, 244 NULL, 245 amd7930_set_in_sr, 246 amd7930_get_in_sr, 247 amd7930_set_out_sr, 248 amd7930_get_out_sr, 249 amd7930_query_encoding, 250 amd7930_set_encoding, 251 amd7930_get_encoding, 252 amd7930_set_precision, 253 amd7930_get_precision, 254 amd7930_set_channels, 255 amd7930_get_channels, 256 amd7930_round_blocksize, 257 amd7930_set_out_port, 258 amd7930_get_out_port, 259 amd7930_set_in_port, 260 amd7930_get_in_port, 261 amd7930_commit_settings, 262 amd7930_get_silence, 263 NULL, 264 NULL, 265 amd7930_start_output, 266 amd7930_start_input, 267 amd7930_halt_output, 268 amd7930_halt_input, 269 amd7930_cont_output, 270 amd7930_cont_input, 271 NULL, 272 amd7930_getdev, 273 amd7930_setfd, 274 amd7930_set_port, 275 amd7930_get_port, 276 amd7930_query_devinfo, 277 1, 278 0 279 }; 280 281 /* autoconfig routines */ 282 283 int 284 amd7930match(parent, vcf, aux) 285 struct device *parent; 286 void *vcf, *aux; 287 { 288 struct cfdata *cf = vcf; 289 register struct confargs *ca = aux; 290 register struct romaux *ra = &ca->ca_ra; 291 292 if (CPU_ISSUN4) 293 return (0); 294 return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0); 295 } 296 297 /* 298 * Audio chip found. 299 */ 300 void 301 amd7930attach(parent, self, args) 302 struct device *parent, *self; 303 void *args; 304 { 305 register struct amd7930_softc *sc = (struct amd7930_softc *)self; 306 register struct confargs *ca = args; 307 register struct romaux *ra = &ca->ca_ra; 308 register volatile struct amd7930 *amd; 309 register int pri; 310 311 if (ra->ra_nintr != 1) { 312 printf(": expected 1 interrupt, got %d\n", ra->ra_nintr); 313 return; 314 } 315 pri = ra->ra_intr[0].int_pri; 316 printf(" pri %d, softpri %d\n", pri, PIL_AUSOFT); 317 amd = (volatile struct amd7930 *)(ra->ra_vaddr ? 318 ra->ra_vaddr : mapiodev(ra->ra_reg, 0, sizeof (*amd), 319 ca->ca_bustype)); 320 321 sc->sc_map.mr_mmr1 = AMD_MMR1_GX | AMD_MMR1_GER | 322 AMD_MMR1_GR | AMD_MMR1_STG; 323 sc->sc_au.au_amd = amd; 324 /* set boot defaults */ 325 sc->sc_rlevel = 128; 326 sc->sc_plevel = 128; 327 sc->sc_mlevel = 0; 328 sc->sc_out_port = SUNAUDIO_SPEAKER; 329 330 init_amd(amd); 331 332 #ifndef AUDIO_C_HANDLER 333 auiop = &sc->sc_au; 334 intr_fasttrap(pri, amd7930_trap); 335 #else 336 sc->sc_hwih.ih_fun = amd7930hwintr; 337 sc->sc_hwih.ih_arg = &sc->sc_au; 338 intr_establish(pri, &sc->sc_hwih); 339 #endif 340 sc->sc_swih.ih_fun = amd7930swintr; 341 sc->sc_swih.ih_arg = sc; 342 intr_establish(PIL_AUSOFT, &sc->sc_swih); 343 344 evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt); 345 346 if (audio_hardware_attach(&sa_hw_if, sc) != 0) 347 printf("audio: could not attach to audio pseudo-device driver\n"); 348 } 349 350 static void 351 init_amd(amd) 352 register volatile struct amd7930 *amd; 353 { 354 /* disable interrupts */ 355 amd->cr = AMDR_INIT; 356 amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 357 358 /* 359 * Initialize the mux unit. We use MCR3 to route audio (MAP) 360 * through channel Bb. MCR1 and MCR2 are unused. 361 * Setting the INT enable bit in MCR4 will generate an interrupt 362 * on each converted audio sample. 363 */ 364 amd->cr = AMDR_MUX_1_4; 365 amd->dr = 0; 366 amd->dr = 0; 367 amd->dr = (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA; 368 amd->dr = AMD_MCR4_INT_ENABLE; 369 } 370 371 int 372 amd7930_open(dev, flags) 373 dev_t dev; 374 int flags; 375 { 376 register struct amd7930_softc *sc; 377 int unit = AUDIOUNIT(dev); 378 379 DPRINTF(("sa_open: unit %d\n",unit)); 380 381 if (unit >= audio_cd.cd_ndevs) 382 return (ENODEV); 383 if ((sc = audio_cd.cd_devs[unit]) == NULL) 384 return (ENXIO); 385 if (sc->sc_open) 386 return (EBUSY); 387 sc->sc_open = 1; 388 sc->sc_locked = 0; 389 sc->sc_rintr = 0; 390 sc->sc_rarg = 0; 391 sc->sc_pintr = 0; 392 sc->sc_parg = 0; 393 394 sc->sc_au.au_rdata = 0; 395 sc->sc_au.au_pdata = 0; 396 397 DPRINTF(("saopen: ok -> sc=0x%x\n",sc)); 398 399 return (0); 400 } 401 402 void 403 amd7930_close(addr) 404 void *addr; 405 { 406 register struct amd7930_softc *sc = addr; 407 408 DPRINTF(("sa_close: sc=0x%x\n", sc)); 409 /* 410 * halt i/o, clear open flag, and done. 411 */ 412 amd7930_halt_input(sc); 413 amd7930_halt_output(sc); 414 sc->sc_open = 0; 415 416 DPRINTF(("sa_close: closed.\n")); 417 } 418 419 int 420 amd7930_set_in_sr(addr, sr) 421 void *addr; 422 u_long sr; 423 { 424 if (sr != 8000) 425 return EINVAL; 426 427 return(0); /* no other sampling rates supported by amd chip */ 428 } 429 430 u_long 431 amd7930_get_in_sr(addr) 432 void *addr; 433 { 434 return(8000); 435 } 436 437 int 438 amd7930_set_out_sr(addr, sr) 439 void *addr; 440 u_long sr; 441 { 442 if (sr != 8000) 443 return(EINVAL); 444 445 return(0); /* no other sampling rates supported by amd chip */ 446 } 447 448 u_long 449 amd7930_get_out_sr(addr) 450 void *addr; 451 { 452 return(8000); 453 } 454 455 int 456 amd7930_query_encoding(addr, fp) 457 void *addr; 458 struct audio_encoding *fp; 459 { 460 switch (fp->index) { /* ??? */ 461 case 0: 462 strcpy(fp->name, "MU-Law"); 463 fp->format_id = AUDIO_ENCODING_ULAW; 464 break; 465 default: 466 return(EINVAL); 467 /*NOTREACHED*/ 468 } 469 return(0); 470 } 471 472 int 473 amd7930_set_encoding(addr, enc) 474 void *addr; 475 u_int enc; 476 { 477 if (enc != AUDIO_ENCODING_ULAW) 478 return(EINVAL); 479 480 return(0); /* no other encoding supported by amd chip */ 481 } 482 483 int 484 amd7930_get_encoding(addr) 485 void *addr; 486 { 487 return(AUDIO_ENCODING_ULAW); 488 } 489 490 int 491 amd7930_set_precision(addr, prec) 492 void *addr; 493 u_int prec; 494 { 495 if (prec != 8) 496 return(EINVAL); 497 498 return(0); /* no other precision supported by amd chip */ 499 } 500 501 int 502 amd7930_get_precision(addr) 503 void *addr; 504 { 505 return(8); 506 } 507 508 int 509 amd7930_set_channels(addr, chans) 510 void *addr; 511 int chans; 512 { 513 if (chans != 1) 514 return(EINVAL); 515 516 return(0); /* only 1 channel supported by amd chip */ 517 } 518 519 int 520 amd7930_get_channels(addr) 521 void *addr; 522 { 523 return(1); 524 } 525 526 int 527 amd7930_round_blocksize(addr, blk) 528 void *addr; 529 int blk; 530 { 531 return(blk); 532 } 533 534 int 535 amd7930_set_out_port(addr, port) 536 void *addr; 537 int port; 538 { 539 register struct amd7930_softc *sc = addr; 540 541 switch(port) { 542 case SUNAUDIO_SPEAKER: 543 case SUNAUDIO_HEADPHONES: 544 sc->sc_out_port = port; /* set on commit */ 545 break; 546 default: 547 return(EINVAL); 548 } 549 return(0); 550 } 551 552 int 553 amd7930_get_out_port(addr) 554 void *addr; 555 { 556 register struct amd7930_softc *sc = addr; 557 558 return(sc->sc_out_port); 559 } 560 561 int 562 amd7930_set_in_port(addr, port) 563 void *addr; 564 int port; 565 { 566 if (port != SUNAUDIO_MIC_PORT) 567 return(EINVAL); 568 569 return(0); /* only microphone input supported by amd chip */ 570 } 571 572 int 573 amd7930_get_in_port(addr) 574 void *addr; 575 { 576 return(SUNAUDIO_MIC_PORT); 577 } 578 579 int 580 amd7930_commit_settings(addr) 581 void *addr; 582 { 583 register struct amd7930_softc *sc = addr; 584 register struct mapreg *map; 585 register volatile struct amd7930 *amd; 586 register int s, level; 587 588 DPRINTF(("sa_commit.\n")); 589 590 map = &sc->sc_map; 591 amd = sc->sc_au.au_amd; 592 593 map->mr_gx = gx_coeff[sc->sc_rlevel]; 594 map->mr_stgr = gx_coeff[sc->sc_mlevel]; 595 596 level = (sc->sc_plevel * (256 + NGER)) >> 8; 597 if (level >= 256) { 598 map->mr_ger = ger_coeff[level - 256]; 599 map->mr_gr = gx_coeff[255]; 600 } else { 601 map->mr_ger = ger_coeff[0]; 602 map->mr_gr = gx_coeff[level]; 603 } 604 605 if (sc->sc_out_port == SUNAUDIO_SPEAKER) 606 map->mr_mmr2 |= AMD_MMR2_LS; 607 else 608 map->mr_mmr2 &= ~AMD_MMR2_LS; 609 610 s = splaudio(); 611 612 amd->cr = AMDR_MAP_MMR1; 613 amd->dr = map->mr_mmr1; 614 amd->cr = AMDR_MAP_GX; 615 WAMD16(amd, map->mr_gx); 616 amd->cr = AMDR_MAP_STG; 617 WAMD16(amd, map->mr_stgr); 618 amd->cr = AMDR_MAP_GR; 619 WAMD16(amd, map->mr_gr); 620 amd->cr = AMDR_MAP_GER; 621 WAMD16(amd, map->mr_ger); 622 amd->cr = AMDR_MAP_MMR2; 623 amd->dr = map->mr_mmr2; 624 625 splx(s); 626 return(0); 627 } 628 629 u_int 630 amd7930_get_silence(enc) 631 int enc; 632 { 633 return(0x7f); 634 } 635 636 int 637 amd7930_start_output(addr, p, cc, intr, arg) 638 void *addr; 639 void *p; 640 int cc; 641 void (*intr) __P((void *)); 642 void *arg; 643 { 644 register struct amd7930_softc *sc = addr; 645 646 #ifdef AUDIO_DEBUG 647 if (amd7930debug > 1) 648 Dprintf("sa_start_output: cc=%d 0x%x (0x%x)\n", cc, intr, arg); 649 #endif 650 651 if (!sc->sc_locked) { 652 register volatile struct amd7930 *amd; 653 654 amd = sc->sc_au.au_amd; 655 amd->cr = AMDR_INIT; 656 amd->dr = AMD_INIT_PMS_ACTIVE; 657 sc->sc_locked = 1; 658 DPRINTF(("sa_start_output: started intrs.\n")); 659 } 660 sc->sc_pintr = intr; 661 sc->sc_parg = arg; 662 sc->sc_au.au_pdata = p; 663 sc->sc_au.au_pend = p + cc - 1; 664 return(0); 665 } 666 667 /* ARGSUSED */ 668 int 669 amd7930_start_input(addr, p, cc, intr, arg) 670 void *addr; 671 void *p; 672 int cc; 673 void (*intr) __P((void *)); 674 void *arg; 675 { 676 register struct amd7930_softc *sc = addr; 677 678 #ifdef AUDIO_DEBUG 679 if (amd7930debug > 1) 680 Dprintf("sa_start_input: cc=%d 0x%x (0x%x)\n", cc, intr, arg); 681 #endif 682 683 if (!sc->sc_locked) { 684 register volatile struct amd7930 *amd; 685 686 amd = sc->sc_au.au_amd; 687 amd->cr = AMDR_INIT; 688 amd->dr = AMD_INIT_PMS_ACTIVE; 689 sc->sc_locked = 1; 690 DPRINTF(("sa_start_input: started intrs.\n")); 691 } 692 sc->sc_rintr = intr; 693 sc->sc_rarg = arg; 694 sc->sc_au.au_rdata = p; 695 sc->sc_au.au_rend = p + cc -1; 696 return(0); 697 } 698 699 int 700 amd7930_halt_output(addr) 701 void *addr; 702 { 703 register struct amd7930_softc *sc = addr; 704 register volatile struct amd7930 *amd; 705 706 /* XXX only halt, if input is also halted ?? */ 707 amd = sc->sc_au.au_amd; 708 amd->cr = AMDR_INIT; 709 amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 710 sc->sc_locked = 0; 711 712 return(0); 713 } 714 715 int 716 amd7930_halt_input(addr) 717 void *addr; 718 { 719 register struct amd7930_softc *sc = addr; 720 register volatile struct amd7930 *amd; 721 722 /* XXX only halt, if output is also halted ?? */ 723 amd = sc->sc_au.au_amd; 724 amd->cr = AMDR_INIT; 725 amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 726 sc->sc_locked = 0; 727 728 return(0); 729 } 730 731 int 732 amd7930_cont_output(addr) 733 void *addr; 734 { 735 DPRINTF(("amd7930_cont_output: never called, what should it do?!\n")); 736 return(0); 737 } 738 739 int 740 amd7930_cont_input(addr) 741 void *addr; 742 { 743 DPRINTF(("amd7930_cont_input: never called, what should it do?!\n")); 744 return(0); 745 } 746 747 int 748 amd7930_getdev(addr, retp) 749 void *addr; 750 struct audio_device *retp; 751 { 752 *retp = amd7930_device; 753 return 0; 754 } 755 756 int 757 amd7930_setfd(addr, flag) 758 void *addr; 759 int flag; 760 { 761 /* Always full-duplex */ 762 return(0); 763 } 764 765 int 766 amd7930_set_port(addr, cp) 767 void *addr; 768 mixer_ctrl_t *cp; 769 { 770 register struct amd7930_softc *sc = addr; 771 772 DPRINTF(("amd7930_set_port: port=%d", cp->dev)); 773 774 if (cp->type != AUDIO_MIXER_VALUE || cp->un.value.num_channels != 1) 775 return(EINVAL); 776 777 switch(cp->dev) { 778 case SUNAUDIO_MIC_PORT: 779 sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 780 break; 781 case SUNAUDIO_SPEAKER: 782 case SUNAUDIO_HEADPHONES: 783 sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 784 break; 785 case SUNAUDIO_MONITOR: 786 sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 787 break; 788 default: 789 return(EINVAL); 790 /* NOTREACHED */ 791 } 792 return(0); 793 } 794 795 int 796 amd7930_get_port(addr, cp) 797 void *addr; 798 mixer_ctrl_t *cp; 799 { 800 register struct amd7930_softc *sc = addr; 801 802 DPRINTF(("amd7930_get_port: port=%d", cp->dev)); 803 804 if (cp->type != AUDIO_MIXER_VALUE || cp->un.value.num_channels != 1) 805 return(EINVAL); 806 807 switch(cp->dev) { 808 case SUNAUDIO_MIC_PORT: 809 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel; 810 break; 811 case SUNAUDIO_SPEAKER: 812 case SUNAUDIO_HEADPHONES: 813 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel; 814 break; 815 case SUNAUDIO_MONITOR: 816 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel; 817 break; 818 default: 819 return(EINVAL); 820 /* NOTREACHED */ 821 } 822 return(0); 823 } 824 825 int 826 amd7930_query_devinfo(addr, dip) 827 void *addr; 828 register mixer_devinfo_t *dip; 829 { 830 switch(dip->index) { 831 case SUNAUDIO_MIC_PORT: 832 dip->type = AUDIO_MIXER_VALUE; 833 dip->mixer_class = SUNAUDIO_INPUT_CLASS; 834 dip->prev = dip->next = AUDIO_MIXER_LAST; 835 strcpy(dip->label.name, AudioNmicrophone); 836 dip->un.v.num_channels = 1; 837 strcpy(dip->un.v.units.name, AudioNvolume); 838 break; 839 case SUNAUDIO_SPEAKER: 840 dip->type = AUDIO_MIXER_VALUE; 841 dip->mixer_class = SUNAUDIO_OUTPUT_CLASS; 842 dip->prev = dip->next = AUDIO_MIXER_LAST; 843 strcpy(dip->label.name, AudioNspeaker); 844 dip->un.v.num_channels = 1; 845 strcpy(dip->un.v.units.name, AudioNvolume); 846 break; 847 case SUNAUDIO_HEADPHONES: 848 dip->type = AUDIO_MIXER_VALUE; 849 dip->mixer_class = SUNAUDIO_OUTPUT_CLASS; 850 dip->prev = dip->next = AUDIO_MIXER_LAST; 851 strcpy(dip->label.name, AudioNheadphone); 852 dip->un.v.num_channels = 1; 853 strcpy(dip->un.v.units.name, AudioNvolume); 854 break; 855 case SUNAUDIO_MONITOR: 856 dip->type = AUDIO_MIXER_VALUE; 857 dip->mixer_class = SUNAUDIO_OUTPUT_CLASS; 858 dip->next = dip->prev = AUDIO_MIXER_LAST; 859 strcpy(dip->label.name, AudioNmonitor); 860 dip->un.v.num_channels = 1; 861 strcpy(dip->un.v.units.name, AudioNvolume); 862 break; 863 case SUNAUDIO_INPUT_CLASS: 864 dip->type = AUDIO_MIXER_CLASS; 865 dip->mixer_class = SUNAUDIO_INPUT_CLASS; 866 dip->next = dip->prev = AUDIO_MIXER_LAST; 867 strcpy(dip->label.name, AudioCInputs); 868 break; 869 case SUNAUDIO_OUTPUT_CLASS: 870 dip->type = AUDIO_MIXER_CLASS; 871 dip->mixer_class = SUNAUDIO_OUTPUT_CLASS; 872 dip->next = dip->prev = AUDIO_MIXER_LAST; 873 strcpy(dip->label.name, AudioCOutputs); 874 break; 875 default: 876 return ENXIO; 877 /*NOTREACHED*/ 878 } 879 880 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name)); 881 882 return(0); 883 } 884 885 #ifdef AUDIO_C_HANDLER 886 int 887 amd7930hwintr(au0) 888 void *au0; 889 { 890 register struct auio *au = au0; 891 register volatile struct amd7930 *amd = au->au_amd; 892 register u_char *d, *e; 893 register int k; 894 895 k = amd->ir; /* clear interrupt */ 896 897 /* receive incoming data */ 898 d = au->au_rdata; 899 e = au->au_rend; 900 if (d && d <= e) { 901 *d = amd->bbrb; 902 au->au_rdata++; 903 if (d == e) { 904 #ifdef AUDIO_DEBUG 905 if (amd7930debug > 1) 906 Dprintf("amd7930hwintr: swintr(r) requested"); 907 #endif 908 AUDIO_SET_SWINTR; 909 } 910 } 911 912 /* send outgoing data */ 913 d = au->au_pdata; 914 e = au->au_pend; 915 if (d && d <= e) { 916 amd->bbtb = *d; 917 au->au_pdata++; 918 if (d == e) { 919 #ifdef AUDIO_DEBUG 920 if (amd7930debug > 1) 921 Dprintf("amd7930hwintr: swintr(p) requested"); 922 #endif 923 AUDIO_SET_SWINTR; 924 } 925 } 926 927 *(au->au_intrcnt)++; 928 return (1); 929 } 930 #endif /* AUDIO_C_HANDLER */ 931 932 int 933 amd7930swintr(sc0) 934 void *sc0; 935 { 936 register struct amd7930_softc *sc = sc0; 937 register struct auio *au; 938 register int s, ret = 0; 939 940 #ifdef AUDIO_DEBUG 941 if (amd7930debug > 1) 942 Dprintf("audiointr: sc=0x%x\n",sc); 943 #endif 944 945 au = &sc->sc_au; 946 s = splaudio(); 947 if (au->au_rdata > au->au_rend && sc->sc_rintr != NULL) { 948 splx(s); 949 ret = 1; 950 (*sc->sc_rintr)(sc->sc_rarg); 951 s = splaudio(); 952 } 953 if (au->au_pdata > au->au_pend && sc->sc_pintr != NULL) { 954 splx(s); 955 ret = 1; 956 (*sc->sc_pintr)(sc->sc_parg); 957 } else 958 splx(s); 959 return (ret); 960 } 961 #endif /* NAUDIO > 0 */ 962