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