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