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