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