1 /* $NetBSD: ym.c,v 1.13 1999/12/27 03:21:56 itohy Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by ITOH Yasufumi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Copyright (c) 1998 Constantine Sapuntzakis. All rights reserved. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. The name of the author may not be used to endorse or promote products 51 * derived from this software without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 54 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 55 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 56 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 57 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 58 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 59 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 60 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 61 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 62 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 63 */ 64 65 /* 66 * Original code from OpenBSD. 67 */ 68 69 #include "mpu_ym.h" 70 #include "opt_ym.h" 71 72 #include <sys/param.h> 73 #include <sys/systm.h> 74 #include <sys/errno.h> 75 #include <sys/device.h> 76 #include <sys/fcntl.h> 77 #include <sys/kernel.h> 78 #include <sys/proc.h> 79 80 #include <machine/cpu.h> 81 #include <machine/intr.h> 82 #include <machine/bus.h> 83 84 #include <sys/audioio.h> 85 #include <dev/audio_if.h> 86 87 #include <dev/isa/isavar.h> 88 #include <dev/isa/isadmavar.h> 89 90 #include <dev/ic/ad1848reg.h> 91 #include <dev/isa/ad1848var.h> 92 #include <dev/ic/opl3sa3reg.h> 93 #include <dev/isa/wssreg.h> 94 #if NMPU_YM > 0 95 #include <dev/ic/mpuvar.h> 96 #endif 97 #include <dev/isa/ymvar.h> 98 #include <dev/isa/sbreg.h> 99 100 #ifndef spllowersoftclock 101 #error "We depend on the new semantics of splsoftclock(9)." 102 #endif 103 104 /* Power management mode. */ 105 #ifndef YM_POWER_MODE 106 #define YM_POWER_MODE YM_POWER_POWERSAVE 107 #endif 108 109 /* Time in second before power down the chip. */ 110 #ifndef YM_POWER_OFF_SEC 111 #define YM_POWER_OFF_SEC 5 112 #endif 113 114 /* Default mixer settings. */ 115 #ifndef YM_VOL_MASTER 116 #define YM_VOL_MASTER 220 117 #endif 118 119 #ifndef YM_VOL_DAC 120 #define YM_VOL_DAC 224 121 #endif 122 123 #ifndef YM_VOL_OPL3 124 #define YM_VOL_OPL3 184 125 #endif 126 127 #ifdef __i386__ /* XXX */ 128 # include "joy.h" 129 #else 130 # define NJOY 0 131 #endif 132 133 #ifdef AUDIO_DEBUG 134 #define DPRINTF(x) if (ymdebug) printf x 135 int ymdebug = 0; 136 #else 137 #define DPRINTF(x) 138 #endif 139 #define DVNAME(softc) ((softc)->sc_ad1848.sc_ad1848.sc_dev.dv_xname) 140 141 int ym_getdev __P((void *, struct audio_device *)); 142 int ym_mixer_set_port __P((void *, mixer_ctrl_t *)); 143 int ym_mixer_get_port __P((void *, mixer_ctrl_t *)); 144 int ym_query_devinfo __P((void *, mixer_devinfo_t *)); 145 int ym_intr __P((void *)); 146 #ifndef AUDIO_NO_POWER_CTL 147 static void ym_save_codec_regs __P((struct ym_softc *)); 148 static void ym_restore_codec_regs __P((struct ym_softc *)); 149 void ym_power_hook __P((int, void *)); 150 int ym_codec_power_ctl __P((void *, int)); 151 static void ym_chip_powerdown __P((struct ym_softc *)); 152 static void ym_chip_powerup __P((struct ym_softc *, int)); 153 void ym_powerdown_blocks __P((void *)); 154 void ym_power_ctl __P((struct ym_softc *, int, int)); 155 #endif 156 157 static void ym_init __P((struct ym_softc *)); 158 static void ym_mute __P((struct ym_softc *, int, int)); 159 static void ym_set_master_gain __P((struct ym_softc *, struct ad1848_volume*)); 160 static void ym_set_mic_gain __P((struct ym_softc *, int)); 161 static void ym_set_3d __P((struct ym_softc *, mixer_ctrl_t *, 162 struct ad1848_volume *, int)); 163 164 165 struct audio_hw_if ym_hw_if = { 166 ad1848_isa_open, 167 ad1848_isa_close, 168 NULL, 169 ad1848_query_encoding, 170 ad1848_set_params, 171 ad1848_round_blocksize, 172 ad1848_commit_settings, 173 NULL, 174 NULL, 175 NULL, 176 NULL, 177 ad1848_isa_halt_output, 178 ad1848_isa_halt_input, 179 NULL, 180 ym_getdev, 181 NULL, 182 ym_mixer_set_port, 183 ym_mixer_get_port, 184 ym_query_devinfo, 185 ad1848_isa_malloc, 186 ad1848_isa_free, 187 ad1848_isa_round_buffersize, 188 ad1848_isa_mappage, 189 ad1848_isa_get_props, 190 ad1848_isa_trigger_output, 191 ad1848_isa_trigger_input, 192 }; 193 194 static __inline int ym_read __P((struct ym_softc *, int)); 195 static __inline void ym_write __P((struct ym_softc *, int, int)); 196 197 void 198 ym_attach(sc) 199 struct ym_softc *sc; 200 { 201 struct ad1848_softc *ac = &sc->sc_ad1848.sc_ad1848; 202 static struct ad1848_volume vol_master = {YM_VOL_MASTER, YM_VOL_MASTER}; 203 static struct ad1848_volume vol_dac = {YM_VOL_DAC, YM_VOL_DAC}; 204 static struct ad1848_volume vol_opl3 = {YM_VOL_OPL3, YM_VOL_OPL3}; 205 struct audio_attach_args arg; 206 207 /* Mute the output to reduce noise during initialization. */ 208 ym_mute(sc, SA3_VOL_L, 1); 209 ym_mute(sc, SA3_VOL_R, 1); 210 211 sc->sc_ad1848.sc_ih = isa_intr_establish(sc->sc_ic, sc->ym_irq, 212 IST_EDGE, IPL_AUDIO, 213 ym_intr, sc); 214 215 #ifndef AUDIO_NO_POWER_CTL 216 sc->sc_ad1848.powerctl = ym_codec_power_ctl; 217 sc->sc_ad1848.powerarg = sc; 218 #endif 219 ad1848_isa_attach(&sc->sc_ad1848); 220 printf("\n"); 221 ac->parent = sc; 222 223 /* Establish chip in well known mode */ 224 ym_set_master_gain(sc, &vol_master); 225 ym_set_mic_gain(sc, 0); 226 sc->master_mute = 0; 227 228 sc->mic_mute = 1; 229 ym_mute(sc, SA3_MIC_VOL, sc->mic_mute); 230 231 /* Override ad1848 settings. */ 232 ad1848_set_channel_gain(ac, AD1848_DAC_CHANNEL, &vol_dac); 233 ad1848_set_channel_gain(ac, AD1848_AUX2_CHANNEL, &vol_opl3); 234 235 /* 236 * Mute all external sources. If you change this, you must 237 * also change the initial value of sc->sc_external_sources 238 * (currently 0 --- no external source is active). 239 */ 240 ad1848_mute_channel(ac, AD1848_AUX1_CHANNEL, MUTE_ALL); /* CD */ 241 ad1848_mute_channel(ac, AD1848_LINE_CHANNEL, MUTE_ALL); /* line */ 242 ac->mute[AD1848_AUX1_CHANNEL] = MUTE_ALL; 243 ac->mute[AD1848_LINE_CHANNEL] = MUTE_ALL; 244 /* speaker is muted by default */ 245 246 sc->sc_version = ym_read(sc, SA3_MISC) & SA3_MISC_VER; 247 248 /* We use only one IRQ (IRQ-A). */ 249 ym_write(sc, SA3_IRQ_CONF, SA3_IRQ_CONF_MPU_A | SA3_IRQ_CONF_WSS_A); 250 ym_write(sc, SA3_HVOL_INTR_CNF, SA3_HVOL_INTR_CNF_A); 251 252 /* audio at ym attachment */ 253 sc->sc_audiodev = audio_attach_mi(&ym_hw_if, ac, &ac->sc_dev); 254 255 /* opl at ym attachment */ 256 if (sc->sc_opl_ioh) { 257 arg.type = AUDIODEV_TYPE_OPL; 258 arg.hwif = 0; 259 arg.hdl = 0; 260 (void)config_found(&ac->sc_dev, &arg, audioprint); 261 } 262 263 #if NMPU_YM > 0 264 /* mpu at ym attachment */ 265 if (sc->sc_mpu_ioh) { 266 arg.type = AUDIODEV_TYPE_MPU; 267 arg.hwif = 0; 268 arg.hdl = 0; 269 sc->sc_mpudev = config_found(&ac->sc_dev, &arg, audioprint); 270 } 271 #endif 272 273 /* This must be AFTER the attachment of sub-devices. */ 274 ym_init(sc); 275 276 #ifndef AUDIO_NO_POWER_CTL 277 /* 278 * Initialize power control. 279 */ 280 sc->sc_pow_mode = YM_POWER_MODE; 281 sc->sc_pow_timeout = YM_POWER_OFF_SEC; 282 283 sc->sc_on_blocks = sc->sc_turning_off = 284 YM_POWER_CODEC_P | YM_POWER_CODEC_R | 285 YM_POWER_OPL3 | YM_POWER_MPU401 | YM_POWER_3D | 286 YM_POWER_CODEC_DA | YM_POWER_CODEC_AD | YM_POWER_OPL3_DA; 287 #if NJOY > 0 288 sc->sc_on_blocks |= YM_POWER_JOYSTICK; /* prevents chip powerdown */ 289 #endif 290 ym_powerdown_blocks(sc); 291 292 powerhook_establish(ym_power_hook, sc); 293 294 if (sc->sc_on_blocks /* & YM_POWER_ACTIVE */) 295 #endif 296 { 297 /* Unmute the output now if the chip is on. */ 298 ym_mute(sc, SA3_VOL_L, sc->master_mute); 299 ym_mute(sc, SA3_VOL_R, sc->master_mute); 300 } 301 } 302 303 static __inline int 304 ym_read(sc, reg) 305 struct ym_softc *sc; 306 int reg; 307 { 308 bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 309 SA3_CTL_INDEX, (reg & 0xff)); 310 return (bus_space_read_1(sc->sc_iot, sc->sc_controlioh, SA3_CTL_DATA)); 311 } 312 313 static __inline void 314 ym_write(sc, reg, data) 315 struct ym_softc *sc; 316 int reg; 317 int data; 318 { 319 bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 320 SA3_CTL_INDEX, (reg & 0xff)); 321 bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 322 SA3_CTL_DATA, (data & 0xff)); 323 } 324 325 static void 326 ym_init(sc) 327 struct ym_softc *sc; 328 { 329 u_int8_t dpd, apd; 330 331 /* Mute SoundBlaster output if possible. */ 332 if (sc->sc_sb_ioh) { 333 bus_space_write_1(sc->sc_iot, sc->sc_sb_ioh, SBP_MIXER_ADDR, 334 SBP_MASTER_VOL); 335 bus_space_write_1(sc->sc_iot, sc->sc_sb_ioh, SBP_MIXER_DATA, 336 0x00); 337 } 338 339 /* Figure out which part can be power down. */ 340 dpd = SA3_DPWRDWN_SB /* we never use SB */ 341 #if NMPU_YM > 0 342 | (sc->sc_mpu_ioh ? 0 : SA3_DPWRDWN_MPU) 343 #else 344 | SA3_DPWRDWN_MPU 345 #endif 346 #if NJOY == 0 347 | SA3_DPWRDWN_JOY 348 #endif 349 | SA3_DPWRDWN_PNP /* ISA Plug and Play is done */ 350 /* 351 * The master clock is for external wavetable synthesizer 352 * OPL4-ML (YMF704) or OPL4-ML2 (YMF721), 353 * and is currently unused. 354 */ 355 | SA3_DPWRDWN_MCLKO; 356 357 apd = SA3_APWRDWN_SBDAC; /* we never use SB */ 358 359 /* Power down OPL3 if not attached. */ 360 if (sc->sc_opl_ioh == 0) { 361 dpd |= SA3_DPWRDWN_FM; 362 apd |= SA3_APWRDWN_FMDAC; 363 } 364 /* CODEC is always attached. */ 365 366 /* Power down unused digital parts. */ 367 ym_write(sc, SA3_DPWRDWN, dpd); 368 369 /* Power down unused analog parts. */ 370 ym_write(sc, SA3_APWRDWN, apd); 371 } 372 373 374 int 375 ym_getdev(addr, retp) 376 void *addr; 377 struct audio_device *retp; 378 { 379 struct ym_softc *sc = addr; 380 381 strcpy(retp->name, "OPL3-SA3"); 382 sprintf(retp->version, "%d", sc->sc_version); 383 strcpy(retp->config, "ym"); 384 385 return 0; 386 } 387 388 389 static ad1848_devmap_t mappings[] = { 390 { YM_DAC_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL }, 391 { YM_MIDI_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL }, 392 { YM_CD_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL }, 393 { YM_LINE_LVL, AD1848_KIND_LVL, AD1848_LINE_CHANNEL }, 394 { YM_SPEAKER_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL }, 395 { YM_MONITOR_LVL, AD1848_KIND_LVL, AD1848_MONITOR_CHANNEL }, 396 { YM_DAC_MUTE, AD1848_KIND_MUTE, AD1848_DAC_CHANNEL }, 397 { YM_MIDI_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL }, 398 { YM_CD_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL }, 399 { YM_LINE_MUTE, AD1848_KIND_MUTE, AD1848_LINE_CHANNEL }, 400 { YM_SPEAKER_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL }, 401 { YM_MONITOR_MUTE, AD1848_KIND_MUTE, AD1848_MONITOR_CHANNEL }, 402 { YM_REC_LVL, AD1848_KIND_RECORDGAIN, -1 }, 403 { YM_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1} 404 }; 405 406 #define NUMMAP (sizeof(mappings) / sizeof(mappings[0])) 407 408 409 static void 410 ym_mute(sc, left_reg, mute) 411 struct ym_softc *sc; 412 int left_reg; 413 int mute; 414 415 { 416 u_int8_t reg; 417 418 reg = ym_read(sc, left_reg); 419 if (mute) 420 ym_write(sc, left_reg, reg | 0x80); 421 else 422 ym_write(sc, left_reg, reg & ~0x80); 423 } 424 425 426 static void 427 ym_set_master_gain(sc, vol) 428 struct ym_softc *sc; 429 struct ad1848_volume *vol; 430 { 431 u_int atten; 432 433 sc->master_gain = *vol; 434 435 atten = ((AUDIO_MAX_GAIN - vol->left) * (SA3_VOL_MV + 1)) / 436 (AUDIO_MAX_GAIN + 1); 437 438 ym_write(sc, SA3_VOL_L, (ym_read(sc, SA3_VOL_L) & ~SA3_VOL_MV) | atten); 439 440 atten = ((AUDIO_MAX_GAIN - vol->right) * (SA3_VOL_MV + 1)) / 441 (AUDIO_MAX_GAIN + 1); 442 443 ym_write(sc, SA3_VOL_R, (ym_read(sc, SA3_VOL_R) & ~SA3_VOL_MV) | atten); 444 } 445 446 static void 447 ym_set_mic_gain(sc, vol) 448 struct ym_softc *sc; 449 int vol; 450 { 451 u_int atten; 452 453 sc->mic_gain = vol; 454 455 atten = ((AUDIO_MAX_GAIN - vol) * (SA3_MIC_MCV + 1)) / 456 (AUDIO_MAX_GAIN + 1); 457 458 ym_write(sc, SA3_MIC_VOL, 459 (ym_read(sc, SA3_MIC_VOL) & ~SA3_MIC_MCV) | atten); 460 } 461 462 static void 463 ym_set_3d(sc, cp, val, reg) 464 struct ym_softc *sc; 465 mixer_ctrl_t *cp; 466 struct ad1848_volume *val; 467 int reg; 468 { 469 u_int8_t e; 470 471 ad1848_to_vol(cp, val); 472 473 e = (val->left * (SA3_3D_BITS + 1) + (SA3_3D_BITS + 1) / 2) / 474 (AUDIO_MAX_GAIN + 1) << SA3_3D_LSHIFT | 475 (val->right * (SA3_3D_BITS + 1) + (SA3_3D_BITS + 1) / 2) / 476 (AUDIO_MAX_GAIN + 1) << SA3_3D_RSHIFT; 477 478 #ifndef AUDIO_NO_POWER_CTL 479 /* turn wide stereo on if necessary */ 480 if (e) 481 ym_power_ctl(sc, YM_POWER_3D, 1); 482 #endif 483 484 ym_write(sc, reg, e); 485 486 #ifndef AUDIO_NO_POWER_CTL 487 /* turn wide stereo off if necessary */ 488 if (YM_EQ_OFF(&sc->sc_treble) && YM_EQ_OFF(&sc->sc_bass) && 489 YM_EQ_OFF(&sc->sc_wide)) 490 ym_power_ctl(sc, YM_POWER_3D, 0); 491 #endif 492 } 493 494 int 495 ym_mixer_set_port(addr, cp) 496 void *addr; 497 mixer_ctrl_t *cp; 498 { 499 struct ad1848_softc *ac = addr; 500 struct ym_softc *sc = ac->parent; 501 struct ad1848_volume vol; 502 int error = 0; 503 u_int8_t extsources; 504 505 DPRINTF(("%s: ym_mixer_set_port: dev 0x%x, type 0x%x, 0x%x (%d; %d, %d)\n", 506 DVNAME(sc), cp->dev, cp->type, cp->un.ord, 507 cp->un.value.num_channels, cp->un.value.level[0], 508 cp->un.value.level[1])); 509 510 #ifndef AUDIO_NO_POWER_CTL 511 /* Power-up chip */ 512 ym_power_ctl(sc, YM_POWER_CODEC_CTL, 1); 513 #endif 514 515 switch (cp->dev) { 516 case YM_OUTPUT_LVL: 517 ad1848_to_vol(cp, &vol); 518 ym_set_master_gain(sc, &vol); 519 goto out; 520 521 case YM_OUTPUT_MUTE: 522 sc->master_mute = (cp->un.ord != 0); 523 ym_mute(sc, SA3_VOL_L, sc->master_mute); 524 ym_mute(sc, SA3_VOL_R, sc->master_mute); 525 goto out; 526 527 case YM_MIC_LVL: 528 if (cp->un.value.num_channels != 1) 529 error = EINVAL; 530 else 531 ym_set_mic_gain(sc, 532 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); 533 goto out; 534 535 case YM_MASTER_EQMODE: 536 sc->sc_eqmode = cp->un.ord & SA3_SYS_CTL_YMODE; 537 ym_write(sc, SA3_SYS_CTL, (ym_read(sc, SA3_SYS_CTL) & 538 ~SA3_SYS_CTL_YMODE) | sc->sc_eqmode); 539 goto out; 540 541 case YM_MASTER_TREBLE: 542 ym_set_3d(sc, cp, &sc->sc_treble, SA3_3D_TREBLE); 543 goto out; 544 545 case YM_MASTER_BASS: 546 ym_set_3d(sc, cp, &sc->sc_bass, SA3_3D_BASS); 547 goto out; 548 549 case YM_MASTER_WIDE: 550 ym_set_3d(sc, cp, &sc->sc_wide, SA3_3D_WIDE); 551 goto out; 552 553 #ifndef AUDIO_NO_POWER_CTL 554 case YM_PWR_MODE: 555 if ((unsigned) cp->un.ord > YM_POWER_NOSAVE) 556 error = EINVAL; 557 else 558 sc->sc_pow_mode = cp->un.ord; 559 goto out; 560 561 case YM_PWR_TIMEOUT: 562 if (cp->un.value.num_channels != 1) 563 error = EINVAL; 564 else 565 sc->sc_pow_timeout = 566 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 567 goto out; 568 569 /* 570 * Needs power-up to hear external sources. 571 */ 572 case YM_CD_MUTE: 573 case YM_LINE_MUTE: 574 case YM_SPEAKER_MUTE: 575 extsources = YM_MIXER_TO_XS(cp->dev); 576 if (cp->un.ord) { 577 if ((sc->sc_external_sources &= ~extsources) == 0) { 578 /* 579 * All the external sources are muted 580 * --- no need to keep the chip on. 581 */ 582 ym_power_ctl(sc, YM_POWER_EXT_SRC, 0); 583 DPRINTF(("%s: ym_mixer_set_port: off for ext\n", 584 DVNAME(sc))); 585 } 586 } else { 587 /* mute off - power-up the chip */ 588 sc->sc_external_sources |= extsources; 589 ym_power_ctl(sc, YM_POWER_EXT_SRC, 1); 590 DPRINTF(("%s: ym_mixer_set_port: on for ext\n", 591 DVNAME(sc))); 592 } 593 break; /* fall to ad1848_mixer_set_port() */ 594 595 /* 596 * Power on/off the playback part for monitoring. 597 */ 598 case YM_MONITOR_MUTE: 599 if ((ac->open_mode & (FREAD | FWRITE)) == FREAD) 600 ym_power_ctl(sc, YM_POWER_CODEC_P | YM_POWER_CODEC_DA, 601 cp->un.ord == 0); 602 break; /* fall to ad1848_mixer_set_port() */ 603 #endif 604 } 605 606 error = ad1848_mixer_set_port(ac, mappings, NUMMAP, cp); 607 608 if (error != ENXIO) 609 goto out; 610 611 error = 0; 612 613 switch (cp->dev) { 614 case YM_MIC_MUTE: 615 sc->mic_mute = (cp->un.ord != 0); 616 ym_mute(sc, SA3_MIC_VOL, sc->mic_mute); 617 break; 618 619 default: 620 error = ENXIO; 621 break; 622 } 623 624 out: 625 #ifndef AUDIO_NO_POWER_CTL 626 /* Power-down chip */ 627 ym_power_ctl(sc, YM_POWER_CODEC_CTL, 0); 628 #endif 629 630 return (error); 631 } 632 633 int 634 ym_mixer_get_port(addr, cp) 635 void *addr; 636 mixer_ctrl_t *cp; 637 { 638 struct ad1848_softc *ac = addr; 639 struct ym_softc *sc = ac->parent; 640 int error; 641 642 switch (cp->dev) { 643 case YM_OUTPUT_LVL: 644 ad1848_from_vol(cp, &sc->master_gain); 645 return 0; 646 647 case YM_OUTPUT_MUTE: 648 cp->un.ord = sc->master_mute; 649 return 0; 650 651 case YM_MIC_LVL: 652 if (cp->un.value.num_channels != 1) 653 return EINVAL; 654 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->mic_gain; 655 return 0; 656 657 case YM_MASTER_EQMODE: 658 cp->un.ord = sc->sc_eqmode; 659 return 0; 660 661 case YM_MASTER_TREBLE: 662 ad1848_from_vol(cp, &sc->sc_treble); 663 return 0; 664 665 case YM_MASTER_BASS: 666 ad1848_from_vol(cp, &sc->sc_bass); 667 return 0; 668 669 case YM_MASTER_WIDE: 670 ad1848_from_vol(cp, &sc->sc_wide); 671 return 0; 672 673 #ifndef AUDIO_NO_POWER_CTL 674 case YM_PWR_MODE: 675 cp->un.ord = sc->sc_pow_mode; 676 return 0; 677 678 case YM_PWR_TIMEOUT: 679 if (cp->un.value.num_channels != 1) 680 return EINVAL; 681 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_pow_timeout; 682 return 0; 683 #endif 684 } 685 686 error = ad1848_mixer_get_port(ac, mappings, NUMMAP, cp); 687 688 if (error != ENXIO) 689 return (error); 690 691 error = 0; 692 693 switch (cp->dev) { 694 case YM_MIC_MUTE: 695 cp->un.ord = sc->mic_mute; 696 break; 697 698 default: 699 error = ENXIO; 700 break; 701 } 702 703 return(error); 704 } 705 706 static char *mixer_classes[] = { 707 AudioCinputs, AudioCrecord, AudioCoutputs, AudioCmonitor, 708 AudioCequalization 709 #ifndef AUDIO_NO_POWER_CTL 710 , AudioCpower 711 #endif 712 }; 713 714 int 715 ym_query_devinfo(addr, dip) 716 void *addr; 717 mixer_devinfo_t *dip; 718 { 719 static char *mixer_port_names[] = { 720 AudioNdac, AudioNmidi, AudioNcd, AudioNline, AudioNspeaker, 721 AudioNmicrophone, AudioNmonitor 722 }; 723 724 dip->next = dip->prev = AUDIO_MIXER_LAST; 725 726 switch(dip->index) { 727 case YM_INPUT_CLASS: /* input class descriptor */ 728 case YM_OUTPUT_CLASS: 729 case YM_MONITOR_CLASS: 730 case YM_RECORD_CLASS: 731 case YM_EQ_CLASS: 732 #ifndef AUDIO_NO_POWER_CTL 733 case YM_PWR_CLASS: 734 #endif 735 dip->type = AUDIO_MIXER_CLASS; 736 dip->mixer_class = dip->index; 737 strcpy(dip->label.name, 738 mixer_classes[dip->index - YM_INPUT_CLASS]); 739 break; 740 741 case YM_DAC_LVL: 742 case YM_MIDI_LVL: 743 case YM_CD_LVL: 744 case YM_LINE_LVL: 745 case YM_SPEAKER_LVL: 746 case YM_MIC_LVL: 747 case YM_MONITOR_LVL: 748 dip->type = AUDIO_MIXER_VALUE; 749 if (dip->index == YM_MONITOR_LVL) 750 dip->mixer_class = YM_MONITOR_CLASS; 751 else 752 dip->mixer_class = YM_INPUT_CLASS; 753 754 dip->next = dip->index + 7; 755 756 strcpy(dip->label.name, 757 mixer_port_names[dip->index - YM_DAC_LVL]); 758 759 if (dip->index == YM_SPEAKER_LVL || 760 dip->index == YM_MIC_LVL) 761 dip->un.v.num_channels = 1; 762 else 763 dip->un.v.num_channels = 2; 764 765 strcpy(dip->un.v.units.name, AudioNvolume); 766 break; 767 768 case YM_DAC_MUTE: 769 case YM_MIDI_MUTE: 770 case YM_CD_MUTE: 771 case YM_LINE_MUTE: 772 case YM_SPEAKER_MUTE: 773 case YM_MIC_MUTE: 774 case YM_MONITOR_MUTE: 775 if (dip->index == YM_MONITOR_MUTE) 776 dip->mixer_class = YM_MONITOR_CLASS; 777 else 778 dip->mixer_class = YM_INPUT_CLASS; 779 dip->type = AUDIO_MIXER_ENUM; 780 dip->prev = dip->index - 7; 781 mute: 782 strcpy(dip->label.name, AudioNmute); 783 dip->un.e.num_mem = 2; 784 strcpy(dip->un.e.member[0].label.name, AudioNoff); 785 dip->un.e.member[0].ord = 0; 786 strcpy(dip->un.e.member[1].label.name, AudioNon); 787 dip->un.e.member[1].ord = 1; 788 break; 789 790 791 case YM_OUTPUT_LVL: 792 dip->type = AUDIO_MIXER_VALUE; 793 dip->mixer_class = YM_OUTPUT_CLASS; 794 dip->next = YM_OUTPUT_MUTE; 795 strcpy(dip->label.name, AudioNmaster); 796 dip->un.v.num_channels = 2; 797 strcpy(dip->un.v.units.name, AudioNvolume); 798 break; 799 800 case YM_OUTPUT_MUTE: 801 dip->mixer_class = YM_OUTPUT_CLASS; 802 dip->type = AUDIO_MIXER_ENUM; 803 dip->prev = YM_OUTPUT_LVL; 804 goto mute; 805 806 807 case YM_REC_LVL: /* record level */ 808 dip->type = AUDIO_MIXER_VALUE; 809 dip->mixer_class = YM_RECORD_CLASS; 810 dip->next = YM_RECORD_SOURCE; 811 strcpy(dip->label.name, AudioNrecord); 812 dip->un.v.num_channels = 2; 813 strcpy(dip->un.v.units.name, AudioNvolume); 814 break; 815 816 case YM_RECORD_SOURCE: 817 dip->mixer_class = YM_RECORD_CLASS; 818 dip->type = AUDIO_MIXER_ENUM; 819 dip->prev = YM_REC_LVL; 820 strcpy(dip->label.name, AudioNsource); 821 dip->un.e.num_mem = 4; 822 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone); 823 dip->un.e.member[0].ord = MIC_IN_PORT; 824 strcpy(dip->un.e.member[1].label.name, AudioNline); 825 dip->un.e.member[1].ord = LINE_IN_PORT; 826 strcpy(dip->un.e.member[2].label.name, AudioNdac); 827 dip->un.e.member[2].ord = DAC_IN_PORT; 828 strcpy(dip->un.e.member[3].label.name, AudioNcd); 829 dip->un.e.member[3].ord = AUX1_IN_PORT; 830 break; 831 832 833 case YM_MASTER_EQMODE: 834 dip->type = AUDIO_MIXER_ENUM; 835 dip->mixer_class = YM_EQ_CLASS; 836 strcpy(dip->label.name, AudioNmode); 837 strcpy(dip->un.v.units.name, AudioNmode); 838 dip->un.e.num_mem = 4; 839 strcpy(dip->un.e.member[0].label.name, AudioNdesktop); 840 dip->un.e.member[0].ord = SA3_SYS_CTL_YMODE0; 841 strcpy(dip->un.e.member[1].label.name, AudioNlaptop); 842 dip->un.e.member[1].ord = SA3_SYS_CTL_YMODE1; 843 strcpy(dip->un.e.member[2].label.name, AudioNsubnote); 844 dip->un.e.member[2].ord = SA3_SYS_CTL_YMODE2; 845 strcpy(dip->un.e.member[3].label.name, AudioNhifi); 846 dip->un.e.member[3].ord = SA3_SYS_CTL_YMODE3; 847 break; 848 849 case YM_MASTER_TREBLE: 850 dip->type = AUDIO_MIXER_VALUE; 851 dip->mixer_class = YM_EQ_CLASS; 852 strcpy(dip->label.name, AudioNtreble); 853 dip->un.v.num_channels = 2; 854 strcpy(dip->un.v.units.name, AudioNtreble); 855 break; 856 857 case YM_MASTER_BASS: 858 dip->type = AUDIO_MIXER_VALUE; 859 dip->mixer_class = YM_EQ_CLASS; 860 strcpy(dip->label.name, AudioNbass); 861 dip->un.v.num_channels = 2; 862 strcpy(dip->un.v.units.name, AudioNbass); 863 break; 864 865 case YM_MASTER_WIDE: 866 dip->type = AUDIO_MIXER_VALUE; 867 dip->mixer_class = YM_EQ_CLASS; 868 strcpy(dip->label.name, AudioNsurround); 869 dip->un.v.num_channels = 2; 870 strcpy(dip->un.v.units.name, AudioNsurround); 871 break; 872 873 874 #ifndef AUDIO_NO_POWER_CTL 875 case YM_PWR_MODE: 876 dip->type = AUDIO_MIXER_ENUM; 877 dip->mixer_class = YM_PWR_CLASS; 878 dip->next = YM_PWR_TIMEOUT; 879 strcpy(dip->label.name, AudioNsave); 880 dip->un.e.num_mem = 3; 881 strcpy(dip->un.e.member[0].label.name, AudioNpowerdown); 882 dip->un.e.member[0].ord = YM_POWER_POWERDOWN; 883 strcpy(dip->un.e.member[1].label.name, AudioNpowersave); 884 dip->un.e.member[1].ord = YM_POWER_POWERSAVE; 885 strcpy(dip->un.e.member[2].label.name, AudioNnosave); 886 dip->un.e.member[2].ord = YM_POWER_NOSAVE; 887 break; 888 889 case YM_PWR_TIMEOUT: 890 dip->type = AUDIO_MIXER_VALUE; 891 dip->mixer_class = YM_PWR_CLASS; 892 dip->prev = YM_PWR_MODE; 893 strcpy(dip->label.name, AudioNtimeout); 894 dip->un.v.num_channels = 1; 895 strcpy(dip->un.v.units.name, AudioNtimeout); 896 break; 897 #endif /* not AUDIO_NO_POWER_CTL */ 898 899 default: 900 return ENXIO; 901 /*NOTREACHED*/ 902 } 903 904 return 0; 905 } 906 907 int 908 ym_intr(arg) 909 void *arg; 910 { 911 struct ym_softc *sc = arg; 912 u_int8_t ist; 913 int processed; 914 915 /* OPL3 timer is currently unused. */ 916 if (((ist = ym_read(sc, SA3_IRQA_STAT)) & 917 ~(SA3_IRQ_STAT_SB|SA3_IRQ_STAT_OPL3)) == 0) { 918 DPRINTF(("%s: ym_intr: spurious interrupt\n", DVNAME(sc))); 919 return 0; 920 } 921 922 /* Process pending interrupts. */ 923 do { 924 processed = 0; 925 /* 926 * CODEC interrupts. 927 */ 928 if (ist & (SA3_IRQ_STAT_TI|SA3_IRQ_STAT_CI|SA3_IRQ_STAT_PI)) { 929 ad1848_isa_intr(&sc->sc_ad1848); 930 processed = 1; 931 } 932 #if NMPU_YM > 0 933 /* 934 * MPU401 interrupt. 935 */ 936 if (ist & SA3_IRQ_STAT_MPU) { 937 mpu_intr(sc->sc_mpudev); 938 processed = 1; 939 } 940 #endif 941 /* 942 * Hardware volume interrupt. 943 * Recalculate master volume from the hardware setting. 944 */ 945 if (ist & SA3_IRQ_STAT_MV) { 946 sc->master_gain.left = 947 (SA3_VOL_MV & ~ym_read(sc, SA3_VOL_L)) * 948 (SA3_VOL_MV + 1) + (SA3_VOL_MV + 1) / 2; 949 sc->master_gain.right = 950 (SA3_VOL_MV & ~ym_read(sc, SA3_VOL_R)) * 951 (SA3_VOL_MV + 1) + (SA3_VOL_MV + 1) / 2; 952 953 #if 0 /* XXX NOT YET */ 954 /* Notify the change to async processes. */ 955 if (sc->sc_audiodev) 956 mixer_signal(sc->sc_audiodev); 957 #endif 958 processed = 1; 959 } 960 } while (processed && (ist = ym_read(sc, SA3_IRQA_STAT))); 961 962 return 1; 963 } 964 965 966 #ifndef AUDIO_NO_POWER_CTL 967 static void 968 ym_save_codec_regs(sc) 969 struct ym_softc *sc; 970 { 971 struct ad1848_softc *ac = &sc->sc_ad1848.sc_ad1848; 972 int i; 973 974 DPRINTF(("%s: ym_save_codec_regs\n", DVNAME(sc))); 975 976 for (i = 0; i <= 0x1f; i++) 977 sc->sc_codec_scan[i] = ad_read(ac, i); 978 } 979 980 static void 981 ym_restore_codec_regs(sc) 982 struct ym_softc *sc; 983 { 984 struct ad1848_softc *ac = &sc->sc_ad1848.sc_ad1848; 985 int i, t; 986 987 DPRINTF(("%s: ym_restore_codec_regs\n", DVNAME(sc))); 988 989 for (i = 0; i <= 0x1f; i++) { 990 /* 991 * Wait til the chip becomes ready. 992 * This is required after suspend/resume. 993 */ 994 for (t = 0; 995 t < 100000 && ADREAD(ac, AD1848_IADDR) & SP_IN_INIT; t++) 996 ; 997 #ifdef AUDIO_DEBUG 998 if (t) 999 DPRINTF(("%s: ym_restore_codec_regs: reg %d, t %d\n", 1000 DVNAME(sc), i, t)); 1001 #endif 1002 ad_write(ac, i, sc->sc_codec_scan[i]); 1003 } 1004 } 1005 1006 /* 1007 * Save and restore the state on suspending / resumning. 1008 * 1009 * XXX This is not complete. 1010 * Currently only the parameters, such as output gain, are restored. 1011 * DMA state should also be restored. FIXME. 1012 */ 1013 void 1014 ym_power_hook(why, v) 1015 int why; 1016 void *v; 1017 { 1018 struct ym_softc *sc = v; 1019 int i; 1020 int s; 1021 1022 DPRINTF(("%s: ym_power_hook: why = %d\n", DVNAME(sc), why)); 1023 1024 s = splaudio(); 1025 1026 if (why != PWR_RESUME) { 1027 /* 1028 * suspending... 1029 */ 1030 untimeout(ym_powerdown_blocks, sc); 1031 if (sc->sc_turning_off) 1032 ym_powerdown_blocks(sc); 1033 1034 /* 1035 * Save CODEC registers. 1036 * Note that the registers read incorrect 1037 * if the CODEC part is in power-down mode. 1038 */ 1039 if (sc->sc_on_blocks & YM_POWER_CODEC_DIGITAL) 1040 ym_save_codec_regs(sc); 1041 1042 /* 1043 * Save OPL3-SA3 control registers and power-down the chip. 1044 * Note that the registers read incorrect 1045 * if the chip is in global power-down mode. 1046 */ 1047 sc->sc_sa3_scan[SA3_PWR_MNG] = ym_read(sc, SA3_PWR_MNG); 1048 if (sc->sc_on_blocks) 1049 ym_chip_powerdown(sc); 1050 } else { 1051 /* 1052 * resuming... 1053 */ 1054 ym_chip_powerup(sc, 1); 1055 ym_init(sc); /* power-on CODEC */ 1056 1057 /* Restore control registers. */ 1058 for (i = SA3_PWR_MNG + 1; i <= YM_SAVE_REG_MAX; i++) { 1059 if (i == SA3_SB_SCAN || i == SA3_SB_SCAN_DATA || 1060 i == SA3_DPWRDWN) 1061 continue; 1062 ym_write(sc, i, sc->sc_sa3_scan[i]); 1063 } 1064 1065 /* Restore CODEC registers (including mixer). */ 1066 ym_restore_codec_regs(sc); 1067 1068 /* Restore global/digital power-down state. */ 1069 ym_write(sc, SA3_PWR_MNG, sc->sc_sa3_scan[SA3_PWR_MNG]); 1070 ym_write(sc, SA3_DPWRDWN, sc->sc_sa3_scan[SA3_DPWRDWN]); 1071 } 1072 splx(s); 1073 } 1074 1075 int 1076 ym_codec_power_ctl(arg, flags) 1077 void *arg; 1078 int flags; 1079 { 1080 struct ym_softc *sc = arg; 1081 struct ad1848_softc *ac = &sc->sc_ad1848.sc_ad1848; 1082 int parts; 1083 1084 DPRINTF(("%s: ym_codec_power_ctl: flags = 0x%x\n", DVNAME(sc), flags)); 1085 1086 if (flags != 0) { 1087 parts = 0; 1088 if (flags & FREAD) { 1089 parts |= YM_POWER_CODEC_R | YM_POWER_CODEC_AD; 1090 if (ac->mute[AD1848_MONITOR_CHANNEL] == 0) 1091 parts |= YM_POWER_CODEC_P | YM_POWER_CODEC_DA; 1092 } 1093 if (flags & FWRITE) 1094 parts |= YM_POWER_CODEC_P | YM_POWER_CODEC_DA; 1095 } else 1096 parts = YM_POWER_CODEC_P | YM_POWER_CODEC_R | 1097 YM_POWER_CODEC_DA | YM_POWER_CODEC_AD; 1098 1099 ym_power_ctl(sc, parts, flags); 1100 1101 return 0; 1102 } 1103 1104 /* 1105 * Enter Power Save mode or Global Power Down mode. 1106 * Total dissipation becomes 5mA and 10uA (typ.) respective. 1107 * 1108 * This must be called at splaudio(). 1109 */ 1110 static void 1111 ym_chip_powerdown(sc) 1112 struct ym_softc *sc; 1113 { 1114 int i; 1115 1116 DPRINTF(("%s: ym_chip_powerdown\n", DVNAME(sc))); 1117 1118 /* Save control registers. */ 1119 for (i = SA3_PWR_MNG + 1; i <= YM_SAVE_REG_MAX; i++) { 1120 if (i == SA3_SB_SCAN || i == SA3_SB_SCAN_DATA) 1121 continue; 1122 sc->sc_sa3_scan[i] = ym_read(sc, i); 1123 } 1124 ym_write(sc, SA3_PWR_MNG, 1125 (sc->sc_pow_mode == YM_POWER_POWERDOWN ? 1126 SA3_PWR_MNG_PDN : SA3_PWR_MNG_PSV) | SA3_PWR_MNG_PDX); 1127 } 1128 1129 /* 1130 * Power up from Power Save / Global Power Down Mode. 1131 * 1132 * We assume no ym interrupt shall occur, since the chip is 1133 * in power-down mode (or should be blocked by splaudio()). 1134 */ 1135 static void 1136 ym_chip_powerup(sc, nosleep) 1137 struct ym_softc *sc; 1138 int nosleep; 1139 { 1140 int wchan; 1141 u_int8_t pw; 1142 1143 DPRINTF(("%s: ym_chip_powerup\n", DVNAME(sc))); 1144 1145 pw = ym_read(sc, SA3_PWR_MNG); 1146 1147 if ((pw & (SA3_PWR_MNG_PSV | SA3_PWR_MNG_PDN | SA3_PWR_MNG_PDX)) == 0) 1148 return; /* already on */ 1149 1150 pw &= ~SA3_PWR_MNG_PDX; 1151 ym_write(sc, SA3_PWR_MNG, pw); 1152 1153 /* wait 100 ms */ 1154 if (nosleep) 1155 delay(100000); 1156 else 1157 tsleep(&wchan, PWAIT, "ym_pu1", hz / 10); 1158 1159 pw &= ~(SA3_PWR_MNG_PSV | SA3_PWR_MNG_PDN); 1160 ym_write(sc, SA3_PWR_MNG, pw); 1161 1162 /* wait 70 ms */ 1163 if (nosleep) 1164 delay(70000); 1165 else 1166 tsleep(&wchan, PWAIT, "ym_pu2", hz / 14); 1167 1168 /* The chip is muted automatically --- unmute it now. */ 1169 ym_mute(sc, SA3_VOL_L, sc->master_mute); 1170 ym_mute(sc, SA3_VOL_R, sc->master_mute); 1171 } 1172 1173 /* timeout() handler for power-down */ 1174 void 1175 ym_powerdown_blocks(arg) 1176 void *arg; 1177 { 1178 struct ym_softc *sc = arg; 1179 u_int16_t parts; 1180 u_int16_t on_blocks = sc->sc_on_blocks; 1181 u_int8_t sv; 1182 int s; 1183 1184 DPRINTF(("%s: ym_powerdown_blocks: turning_off 0x%x\n", 1185 DVNAME(sc), sc->sc_turning_off)); 1186 1187 s = splaudio(); 1188 1189 on_blocks = sc->sc_on_blocks; 1190 1191 /* Be sure not to change the state of the chip. Save it first. */ 1192 sv = bus_space_read_1(sc->sc_iot, sc->sc_controlioh, SA3_CTL_INDEX); 1193 1194 parts = sc->sc_turning_off; 1195 1196 if (on_blocks & ~parts & YM_POWER_CODEC_CTL) 1197 parts &= ~(YM_POWER_CODEC_P | YM_POWER_CODEC_R); 1198 if (parts & YM_POWER_CODEC_CTL) { 1199 if ((on_blocks & YM_POWER_CODEC_P) == 0) 1200 parts |= YM_POWER_CODEC_P; 1201 if ((on_blocks & YM_POWER_CODEC_R) == 0) 1202 parts |= YM_POWER_CODEC_R; 1203 } 1204 parts &= ~YM_POWER_CODEC_PSEUDO; 1205 1206 /* If CODEC is being off, save the state. */ 1207 if ((sc->sc_on_blocks & YM_POWER_CODEC_DIGITAL) && 1208 (sc->sc_on_blocks & ~sc->sc_turning_off & 1209 YM_POWER_CODEC_DIGITAL) == 0) 1210 ym_save_codec_regs(sc); 1211 1212 ym_write(sc, SA3_DPWRDWN, ym_read(sc, SA3_DPWRDWN) | (u_int8_t) parts); 1213 ym_write(sc, SA3_APWRDWN, ym_read(sc, SA3_APWRDWN) | (parts >> 8)); 1214 1215 if (((sc->sc_on_blocks &= ~sc->sc_turning_off) & YM_POWER_ACTIVE) == 0) 1216 ym_chip_powerdown(sc); 1217 1218 sc->sc_turning_off = 0; 1219 1220 /* Restore the state of the chip. */ 1221 bus_space_write_1(sc->sc_iot, sc->sc_controlioh, SA3_CTL_INDEX, sv); 1222 1223 splx(s); 1224 } 1225 1226 /* 1227 * Power control entry point. 1228 */ 1229 void 1230 ym_power_ctl(sc, parts, onoff) 1231 struct ym_softc *sc; 1232 int parts, onoff; 1233 { 1234 int s; 1235 int need_restore_codec; 1236 1237 DPRINTF(("%s: ym_power_ctl: parts = 0x%x, %s\n", 1238 DVNAME(sc), parts, onoff ? "on" : "off")); 1239 1240 #ifdef DIAGNOSTIC 1241 if (curproc == NULL) 1242 panic("ym_power_ctl: no curproc"); 1243 #endif 1244 /* This function may sleep --- needs locking. */ 1245 while (sc->sc_in_power_ctl & YM_POWER_CTL_INUSE) { 1246 sc->sc_in_power_ctl |= YM_POWER_CTL_WANTED; 1247 DPRINTF(("%s: ym_power_ctl: sleeping\n", DVNAME(sc))); 1248 tsleep(&sc->sc_in_power_ctl, PWAIT, "ym_pc", 0); 1249 DPRINTF(("%s: ym_power_ctl: awaken\n", DVNAME(sc))); 1250 } 1251 sc->sc_in_power_ctl |= YM_POWER_CTL_INUSE; 1252 1253 /* Defeat timeout(9) interrupts. */ 1254 s = splsoftclock(); 1255 1256 /* If ON requested to parts which are scheduled to OFF, cancel it. */ 1257 if (onoff && sc->sc_turning_off && (sc->sc_turning_off &= ~parts) == 0) 1258 untimeout(ym_powerdown_blocks, sc); 1259 1260 if (!onoff && sc->sc_turning_off) 1261 parts &= ~sc->sc_turning_off; 1262 1263 /* Discard bits which are currently {on,off}. */ 1264 parts &= onoff ? ~sc->sc_on_blocks : sc->sc_on_blocks; 1265 1266 /* Cancel previous timeout if needed. */ 1267 if (parts != 0 && sc->sc_turning_off) 1268 untimeout(ym_powerdown_blocks, sc); 1269 1270 (void) splx(s); 1271 1272 if (parts == 0) 1273 goto unlock; /* no work to do */ 1274 1275 if (onoff) { 1276 /* Turning on is done immediately. */ 1277 1278 /* If the chip is off, turn it on. */ 1279 if ((sc->sc_on_blocks & YM_POWER_ACTIVE) == 0) 1280 ym_chip_powerup(sc, 0); 1281 1282 need_restore_codec = (parts & YM_POWER_CODEC_DIGITAL) && 1283 (sc->sc_on_blocks & YM_POWER_CODEC_DIGITAL) == 0; 1284 1285 sc->sc_on_blocks |= parts; 1286 if (parts & YM_POWER_CODEC_CTL) 1287 parts |= YM_POWER_CODEC_P | YM_POWER_CODEC_R; 1288 1289 s = splaudio(); 1290 1291 ym_write(sc, SA3_DPWRDWN, 1292 ym_read(sc, SA3_DPWRDWN) & (u_int8_t)~parts); 1293 ym_write(sc, SA3_APWRDWN, 1294 ym_read(sc, SA3_APWRDWN) & ~(parts >> 8)); 1295 if (need_restore_codec) 1296 ym_restore_codec_regs(sc); 1297 1298 (void) splx(s); 1299 } else { 1300 /* Turning off is delayed. */ 1301 sc->sc_turning_off |= parts; 1302 } 1303 1304 /* Schedule turning off. */ 1305 if (sc->sc_pow_mode != YM_POWER_NOSAVE && sc->sc_turning_off) 1306 timeout(ym_powerdown_blocks, sc, hz * sc->sc_pow_timeout); 1307 1308 unlock: 1309 if (sc->sc_in_power_ctl & YM_POWER_CTL_WANTED) 1310 wakeup(&sc->sc_in_power_ctl); 1311 sc->sc_in_power_ctl = 0; 1312 } 1313 #endif /* not AUDIO_NO_POWER_CTL */ 1314