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