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