1139749Simp/*-
274711Scg * Copyright (c) 2001 George Reid <greid@ukug.uk.freebsd.org>
3119853Scg * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
4166426Sjoel * Copyright (c) 1997,1998 Luigi Rizzo
5166426Sjoel * Copyright (c) 1994,1995 Hannu Savolainen
650723Scg * All rights reserved.
750723Scg *
829415Sjmg * Redistribution and use in source and binary forms, with or without
929415Sjmg * modification, are permitted provided that the following conditions
1030869Sjmg * are met:
1130869Sjmg * 1. Redistributions of source code must retain the above copyright
1230869Sjmg *    notice, this list of conditions and the following disclaimer.
1330869Sjmg * 2. Redistributions in binary form must reproduce the above copyright
1450723Scg *    notice, this list of conditions and the following disclaimer in the
1550723Scg *    documentation and/or other materials provided with the distribution.
1630869Sjmg *
1750723Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1850723Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1950723Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2050723Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2150723Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2250723Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2350723Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2450723Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2550723Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2650723Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2750723Scg * SUCH DAMAGE.
2829415Sjmg */
2929415Sjmg
30193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
31193640Sariff#include "opt_snd.h"
32193640Sariff#endif
33193640Sariff
3453465Scg#include <dev/sound/pcm/sound.h>
3550723Scg
3682180ScgSND_DECLARE_FILE("$FreeBSD: releng/10.3/sys/dev/sound/isa/mss.c 193640 2009-06-07 19:12:08Z ariff $");
3782180Scg
3850723Scg/* board-specific include files */
3953465Scg#include <dev/sound/isa/mss.h>
4090241Stg#include <dev/sound/isa/sb.h>
4153553Stanimura#include <dev/sound/chip.h>
4229415Sjmg
43110499Snyan#include <isa/isavar.h>
44110499Snyan
4570134Scg#include "mixer_if.h"
4670134Scg
4783619Scg#define MSS_DEFAULT_BUFSZ (4096)
4864032Scg#define MSS_INDEXED_REGS 0x20
4964032Scg#define OPL_INDEXED_REGS 0x19
5053512Scg
5150723Scgstruct mss_info;
5229415Sjmg
5350723Scgstruct mss_chinfo {
5450723Scg	struct mss_info *parent;
5574763Scg	struct pcm_channel *channel;
5674763Scg	struct snd_dbuf *buffer;
5750723Scg	int dir;
5870291Scg	u_int32_t fmt, blksz;
5950723Scg};
6029415Sjmg
6150723Scgstruct mss_info {
6250723Scg    struct resource *io_base;	/* primary I/O address for the board */
6350723Scg    int		     io_rid;
6450723Scg    struct resource *conf_base; /* and the opti931 also has a config space */
6550723Scg    int		     conf_rid;
6650723Scg    struct resource *irq;
6750723Scg    int		     irq_rid;
6850723Scg    struct resource *drq1; /* play */
6950723Scg    int		     drq1_rid;
7050723Scg    struct resource *drq2; /* rec */
7150723Scg    int		     drq2_rid;
7265644Scg    void 	    *ih;
7350723Scg    bus_dma_tag_t    parent_dmat;
74107285Scg    struct mtx	    *lock;
7529415Sjmg
7664032Scg    char mss_indexed_regs[MSS_INDEXED_REGS];
7764032Scg    char opl_indexed_regs[OPL_INDEXED_REGS];
7850723Scg    int bd_id;      /* used to hold board-id info, eg. sb version,
7950723Scg		     * mss codec type, etc. etc.
8050723Scg		     */
8152169Sdfr    int opti_offset;		/* offset from config_base for opti931 */
8250723Scg    u_long  bd_flags;       /* board-specific flags */
8374711Scg    int optibase;		/* base address for OPTi9xx config */
8474711Scg    struct resource *indir;	/* Indirect register index address */
8574711Scg    int indir_rid;
8674711Scg    int password;		/* password for opti9xx cards */
8774711Scg    int passwdreg;		/* password register */
8883619Scg    unsigned int bufsize;
8950723Scg    struct mss_chinfo pch, rch;
9050723Scg};
9129415Sjmg
9250723Scgstatic int 		mss_probe(device_t dev);
9350723Scgstatic int 		mss_attach(device_t dev);
9429415Sjmg
9550723Scgstatic driver_intr_t 	mss_intr;
9629415Sjmg
9750723Scg/* prototypes for local functions */
9850723Scgstatic int 		mss_detect(device_t dev, struct mss_info *mss);
99150014Simp#ifndef PC98
10074711Scgstatic int		opti_detect(device_t dev, struct mss_info *mss);
101150014Simp#endif
10250723Scgstatic char 		*ymf_test(device_t dev, struct mss_info *mss);
10350723Scgstatic void		ad_unmute(struct mss_info *mss);
10442284Sluigi
10550723Scg/* mixer set funcs */
10650723Scgstatic int 		mss_mixer_set(struct mss_info *mss, int dev, int left, int right);
10750723Scgstatic int 		mss_set_recsrc(struct mss_info *mss, int mask);
10850723Scg
10950723Scg/* io funcs */
11050723Scgstatic int 		ad_wait_init(struct mss_info *mss, int x);
11150723Scgstatic int 		ad_read(struct mss_info *mss, int reg);
11250723Scgstatic void 		ad_write(struct mss_info *mss, int reg, u_char data);
11350723Scgstatic void 		ad_write_cnt(struct mss_info *mss, int reg, u_short data);
11457770Scgstatic void    		ad_enter_MCE(struct mss_info *mss);
11557770Scgstatic void             ad_leave_MCE(struct mss_info *mss);
11650723Scg
11774711Scg/* OPTi-specific functions */
11874711Scgstatic void		opti_write(struct mss_info *mss, u_char reg,
11974711Scg				   u_char data);
120150038Snyan#ifndef PC98
12174711Scgstatic u_char		opti_read(struct mss_info *mss, u_char reg);
122150038Snyan#endif
12374711Scgstatic int		opti_init(device_t dev, struct mss_info *mss);
12474711Scg
12550723Scg/* io primitives */
12650723Scgstatic void 		conf_wr(struct mss_info *mss, u_char reg, u_char data);
12750723Scgstatic u_char 		conf_rd(struct mss_info *mss, u_char reg);
12850723Scg
12950723Scgstatic int 		pnpmss_probe(device_t dev);
13050723Scgstatic int 		pnpmss_attach(device_t dev);
13150723Scg
13250723Scgstatic driver_intr_t 	opti931_intr;
13342284Sluigi
13464881Scgstatic u_int32_t mss_fmt[] = {
135193640Sariff	SND_FORMAT(AFMT_U8, 1, 0),
136193640Sariff	SND_FORMAT(AFMT_U8, 2, 0),
137193640Sariff	SND_FORMAT(AFMT_S16_LE, 1, 0),
138193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
139193640Sariff	SND_FORMAT(AFMT_MU_LAW, 1, 0),
140193640Sariff	SND_FORMAT(AFMT_MU_LAW, 2, 0),
141193640Sariff	SND_FORMAT(AFMT_A_LAW, 1, 0),
142193640Sariff	SND_FORMAT(AFMT_A_LAW, 2, 0),
14364881Scg	0
14450723Scg};
14574763Scgstatic struct pcmchan_caps mss_caps = {4000, 48000, mss_fmt, 0};
14629415Sjmg
14764881Scgstatic u_int32_t guspnp_fmt[] = {
148193640Sariff	SND_FORMAT(AFMT_U8, 1, 0),
149193640Sariff	SND_FORMAT(AFMT_U8, 2, 0),
150193640Sariff	SND_FORMAT(AFMT_S16_LE, 1, 0),
151193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
152193640Sariff	SND_FORMAT(AFMT_A_LAW, 1, 0),
153193640Sariff	SND_FORMAT(AFMT_A_LAW, 2, 0),
15464881Scg	0
15550723Scg};
15674763Scgstatic struct pcmchan_caps guspnp_caps = {4000, 48000, guspnp_fmt, 0};
15750723Scg
15864881Scgstatic u_int32_t opti931_fmt[] = {
159193640Sariff	SND_FORMAT(AFMT_U8, 1, 0),
160193640Sariff	SND_FORMAT(AFMT_U8, 2, 0),
161193640Sariff	SND_FORMAT(AFMT_S16_LE, 1, 0),
162193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
16364881Scg	0
16450723Scg};
16574763Scgstatic struct pcmchan_caps opti931_caps = {4000, 48000, opti931_fmt, 0};
16650723Scg
16750723Scg#define MD_AD1848	0x91
16850723Scg#define MD_AD1845	0x92
16954962Speter#define MD_CS42XX	0xA1
170108925Smdodd#define MD_CS423X	0xA2
17174711Scg#define MD_OPTI930	0xB0
17250723Scg#define	MD_OPTI931	0xB1
17350723Scg#define MD_OPTI925	0xB2
17474711Scg#define MD_OPTI924	0xB3
17550723Scg#define	MD_GUSPNP	0xB8
17653553Stanimura#define MD_GUSMAX	0xB9
17750723Scg#define	MD_YM0020	0xC1
17850723Scg#define	MD_VIVO		0xD1
17950723Scg
18050723Scg#define	DV_F_TRUE_MSS	0x00010000	/* mss _with_ base regs */
18150723Scg
18250723Scg#define FULL_DUPLEX(x) ((x)->bd_flags & BD_F_DUPLEX)
18350723Scg
18474763Scgstatic void
18574763Scgmss_lock(struct mss_info *mss)
18674763Scg{
18774788Scg	snd_mtxlock(mss->lock);
18874763Scg}
18974763Scg
19074763Scgstatic void
19174763Scgmss_unlock(struct mss_info *mss)
19274763Scg{
19374788Scg	snd_mtxunlock(mss->lock);
19474763Scg}
19574763Scg
19650723Scgstatic int
19750723Scgport_rd(struct resource *port, int off)
19850723Scg{
19950723Scg	if (port)
20050723Scg		return bus_space_read_1(rman_get_bustag(port),
20150723Scg					rman_get_bushandle(port),
20250723Scg					off);
20350723Scg	else
20450723Scg		return -1;
20550723Scg}
20650723Scg
20750723Scgstatic void
20850723Scgport_wr(struct resource *port, int off, u_int8_t data)
20950723Scg{
21050723Scg	if (port)
211108064Ssemenu		bus_space_write_1(rman_get_bustag(port),
212108064Ssemenu				  rman_get_bushandle(port),
213108064Ssemenu				  off, data);
21450723Scg}
21550723Scg
21650723Scgstatic int
21750723Scgio_rd(struct mss_info *mss, int reg)
21850723Scg{
21950723Scg	if (mss->bd_flags & BD_F_MSS_OFFSET) reg -= 4;
22050723Scg	return port_rd(mss->io_base, reg);
22150723Scg}
22250723Scg
22350723Scgstatic void
22450723Scgio_wr(struct mss_info *mss, int reg, u_int8_t data)
22550723Scg{
22650723Scg	if (mss->bd_flags & BD_F_MSS_OFFSET) reg -= 4;
227108064Ssemenu	port_wr(mss->io_base, reg, data);
22850723Scg}
22950723Scg
23050723Scgstatic void
23150723Scgconf_wr(struct mss_info *mss, u_char reg, u_char value)
23250723Scg{
23350723Scg    	port_wr(mss->conf_base, 0, reg);
23450723Scg    	port_wr(mss->conf_base, 1, value);
23550723Scg}
23650723Scg
23750723Scgstatic u_char
23850723Scgconf_rd(struct mss_info *mss, u_char reg)
23950723Scg{
24050723Scg	port_wr(mss->conf_base, 0, reg);
24150723Scg    	return port_rd(mss->conf_base, 1);
24250723Scg}
24350723Scg
24452169Sdfrstatic void
24552169Sdfropti_wr(struct mss_info *mss, u_char reg, u_char value)
24652169Sdfr{
24752169Sdfr    	port_wr(mss->conf_base, mss->opti_offset + 0, reg);
24852169Sdfr    	port_wr(mss->conf_base, mss->opti_offset + 1, value);
24952169Sdfr}
25052169Sdfr
25152169Sdfrstatic u_char
25252169Sdfropti_rd(struct mss_info *mss, u_char reg)
25352169Sdfr{
25452169Sdfr	port_wr(mss->conf_base, mss->opti_offset + 0, reg);
25552169Sdfr    	return port_rd(mss->conf_base, mss->opti_offset + 1);
25652169Sdfr}
25752169Sdfr
25850723Scgstatic void
25950723Scggus_wr(struct mss_info *mss, u_char reg, u_char value)
26050723Scg{
26150723Scg    	port_wr(mss->conf_base, 3, reg);
26250723Scg    	port_wr(mss->conf_base, 5, value);
26350723Scg}
26450723Scg
26550723Scgstatic u_char
26650723Scggus_rd(struct mss_info *mss, u_char reg)
26750723Scg{
26850723Scg    	port_wr(mss->conf_base, 3, reg);
26950723Scg    	return port_rd(mss->conf_base, 5);
27050723Scg}
27150723Scg
27250723Scgstatic void
27350723Scgmss_release_resources(struct mss_info *mss, device_t dev)
27450723Scg{
27550723Scg    	if (mss->irq) {
27665644Scg    		if (mss->ih)
27765644Scg			bus_teardown_intr(dev, mss->irq, mss->ih);
27865644Scg 		bus_release_resource(dev, SYS_RES_IRQ, mss->irq_rid,
27950723Scg				     mss->irq);
28050723Scg		mss->irq = 0;
28150723Scg    	}
28284112Scg    	if (mss->drq2) {
28384112Scg		if (mss->drq2 != mss->drq1) {
28484112Scg			isa_dma_release(rman_get_start(mss->drq2));
28584112Scg			bus_release_resource(dev, SYS_RES_DRQ, mss->drq2_rid,
28684112Scg				     	mss->drq2);
28784112Scg		}
28870291Scg		mss->drq2 = 0;
28970291Scg    	}
29070291Scg     	if (mss->drq1) {
29184112Scg		isa_dma_release(rman_get_start(mss->drq1));
29250723Scg		bus_release_resource(dev, SYS_RES_DRQ, mss->drq1_rid,
29350723Scg				     mss->drq1);
29450723Scg		mss->drq1 = 0;
29550723Scg    	}
29670291Scg   	if (mss->io_base) {
29750723Scg		bus_release_resource(dev, SYS_RES_IOPORT, mss->io_rid,
29850723Scg				     mss->io_base);
29950723Scg		mss->io_base = 0;
30050723Scg    	}
30150723Scg    	if (mss->conf_base) {
30250723Scg		bus_release_resource(dev, SYS_RES_IOPORT, mss->conf_rid,
30350723Scg				     mss->conf_base);
30450723Scg		mss->conf_base = 0;
30550723Scg    	}
30674789Scg	if (mss->indir) {
30774789Scg		bus_release_resource(dev, SYS_RES_IOPORT, mss->indir_rid,
30874789Scg				     mss->indir);
30974789Scg		mss->indir = 0;
31074789Scg	}
31165644Scg    	if (mss->parent_dmat) {
31265644Scg		bus_dma_tag_destroy(mss->parent_dmat);
31365644Scg		mss->parent_dmat = 0;
31465644Scg    	}
31574763Scg	if (mss->lock) snd_mtxfree(mss->lock);
31674763Scg
31765644Scg     	free(mss, M_DEVBUF);
31850723Scg}
31950723Scg
32050723Scgstatic int
32150723Scgmss_alloc_resources(struct mss_info *mss, device_t dev)
32250723Scg{
32370291Scg    	int pdma, rdma, ok = 1;
32450723Scg	if (!mss->io_base)
325127135Snjl    		mss->io_base = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
326127135Snjl						      &mss->io_rid, RF_ACTIVE);
32750723Scg	if (!mss->irq)
328127135Snjl    		mss->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
329127135Snjl						  &mss->irq_rid, RF_ACTIVE);
33050723Scg	if (!mss->drq1)
331127135Snjl    		mss->drq1 = bus_alloc_resource_any(dev, SYS_RES_DRQ,
332127135Snjl						   &mss->drq1_rid,
333127135Snjl						   RF_ACTIVE);
33450723Scg    	if (mss->conf_rid >= 0 && !mss->conf_base)
335127135Snjl        	mss->conf_base = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
336127135Snjl							&mss->conf_rid,
337127135Snjl							RF_ACTIVE);
33850723Scg    	if (mss->drq2_rid >= 0 && !mss->drq2)
339127135Snjl        	mss->drq2 = bus_alloc_resource_any(dev, SYS_RES_DRQ,
340127135Snjl						   &mss->drq2_rid,
341127135Snjl						   RF_ACTIVE);
34250723Scg
34374711Scg	if (!mss->io_base || !mss->drq1 || !mss->irq) ok = 0;
34474711Scg	if (mss->conf_rid >= 0 && !mss->conf_base) ok = 0;
34574711Scg	if (mss->drq2_rid >= 0 && !mss->drq2) ok = 0;
34650723Scg
34750723Scg	if (ok) {
34870291Scg		pdma = rman_get_start(mss->drq1);
34970291Scg		isa_dma_acquire(pdma);
35083619Scg		isa_dmainit(pdma, mss->bufsize);
35150723Scg		mss->bd_flags &= ~BD_F_DUPLEX;
35250723Scg		if (mss->drq2) {
35370291Scg			rdma = rman_get_start(mss->drq2);
35470291Scg			isa_dma_acquire(rdma);
35583619Scg			isa_dmainit(rdma, mss->bufsize);
35650723Scg			mss->bd_flags |= BD_F_DUPLEX;
35770291Scg		} else mss->drq2 = mss->drq1;
35850723Scg	}
35950723Scg    	return ok;
36050723Scg}
36150723Scg
36274763Scg/*
36374763Scg * The various mixers use a variety of bitmasks etc. The Voxware
36474763Scg * driver had a very nice technique to describe a mixer and interface
36574763Scg * to it. A table defines, for each channel, which register, bits,
36674763Scg * offset, polarity to use. This procedure creates the new value
36774763Scg * using the table and the old value.
36874763Scg */
36974763Scg
37074763Scgstatic void
37174763Scgchange_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval)
37274763Scg{
37374763Scg    	u_char mask;
37474763Scg    	int shift;
37574763Scg
37674763Scg    	DEB(printf("ch_bits dev %d ch %d val %d old 0x%02x "
37774763Scg		"r %d p %d bit %d off %d\n",
37874763Scg		dev, chn, newval, *regval,
37974763Scg		(*t)[dev][chn].regno, (*t)[dev][chn].polarity,
38074763Scg		(*t)[dev][chn].nbits, (*t)[dev][chn].bitoffs ) );
38174763Scg
38274763Scg    	if ( (*t)[dev][chn].polarity == 1)	/* reverse */
38374763Scg		newval = 100 - newval ;
38474763Scg
38574763Scg    	mask = (1 << (*t)[dev][chn].nbits) - 1;
38674763Scg    	newval = (int) ((newval * mask) + 50) / 100; /* Scale it */
38774763Scg    	shift = (*t)[dev][chn].bitoffs /*- (*t)[dev][LEFT_CHN].nbits + 1*/;
38874763Scg
38974763Scg    	*regval &= ~(mask << shift);        /* Filter out the previous value */
39074763Scg    	*regval |= (newval & mask) << shift;        /* Set the new value */
39174763Scg}
39274763Scg
39370134Scg/* -------------------------------------------------------------------- */
39470134Scg/* only one source can be set... */
39570134Scgstatic int
39670134Scgmss_set_recsrc(struct mss_info *mss, int mask)
39770134Scg{
39870134Scg    	u_char   recdev;
39970134Scg
40070134Scg    	switch (mask) {
40170134Scg    	case SOUND_MASK_LINE:
40270134Scg    	case SOUND_MASK_LINE3:
40370134Scg		recdev = 0;
40470134Scg		break;
40570134Scg
40670134Scg    	case SOUND_MASK_CD:
40770134Scg    	case SOUND_MASK_LINE1:
40870134Scg		recdev = 0x40;
40970134Scg		break;
41070134Scg
41170134Scg    	case SOUND_MASK_IMIX:
41270134Scg		recdev = 0xc0;
41370134Scg		break;
41470134Scg
41570134Scg    	case SOUND_MASK_MIC:
41670134Scg    	default:
41770134Scg		mask = SOUND_MASK_MIC;
41870134Scg		recdev = 0x80;
41970134Scg    	}
42070134Scg    	ad_write(mss, 0, (ad_read(mss, 0) & 0x3f) | recdev);
42170134Scg    	ad_write(mss, 1, (ad_read(mss, 1) & 0x3f) | recdev);
42270134Scg    	return mask;
42370134Scg}
42470134Scg
42570134Scg/* there are differences in the mixer depending on the actual sound card. */
42670134Scgstatic int
42770134Scgmss_mixer_set(struct mss_info *mss, int dev, int left, int right)
42870134Scg{
42970134Scg    	int        regoffs;
43074711Scg    	mixer_tab *mix_d;
43170134Scg    	u_char     old, val;
43270134Scg
43374711Scg	switch (mss->bd_id) {
43474711Scg		case MD_OPTI931:
43574711Scg			mix_d = &opti931_devices;
43674711Scg			break;
43774711Scg		case MD_OPTI930:
43874711Scg			mix_d = &opti930_devices;
43974711Scg			break;
44074711Scg		default:
44174711Scg			mix_d = &mix_devices;
44274711Scg	}
44374711Scg
44470134Scg    	if ((*mix_d)[dev][LEFT_CHN].nbits == 0) {
44570134Scg		DEB(printf("nbits = 0 for dev %d\n", dev));
44670134Scg		return -1;
44770134Scg    	}
44870134Scg
44970134Scg    	if ((*mix_d)[dev][RIGHT_CHN].nbits == 0) right = left; /* mono */
45070134Scg
45170134Scg    	/* Set the left channel */
45270134Scg
45370134Scg    	regoffs = (*mix_d)[dev][LEFT_CHN].regno;
45470134Scg    	old = val = ad_read(mss, regoffs);
45570134Scg    	/* if volume is 0, mute chan. Otherwise, unmute. */
45670134Scg    	if (regoffs != 0) val = (left == 0)? old | 0x80 : old & 0x7f;
45770134Scg    	change_bits(mix_d, &val, dev, LEFT_CHN, left);
45870134Scg    	ad_write(mss, regoffs, val);
45970134Scg
46070134Scg    	DEB(printf("LEFT: dev %d reg %d old 0x%02x new 0x%02x\n",
46170134Scg		dev, regoffs, old, val));
46270134Scg
46370134Scg    	if ((*mix_d)[dev][RIGHT_CHN].nbits != 0) { /* have stereo */
46470134Scg		/* Set the right channel */
46570134Scg		regoffs = (*mix_d)[dev][RIGHT_CHN].regno;
46670134Scg		old = val = ad_read(mss, regoffs);
46770134Scg		if (regoffs != 1) val = (right == 0)? old | 0x80 : old & 0x7f;
46870134Scg		change_bits(mix_d, &val, dev, RIGHT_CHN, right);
46970134Scg		ad_write(mss, regoffs, val);
47070134Scg
47170134Scg		DEB(printf("RIGHT: dev %d reg %d old 0x%02x new 0x%02x\n",
47270134Scg	    	dev, regoffs, old, val));
47370134Scg    	}
47470134Scg    	return 0; /* success */
47570134Scg}
47670134Scg
47770134Scg/* -------------------------------------------------------------------- */
47870134Scg
47970134Scgstatic int
48074763Scgmssmix_init(struct snd_mixer *m)
48170134Scg{
48270134Scg	struct mss_info *mss = mix_getdevinfo(m);
48370134Scg
48470134Scg	mix_setdevs(m, MODE2_MIXER_DEVICES);
48570134Scg	mix_setrecdevs(m, MSS_REC_DEVICES);
48670134Scg	switch(mss->bd_id) {
48774711Scg	case MD_OPTI930:
48874711Scg		mix_setdevs(m, OPTI930_MIXER_DEVICES);
48974711Scg		break;
49074711Scg
49170134Scg	case MD_OPTI931:
49270134Scg		mix_setdevs(m, OPTI931_MIXER_DEVICES);
49374763Scg		mss_lock(mss);
49470134Scg		ad_write(mss, 20, 0x88);
49570134Scg		ad_write(mss, 21, 0x88);
49674763Scg		mss_unlock(mss);
49770134Scg		break;
49870134Scg
49970134Scg	case MD_AD1848:
50070134Scg		mix_setdevs(m, MODE1_MIXER_DEVICES);
50170134Scg		break;
50270134Scg
50370134Scg	case MD_GUSPNP:
50470134Scg	case MD_GUSMAX:
50570134Scg		/* this is only necessary in mode 3 ... */
50674763Scg		mss_lock(mss);
50770134Scg		ad_write(mss, 22, 0x88);
50870134Scg		ad_write(mss, 23, 0x88);
50974763Scg		mss_unlock(mss);
51070134Scg		break;
51170134Scg	}
51270134Scg	return 0;
51370134Scg}
51470134Scg
51570134Scgstatic int
51674763Scgmssmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
51770134Scg{
51870134Scg	struct mss_info *mss = mix_getdevinfo(m);
51970134Scg
52074763Scg	mss_lock(mss);
52170134Scg	mss_mixer_set(mss, dev, left, right);
52274763Scg	mss_unlock(mss);
52370134Scg
52470134Scg	return left | (right << 8);
52570134Scg}
52670134Scg
527193640Sariffstatic u_int32_t
52874763Scgmssmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
52970134Scg{
53070134Scg	struct mss_info *mss = mix_getdevinfo(m);
53170134Scg
53274763Scg	mss_lock(mss);
53370134Scg	src = mss_set_recsrc(mss, src);
53474763Scg	mss_unlock(mss);
53570134Scg	return src;
53670134Scg}
53770134Scg
53870134Scgstatic kobj_method_t mssmix_mixer_methods[] = {
53970134Scg    	KOBJMETHOD(mixer_init,		mssmix_init),
54070134Scg    	KOBJMETHOD(mixer_set,		mssmix_set),
54170134Scg    	KOBJMETHOD(mixer_setrecsrc,	mssmix_setrecsrc),
542193640Sariff	KOBJMETHOD_END
54370134Scg};
54470134ScgMIXER_DECLARE(mssmix_mixer);
54570134Scg
54670134Scg/* -------------------------------------------------------------------- */
54770134Scg
54870134Scgstatic int
54974763Scgymmix_init(struct snd_mixer *m)
55070134Scg{
55170134Scg	struct mss_info *mss = mix_getdevinfo(m);
55270134Scg
55370134Scg	mssmix_init(m);
55470134Scg	mix_setdevs(m, mix_getdevs(m) | SOUND_MASK_VOLUME | SOUND_MASK_MIC
55570134Scg				      | SOUND_MASK_BASS | SOUND_MASK_TREBLE);
55670134Scg	/* Set master volume */
55774763Scg	mss_lock(mss);
55870134Scg	conf_wr(mss, OPL3SAx_VOLUMEL, 7);
55970134Scg	conf_wr(mss, OPL3SAx_VOLUMER, 7);
56074763Scg	mss_unlock(mss);
56170134Scg
56270134Scg	return 0;
56370134Scg}
56470134Scg
56570134Scgstatic int
56674763Scgymmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
56770134Scg{
56870134Scg	struct mss_info *mss = mix_getdevinfo(m);
56970134Scg	int t, l, r;
57070134Scg
57174763Scg	mss_lock(mss);
57270134Scg	switch (dev) {
57370134Scg	case SOUND_MIXER_VOLUME:
57470134Scg		if (left) t = 15 - (left * 15) / 100;
57570134Scg		else t = 0x80; /* mute */
57670134Scg		conf_wr(mss, OPL3SAx_VOLUMEL, t);
57770134Scg		if (right) t = 15 - (right * 15) / 100;
57870134Scg		else t = 0x80; /* mute */
57970134Scg		conf_wr(mss, OPL3SAx_VOLUMER, t);
58070134Scg		break;
58170134Scg
58270134Scg	case SOUND_MIXER_MIC:
58370134Scg		t = left;
58470134Scg		if (left) t = 31 - (left * 31) / 100;
58570134Scg		else t = 0x80; /* mute */
58670134Scg		conf_wr(mss, OPL3SAx_MIC, t);
58770134Scg		break;
58870134Scg
58970134Scg	case SOUND_MIXER_BASS:
59070134Scg		l = (left * 7) / 100;
59170134Scg		r = (right * 7) / 100;
59270134Scg		t = (r << 4) | l;
59370134Scg		conf_wr(mss, OPL3SAx_BASS, t);
59470134Scg		break;
59570134Scg
59670134Scg	case SOUND_MIXER_TREBLE:
59770134Scg		l = (left * 7) / 100;
59870134Scg		r = (right * 7) / 100;
59970134Scg		t = (r << 4) | l;
60070134Scg		conf_wr(mss, OPL3SAx_TREBLE, t);
60170134Scg		break;
60270134Scg
60370134Scg	default:
60470134Scg		mss_mixer_set(mss, dev, left, right);
60570134Scg	}
60674763Scg	mss_unlock(mss);
60770134Scg
60870134Scg	return left | (right << 8);
60970134Scg}
61070134Scg
611193640Sariffstatic u_int32_t
61274763Scgymmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
61370134Scg{
61470134Scg	struct mss_info *mss = mix_getdevinfo(m);
61574763Scg	mss_lock(mss);
61670134Scg	src = mss_set_recsrc(mss, src);
61774763Scg	mss_unlock(mss);
61870134Scg	return src;
61970134Scg}
62070134Scg
62170134Scgstatic kobj_method_t ymmix_mixer_methods[] = {
62270134Scg    	KOBJMETHOD(mixer_init,		ymmix_init),
62370134Scg    	KOBJMETHOD(mixer_set,		ymmix_set),
62470134Scg    	KOBJMETHOD(mixer_setrecsrc,	ymmix_setrecsrc),
625193640Sariff	KOBJMETHOD_END
62670134Scg};
62770134ScgMIXER_DECLARE(ymmix_mixer);
62870134Scg
62970134Scg/* -------------------------------------------------------------------- */
63053553Stanimura/*
63153553Stanimura * XXX This might be better off in the gusc driver.
63253553Stanimura */
63353553Stanimurastatic void
63453553Stanimuragusmax_setup(struct mss_info *mss, device_t dev, struct resource *alt)
63553553Stanimura{
63653553Stanimura	static const unsigned char irq_bits[16] = {
63753553Stanimura		0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7
63853553Stanimura	};
63953553Stanimura	static const unsigned char dma_bits[8] = {
64053553Stanimura		0, 1, 0, 2, 0, 3, 4, 5
64153553Stanimura	};
64253553Stanimura	device_t parent = device_get_parent(dev);
64353553Stanimura	unsigned char irqctl, dmactl;
64453553Stanimura	int s;
64553553Stanimura
64653553Stanimura	s = splhigh();
64753553Stanimura
64853553Stanimura	port_wr(alt, 0x0f, 0x05);
64953553Stanimura	port_wr(alt, 0x00, 0x0c);
65053553Stanimura	port_wr(alt, 0x0b, 0x00);
65153553Stanimura
65253553Stanimura	port_wr(alt, 0x0f, 0x00);
65353553Stanimura
65453553Stanimura	irqctl = irq_bits[isa_get_irq(parent)];
65553553Stanimura	/* Share the IRQ with the MIDI driver.  */
65653553Stanimura	irqctl |= 0x40;
65753553Stanimura	dmactl = dma_bits[isa_get_drq(parent)];
65853553Stanimura	if (device_get_flags(parent) & DV_F_DUAL_DMA)
65953553Stanimura		dmactl |= dma_bits[device_get_flags(parent) & DV_F_DRQ_MASK]
66053553Stanimura		    << 3;
66153553Stanimura
66253553Stanimura	/*
66353553Stanimura	 * Set the DMA and IRQ control latches.
66453553Stanimura	 */
66553553Stanimura	port_wr(alt, 0x00, 0x0c);
66653553Stanimura	port_wr(alt, 0x0b, dmactl | 0x80);
66753553Stanimura	port_wr(alt, 0x00, 0x4c);
66853553Stanimura	port_wr(alt, 0x0b, irqctl);
66953553Stanimura
67053553Stanimura	port_wr(alt, 0x00, 0x0c);
67153553Stanimura	port_wr(alt, 0x0b, dmactl);
67253553Stanimura	port_wr(alt, 0x00, 0x4c);
67353553Stanimura	port_wr(alt, 0x0b, irqctl);
67453553Stanimura
67553553Stanimura	port_wr(mss->conf_base, 2, 0);
67653553Stanimura	port_wr(alt, 0x00, 0x0c);
67753553Stanimura	port_wr(mss->conf_base, 2, 0);
67853553Stanimura
67953553Stanimura	splx(s);
68053553Stanimura}
68153553Stanimura
68250723Scgstatic int
68350723Scgmss_init(struct mss_info *mss, device_t dev)
68450723Scg{
68551766Scg       	u_char r6, r9;
68651766Scg	struct resource *alt;
68751766Scg	int rid, tmp;
68851766Scg
68950723Scg	mss->bd_flags |= BD_F_MCE_BIT;
69050723Scg	switch(mss->bd_id) {
69150723Scg	case MD_OPTI931:
69252169Sdfr		/*
69352169Sdfr		 * The MED3931 v.1.0 allocates 3 bytes for the config
69452169Sdfr		 * space, whereas v.2.0 allocates 4 bytes. What I know
69552169Sdfr		 * for sure is that the upper two ports must be used,
69652169Sdfr		 * and they should end on a boundary of 4 bytes. So I
69752169Sdfr		 * need the following trick.
69852169Sdfr		 */
69952169Sdfr		mss->opti_offset =
70052169Sdfr			(rman_get_start(mss->conf_base) & ~3) + 2
70152169Sdfr			- rman_get_start(mss->conf_base);
70254165Scg		BVDDB(printf("mss_init: opti_offset=%d\n", mss->opti_offset));
70352169Sdfr    		opti_wr(mss, 4, 0xd6); /* fifo empty, OPL3, audio enable, SB3.2 */
70450723Scg    		ad_write(mss, 10, 2); /* enable interrupts */
70552169Sdfr    		opti_wr(mss, 6, 2);  /* MCIR6: mss enable, sb disable */
70652169Sdfr    		opti_wr(mss, 5, 0x28);  /* MCIR5: codec in exp. mode,fifo */
70750723Scg		break;
70850723Scg
70950723Scg	case MD_GUSPNP:
71053553Stanimura	case MD_GUSMAX:
71150723Scg		gus_wr(mss, 0x4c /* _URSTI */, 0);/* Pull reset */
71250723Scg    		DELAY(1000 * 30);
71350723Scg    		/* release reset  and enable DAC */
71450723Scg    		gus_wr(mss, 0x4c /* _URSTI */, 3);
71550723Scg    		DELAY(1000 * 30);
71650723Scg    		/* end of reset */
71750723Scg
71850723Scg		rid = 0;
719127135Snjl    		alt = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
720127135Snjl					     RF_ACTIVE);
72153553Stanimura		if (alt == NULL) {
72253553Stanimura			printf("XXX couldn't init GUS PnP/MAX\n");
72353553Stanimura			break;
72453553Stanimura		}
72550723Scg    		port_wr(alt, 0, 0xC); /* enable int and dma */
72653553Stanimura		if (mss->bd_id == MD_GUSMAX)
72753553Stanimura			gusmax_setup(mss, dev, alt);
72850723Scg		bus_release_resource(dev, SYS_RES_IOPORT, rid, alt);
72950723Scg
73050723Scg    		/*
73150723Scg     		 * unmute left & right line. Need to go in mode3, unmute,
73250723Scg     		 * and back to mode 2
73350723Scg     		 */
73450723Scg    		tmp = ad_read(mss, 0x0c);
73550723Scg    		ad_write(mss, 0x0c, 0x6c); /* special value to enter mode 3 */
73650723Scg    		ad_write(mss, 0x19, 0); /* unmute left */
73750723Scg    		ad_write(mss, 0x1b, 0); /* unmute right */
73850723Scg    		ad_write(mss, 0x0c, tmp); /* restore old mode */
73950723Scg
74050723Scg    		/* send codec interrupts on irq1 and only use that one */
74150723Scg    		gus_wr(mss, 0x5a, 0x4f);
74250723Scg
74350723Scg    		/* enable access to hidden regs */
74450723Scg    		tmp = gus_rd(mss, 0x5b /* IVERI */);
74550723Scg    		gus_wr(mss, 0x5b, tmp | 1);
74650723Scg    		BVDDB(printf("GUS: silicon rev %c\n", 'A' + ((tmp & 0xf) >> 4)));
74750723Scg		break;
74853553Stanimura
74950723Scg    	case MD_YM0020:
75051766Scg         	conf_wr(mss, OPL3SAx_DMACONF, 0xa9); /* dma-b rec, dma-a play */
75150723Scg        	r6 = conf_rd(mss, OPL3SAx_DMACONF);
75250723Scg        	r9 = conf_rd(mss, OPL3SAx_MISC); /* version */
75350723Scg        	BVDDB(printf("Yamaha: ver 0x%x DMA config 0x%x\n", r6, r9);)
75450723Scg		/* yamaha - set volume to max */
75550723Scg		conf_wr(mss, OPL3SAx_VOLUMEL, 0);
75650723Scg		conf_wr(mss, OPL3SAx_VOLUMER, 0);
75750723Scg		conf_wr(mss, OPL3SAx_DMACONF, FULL_DUPLEX(mss)? 0xa9 : 0x8b);
75850723Scg		break;
75951766Scg 	}
76050723Scg    	if (FULL_DUPLEX(mss) && mss->bd_id != MD_OPTI931)
76150723Scg    		ad_write(mss, 12, ad_read(mss, 12) | 0x40); /* mode 2 */
76257770Scg	ad_enter_MCE(mss);
76350723Scg    	ad_write(mss, 9, FULL_DUPLEX(mss)? 0 : 4);
76457770Scg    	ad_leave_MCE(mss);
76557770Scg	ad_write(mss, 10, 2); /* int enable */
76650723Scg    	io_wr(mss, MSS_STATUS, 0); /* Clear interrupt status */
76750723Scg    	/* the following seem required on the CS4232 */
76850723Scg    	ad_unmute(mss);
76950723Scg	return 0;
77050723Scg}
77150723Scg
77270134Scg
77329415Sjmg/*
77470134Scg * main irq handler for the CS423x. The OPTi931 code is
77570134Scg * a separate one.
77670134Scg * The correct way to operate for a device with multiple internal
77770134Scg * interrupt sources is to loop on the status register and ack
77870134Scg * interrupts until all interrupts are served and none are reported. At
77970134Scg * this point the IRQ line to the ISA IRQ controller should go low
78070134Scg * and be raised at the next interrupt.
78170134Scg *
78270134Scg * Since the ISA IRQ controller is sent EOI _before_ passing control
78370134Scg * to the isr, it might happen that we serve an interrupt early, in
78470134Scg * which case the status register at the next interrupt should just
78570134Scg * say that there are no more interrupts...
78670134Scg */
78770134Scg
78870134Scgstatic void
78970134Scgmss_intr(void *arg)
79070134Scg{
79170134Scg    	struct mss_info *mss = arg;
79270134Scg    	u_char c = 0, served = 0;
79370134Scg    	int i;
79470134Scg
79570134Scg    	DEB(printf("mss_intr\n"));
79674763Scg	mss_lock(mss);
79770134Scg    	ad_read(mss, 11); /* fake read of status bits */
79870134Scg
79970134Scg    	/* loop until there are interrupts, but no more than 10 times. */
80070134Scg    	for (i = 10; i > 0 && io_rd(mss, MSS_STATUS) & 1; i--) {
80170134Scg		/* get exact reason for full-duplex boards */
80270134Scg		c = FULL_DUPLEX(mss)? ad_read(mss, 24) : 0x30;
80370134Scg		c &= ~served;
80470291Scg		if (sndbuf_runsz(mss->pch.buffer) && (c & 0x10)) {
80570134Scg	    		served |= 0x10;
806148598Snetchild			mss_unlock(mss);
80770134Scg	    		chn_intr(mss->pch.channel);
808148598Snetchild			mss_lock(mss);
80970134Scg		}
81070291Scg		if (sndbuf_runsz(mss->rch.buffer) && (c & 0x20)) {
81170134Scg	    		served |= 0x20;
812148598Snetchild			mss_unlock(mss);
81370134Scg	    		chn_intr(mss->rch.channel);
814152150Sariff			mss_lock(mss);
81570134Scg		}
81670134Scg		/* now ack the interrupt */
81770134Scg		if (FULL_DUPLEX(mss)) ad_write(mss, 24, ~c); /* ack selectively */
81870134Scg		else io_wr(mss, MSS_STATUS, 0);	/* Clear interrupt status */
81970134Scg    	}
82070134Scg    	if (i == 10) {
82170134Scg		BVDDB(printf("mss_intr: irq, but not from mss\n"));
82270134Scg	} else if (served == 0) {
82370134Scg		BVDDB(printf("mss_intr: unexpected irq with reason %x\n", c));
82470134Scg		/*
82570134Scg	 	* this should not happen... I have no idea what to do now.
82670134Scg	 	* maybe should do a sanity check and restart dmas ?
82770134Scg	 	*/
82870134Scg		io_wr(mss, MSS_STATUS, 0);	/* Clear interrupt status */
82970134Scg    	}
83074763Scg	mss_unlock(mss);
83170134Scg}
83270134Scg
83370134Scg/*
83470134Scg * AD_WAIT_INIT waits if we are initializing the board and
83570134Scg * we cannot modify its settings
83670134Scg */
83770134Scgstatic int
83870134Scgad_wait_init(struct mss_info *mss, int x)
83970134Scg{
84070134Scg    	int arg = x, n = 0; /* to shut up the compiler... */
84170134Scg    	for (; x > 0; x--)
84288384Spb		if ((n = io_rd(mss, MSS_INDEX)) & MSS_IDXBUSY) DELAY(10);
84370134Scg		else return n;
84470134Scg    	printf("AD_WAIT_INIT FAILED %d 0x%02x\n", arg, n);
84570134Scg    	return n;
84670134Scg}
84770134Scg
84870134Scgstatic int
84970134Scgad_read(struct mss_info *mss, int reg)
85070134Scg{
85170134Scg    	int             x;
85270134Scg
85373775Scg    	ad_wait_init(mss, 201000);
85470134Scg    	x = io_rd(mss, MSS_INDEX) & ~MSS_IDXMASK;
85570134Scg    	io_wr(mss, MSS_INDEX, (u_char)(reg & MSS_IDXMASK) | x);
85670134Scg    	x = io_rd(mss, MSS_IDATA);
85770134Scg	/* printf("ad_read %d, %x\n", reg, x); */
85870134Scg    	return x;
85970134Scg}
86070134Scg
86170134Scgstatic void
86270134Scgad_write(struct mss_info *mss, int reg, u_char data)
86370134Scg{
86474763Scg    	int x;
86570134Scg
86670134Scg	/* printf("ad_write %d, %x\n", reg, data); */
86773775Scg    	ad_wait_init(mss, 1002000);
86870134Scg    	x = io_rd(mss, MSS_INDEX) & ~MSS_IDXMASK;
86970134Scg    	io_wr(mss, MSS_INDEX, (u_char)(reg & MSS_IDXMASK) | x);
87070134Scg    	io_wr(mss, MSS_IDATA, data);
87170134Scg}
87270134Scg
87370134Scgstatic void
87470134Scgad_write_cnt(struct mss_info *mss, int reg, u_short cnt)
87570134Scg{
87670134Scg    	ad_write(mss, reg+1, cnt & 0xff);
87770134Scg    	ad_write(mss, reg, cnt >> 8); /* upper base must be last */
87870134Scg}
87970134Scg
88070134Scgstatic void
88170134Scgwait_for_calibration(struct mss_info *mss)
88270134Scg{
88370134Scg    	int t;
88470134Scg
88570134Scg    	/*
88670134Scg     	 * Wait until the auto calibration process has finished.
88770134Scg     	 *
88870134Scg     	 * 1) Wait until the chip becomes ready (reads don't return 0x80).
88970134Scg     	 * 2) Wait until the ACI bit of I11 gets on
89070134Scg     	 * 3) Wait until the ACI bit of I11 gets off
89170134Scg     	 */
89270134Scg
89373775Scg    	t = ad_wait_init(mss, 1000000);
89470134Scg    	if (t & MSS_IDXBUSY) printf("mss: Auto calibration timed out(1).\n");
89570134Scg
89670134Scg	/*
89770134Scg	 * The calibration mode for chips that support it is set so that
89870134Scg	 * we never see ACI go on.
89970134Scg	 */
90070134Scg	if (mss->bd_id == MD_GUSMAX || mss->bd_id == MD_GUSPNP) {
90170134Scg		for (t = 100; t > 0 && (ad_read(mss, 11) & 0x20) == 0; t--);
90270134Scg	} else {
90370134Scg       		/*
90470134Scg		 * XXX This should only be enabled for cards that *really*
90570134Scg		 * need it.  Are there any?
90670134Scg		 */
90770134Scg  		for (t = 100; t > 0 && (ad_read(mss, 11) & 0x20) == 0; t--) DELAY(100);
90870134Scg	}
90970134Scg    	for (t = 100; t > 0 && ad_read(mss, 11) & 0x20; t--) DELAY(100);
91070134Scg}
91170134Scg
91270134Scgstatic void
91370134Scgad_unmute(struct mss_info *mss)
91470134Scg{
91570134Scg    	ad_write(mss, 6, ad_read(mss, 6) & ~I6_MUTE);
91670134Scg    	ad_write(mss, 7, ad_read(mss, 7) & ~I6_MUTE);
91770134Scg}
91870134Scg
91970134Scgstatic void
92070134Scgad_enter_MCE(struct mss_info *mss)
92170134Scg{
92270134Scg    	int prev;
92370134Scg
92470134Scg    	mss->bd_flags |= BD_F_MCE_BIT;
92573775Scg    	ad_wait_init(mss, 203000);
92670134Scg    	prev = io_rd(mss, MSS_INDEX);
92770134Scg    	prev &= ~MSS_TRD;
92870134Scg    	io_wr(mss, MSS_INDEX, prev | MSS_MCE);
92970134Scg}
93070134Scg
93170134Scgstatic void
93270134Scgad_leave_MCE(struct mss_info *mss)
93370134Scg{
93470134Scg    	u_char   prev;
93570134Scg
93670134Scg    	if ((mss->bd_flags & BD_F_MCE_BIT) == 0) {
93770134Scg		DEB(printf("--- hey, leave_MCE: MCE bit was not set!\n"));
93870134Scg		return;
93970134Scg    	}
94070134Scg
94173775Scg    	ad_wait_init(mss, 1000000);
94270134Scg
94370134Scg    	mss->bd_flags &= ~BD_F_MCE_BIT;
94470134Scg
94570134Scg    	prev = io_rd(mss, MSS_INDEX);
94670134Scg    	prev &= ~MSS_TRD;
94770134Scg    	io_wr(mss, MSS_INDEX, prev & ~MSS_MCE); /* Clear the MCE bit */
94870134Scg    	wait_for_calibration(mss);
94970134Scg}
95070134Scg
95170134Scgstatic int
95270134Scgmss_speed(struct mss_chinfo *ch, int speed)
95370134Scg{
95470134Scg    	struct mss_info *mss = ch->parent;
95570134Scg    	/*
95670134Scg     	* In the CS4231, the low 4 bits of I8 are used to hold the
95770134Scg     	* sample rate.  Only a fixed number of values is allowed. This
95870134Scg     	* table lists them. The speed-setting routines scans the table
95970134Scg     	* looking for the closest match. This is the only supported method.
96070134Scg     	*
96170134Scg     	* In the CS4236, there is an alternate metod (which we do not
96270134Scg     	* support yet) which provides almost arbitrary frequency setting.
96370134Scg     	* In the AD1845, it looks like the sample rate can be
96470134Scg     	* almost arbitrary, and written directly to a register.
96570134Scg     	* In the OPTi931, there is a SB command which provides for
96670134Scg     	* almost arbitrary frequency setting.
96770134Scg     	*
96870134Scg     	*/
96970134Scg    	ad_enter_MCE(mss);
97070134Scg    	if (mss->bd_id == MD_AD1845) { /* Use alternate speed select regs */
97170134Scg		ad_write(mss, 22, (speed >> 8) & 0xff);	/* Speed MSB */
97270134Scg		ad_write(mss, 23, speed & 0xff);	/* Speed LSB */
97370134Scg		/* XXX must also do something in I27 for the ad1845 */
97470134Scg    	} else {
97570134Scg        	int i, sel = 0; /* assume entry 0 does not contain -1 */
97670134Scg        	static int speeds[] =
97770134Scg      	    	{8000, 5512, 16000, 11025, 27429, 18900, 32000, 22050,
97870134Scg	    	-1, 37800, -1, 44100, 48000, 33075, 9600, 6615};
97970134Scg
98070134Scg        	for (i = 1; i < 16; i++)
98170134Scg   		    	if (speeds[i] > 0 &&
98270134Scg			    abs(speed-speeds[i]) < abs(speed-speeds[sel])) sel = i;
98370134Scg        	speed = speeds[sel];
98470134Scg        	ad_write(mss, 8, (ad_read(mss, 8) & 0xf0) | sel);
985149987Snetchild		ad_wait_init(mss, 10000);
98670134Scg    	}
98770134Scg    	ad_leave_MCE(mss);
98870134Scg
98970134Scg    	return speed;
99070134Scg}
99170134Scg
99270134Scg/*
99370134Scg * mss_format checks that the format is supported (or defaults to AFMT_U8)
99470134Scg * and returns the bit setting for the 1848 register corresponding to
99570134Scg * the desired format.
99670134Scg *
99770134Scg * fixed lr970724
99870134Scg */
99970134Scg
100070134Scgstatic int
100170134Scgmss_format(struct mss_chinfo *ch, u_int32_t format)
100270134Scg{
100370134Scg    	struct mss_info *mss = ch->parent;
1004193640Sariff    	int i, arg = AFMT_ENCODING(format);
100570134Scg
100670134Scg    	/*
100770134Scg     	* The data format uses 3 bits (just 2 on the 1848). For each
100870134Scg     	* bit setting, the following array returns the corresponding format.
100970134Scg     	* The code scans the array looking for a suitable format. In
101070134Scg     	* case it is not found, default to AFMT_U8 (not such a good
101170134Scg     	* choice, but let's do it for compatibility...).
101270134Scg     	*/
101370134Scg
101470134Scg    	static int fmts[] =
101570134Scg        	{AFMT_U8, AFMT_MU_LAW, AFMT_S16_LE, AFMT_A_LAW,
101670134Scg		-1, AFMT_IMA_ADPCM, AFMT_U16_BE, -1};
101770134Scg
101870134Scg	ch->fmt = format;
101970134Scg    	for (i = 0; i < 8; i++) if (arg == fmts[i]) break;
102070134Scg    	arg = i << 1;
1021193640Sariff    	if (AFMT_CHANNEL(format) > 1) arg |= 1;
102270134Scg    	arg <<= 4;
102370134Scg    	ad_enter_MCE(mss);
102470134Scg    	ad_write(mss, 8, (ad_read(mss, 8) & 0x0f) | arg);
1025149987Snetchild	ad_wait_init(mss, 10000);
1026149987Snetchild    	if (ad_read(mss, 12) & 0x40) {	/* mode2? */
1027149986Snetchild		ad_write(mss, 28, arg); /* capture mode */
1028149987Snetchild		ad_wait_init(mss, 10000);
1029149987Snetchild	}
103070134Scg    	ad_leave_MCE(mss);
103170134Scg    	return format;
103270134Scg}
103370134Scg
103470134Scgstatic int
103570134Scgmss_trigger(struct mss_chinfo *ch, int go)
103670134Scg{
103770134Scg    	struct mss_info *mss = ch->parent;
103870134Scg    	u_char m;
103970134Scg    	int retry, wr, cnt, ss;
104070134Scg
104170134Scg	ss = 1;
1042193640Sariff	ss <<= (AFMT_CHANNEL(ch->fmt) > 1)? 1 : 0;
104370134Scg	ss <<= (ch->fmt & AFMT_16BIT)? 1 : 0;
104470134Scg
104570134Scg	wr = (ch->dir == PCMDIR_PLAY)? 1 : 0;
104670134Scg    	m = ad_read(mss, 9);
104770134Scg    	switch (go) {
104870134Scg    	case PCMTRIG_START:
104970291Scg		cnt = (ch->blksz / ss) - 1;
105070134Scg
105170134Scg		DEB(if (m & 4) printf("OUCH! reg 9 0x%02x\n", m););
105270134Scg		m |= wr? I9_PEN : I9_CEN; /* enable DMA */
105370134Scg		ad_write_cnt(mss, (wr || !FULL_DUPLEX(mss))? 14 : 30, cnt);
105470134Scg		break;
105570134Scg
105670134Scg    	case PCMTRIG_STOP:
105770134Scg    	case PCMTRIG_ABORT: /* XXX check this... */
105870134Scg		m &= ~(wr? I9_PEN : I9_CEN); /* Stop DMA */
105970134Scg#if 0
106070134Scg		/*
106170134Scg	 	* try to disable DMA by clearing count registers. Not sure it
106270134Scg	 	* is needed, and it might cause false interrupts when the
106370134Scg	 	* DMA is re-enabled later.
106470134Scg	 	*/
106570134Scg		ad_write_cnt(mss, (wr || !FULL_DUPLEX(mss))? 14 : 30, 0);
106670134Scg#endif
106770134Scg    	}
106870134Scg    	/* on the OPTi931 the enable bit seems hard to set... */
106970134Scg    	for (retry = 10; retry > 0; retry--) {
107070134Scg        	ad_write(mss, 9, m);
107170134Scg        	if (ad_read(mss, 9) == m) break;
107270134Scg    	}
107370134Scg    	if (retry == 0) BVDDB(printf("stop dma, failed to set bit 0x%02x 0x%02x\n", \
107470134Scg			       m, ad_read(mss, 9)));
107570134Scg    	return 0;
107670134Scg}
107770134Scg
107870134Scg
107970134Scg/*
108070134Scg * the opti931 seems to miss interrupts when working in full
108170134Scg * duplex, so we try some heuristics to catch them.
108270134Scg */
108370134Scgstatic void
108470134Scgopti931_intr(void *arg)
108570134Scg{
108670134Scg    	struct mss_info *mss = (struct mss_info *)arg;
108770134Scg    	u_char masked = 0, i11, mc11, c = 0;
108870134Scg    	u_char reason; /* b0 = playback, b1 = capture, b2 = timer */
108970134Scg    	int loops = 10;
109070134Scg
109170134Scg#if 0
109270134Scg    	reason = io_rd(mss, MSS_STATUS);
109370134Scg    	if (!(reason & 1)) {/* no int, maybe a shared line ? */
109470134Scg		DEB(printf("intr: flag 0, mcir11 0x%02x\n", ad_read(mss, 11)));
109570134Scg		return;
109670134Scg    	}
109770134Scg#endif
109874763Scg	mss_lock(mss);
109970134Scg    	i11 = ad_read(mss, 11); /* XXX what's for ? */
110070134Scg	again:
110170134Scg
110270134Scg    	c = mc11 = FULL_DUPLEX(mss)? opti_rd(mss, 11) : 0xc;
110370134Scg    	mc11 &= 0x0c;
110470134Scg    	if (c & 0x10) {
110570134Scg		DEB(printf("Warning: CD interrupt\n");)
110670134Scg		mc11 |= 0x10;
110770134Scg    	}
110870134Scg    	if (c & 0x20) {
110970134Scg		DEB(printf("Warning: MPU interrupt\n");)
111070134Scg		mc11 |= 0x20;
111170134Scg    	}
111270134Scg    	if (mc11 & masked) BVDDB(printf("irq reset failed, mc11 0x%02x, 0x%02x\n",\
111370134Scg                              	  mc11, masked));
111470134Scg    	masked |= mc11;
111570134Scg    	/*
111670134Scg     	* the nice OPTi931 sets the IRQ line before setting the bits in
111770134Scg     	* mc11. So, on some occasions I have to retry (max 10 times).
111870134Scg     	*/
111970134Scg    	if (mc11 == 0) { /* perhaps can return ... */
112070134Scg		reason = io_rd(mss, MSS_STATUS);
112170134Scg		if (reason & 1) {
112270134Scg	    		DEB(printf("one more try...\n");)
112370134Scg	    		if (--loops) goto again;
1124131918Smarcel	    		else BVDDB(printf("intr, but mc11 not set\n");)
112570134Scg		}
112670134Scg		if (loops == 0) BVDDB(printf("intr, nothing in mcir11 0x%02x\n", mc11));
112774763Scg		mss_unlock(mss);
112870134Scg		return;
112970134Scg    	}
113070134Scg
1131148598Snetchild    	if (sndbuf_runsz(mss->rch.buffer) && (mc11 & 8)) {
1132148598Snetchild		mss_unlock(mss);
1133148598Snetchild		chn_intr(mss->rch.channel);
1134148598Snetchild		mss_lock(mss);
1135148598Snetchild	}
1136148598Snetchild    	if (sndbuf_runsz(mss->pch.buffer) && (mc11 & 4)) {
1137148598Snetchild		mss_unlock(mss);
1138148598Snetchild		chn_intr(mss->pch.channel);
1139148598Snetchild		mss_lock(mss);
1140148598Snetchild	}
114170134Scg    	opti_wr(mss, 11, ~mc11); /* ack */
114270134Scg    	if (--loops) goto again;
114374763Scg	mss_unlock(mss);
114470134Scg    	DEB(printf("xxx too many loops\n");)
114570134Scg}
114670134Scg
114770134Scg/* -------------------------------------------------------------------- */
114870134Scg/* channel interface */
114970134Scgstatic void *
115074763Scgmsschan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
115170134Scg{
115270134Scg	struct mss_info *mss = devinfo;
115370134Scg	struct mss_chinfo *ch = (dir == PCMDIR_PLAY)? &mss->pch : &mss->rch;
115470134Scg
115570134Scg	ch->parent = mss;
115670134Scg	ch->channel = c;
115770134Scg	ch->buffer = b;
115870134Scg	ch->dir = dir;
1159168847Sariff	if (sndbuf_alloc(ch->buffer, mss->parent_dmat, 0, mss->bufsize) != 0)
1160136469Syongari		return NULL;
1161110499Snyan	sndbuf_dmasetup(ch->buffer, (dir == PCMDIR_PLAY)? mss->drq1 : mss->drq2);
116270134Scg	return ch;
116370134Scg}
116470134Scg
116570134Scgstatic int
116670134Scgmsschan_setformat(kobj_t obj, void *data, u_int32_t format)
116770134Scg{
116870134Scg	struct mss_chinfo *ch = data;
116974763Scg	struct mss_info *mss = ch->parent;
117070134Scg
117174763Scg	mss_lock(mss);
117270134Scg	mss_format(ch, format);
117374763Scg	mss_unlock(mss);
117470134Scg	return 0;
117570134Scg}
117670134Scg
1177193640Sariffstatic u_int32_t
117870134Scgmsschan_setspeed(kobj_t obj, void *data, u_int32_t speed)
117970134Scg{
118070134Scg	struct mss_chinfo *ch = data;
118174763Scg	struct mss_info *mss = ch->parent;
1182193640Sariff	u_int32_t r;
118370134Scg
118474763Scg	mss_lock(mss);
118574763Scg	r = mss_speed(ch, speed);
118674763Scg	mss_unlock(mss);
118774763Scg
118874763Scg	return r;
118970134Scg}
119070134Scg
1191193640Sariffstatic u_int32_t
119270134Scgmsschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
119370134Scg{
119470291Scg	struct mss_chinfo *ch = data;
119570291Scg
119670291Scg	ch->blksz = blocksize;
119783621Scg	sndbuf_resize(ch->buffer, 2, ch->blksz);
119883621Scg
119970291Scg	return ch->blksz;
120070134Scg}
120170134Scg
120270134Scgstatic int
120370134Scgmsschan_trigger(kobj_t obj, void *data, int go)
120470134Scg{
120570134Scg	struct mss_chinfo *ch = data;
120674763Scg	struct mss_info *mss = ch->parent;
120770134Scg
1208170521Sariff	if (!PCMTRIG_COMMON(go))
120970134Scg		return 0;
121070134Scg
1211110499Snyan	sndbuf_dma(ch->buffer, go);
121274763Scg	mss_lock(mss);
121370134Scg	mss_trigger(ch, go);
121474763Scg	mss_unlock(mss);
121570134Scg	return 0;
121670134Scg}
121770134Scg
1218193640Sariffstatic u_int32_t
121970134Scgmsschan_getptr(kobj_t obj, void *data)
122070134Scg{
122170134Scg	struct mss_chinfo *ch = data;
1222110499Snyan	return sndbuf_dmaptr(ch->buffer);
122370134Scg}
122470134Scg
122574763Scgstatic struct pcmchan_caps *
122670134Scgmsschan_getcaps(kobj_t obj, void *data)
122770134Scg{
122870134Scg	struct mss_chinfo *ch = data;
122970134Scg
123070134Scg	switch(ch->parent->bd_id) {
123170134Scg	case MD_OPTI931:
123270134Scg		return &opti931_caps;
123370134Scg		break;
123470134Scg
123570134Scg	case MD_GUSPNP:
123670134Scg	case MD_GUSMAX:
123770134Scg		return &guspnp_caps;
123870134Scg		break;
123970134Scg
124070134Scg	default:
124170134Scg		return &mss_caps;
124270134Scg		break;
124370134Scg	}
124470134Scg}
124570134Scg
124670134Scgstatic kobj_method_t msschan_methods[] = {
124770134Scg    	KOBJMETHOD(channel_init,		msschan_init),
124870134Scg    	KOBJMETHOD(channel_setformat,		msschan_setformat),
124970134Scg    	KOBJMETHOD(channel_setspeed,		msschan_setspeed),
125070134Scg    	KOBJMETHOD(channel_setblocksize,	msschan_setblocksize),
125170134Scg    	KOBJMETHOD(channel_trigger,		msschan_trigger),
125270134Scg    	KOBJMETHOD(channel_getptr,		msschan_getptr),
125370134Scg    	KOBJMETHOD(channel_getcaps,		msschan_getcaps),
1254193640Sariff	KOBJMETHOD_END
125570134Scg};
125670134ScgCHANNEL_DECLARE(msschan);
125770134Scg
125870134Scg/* -------------------------------------------------------------------- */
125970134Scg
126070134Scg/*
126130869Sjmg * mss_probe() is the probe routine. Note, it is not necessary to
126229415Sjmg * go through this for PnP devices, since they are already
126329415Sjmg * indentified precisely using their PnP id.
126429415Sjmg *
126529415Sjmg * The base address supplied in the device refers to the old MSS
126629415Sjmg * specs where the four 4 registers in io space contain configuration
126729415Sjmg * information. Some boards (as an example, early MSS boards)
126829415Sjmg * has such a block of registers, whereas others (generally CS42xx)
126929415Sjmg * do not.  In order to distinguish between the two and do not have
127029415Sjmg * to supply two separate probe routines, the flags entry in isa_device
127129415Sjmg * has a bit to mark this.
127229415Sjmg *
127329415Sjmg */
127429415Sjmg
127529415Sjmgstatic int
127650723Scgmss_probe(device_t dev)
127729415Sjmg{
127850723Scg    	u_char tmp, tmpx;
127950723Scg    	int flags, irq, drq, result = ENXIO, setres = 0;
128050723Scg    	struct mss_info *mss;
128129415Sjmg
128262947Stanimura    	if (isa_get_logicalid(dev)) return ENXIO; /* not yet */
128329415Sjmg
128478564Sgreid    	mss = (struct mss_info *)malloc(sizeof *mss, M_DEVBUF, M_NOWAIT | M_ZERO);
128550723Scg    	if (!mss) return ENXIO;
128629415Sjmg
128750723Scg    	mss->io_rid = 0;
128850723Scg    	mss->conf_rid = -1;
128950723Scg    	mss->irq_rid = 0;
129050723Scg    	mss->drq1_rid = 0;
129150723Scg    	mss->drq2_rid = -1;
129250723Scg    	mss->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &mss->io_rid,
129350723Scg				      	0, ~0, 8, RF_ACTIVE);
129450723Scg    	if (!mss->io_base) {
129550723Scg        	BVDDB(printf("mss_probe: no address given, try 0x%x\n", 0x530));
129650723Scg		mss->io_rid = 0;
129750723Scg		/* XXX verify this */
129850723Scg		setres = 1;
129952174Sdfr		bus_set_resource(dev, SYS_RES_IOPORT, mss->io_rid,
130050723Scg    		         	0x530, 8);
130150723Scg		mss->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &mss->io_rid,
130250723Scg					  	0, ~0, 8, RF_ACTIVE);
130350723Scg    	}
130450723Scg    	if (!mss->io_base) goto no;
130550723Scg
130650723Scg    	/* got irq/dma regs? */
130751052Sdfr    	flags = device_get_flags(dev);
130850723Scg    	irq = isa_get_irq(dev);
130950723Scg    	drq = isa_get_drq(dev);
131050723Scg
131151052Sdfr    	if (!(device_get_flags(dev) & DV_F_TRUE_MSS)) goto mss_probe_end;
131250723Scg
131350723Scg    	/*
131450723Scg     	* Check if the IO port returns valid signature. The original MS
131550723Scg     	* Sound system returns 0x04 while some cards
131650723Scg     	* (AudioTriX Pro for example) return 0x00 or 0x0f.
131750723Scg     	*/
131850723Scg
131950723Scg    	device_set_desc(dev, "MSS");
132050723Scg    	tmpx = tmp = io_rd(mss, 3);
132150723Scg    	if (tmp == 0xff) {	/* Bus float */
132250723Scg		BVDDB(printf("I/O addr inactive (%x), try pseudo_mss\n", tmp));
132351052Sdfr		device_set_flags(dev, flags & ~DV_F_TRUE_MSS);
132450723Scg		goto mss_probe_end;
132550723Scg    	}
132650723Scg    	tmp &= 0x3f;
1327169744Sjoel    	if (!(tmp == 0x04 || tmp == 0x0f || tmp == 0x00 || tmp == 0x05)) {
132850723Scg		BVDDB(printf("No MSS signature detected on port 0x%lx (0x%x)\n",
132950723Scg		     	rman_get_start(mss->io_base), tmpx));
133050723Scg		goto no;
133150723Scg    	}
133260711Snyan#ifdef PC98
133360711Snyan    	if (irq > 12) {
133460711Snyan#else
133550723Scg    	if (irq > 11) {
133660711Snyan#endif
133750723Scg		printf("MSS: Bad IRQ %d\n", irq);
133850723Scg		goto no;
133950723Scg    	}
134050723Scg    	if (!(drq == 0 || drq == 1 || drq == 3)) {
134150723Scg		printf("MSS: Bad DMA %d\n", drq);
134250723Scg		goto no;
134350723Scg    	}
134450723Scg    	if (tmpx & 0x80) {
134550723Scg		/* 8-bit board: only drq1/3 and irq7/9 */
134650723Scg		if (drq == 0) {
134751766Scg		    	printf("MSS: Can't use DMA0 with a 8 bit card/slot\n");
134851766Scg		    	goto no;
134950723Scg		}
135050723Scg		if (!(irq == 7 || irq == 9)) {
135151766Scg		    	printf("MSS: Can't use IRQ%d with a 8 bit card/slot\n",
135251766Scg			       irq);
135351766Scg		    	goto no;
135450723Scg		}
135550723Scg    	}
135650723Scg	mss_probe_end:
135750723Scg    	result = mss_detect(dev, mss);
135850723Scg	no:
135950769Sdfr    	mss_release_resources(mss, dev);
136050769Sdfr#if 0
136150723Scg    	if (setres) ISA_DELETE_RESOURCE(device_get_parent(dev), dev,
136250723Scg    				    	SYS_RES_IOPORT, mss->io_rid); /* XXX ? */
136350769Sdfr#endif
136450723Scg    	return result;
136529415Sjmg}
136629415Sjmg
136742284Sluigistatic int
136850723Scgmss_detect(device_t dev, struct mss_info *mss)
136942284Sluigi{
137050723Scg    	int          i;
137154942Scg    	u_char       tmp = 0, tmp1, tmp2;
137250723Scg    	char        *name, *yamaha;
137342284Sluigi
137450723Scg    	if (mss->bd_id != 0) {
137550723Scg		device_printf(dev, "presel bd_id 0x%04x -- %s\n", mss->bd_id,
137650723Scg		      	device_get_desc(dev));
137750723Scg		return 0;
137850723Scg    	}
137942284Sluigi
138050723Scg    	name = "AD1848";
138150723Scg    	mss->bd_id = MD_AD1848; /* AD1848 or CS4248 */
138242284Sluigi
1383149981Snetchild#ifndef PC98
138474711Scg	if (opti_detect(dev, mss)) {
138574711Scg		switch (mss->bd_id) {
138674711Scg			case MD_OPTI924:
138774711Scg				name = "OPTi924";
138874711Scg				break;
138974711Scg			case MD_OPTI930:
139074711Scg				name = "OPTi930";
139174711Scg				break;
139274711Scg		}
139374711Scg		printf("Found OPTi device %s\n", name);
139474711Scg		if (opti_init(dev, mss) == 0) goto gotit;
139574711Scg	}
1396149981Snetchild#endif
139774711Scg
139874711Scg   	/*
139950723Scg     	* Check that the I/O address is in use.
140050723Scg     	*
140150723Scg     	* bit 7 of the base I/O port is known to be 0 after the chip has
140250723Scg     	* performed its power on initialization. Just assume this has
140350723Scg     	* happened before the OS is starting.
140450723Scg     	*
140550723Scg     	* If the I/O address is unused, it typically returns 0xff.
140650723Scg     	*/
140742284Sluigi
140850723Scg    	for (i = 0; i < 10; i++)
140950723Scg		if ((tmp = io_rd(mss, MSS_INDEX)) & MSS_IDXBUSY) DELAY(10000);
141050723Scg		else break;
141142284Sluigi
1412108533Sschweikh    	if (i >= 10) {	/* Not an AD1848 */
141350723Scg		BVDDB(printf("mss_detect, busy still set (0x%02x)\n", tmp));
141450723Scg		goto no;
141550723Scg    	}
141650723Scg    	/*
141750723Scg     	* Test if it's possible to change contents of the indirect
141850723Scg     	* registers. Registers 0 and 1 are ADC volume registers. The bit
141950723Scg     	* 0x10 is read only so try to avoid using it.
142050723Scg     	*/
142129415Sjmg
142250723Scg    	ad_write(mss, 0, 0xaa);
142350723Scg    	ad_write(mss, 1, 0x45);/* 0x55 with bit 0x10 clear */
142450723Scg    	tmp1 = ad_read(mss, 0);
142550723Scg    	tmp2 = ad_read(mss, 1);
142650723Scg    	if (tmp1 != 0xaa || tmp2 != 0x45) {
142750723Scg		BVDDB(printf("mss_detect error - IREG (%x/%x)\n", tmp1, tmp2));
142850723Scg		goto no;
142950723Scg    	}
143029415Sjmg
143150723Scg    	ad_write(mss, 0, 0x45);
143250723Scg    	ad_write(mss, 1, 0xaa);
143350723Scg    	tmp1 = ad_read(mss, 0);
143450723Scg    	tmp2 = ad_read(mss, 1);
143550723Scg    	if (tmp1 != 0x45 || tmp2 != 0xaa) {
143650723Scg		BVDDB(printf("mss_detect error - IREG2 (%x/%x)\n", tmp1, tmp2));
143750723Scg		goto no;
143850723Scg    	}
143929415Sjmg
144050723Scg    	/*
144150723Scg     	* The indirect register I12 has some read only bits. Lets try to
144250723Scg     	* change them.
144350723Scg     	*/
144450723Scg
144550723Scg    	tmp = ad_read(mss, 12);
144650723Scg    	ad_write(mss, 12, (~tmp) & 0x0f);
144750723Scg    	tmp1 = ad_read(mss, 12);
144850723Scg
144950723Scg    	if ((tmp & 0x0f) != (tmp1 & 0x0f)) {
145050723Scg		BVDDB(printf("mss_detect - I12 (0x%02x was 0x%02x)\n", tmp1, tmp));
145150723Scg		goto no;
145250723Scg    	}
145350723Scg
145450723Scg    	/*
145550723Scg     	* NOTE! Last 4 bits of the reg I12 tell the chip revision.
145650723Scg     	*	0x01=RevB
145750723Scg     	*  0x0A=RevC. also CS4231/CS4231A and OPTi931
145850723Scg     	*/
145950723Scg
146050723Scg    	BVDDB(printf("mss_detect - chip revision 0x%02x\n", tmp & 0x0f);)
146150723Scg
146250723Scg    	/*
146350723Scg     	* The original AD1848/CS4248 has just 16 indirect registers. This
146450723Scg     	* means that I0 and I16 should return the same value (etc.). Ensure
146550723Scg     	* that the Mode2 enable bit of I12 is 0. Otherwise this test fails
146650723Scg     	* with new parts.
146750723Scg     	*/
146850723Scg
146950723Scg    	ad_write(mss, 12, 0);	/* Mode2=disabled */
147050723Scg#if 0
147150723Scg    	for (i = 0; i < 16; i++) {
147250723Scg		if ((tmp1 = ad_read(mss, i)) != (tmp2 = ad_read(mss, i + 16))) {
147350723Scg	    	BVDDB(printf("mss_detect warning - I%d: 0x%02x/0x%02x\n",
147450723Scg			i, tmp1, tmp2));
147550723Scg	    	/*
147650723Scg	     	* note - this seems to fail on the 4232 on I11. So we just break
147750723Scg	     	* rather than fail.  (which makes this test pointless - cg)
147850723Scg	     	*/
147950723Scg	    	break; /* return 0; */
148050723Scg		}
148150723Scg    	}
148242292Sluigi#endif
148350723Scg    	/*
148450723Scg     	* Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit
148550723Scg     	* (0x40). The bit 0x80 is always 1 in CS4248 and CS4231.
148650723Scg     	*
148750723Scg     	* On the OPTi931, however, I12 is readonly and only contains the
148850723Scg     	* chip revision ID (as in the CS4231A). The upper bits return 0.
148950723Scg     	*/
149030869Sjmg
149150723Scg    	ad_write(mss, 12, 0x40);	/* Set mode2, clear 0x80 */
149229415Sjmg
149350723Scg    	tmp1 = ad_read(mss, 12);
149450723Scg    	if (tmp1 & 0x80) name = "CS4248"; /* Our best knowledge just now */
149550723Scg    	if ((tmp1 & 0xf0) == 0x00) {
149650723Scg		BVDDB(printf("this should be an OPTi931\n");)
149750723Scg    	} else if ((tmp1 & 0xc0) != 0xC0) goto gotit;
149850723Scg	/*
149950723Scg	* The 4231 has bit7=1 always, and bit6 we just set to 1.
150050723Scg	* We want to check that this is really a CS4231
150150723Scg	* Verify that setting I0 doesn't change I16.
150250723Scg	*/
150350723Scg	ad_write(mss, 16, 0);	/* Set I16 to known value */
150450723Scg	ad_write(mss, 0, 0x45);
150550723Scg	if ((tmp1 = ad_read(mss, 16)) == 0x45) goto gotit;
150650723Scg
150750723Scg	ad_write(mss, 0, 0xaa);
150850723Scg       	if ((tmp1 = ad_read(mss, 16)) == 0xaa) {	/* Rotten bits? */
150950723Scg       		BVDDB(printf("mss_detect error - step H(%x)\n", tmp1));
151050723Scg		goto no;
151129415Sjmg	}
151250723Scg	/* Verify that some bits of I25 are read only. */
151350723Scg	tmp1 = ad_read(mss, 25);	/* Original bits */
151450723Scg	ad_write(mss, 25, ~tmp1);	/* Invert all bits */
151550723Scg	if ((ad_read(mss, 25) & 0xe7) == (tmp1 & 0xe7)) {
151650723Scg		int id;
151729415Sjmg
151850723Scg		/* It's at least CS4231 */
151950723Scg		name = "CS4231";
152054962Speter		mss->bd_id = MD_CS42XX;
152129415Sjmg
152250723Scg		/*
152350723Scg		* It could be an AD1845 or CS4231A as well.
152450723Scg		* CS4231 and AD1845 report the same revision info in I25
152550723Scg		* while the CS4231A reports different.
152650723Scg		*/
152729415Sjmg
152850723Scg		id = ad_read(mss, 25) & 0xe7;
152950723Scg		/*
153050723Scg		* b7-b5 = version number;
153150723Scg		*	100 : all CS4231
153250723Scg		*	101 : CS4231A
153350723Scg		*
153450723Scg		* b2-b0 = chip id;
153550723Scg		*/
153650723Scg		switch (id) {
153729415Sjmg
153850723Scg		case 0xa0:
153950723Scg			name = "CS4231A";
154054962Speter			mss->bd_id = MD_CS42XX;
154150723Scg		break;
154229415Sjmg
154350723Scg		case 0xa2:
154450723Scg			name = "CS4232";
154554962Speter			mss->bd_id = MD_CS42XX;
154650723Scg		break;
154729415Sjmg
154850723Scg		case 0xb2:
154950723Scg		/* strange: the 4231 data sheet says b4-b3 are XX
155050723Scg		* so this should be the same as 0xa2
155150723Scg		*/
155250723Scg			name = "CS4232A";
155354962Speter			mss->bd_id = MD_CS42XX;
155450723Scg		break;
155529415Sjmg
155650723Scg		case 0x80:
155750723Scg			/*
155850723Scg			* It must be a CS4231 or AD1845. The register I23
155950723Scg			* of CS4231 is undefined and it appears to be read
156050723Scg			* only. AD1845 uses I23 for setting sample rate.
156150723Scg			* Assume the chip is AD1845 if I23 is changeable.
156250723Scg			*/
156331361Sjmg
156450723Scg			tmp = ad_read(mss, 23);
156529415Sjmg
156650723Scg			ad_write(mss, 23, ~tmp);
156750723Scg			if (ad_read(mss, 23) != tmp) {	/* AD1845 ? */
156850723Scg				name = "AD1845";
156950723Scg				mss->bd_id = MD_AD1845;
157050723Scg			}
157150723Scg			ad_write(mss, 23, tmp);	/* Restore */
157250723Scg
157350723Scg			yamaha = ymf_test(dev, mss);
157450723Scg			if (yamaha) {
157550723Scg				mss->bd_id = MD_YM0020;
157650723Scg				name = yamaha;
157750723Scg			}
157850723Scg			break;
157950723Scg
158050723Scg		case 0x83:	/* CS4236 */
158150723Scg		case 0x03:      /* CS4236 on Intel PR440FX motherboard XXX */
158250723Scg			name = "CS4236";
158354962Speter			mss->bd_id = MD_CS42XX;
158450723Scg			break;
158550723Scg
158650723Scg		default:	/* Assume CS4231 */
158750723Scg	 		BVDDB(printf("unknown id 0x%02x, assuming CS4231\n", id);)
158854962Speter			mss->bd_id = MD_CS42XX;
158950723Scg		}
159029415Sjmg	}
159150723Scg	ad_write(mss, 25, tmp1);	/* Restore bits */
159250723Scggotit:
159350723Scg    	BVDDB(printf("mss_detect() - Detected %s\n", name));
159450723Scg    	device_set_desc(dev, name);
159551052Sdfr    	device_set_flags(dev,
159651052Sdfr			 ((device_get_flags(dev) & ~DV_F_DEV_MASK) |
159751052Sdfr			  ((mss->bd_id << DV_F_DEV_SHIFT) & DV_F_DEV_MASK)));
159850723Scg    	return 0;
159950723Scgno:
160050723Scg    	return ENXIO;
160129415Sjmg}
160229415Sjmg
1603150014Simp#ifndef PC98
160474711Scgstatic int
160574711Scgopti_detect(device_t dev, struct mss_info *mss)
160674711Scg{
160774711Scg	int c;
160874711Scg	static const struct opticard {
160974711Scg		int boardid;
161074711Scg		int passwdreg;
161174711Scg		int password;
161274711Scg		int base;
161374711Scg		int indir_reg;
161474711Scg	} cards[] = {
161574711Scg		{ MD_OPTI930, 0, 0xe4, 0xf8f, 0xe0e },	/* 930 */
161674711Scg		{ MD_OPTI924, 3, 0xe5, 0xf8c, 0,    },	/* 924 */
161774711Scg		{ 0 },
161874711Scg	};
161974711Scg	mss->conf_rid = 3;
162074711Scg	mss->indir_rid = 4;
162174711Scg	for (c = 0; cards[c].base; c++) {
162274711Scg		mss->optibase = cards[c].base;
162374711Scg		mss->password = cards[c].password;
162474711Scg		mss->passwdreg = cards[c].passwdreg;
162574711Scg		mss->bd_id = cards[c].boardid;
162674711Scg
162774711Scg		if (cards[c].indir_reg)
162874711Scg			mss->indir = bus_alloc_resource(dev, SYS_RES_IOPORT,
162974711Scg				&mss->indir_rid, cards[c].indir_reg,
163074711Scg				cards[c].indir_reg+1, 1, RF_ACTIVE);
163174711Scg
163274711Scg		mss->conf_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
163374711Scg			&mss->conf_rid, mss->optibase, mss->optibase+9,
163474711Scg			9, RF_ACTIVE);
163574711Scg
163674711Scg		if (opti_read(mss, 1) != 0xff) {
163774711Scg			return 1;
163874789Scg		} else {
163974789Scg			if (mss->indir)
164074789Scg				bus_release_resource(dev, SYS_RES_IOPORT, mss->indir_rid, mss->indir);
164174789Scg			mss->indir = NULL;
164274789Scg			if (mss->conf_base)
164374789Scg				bus_release_resource(dev, SYS_RES_IOPORT, mss->conf_rid, mss->conf_base);
164474789Scg			mss->conf_base = NULL;
164574711Scg		}
164674711Scg	}
164774711Scg	return 0;
164874711Scg}
1649150014Simp#endif
165074711Scg
165150723Scgstatic char *
165250723Scgymf_test(device_t dev, struct mss_info *mss)
165329415Sjmg{
165450723Scg    	static int ports[] = {0x370, 0x310, 0x538};
165550723Scg    	int p, i, j, version;
165650723Scg    	static char *chipset[] = {
165750723Scg		NULL,			/* 0 */
165850723Scg		"OPL3-SA2 (YMF711)",	/* 1 */
165950723Scg		"OPL3-SA3 (YMF715)",	/* 2 */
166050723Scg		"OPL3-SA3 (YMF715)",	/* 3 */
166150723Scg		"OPL3-SAx (YMF719)",	/* 4 */
166250723Scg		"OPL3-SAx (YMF719)",	/* 5 */
166350723Scg		"OPL3-SAx (YMF719)",	/* 6 */
166450723Scg		"OPL3-SAx (YMF719)",	/* 7 */
166550723Scg    	};
166629415Sjmg
166750723Scg    	for (p = 0; p < 3; p++) {
166850723Scg		mss->conf_rid = 1;
166950723Scg		mss->conf_base = bus_alloc_resource(dev,
167050723Scg					  	SYS_RES_IOPORT,
167150723Scg					  	&mss->conf_rid,
167250723Scg					  	ports[p], ports[p] + 1, 2,
167350723Scg					  	RF_ACTIVE);
167450723Scg		if (!mss->conf_base) return 0;
167529415Sjmg
167650723Scg		/* Test the index port of the config registers */
167750723Scg		i = port_rd(mss->conf_base, 0);
167850723Scg		port_wr(mss->conf_base, 0, OPL3SAx_DMACONF);
167950723Scg		j = (port_rd(mss->conf_base, 0) == OPL3SAx_DMACONF)? 1 : 0;
168050723Scg		port_wr(mss->conf_base, 0, i);
168150723Scg		if (!j) {
168250723Scg	    		bus_release_resource(dev, SYS_RES_IOPORT,
168350723Scg			 		     mss->conf_rid, mss->conf_base);
168460711Snyan#ifdef PC98
168560711Snyan			/* PC98 need this. I don't know reason why. */
168660711Snyan			bus_delete_resource(dev, SYS_RES_IOPORT, mss->conf_rid);
168760711Snyan#endif
168850723Scg	    		mss->conf_base = 0;
168950723Scg	    		continue;
169050723Scg		}
169150723Scg		version = conf_rd(mss, OPL3SAx_MISC) & 0x07;
169250723Scg		return chipset[version];
169350723Scg    	}
169450723Scg    	return NULL;
169529415Sjmg}
169629415Sjmg
169729415Sjmgstatic int
169850723Scgmss_doattach(device_t dev, struct mss_info *mss)
169929415Sjmg{
170070291Scg    	int pdma, rdma, flags = device_get_flags(dev);
170184111Scg    	char status[SND_STATUSLEN], status2[SND_STATUSLEN];
170229415Sjmg
1703167608Sariff	mss->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_mss softc");
170483619Scg	mss->bufsize = pcm_getbuffersize(dev, 4096, MSS_DEFAULT_BUFSZ, 65536);
170550723Scg    	if (!mss_alloc_resources(mss, dev)) goto no;
170650723Scg    	mss_init(mss, dev);
170770291Scg	pdma = rman_get_start(mss->drq1);
170870291Scg	rdma = rman_get_start(mss->drq2);
170950723Scg    	if (flags & DV_F_TRUE_MSS) {
171050723Scg		/* has IRQ/DMA registers, set IRQ and DMA addr */
171160711Snyan#ifdef PC98 /* CS423[12] in PC98 can use IRQ3,5,10,12 */
171260711Snyan		static char     interrupt_bits[13] =
171360711Snyan	        {-1, -1, -1, 0x08, -1, 0x10, -1, -1, -1, -1, 0x18, -1, 0x20};
171460711Snyan#else
171550723Scg		static char     interrupt_bits[12] =
171650723Scg	    	{-1, -1, -1, -1, -1, 0x28, -1, 0x08, -1, 0x10, 0x18, 0x20};
171760711Snyan#endif
171850723Scg		static char     pdma_bits[4] =  {1, 2, -1, 3};
171950723Scg		static char	valid_rdma[4] = {1, 0, -1, 0};
172050723Scg		char		bits;
172129415Sjmg
172250723Scg		if (!mss->irq || (bits = interrupt_bits[rman_get_start(mss->irq)]) == -1)
172350723Scg			goto no;
172460711Snyan#ifndef PC98 /* CS423[12] in PC98 don't support this. */
172550723Scg		io_wr(mss, 0, bits | 0x40);	/* config port */
172650723Scg		if ((io_rd(mss, 3) & 0x40) == 0) device_printf(dev, "IRQ Conflict?\n");
172760711Snyan#endif
172850723Scg		/* Write IRQ+DMA setup */
172970291Scg		if (pdma_bits[pdma] == -1) goto no;
173070291Scg		bits |= pdma_bits[pdma];
173170291Scg		if (pdma != rdma) {
173270291Scg	    		if (rdma == valid_rdma[pdma]) bits |= 4;
173350723Scg	    		else {
173470291Scg				printf("invalid dual dma config %d:%d\n", pdma, rdma);
173550723Scg				goto no;
173650723Scg	    		}
173750723Scg		}
173850723Scg		io_wr(mss, 0, bits);
173950723Scg		printf("drq/irq conf %x\n", io_rd(mss, 0));
174050723Scg    	}
174170134Scg    	mixer_init(dev, (mss->bd_id == MD_YM0020)? &ymmix_mixer_class : &mssmix_mixer_class, mss);
174250723Scg    	switch (mss->bd_id) {
174350723Scg    	case MD_OPTI931:
1744128232Sgreen		snd_setup_intr(dev, mss->irq, 0, opti931_intr, mss, &mss->ih);
174550723Scg		break;
174650723Scg    	default:
1747128232Sgreen		snd_setup_intr(dev, mss->irq, 0, mss_intr, mss, &mss->ih);
174850723Scg    	}
174970291Scg    	if (pdma == rdma)
175050723Scg		pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
1751166904Snetchild    	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
1752166904Snetchild			/*boundary*/0,
175350723Scg			/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
175450723Scg			/*highaddr*/BUS_SPACE_MAXADDR,
175550723Scg			/*filter*/NULL, /*filterarg*/NULL,
175683619Scg			/*maxsize*/mss->bufsize, /*nsegments*/1,
1757117126Sscottl			/*maxsegz*/0x3ffff, /*flags*/0,
1758117126Sscottl			/*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant,
1759117126Sscottl			&mss->parent_dmat) != 0) {
176050723Scg		device_printf(dev, "unable to create dma tag\n");
176150723Scg		goto no;
176250723Scg    	}
176329415Sjmg
176484111Scg    	if (pdma != rdma)
176584111Scg		snprintf(status2, SND_STATUSLEN, ":%d", rdma);
176684111Scg	else
176784111Scg		status2[0] = '\0';
176884111Scg
176984111Scg    	snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %d%s bufsz %u",
177084111Scg    	     	rman_get_start(mss->io_base), rman_get_start(mss->irq), pdma, status2, mss->bufsize);
177184111Scg
177250723Scg    	if (pcm_register(dev, mss, 1, 1)) goto no;
177370134Scg    	pcm_addchan(dev, PCMDIR_REC, &msschan_class, mss);
177470134Scg    	pcm_addchan(dev, PCMDIR_PLAY, &msschan_class, mss);
177550723Scg    	pcm_setstatus(dev, status);
177629415Sjmg
177750723Scg    	return 0;
177850723Scgno:
177950723Scg    	mss_release_resources(mss, dev);
178050723Scg    	return ENXIO;
178150723Scg}
178250723Scg
178329415Sjmgstatic int
178465644Scgmss_detach(device_t dev)
178565644Scg{
178665644Scg	int r;
178765644Scg    	struct mss_info *mss;
178865644Scg
178965644Scg	r = pcm_unregister(dev);
179065644Scg	if (r)
179165644Scg		return r;
179265644Scg
179365644Scg	mss = pcm_getdevinfo(dev);
179465644Scg    	mss_release_resources(mss, dev);
179565644Scg
179665644Scg	return 0;
179765644Scg}
179865644Scg
179965644Scgstatic int
180050723Scgmss_attach(device_t dev)
180129415Sjmg{
180250723Scg    	struct mss_info *mss;
180351052Sdfr    	int flags = device_get_flags(dev);
180429415Sjmg
180578564Sgreid    	mss = (struct mss_info *)malloc(sizeof *mss, M_DEVBUF, M_NOWAIT | M_ZERO);
180650723Scg    	if (!mss) return ENXIO;
180729415Sjmg
180850723Scg    	mss->io_rid = 0;
180950723Scg    	mss->conf_rid = -1;
181050723Scg    	mss->irq_rid = 0;
181150723Scg    	mss->drq1_rid = 0;
181250723Scg    	mss->drq2_rid = -1;
181350723Scg    	if (flags & DV_F_DUAL_DMA) {
181452174Sdfr        	bus_set_resource(dev, SYS_RES_DRQ, 1,
181550723Scg    		         	 flags & DV_F_DRQ_MASK, 1);
181650723Scg		mss->drq2_rid = 1;
181750723Scg    	}
181851052Sdfr    	mss->bd_id = (device_get_flags(dev) & DV_F_DEV_MASK) >> DV_F_DEV_SHIFT;
181950723Scg    	if (mss->bd_id == MD_YM0020) ymf_test(dev, mss);
182050723Scg    	return mss_doattach(dev, mss);
182150723Scg}
182229415Sjmg
182364032Scg/*
182464032Scg * mss_resume() is the code to allow a laptop to resume using the sound
182564032Scg * card.
182664032Scg *
182764032Scg * This routine re-sets the state of the board to the state before going
182864032Scg * to sleep.  According to the yamaha docs this is the right thing to do,
182964032Scg * but getting DMA restarted appears to be a bit of a trick, so the device
183064032Scg * has to be closed and re-opened to be re-used, but there is no skipping
183164032Scg * problem, and volume, bass/treble and most other things are restored
183264032Scg * properly.
183364032Scg *
183464032Scg */
183564032Scg
183664032Scgstatic int
183764032Scgmss_resume(device_t dev)
183864032Scg{
183964032Scg    	/*
184064032Scg     	 * Restore the state taken below.
184164032Scg     	 */
184264032Scg    	struct mss_info *mss;
184364032Scg    	int i;
184464032Scg
184564032Scg    	mss = pcm_getdevinfo(dev);
184664032Scg
1847108925Smdodd    	if(mss->bd_id == MD_YM0020 || mss->bd_id == MD_CS423X) {
184864032Scg		/* This works on a Toshiba Libretto 100CT. */
184964032Scg		for (i = 0; i < MSS_INDEXED_REGS; i++)
185064032Scg    			ad_write(mss, i, mss->mss_indexed_regs[i]);
185164032Scg		for (i = 0; i < OPL_INDEXED_REGS; i++)
185264032Scg    			conf_wr(mss, i, mss->opl_indexed_regs[i]);
185364032Scg		mss_intr(mss);
185464032Scg    	}
1855108925Smdodd
1856108925Smdodd	if (mss->bd_id == MD_CS423X) {
1857108925Smdodd		/* Needed on IBM Thinkpad 600E */
1858142730Smdodd		mss_lock(mss);
1859142730Smdodd		mss_format(&mss->pch, mss->pch.channel->format);
1860142730Smdodd		mss_speed(&mss->pch, mss->pch.channel->speed);
1861142730Smdodd		mss_unlock(mss);
1862108925Smdodd	}
1863108925Smdodd
186464032Scg    	return 0;
186564032Scg
186664032Scg}
186764032Scg
186864032Scg/*
186964032Scg * mss_suspend() is the code that gets called right before a laptop
187064032Scg * suspends.
187164032Scg *
187264032Scg * This code saves the state of the sound card right before shutdown
187364032Scg * so it can be restored above.
187464032Scg *
187564032Scg */
187664032Scg
187764032Scgstatic int
187864032Scgmss_suspend(device_t dev)
187964032Scg{
188064032Scg    	int i;
188164032Scg    	struct mss_info *mss;
188264032Scg
188364032Scg    	mss = pcm_getdevinfo(dev);
188464032Scg
1885108925Smdodd    	if(mss->bd_id == MD_YM0020 || mss->bd_id == MD_CS423X)
188664032Scg    	{
188764032Scg		/* this stops playback. */
188864032Scg		conf_wr(mss, 0x12, 0x0c);
188964032Scg		for(i = 0; i < MSS_INDEXED_REGS; i++)
189064032Scg    			mss->mss_indexed_regs[i] = ad_read(mss, i);
189164032Scg		for(i = 0; i < OPL_INDEXED_REGS; i++)
189264032Scg    			mss->opl_indexed_regs[i] = conf_rd(mss, i);
189364032Scg		mss->opl_indexed_regs[0x12] = 0x0;
189464032Scg    	}
189564032Scg    	return 0;
189664032Scg}
189764032Scg
189850723Scgstatic device_method_t mss_methods[] = {
189950723Scg	/* Device interface */
190050723Scg	DEVMETHOD(device_probe,		mss_probe),
190150723Scg	DEVMETHOD(device_attach,	mss_attach),
190265644Scg	DEVMETHOD(device_detach,	mss_detach),
190364032Scg	DEVMETHOD(device_suspend,       mss_suspend),
190464032Scg	DEVMETHOD(device_resume,        mss_resume),
190533474Sscrappy
190650723Scg	{ 0, 0 }
190750723Scg};
190829415Sjmg
190950723Scgstatic driver_t mss_driver = {
191050723Scg	"pcm",
191150723Scg	mss_methods,
191282180Scg	PCM_SOFTC_SIZE,
191350723Scg};
191450723Scg
191562483ScgDRIVER_MODULE(snd_mss, isa, mss_driver, pcm_devclass, 0, 0);
1916132236StanimuraMODULE_DEPEND(snd_mss, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
191762483ScgMODULE_VERSION(snd_mss, 1);
191850723Scg
191990241Stgstatic int
192090241Stgazt2320_mss_mode(struct mss_info *mss, device_t dev)
192190241Stg{
192290241Stg	struct resource *sbport;
192390241Stg	int		i, ret, rid;
192490241Stg
192590241Stg	rid = 0;
192690241Stg	ret = -1;
1927127135Snjl	sbport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
192890241Stg	if (sbport) {
192990241Stg		for (i = 0; i < 1000; i++) {
193090241Stg			if ((port_rd(sbport, SBDSP_STATUS) & 0x80))
193190241Stg				DELAY((i > 100) ? 1000 : 10);
193290241Stg			else {
193390241Stg				port_wr(sbport, SBDSP_CMD, 0x09);
193490241Stg				break;
193590241Stg			}
193690241Stg		}
193790241Stg		for (i = 0; i < 1000; i++) {
193890241Stg			if ((port_rd(sbport, SBDSP_STATUS) & 0x80))
193990241Stg				DELAY((i > 100) ? 1000 : 10);
194090241Stg			else {
194190241Stg				port_wr(sbport, SBDSP_CMD, 0x00);
194290241Stg				ret = 0;
194390241Stg				break;
194490241Stg			}
194590241Stg		}
194690241Stg		DELAY(1000);
194790241Stg		bus_release_resource(dev, SYS_RES_IOPORT, rid, sbport);
194890241Stg	}
194990241Stg	return ret;
195090241Stg}
195190241Stg
195254962Speterstatic struct isa_pnp_id pnpmss_ids[] = {
195354962Speter	{0x0000630e, "CS423x"},				/* CSC0000 */
195455279Speter	{0x0001630e, "CS423x-PCI"},			/* CSC0100 */
195554962Speter    	{0x01000000, "CMI8330"},			/* @@@0001 */
195654962Speter	{0x2100a865, "Yamaha OPL-SAx"},			/* YMH0021 */
195754962Speter	{0x1110d315, "ENSONIQ SoundscapeVIVO"},		/* ENS1011 */
195854962Speter	{0x1093143e, "OPTi931"},			/* OPT9310 */
195954962Speter	{0x5092143e, "OPTi925"},			/* OPT9250 XXX guess */
196074711Scg	{0x0000143e, "OPTi924"},			/* OPT0924 */
196156449Speter	{0x1022b839, "Neomagic 256AV (non-ac97)"},	/* NMX2210 */
196290241Stg	{0x01005407, "Aztech 2320"},			/* AZT0001 */
196354962Speter#if 0
196454962Speter	{0x0000561e, "GusPnP"},				/* GRV0000 */
196554962Speter#endif
196654962Speter	{0},
196754962Speter};
196854962Speter
196950723Scgstatic int
197050723Scgpnpmss_probe(device_t dev)
197129415Sjmg{
197256774Scg	u_int32_t lid, vid;
197356774Scg
197456774Scg	lid = isa_get_logicalid(dev);
197556774Scg	vid = isa_get_vendorid(dev);
197656774Scg	if (lid == 0x01000000 && vid != 0x0100a90d) /* CMI0001 */
197756774Scg		return ENXIO;
197854962Speter	return ISA_PNP_PROBE(device_get_parent(dev), dev, pnpmss_ids);
197929415Sjmg}
198029415Sjmg
198150723Scgstatic int
198250723Scgpnpmss_attach(device_t dev)
198329415Sjmg{
198450723Scg	struct mss_info *mss;
198529415Sjmg
1986170873Sariff	mss = malloc(sizeof(*mss), M_DEVBUF, M_WAITOK | M_ZERO);
198750723Scg	mss->io_rid = 0;
198850723Scg	mss->conf_rid = -1;
198950723Scg	mss->irq_rid = 0;
199050723Scg	mss->drq1_rid = 0;
199150723Scg	mss->drq2_rid = 1;
199259574Scg	mss->bd_id = MD_CS42XX;
199342284Sluigi
199454962Speter	switch (isa_get_logicalid(dev)) {
199554962Speter	case 0x0000630e:			/* CSC0000 */
199655279Speter	case 0x0001630e:			/* CSC0100 */
199754962Speter	    mss->bd_flags |= BD_F_MSS_OFFSET;
1998108925Smdodd	    mss->bd_id = MD_CS423X;
199954962Speter	    break;
200054962Speter
200154962Speter	case 0x2100a865:			/* YHM0021 */
200250723Scg	    mss->io_rid = 1;
200350723Scg	    mss->conf_rid = 4;
200450723Scg	    mss->bd_id = MD_YM0020;
200529652Speter	    break;
200630869Sjmg
200754962Speter	case 0x1110d315:			/* ENS1011 */
200850723Scg	    mss->io_rid = 1;
200950723Scg	    mss->bd_id = MD_VIVO;
201030869Sjmg	    break;
201130869Sjmg
201254962Speter	case 0x1093143e:			/* OPT9310 */
201350723Scg            mss->bd_flags |= BD_F_MSS_OFFSET;
201450723Scg    	    mss->conf_rid = 3;
201550723Scg            mss->bd_id = MD_OPTI931;
201629652Speter	    break;
201742284Sluigi
201854962Speter	case 0x5092143e:			/* OPT9250 XXX guess */
201950723Scg            mss->io_rid = 1;
202050723Scg            mss->conf_rid = 3;
202150723Scg	    mss->bd_id = MD_OPTI925;
202250723Scg	    break;
202355879Scg
202474711Scg	case 0x0000143e:			/* OPT0924 */
202574711Scg	    mss->password = 0xe5;
202674711Scg	    mss->passwdreg = 3;
202774711Scg	    mss->optibase = 0xf0c;
202874711Scg	    mss->io_rid = 2;
202974711Scg	    mss->conf_rid = 3;
203074711Scg	    mss->bd_id = MD_OPTI924;
203174711Scg	    mss->bd_flags |= BD_F_924PNP;
2032155336Snetchild	    if(opti_init(dev, mss) != 0) {
2033155336Snetchild		    free(mss, M_DEVBUF);
203474711Scg		    return ENXIO;
2035155336Snetchild	    }
203674711Scg	    break;
203774711Scg
203856449Speter	case 0x1022b839:			/* NMX2210 */
203955879Scg	    mss->io_rid = 1;
204055879Scg	    break;
204156449Speter
204290241Stg	case 0x01005407:			/* AZT0001 */
204390241Stg	    /* put into MSS mode first (snatched from NetBSD) */
2044155336Snetchild	    if (azt2320_mss_mode(mss, dev) == -1) {
2045155336Snetchild		    free(mss, M_DEVBUF);
204690241Stg		    return ENXIO;
2047155336Snetchild	    }
204890241Stg
204990241Stg	    mss->bd_flags |= BD_F_MSS_OFFSET;
205090241Stg	    mss->io_rid = 2;
205190241Stg	    break;
205290241Stg
205353553Stanimura#if 0
205454962Speter	case 0x0000561e:			/* GRV0000 */
205551120Sdfr	    mss->bd_flags |= BD_F_MSS_OFFSET;
205650723Scg            mss->io_rid = 2;
205750723Scg            mss->conf_rid = 1;
205850723Scg	    mss->drq1_rid = 1;
205950723Scg	    mss->drq2_rid = 0;
206050723Scg            mss->bd_id = MD_GUSPNP;
206150723Scg	    break;
206253553Stanimura#endif
206359574Scg	case 0x01000000:			/* @@@0001 */
206459574Scg	    mss->drq2_rid = -1;
206559574Scg            break;
206659574Scg
206754962Speter	/* Unknown MSS default.  We could let the CSC0000 stuff match too */
206850723Scg        default:
206950723Scg	    mss->bd_flags |= BD_F_MSS_OFFSET;
207050723Scg	    break;
207150723Scg	}
207250723Scg    	return mss_doattach(dev, mss);
207329415Sjmg}
207429415Sjmg
207574711Scgstatic int
207674711Scgopti_init(device_t dev, struct mss_info *mss)
207774711Scg{
207874711Scg	int flags = device_get_flags(dev);
207974711Scg	int basebits = 0;
208074711Scg
208174711Scg	if (!mss->conf_base) {
208274711Scg		bus_set_resource(dev, SYS_RES_IOPORT, mss->conf_rid,
208374711Scg			mss->optibase, 0x9);
208474711Scg
208574711Scg		mss->conf_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
208674711Scg			&mss->conf_rid, mss->optibase, mss->optibase+0x9,
208774711Scg			0x9, RF_ACTIVE);
208874711Scg	}
208974711Scg
209074711Scg	if (!mss->conf_base)
209174711Scg		return ENXIO;
209274711Scg
209374711Scg	if (!mss->io_base)
209474711Scg		mss->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
209574711Scg			&mss->io_rid, 0, ~0, 8, RF_ACTIVE);
209674711Scg
209774711Scg	if (!mss->io_base)	/* No hint specified, use 0x530 */
209874711Scg		mss->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
209974711Scg			&mss->io_rid, 0x530, 0x537, 8, RF_ACTIVE);
210074711Scg
210174711Scg	if (!mss->io_base)
210274711Scg		return ENXIO;
210374711Scg
210474711Scg	switch (rman_get_start(mss->io_base)) {
210574711Scg		case 0x530:
210674711Scg			basebits = 0x0;
210774711Scg			break;
210874711Scg		case 0xe80:
210974711Scg			basebits = 0x10;
211074711Scg			break;
211174711Scg		case 0xf40:
211274711Scg			basebits = 0x20;
211374711Scg			break;
211474711Scg		case 0x604:
211574711Scg			basebits = 0x30;
211674711Scg			break;
211774711Scg		default:
211874711Scg			printf("opti_init: invalid MSS base address!\n");
211974711Scg			return ENXIO;
212074711Scg	}
212174711Scg
212274711Scg
212374711Scg	switch (mss->bd_id) {
212474711Scg	case MD_OPTI924:
212574711Scg		opti_write(mss, 1, 0x80 | basebits);	/* MSS mode */
212674711Scg		opti_write(mss, 2, 0x00);	/* Disable CD */
212774711Scg		opti_write(mss, 3, 0xf0);	/* Disable SB IRQ */
212874711Scg		opti_write(mss, 4, 0xf0);
212974711Scg		opti_write(mss, 5, 0x00);
213074711Scg		opti_write(mss, 6, 0x02);	/* MPU stuff */
213174711Scg		break;
213274711Scg
213374711Scg	case MD_OPTI930:
213474711Scg		opti_write(mss, 1, 0x00 | basebits);
213574711Scg		opti_write(mss, 3, 0x00);	/* Disable SB IRQ/DMA */
213674711Scg		opti_write(mss, 4, 0x52);	/* Empty FIFO */
213774711Scg		opti_write(mss, 5, 0x3c);	/* Mode 2 */
213874711Scg		opti_write(mss, 6, 0x02);	/* Enable MSS */
213974711Scg		break;
214074711Scg	}
214174711Scg
214274711Scg	if (mss->bd_flags & BD_F_924PNP) {
214374711Scg		u_int32_t irq = isa_get_irq(dev);
214474711Scg		u_int32_t drq = isa_get_drq(dev);
214574711Scg		bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
214674711Scg		bus_set_resource(dev, SYS_RES_DRQ, mss->drq1_rid, drq, 1);
214774711Scg		if (flags & DV_F_DUAL_DMA) {
214874711Scg			bus_set_resource(dev, SYS_RES_DRQ, 1,
214974711Scg				flags & DV_F_DRQ_MASK, 1);
215074711Scg			mss->drq2_rid = 1;
215174711Scg		}
215274711Scg	}
215374711Scg
215474711Scg	/* OPTixxx has I/DRQ registers */
215574711Scg
215674711Scg	device_set_flags(dev, device_get_flags(dev) | DV_F_TRUE_MSS);
215774711Scg
215874711Scg	return 0;
215974711Scg}
216074711Scg
216174711Scgstatic void
216274711Scgopti_write(struct mss_info *mss, u_char reg, u_char val)
216374711Scg{
216474711Scg	port_wr(mss->conf_base, mss->passwdreg, mss->password);
216574711Scg
216674711Scg	switch(mss->bd_id) {
216774711Scg	case MD_OPTI924:
216874711Scg		if (reg > 7) {		/* Indirect register */
216974711Scg			port_wr(mss->conf_base, mss->passwdreg, reg);
217074711Scg			port_wr(mss->conf_base, mss->passwdreg,
217174711Scg				mss->password);
217274711Scg			port_wr(mss->conf_base, 9, val);
217374711Scg			return;
217474711Scg		}
217574711Scg		port_wr(mss->conf_base, reg, val);
217674711Scg		break;
217774711Scg
217876635Sgreid	case MD_OPTI930:
217974711Scg		port_wr(mss->indir, 0, reg);
218074711Scg		port_wr(mss->conf_base, mss->passwdreg, mss->password);
218174711Scg		port_wr(mss->indir, 1, val);
218274711Scg		break;
218374711Scg	}
218474711Scg}
218574711Scg
2186150038Snyan#ifndef PC98
218774711Scgu_char
218874711Scgopti_read(struct mss_info *mss, u_char reg)
218974711Scg{
219074711Scg	port_wr(mss->conf_base, mss->passwdreg, mss->password);
219174711Scg
219274711Scg	switch(mss->bd_id) {
219374711Scg	case MD_OPTI924:
219474711Scg		if (reg > 7) {		/* Indirect register */
219574711Scg			port_wr(mss->conf_base, mss->passwdreg, reg);
219674711Scg			port_wr(mss->conf_base, mss->passwdreg, mss->password);
219774711Scg			return(port_rd(mss->conf_base, 9));
219874711Scg		}
219974711Scg		return(port_rd(mss->conf_base, reg));
220074711Scg		break;
220174711Scg
220274711Scg	case MD_OPTI930:
220374711Scg		port_wr(mss->indir, 0, reg);
220474711Scg		port_wr(mss->conf_base, mss->passwdreg, mss->password);
220574711Scg		return port_rd(mss->indir, 1);
220674711Scg		break;
220774711Scg	}
220874711Scg	return -1;
220974711Scg}
2210150038Snyan#endif
221174711Scg
221250723Scgstatic device_method_t pnpmss_methods[] = {
221350723Scg	/* Device interface */
221450723Scg	DEVMETHOD(device_probe,		pnpmss_probe),
221550723Scg	DEVMETHOD(device_attach,	pnpmss_attach),
221665644Scg	DEVMETHOD(device_detach,	mss_detach),
221764032Scg	DEVMETHOD(device_suspend,       mss_suspend),
221864032Scg	DEVMETHOD(device_resume,        mss_resume),
221950723Scg
222050723Scg	{ 0, 0 }
222129415Sjmg};
222229415Sjmg
222350723Scgstatic driver_t pnpmss_driver = {
222450723Scg	"pcm",
222550723Scg	pnpmss_methods,
222682180Scg	PCM_SOFTC_SIZE,
222750723Scg};
222829415Sjmg
222962483ScgDRIVER_MODULE(snd_pnpmss, isa, pnpmss_driver, pcm_devclass, 0, 0);
2230136410SnjlDRIVER_MODULE(snd_pnpmss, acpi, pnpmss_driver, pcm_devclass, 0, 0);
2231132236StanimuraMODULE_DEPEND(snd_pnpmss, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
223262483ScgMODULE_VERSION(snd_pnpmss, 1);
223350723Scg
223442284Sluigistatic int
223553553Stanimuraguspcm_probe(device_t dev)
223653553Stanimura{
223753553Stanimura	struct sndcard_func *func;
223853553Stanimura
223953553Stanimura	func = device_get_ivars(dev);
224053553Stanimura	if (func == NULL || func->func != SCF_PCM)
224153553Stanimura		return ENXIO;
224253553Stanimura
224353553Stanimura	device_set_desc(dev, "GUS CS4231");
224453553Stanimura	return 0;
224553553Stanimura}
224653553Stanimura
224753553Stanimurastatic int
224853553Stanimuraguspcm_attach(device_t dev)
224953553Stanimura{
225053553Stanimura	device_t parent = device_get_parent(dev);
225153553Stanimura	struct mss_info *mss;
225253553Stanimura	int base, flags;
225353553Stanimura	unsigned char ctl;
225453553Stanimura
225578564Sgreid	mss = (struct mss_info *)malloc(sizeof *mss, M_DEVBUF, M_NOWAIT | M_ZERO);
225653553Stanimura	if (mss == NULL)
225753553Stanimura		return ENOMEM;
225853553Stanimura
225953553Stanimura	mss->bd_flags = BD_F_MSS_OFFSET;
226053553Stanimura	mss->io_rid = 2;
226153553Stanimura	mss->conf_rid = 1;
226253553Stanimura	mss->irq_rid = 0;
226353553Stanimura	mss->drq1_rid = 1;
226453553Stanimura	mss->drq2_rid = -1;
226553553Stanimura
226662947Stanimura	if (isa_get_logicalid(parent) == 0)
226753553Stanimura		mss->bd_id = MD_GUSMAX;
226853553Stanimura	else {
226953553Stanimura		mss->bd_id = MD_GUSPNP;
227053553Stanimura		mss->drq2_rid = 0;
227153553Stanimura		goto skip_setup;
227253553Stanimura	}
227353553Stanimura
227453553Stanimura	flags = device_get_flags(parent);
227553553Stanimura	if (flags & DV_F_DUAL_DMA)
227653553Stanimura		mss->drq2_rid = 0;
227753553Stanimura
227853553Stanimura	mss->conf_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &mss->conf_rid,
227953553Stanimura					    0, ~0, 8, RF_ACTIVE);
228053553Stanimura
228153553Stanimura	if (mss->conf_base == NULL) {
228253553Stanimura		mss_release_resources(mss, dev);
228353553Stanimura		return ENXIO;
228453553Stanimura	}
228553553Stanimura
228653553Stanimura	base = isa_get_port(parent);
228753553Stanimura
228853553Stanimura	ctl = 0x40;			/* CS4231 enable */
228953553Stanimura	if (isa_get_drq(dev) > 3)
229053553Stanimura		ctl |= 0x10;		/* 16-bit dma channel 1 */
229153553Stanimura	if ((flags & DV_F_DUAL_DMA) != 0 && (flags & DV_F_DRQ_MASK) > 3)
229253553Stanimura		ctl |= 0x20;		/* 16-bit dma channel 2 */
229353553Stanimura	ctl |= (base >> 4) & 0x0f;	/* 2X0 -> 3XC */
229453553Stanimura	port_wr(mss->conf_base, 6, ctl);
229553553Stanimura
229653553Stanimuraskip_setup:
229753553Stanimura	return mss_doattach(dev, mss);
229853553Stanimura}
229953553Stanimura
230053553Stanimurastatic device_method_t guspcm_methods[] = {
230153553Stanimura	DEVMETHOD(device_probe,		guspcm_probe),
230253553Stanimura	DEVMETHOD(device_attach,	guspcm_attach),
230365644Scg	DEVMETHOD(device_detach,	mss_detach),
230453553Stanimura
230553553Stanimura	{ 0, 0 }
230653553Stanimura};
230753553Stanimura
230853553Stanimurastatic driver_t guspcm_driver = {
230953553Stanimura	"pcm",
231053553Stanimura	guspcm_methods,
231182180Scg	PCM_SOFTC_SIZE,
231253553Stanimura};
231353553Stanimura
231462483ScgDRIVER_MODULE(snd_guspcm, gusc, guspcm_driver, pcm_devclass, 0, 0);
2315132236StanimuraMODULE_DEPEND(snd_guspcm, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
231662483ScgMODULE_VERSION(snd_guspcm, 1);
231753553Stanimura
231862483Scg
2319