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