ym.c revision 1.13 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