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