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