1 /* $NetBSD: am7930.c,v 1.22 1997/05/24 20:15:59 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 *, struct cfdata *, 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, 0x8e7c, 0x8e51, 0x8e45, 0x8d42, 0x8d3b, 0x8c36, 0x8c33, 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_query_encoding __P((void *, struct audio_encoding *)); 209 int amd7930_set_params __P((void *, int, struct audio_params *, struct audio_params *)); 210 int amd7930_round_blocksize __P((void *, int)); 211 int amd7930_set_out_port __P((void *, int)); 212 int amd7930_get_out_port __P((void *)); 213 int amd7930_set_in_port __P((void *, int)); 214 int amd7930_get_in_port __P((void *)); 215 int amd7930_commit_settings __P((void *)); 216 int amd7930_start_output __P((void *, void *, int, void (*)(void *), 217 void *)); 218 int amd7930_start_input __P((void *, void *, int, void (*)(void *), 219 void *)); 220 int amd7930_halt_output __P((void *)); 221 int amd7930_halt_input __P((void *)); 222 int amd7930_cont_output __P((void *)); 223 int amd7930_cont_input __P((void *)); 224 int amd7930_getdev __P((void *, struct audio_device *)); 225 int amd7930_setfd __P((void *, int)); 226 int amd7930_set_port __P((void *, mixer_ctrl_t *)); 227 int amd7930_get_port __P((void *, mixer_ctrl_t *)); 228 int amd7930_query_devinfo __P((void *, mixer_devinfo_t *)); 229 230 231 struct audio_hw_if sa_hw_if = { 232 amd7930_open, 233 amd7930_close, 234 NULL, 235 amd7930_query_encoding, 236 amd7930_set_params, 237 amd7930_round_blocksize, 238 amd7930_set_out_port, 239 amd7930_get_out_port, 240 amd7930_set_in_port, 241 amd7930_get_in_port, 242 amd7930_commit_settings, 243 amd7930_start_output, 244 amd7930_start_input, 245 amd7930_halt_output, 246 amd7930_halt_input, 247 amd7930_cont_output, 248 amd7930_cont_input, 249 NULL, 250 amd7930_getdev, 251 amd7930_setfd, 252 amd7930_set_port, 253 amd7930_get_port, 254 amd7930_query_devinfo, 255 1, 256 0 257 }; 258 259 /* autoconfig routines */ 260 261 int 262 amd7930match(parent, cf, aux) 263 struct device *parent; 264 struct cfdata *cf; 265 void *aux; 266 { 267 register struct confargs *ca = aux; 268 register struct romaux *ra = &ca->ca_ra; 269 270 if (CPU_ISSUN4) 271 return (0); 272 return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0); 273 } 274 275 /* 276 * Audio chip found. 277 */ 278 void 279 amd7930attach(parent, self, args) 280 struct device *parent, *self; 281 void *args; 282 { 283 register struct amd7930_softc *sc = (struct amd7930_softc *)self; 284 register struct confargs *ca = args; 285 register struct romaux *ra = &ca->ca_ra; 286 register volatile struct amd7930 *amd; 287 register int pri; 288 289 if (ra->ra_nintr != 1) { 290 printf(": expected 1 interrupt, got %d\n", ra->ra_nintr); 291 return; 292 } 293 pri = ra->ra_intr[0].int_pri; 294 printf(" pri %d, softpri %d\n", pri, PIL_AUSOFT); 295 amd = (volatile struct amd7930 *)(ra->ra_vaddr ? 296 ra->ra_vaddr : mapiodev(ra->ra_reg, 0, sizeof (*amd))); 297 298 sc->sc_map.mr_mmr1 = AMD_MMR1_GX | AMD_MMR1_GER | 299 AMD_MMR1_GR | AMD_MMR1_STG; 300 sc->sc_au.au_amd = amd; 301 /* set boot defaults */ 302 sc->sc_rlevel = 128; 303 sc->sc_plevel = 128; 304 sc->sc_mlevel = 0; 305 sc->sc_out_port = SUNAUDIO_SPEAKER; 306 307 init_amd(amd); 308 309 #ifndef AUDIO_C_HANDLER 310 auiop = &sc->sc_au; 311 intr_fasttrap(pri, amd7930_trap); 312 #else 313 sc->sc_hwih.ih_fun = amd7930hwintr; 314 sc->sc_hwih.ih_arg = &sc->sc_au; 315 intr_establish(pri, &sc->sc_hwih); 316 #endif 317 sc->sc_swih.ih_fun = amd7930swintr; 318 sc->sc_swih.ih_arg = sc; 319 intr_establish(PIL_AUSOFT, &sc->sc_swih); 320 321 evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt); 322 323 if (audio_hardware_attach(&sa_hw_if, sc) != 0) 324 printf("audio: could not attach to audio pseudo-device driver\n"); 325 } 326 327 static void 328 init_amd(amd) 329 register volatile struct amd7930 *amd; 330 { 331 /* disable interrupts */ 332 amd->cr = AMDR_INIT; 333 amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 334 335 /* 336 * Initialize the mux unit. We use MCR3 to route audio (MAP) 337 * through channel Bb. MCR1 and MCR2 are unused. 338 * Setting the INT enable bit in MCR4 will generate an interrupt 339 * on each converted audio sample. 340 */ 341 amd->cr = AMDR_MUX_1_4; 342 amd->dr = 0; 343 amd->dr = 0; 344 amd->dr = (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA; 345 amd->dr = AMD_MCR4_INT_ENABLE; 346 } 347 348 int 349 amd7930_open(dev, flags) 350 dev_t dev; 351 int flags; 352 { 353 register struct amd7930_softc *sc; 354 int unit = AUDIOUNIT(dev); 355 356 DPRINTF(("sa_open: unit %d\n",unit)); 357 358 if (unit >= audio_cd.cd_ndevs) 359 return (ENODEV); 360 if ((sc = audio_cd.cd_devs[unit]) == NULL) 361 return (ENXIO); 362 if (sc->sc_open) 363 return (EBUSY); 364 sc->sc_open = 1; 365 sc->sc_locked = 0; 366 sc->sc_rintr = 0; 367 sc->sc_rarg = 0; 368 sc->sc_pintr = 0; 369 sc->sc_parg = 0; 370 371 sc->sc_au.au_rdata = 0; 372 sc->sc_au.au_pdata = 0; 373 374 DPRINTF(("saopen: ok -> sc=0x%x\n",sc)); 375 376 return (0); 377 } 378 379 void 380 amd7930_close(addr) 381 void *addr; 382 { 383 register struct amd7930_softc *sc = addr; 384 385 DPRINTF(("sa_close: sc=0x%x\n", sc)); 386 /* 387 * halt i/o, clear open flag, and done. 388 */ 389 amd7930_halt_input(sc); 390 amd7930_halt_output(sc); 391 sc->sc_open = 0; 392 393 DPRINTF(("sa_close: closed.\n")); 394 } 395 396 int 397 amd7930_set_params(addr, mode, p, q) 398 void *addr; 399 int mode; 400 struct audio_params *p, *q; 401 { 402 if (p->sample_rate < 7500 || p->sample_rate > 8500 || 403 p->encoding != AUDIO_ENCODING_ULAW || 404 p->precision != 8 || 405 p->channels != 1) 406 return EINVAL; 407 p->sample_rate = 8000; /* no other sampling rates supported by amd chip */ 408 409 /* Update setting for the other mode. */ 410 q->sample_rate = p->sample_rate; 411 q->encoding = p->encoding; 412 q->channels = p->channels; 413 q->precision = p->precision; 414 415 return 0; 416 } 417 418 int 419 amd7930_query_encoding(addr, fp) 420 void *addr; 421 struct audio_encoding *fp; 422 { 423 switch (fp->index) { /* ??? */ 424 case 0: 425 strcpy(fp->name, AudioEmulaw); 426 fp->encoding = AUDIO_ENCODING_ULAW; 427 fp->precision = 8; 428 fp->flags = 0; 429 break; 430 default: 431 return(EINVAL); 432 /*NOTREACHED*/ 433 } 434 return(0); 435 } 436 437 int 438 amd7930_round_blocksize(addr, blk) 439 void *addr; 440 int blk; 441 { 442 return(blk); 443 } 444 445 int 446 amd7930_set_out_port(addr, port) 447 void *addr; 448 int port; 449 { 450 register struct amd7930_softc *sc = addr; 451 452 switch(port) { 453 case SUNAUDIO_SPEAKER: 454 case SUNAUDIO_HEADPHONES: 455 sc->sc_out_port = port; /* set on commit */ 456 break; 457 default: 458 return(EINVAL); 459 } 460 return(0); 461 } 462 463 int 464 amd7930_get_out_port(addr) 465 void *addr; 466 { 467 register struct amd7930_softc *sc = addr; 468 469 return(sc->sc_out_port); 470 } 471 472 int 473 amd7930_set_in_port(addr, port) 474 void *addr; 475 int port; 476 { 477 if (port != SUNAUDIO_MIC_PORT) 478 return(EINVAL); 479 480 return(0); /* only microphone input supported by amd chip */ 481 } 482 483 int 484 amd7930_get_in_port(addr) 485 void *addr; 486 { 487 return(SUNAUDIO_MIC_PORT); 488 } 489 490 int 491 amd7930_commit_settings(addr) 492 void *addr; 493 { 494 register struct amd7930_softc *sc = addr; 495 register struct mapreg *map; 496 register volatile struct amd7930 *amd; 497 register int s, level; 498 499 DPRINTF(("sa_commit.\n")); 500 501 map = &sc->sc_map; 502 amd = sc->sc_au.au_amd; 503 504 map->mr_gx = gx_coeff[sc->sc_rlevel]; 505 map->mr_stgr = gx_coeff[sc->sc_mlevel]; 506 507 level = (sc->sc_plevel * (256 + NGER)) >> 8; 508 if (level >= 256) { 509 map->mr_ger = ger_coeff[level - 256]; 510 map->mr_gr = gx_coeff[255]; 511 } else { 512 map->mr_ger = ger_coeff[0]; 513 map->mr_gr = gx_coeff[level]; 514 } 515 516 if (sc->sc_out_port == SUNAUDIO_SPEAKER) 517 map->mr_mmr2 |= AMD_MMR2_LS; 518 else 519 map->mr_mmr2 &= ~AMD_MMR2_LS; 520 521 s = splaudio(); 522 523 amd->cr = AMDR_MAP_MMR1; 524 amd->dr = map->mr_mmr1; 525 amd->cr = AMDR_MAP_GX; 526 WAMD16(amd, map->mr_gx); 527 amd->cr = AMDR_MAP_STG; 528 WAMD16(amd, map->mr_stgr); 529 amd->cr = AMDR_MAP_GR; 530 WAMD16(amd, map->mr_gr); 531 amd->cr = AMDR_MAP_GER; 532 WAMD16(amd, map->mr_ger); 533 amd->cr = AMDR_MAP_MMR2; 534 amd->dr = map->mr_mmr2; 535 536 splx(s); 537 return(0); 538 } 539 540 int 541 amd7930_start_output(addr, p, cc, intr, arg) 542 void *addr; 543 void *p; 544 int cc; 545 void (*intr) __P((void *)); 546 void *arg; 547 { 548 register struct amd7930_softc *sc = addr; 549 550 #ifdef AUDIO_DEBUG 551 if (amd7930debug > 1) 552 Dprintf("sa_start_output: cc=%d 0x%x (0x%x)\n", cc, intr, arg); 553 #endif 554 555 if (!sc->sc_locked) { 556 register volatile struct amd7930 *amd; 557 558 amd = sc->sc_au.au_amd; 559 amd->cr = AMDR_INIT; 560 amd->dr = AMD_INIT_PMS_ACTIVE; 561 sc->sc_locked = 1; 562 DPRINTF(("sa_start_output: started intrs.\n")); 563 } 564 sc->sc_pintr = intr; 565 sc->sc_parg = arg; 566 sc->sc_au.au_pdata = p; 567 sc->sc_au.au_pend = p + cc - 1; 568 return(0); 569 } 570 571 /* ARGSUSED */ 572 int 573 amd7930_start_input(addr, p, cc, intr, arg) 574 void *addr; 575 void *p; 576 int cc; 577 void (*intr) __P((void *)); 578 void *arg; 579 { 580 register struct amd7930_softc *sc = addr; 581 582 #ifdef AUDIO_DEBUG 583 if (amd7930debug > 1) 584 Dprintf("sa_start_input: cc=%d 0x%x (0x%x)\n", cc, intr, arg); 585 #endif 586 587 if (!sc->sc_locked) { 588 register volatile struct amd7930 *amd; 589 590 amd = sc->sc_au.au_amd; 591 amd->cr = AMDR_INIT; 592 amd->dr = AMD_INIT_PMS_ACTIVE; 593 sc->sc_locked = 1; 594 DPRINTF(("sa_start_input: started intrs.\n")); 595 } 596 sc->sc_rintr = intr; 597 sc->sc_rarg = arg; 598 sc->sc_au.au_rdata = p; 599 sc->sc_au.au_rend = p + cc -1; 600 return(0); 601 } 602 603 int 604 amd7930_halt_output(addr) 605 void *addr; 606 { 607 register struct amd7930_softc *sc = addr; 608 register volatile struct amd7930 *amd; 609 610 /* XXX only halt, if input is also halted ?? */ 611 amd = sc->sc_au.au_amd; 612 amd->cr = AMDR_INIT; 613 amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 614 sc->sc_locked = 0; 615 616 return(0); 617 } 618 619 int 620 amd7930_halt_input(addr) 621 void *addr; 622 { 623 register struct amd7930_softc *sc = addr; 624 register volatile struct amd7930 *amd; 625 626 /* XXX only halt, if output is also halted ?? */ 627 amd = sc->sc_au.au_amd; 628 amd->cr = AMDR_INIT; 629 amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 630 sc->sc_locked = 0; 631 632 return(0); 633 } 634 635 int 636 amd7930_cont_output(addr) 637 void *addr; 638 { 639 DPRINTF(("amd7930_cont_output: never called, what should it do?!\n")); 640 return(0); 641 } 642 643 int 644 amd7930_cont_input(addr) 645 void *addr; 646 { 647 DPRINTF(("amd7930_cont_input: never called, what should it do?!\n")); 648 return(0); 649 } 650 651 int 652 amd7930_getdev(addr, retp) 653 void *addr; 654 struct audio_device *retp; 655 { 656 *retp = amd7930_device; 657 return 0; 658 } 659 660 int 661 amd7930_setfd(addr, flag) 662 void *addr; 663 int flag; 664 { 665 /* Always full-duplex */ 666 return(0); 667 } 668 669 int 670 amd7930_set_port(addr, cp) 671 void *addr; 672 mixer_ctrl_t *cp; 673 { 674 register struct amd7930_softc *sc = addr; 675 676 DPRINTF(("amd7930_set_port: port=%d", cp->dev)); 677 678 if (cp->type != AUDIO_MIXER_VALUE || cp->un.value.num_channels != 1) 679 return(EINVAL); 680 681 switch(cp->dev) { 682 case SUNAUDIO_MIC_PORT: 683 sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 684 break; 685 case SUNAUDIO_SPEAKER: 686 case SUNAUDIO_HEADPHONES: 687 sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 688 break; 689 case SUNAUDIO_MONITOR: 690 sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 691 break; 692 default: 693 return(EINVAL); 694 /* NOTREACHED */ 695 } 696 return(0); 697 } 698 699 int 700 amd7930_get_port(addr, cp) 701 void *addr; 702 mixer_ctrl_t *cp; 703 { 704 register struct amd7930_softc *sc = addr; 705 706 DPRINTF(("amd7930_get_port: port=%d", cp->dev)); 707 708 if (cp->type != AUDIO_MIXER_VALUE || cp->un.value.num_channels != 1) 709 return(EINVAL); 710 711 switch(cp->dev) { 712 case SUNAUDIO_MIC_PORT: 713 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel; 714 break; 715 case SUNAUDIO_SPEAKER: 716 case SUNAUDIO_HEADPHONES: 717 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel; 718 break; 719 case SUNAUDIO_MONITOR: 720 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel; 721 break; 722 default: 723 return(EINVAL); 724 /* NOTREACHED */ 725 } 726 return(0); 727 } 728 729 int 730 amd7930_query_devinfo(addr, dip) 731 void *addr; 732 register mixer_devinfo_t *dip; 733 { 734 switch(dip->index) { 735 case SUNAUDIO_MIC_PORT: 736 dip->type = AUDIO_MIXER_VALUE; 737 dip->mixer_class = SUNAUDIO_INPUT_CLASS; 738 dip->prev = dip->next = AUDIO_MIXER_LAST; 739 strcpy(dip->label.name, AudioNmicrophone); 740 dip->un.v.num_channels = 1; 741 strcpy(dip->un.v.units.name, AudioNvolume); 742 break; 743 case SUNAUDIO_SPEAKER: 744 dip->type = AUDIO_MIXER_VALUE; 745 dip->mixer_class = SUNAUDIO_OUTPUT_CLASS; 746 dip->prev = dip->next = AUDIO_MIXER_LAST; 747 strcpy(dip->label.name, AudioNspeaker); 748 dip->un.v.num_channels = 1; 749 strcpy(dip->un.v.units.name, AudioNvolume); 750 break; 751 case SUNAUDIO_HEADPHONES: 752 dip->type = AUDIO_MIXER_VALUE; 753 dip->mixer_class = SUNAUDIO_OUTPUT_CLASS; 754 dip->prev = dip->next = AUDIO_MIXER_LAST; 755 strcpy(dip->label.name, AudioNheadphone); 756 dip->un.v.num_channels = 1; 757 strcpy(dip->un.v.units.name, AudioNvolume); 758 break; 759 case SUNAUDIO_MONITOR: 760 dip->type = AUDIO_MIXER_VALUE; 761 dip->mixer_class = SUNAUDIO_OUTPUT_CLASS; 762 dip->next = dip->prev = AUDIO_MIXER_LAST; 763 strcpy(dip->label.name, AudioNmonitor); 764 dip->un.v.num_channels = 1; 765 strcpy(dip->un.v.units.name, AudioNvolume); 766 break; 767 case SUNAUDIO_INPUT_CLASS: 768 dip->type = AUDIO_MIXER_CLASS; 769 dip->mixer_class = SUNAUDIO_INPUT_CLASS; 770 dip->next = dip->prev = AUDIO_MIXER_LAST; 771 strcpy(dip->label.name, AudioCInputs); 772 break; 773 case SUNAUDIO_OUTPUT_CLASS: 774 dip->type = AUDIO_MIXER_CLASS; 775 dip->mixer_class = SUNAUDIO_OUTPUT_CLASS; 776 dip->next = dip->prev = AUDIO_MIXER_LAST; 777 strcpy(dip->label.name, AudioCOutputs); 778 break; 779 default: 780 return ENXIO; 781 /*NOTREACHED*/ 782 } 783 784 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name)); 785 786 return(0); 787 } 788 789 #ifdef AUDIO_C_HANDLER 790 int 791 amd7930hwintr(au0) 792 void *au0; 793 { 794 register struct auio *au = au0; 795 register volatile struct amd7930 *amd = au->au_amd; 796 register u_char *d, *e; 797 register int k; 798 799 k = amd->ir; /* clear interrupt */ 800 801 /* receive incoming data */ 802 d = au->au_rdata; 803 e = au->au_rend; 804 if (d && d <= e) { 805 *d = amd->bbrb; 806 au->au_rdata++; 807 if (d == e) { 808 #ifdef AUDIO_DEBUG 809 if (amd7930debug > 1) 810 Dprintf("amd7930hwintr: swintr(r) requested"); 811 #endif 812 AUDIO_SET_SWINTR; 813 } 814 } 815 816 /* send outgoing data */ 817 d = au->au_pdata; 818 e = au->au_pend; 819 if (d && d <= e) { 820 amd->bbtb = *d; 821 au->au_pdata++; 822 if (d == e) { 823 #ifdef AUDIO_DEBUG 824 if (amd7930debug > 1) 825 Dprintf("amd7930hwintr: swintr(p) requested"); 826 #endif 827 AUDIO_SET_SWINTR; 828 } 829 } 830 831 *(au->au_intrcnt)++; 832 return (1); 833 } 834 #endif /* AUDIO_C_HANDLER */ 835 836 int 837 amd7930swintr(sc0) 838 void *sc0; 839 { 840 register struct amd7930_softc *sc = sc0; 841 register struct auio *au; 842 register int s, ret = 0; 843 844 #ifdef AUDIO_DEBUG 845 if (amd7930debug > 1) 846 Dprintf("audiointr: sc=0x%x\n",sc); 847 #endif 848 849 au = &sc->sc_au; 850 s = splaudio(); 851 if (au->au_rdata > au->au_rend && sc->sc_rintr != NULL) { 852 splx(s); 853 ret = 1; 854 (*sc->sc_rintr)(sc->sc_rarg); 855 s = splaudio(); 856 } 857 if (au->au_pdata > au->au_pend && sc->sc_pintr != NULL) { 858 splx(s); 859 ret = 1; 860 (*sc->sc_pintr)(sc->sc_parg); 861 } else 862 splx(s); 863 return (ret); 864 } 865 #endif /* NAUDIO > 0 */ 866