sb16.c revision 54791
129415Sjmg/*
250723Scg * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
339899Sluigi * Copyright 1997,1998 Luigi Rizzo.
429415Sjmg *
529415Sjmg * Derived from files in the Voxware 3.5 distribution,
629415Sjmg * Copyright by Hannu Savolainen 1994, under the same copyright
729415Sjmg * conditions.
850723Scg * All rights reserved.
950723Scg *
1029415Sjmg * Redistribution and use in source and binary forms, with or without
1129415Sjmg * modification, are permitted provided that the following conditions
1230869Sjmg * are met:
1330869Sjmg * 1. Redistributions of source code must retain the above copyright
1430869Sjmg *    notice, this list of conditions and the following disclaimer.
1530869Sjmg * 2. Redistributions in binary form must reproduce the above copyright
1650723Scg *    notice, this list of conditions and the following disclaimer in the
1750723Scg *    documentation and/or other materials provided with the distribution.
1830869Sjmg *
1950723Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2050723Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2150723Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2250723Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2350723Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2450723Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2550723Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2650723Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2750723Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2850723Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2950723Scg * SUCH DAMAGE.
3050723Scg *
3150959Speter * $FreeBSD: head/sys/dev/sound/isa/sb16.c 54791 1999-12-18 22:21:47Z cg $
3229415Sjmg */
3329415Sjmg
3453465Scg#include <dev/sound/pcm/sound.h>
3529415Sjmg
3653553Stanimura#include "sbc.h"
3753553Stanimura
3829415Sjmg#define __SB_MIXER_C__	/* XXX warning... */
3953465Scg#include  <dev/sound/isa/sb.h>
4053553Stanimura#include  <dev/sound/chip.h>
4129415Sjmg
4250723Scg/* channel interface */
4350723Scgstatic void *sbchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
4450723Scgstatic int sbchan_setdir(void *data, int dir);
4550723Scgstatic int sbchan_setformat(void *data, u_int32_t format);
4650723Scgstatic int sbchan_setspeed(void *data, u_int32_t speed);
4750723Scgstatic int sbchan_setblocksize(void *data, u_int32_t blocksize);
4850723Scgstatic int sbchan_trigger(void *data, int go);
4950723Scgstatic int sbchan_getptr(void *data);
5050723Scgstatic pcmchan_caps *sbchan_getcaps(void *data);
5129415Sjmg
5250925Scg/* channel interface for ESS */
5350925Scg#ifdef notyet
5450925Scgstatic void *esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
5550925Scg#endif
5650925Scgstatic int esschan_setdir(void *data, int dir);
5750925Scgstatic int esschan_setformat(void *data, u_int32_t format);
5850925Scgstatic int esschan_setspeed(void *data, u_int32_t speed);
5950925Scgstatic int esschan_setblocksize(void *data, u_int32_t blocksize);
6050925Scgstatic int esschan_trigger(void *data, int go);
6150925Scgstatic int esschan_getptr(void *data);
6250925Scgstatic pcmchan_caps *esschan_getcaps(void *data);
6354462Scg
6450723Scgstatic pcmchan_caps sb_playcaps = {
6550723Scg	4000, 22050,
6650723Scg	AFMT_U8,
6750723Scg	AFMT_U8
6850723Scg};
6929415Sjmg
7050723Scgstatic pcmchan_caps sb_reccaps = {
7150723Scg	4000, 13000,
7250723Scg	AFMT_U8,
7350723Scg	AFMT_U8
7450723Scg};
7529415Sjmg
7650723Scgstatic pcmchan_caps sbpro_playcaps = {
7750723Scg	4000, 45000,
7850723Scg	AFMT_STEREO | AFMT_U8,
7950723Scg	AFMT_STEREO | AFMT_U8
8050723Scg};
8129415Sjmg
8250723Scgstatic pcmchan_caps sbpro_reccaps = {
8350723Scg	4000, 15000,
8450723Scg	AFMT_STEREO | AFMT_U8,
8550723Scg	AFMT_STEREO | AFMT_U8
8650723Scg};
8729415Sjmg
8854462Scgstatic pcmchan_caps sb16_hcaps = {
8950723Scg	5000, 45000,
9050723Scg	AFMT_STEREO | AFMT_S16_LE,
9150723Scg	AFMT_STEREO | AFMT_S16_LE
9250723Scg};
9329415Sjmg
9454462Scgstatic pcmchan_caps sb16_lcaps = {
9550723Scg	5000, 45000,
9650723Scg	AFMT_STEREO | AFMT_U8,
9750723Scg	AFMT_STEREO | AFMT_U8
9850723Scg};
9929415Sjmg
10054462Scgstatic pcmchan_caps sb16x_caps = {
10154462Scg	5000, 49000,
10254462Scg	AFMT_STEREO | AFMT_U8 /* | AFMT_S16_LE */,
10354462Scg	AFMT_STEREO | AFMT_U8 /* AFMT_S16_LE */
10454462Scg};
10554462Scg
10650723Scgstatic pcmchan_caps ess_playcaps = {
10750723Scg	5000, 49000,
10850723Scg	AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
10950723Scg	AFMT_STEREO | AFMT_S16_LE
11050723Scg};
11129415Sjmg
11250723Scgstatic pcmchan_caps ess_reccaps = {
11350723Scg	5000, 49000,
11450723Scg	AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
11550723Scg	AFMT_STEREO | AFMT_S16_LE
11650723Scg};
11729415Sjmg
11850723Scgstatic pcm_channel sb_chantemplate = {
11950723Scg	sbchan_init,
12050723Scg	sbchan_setdir,
12150723Scg	sbchan_setformat,
12250723Scg	sbchan_setspeed,
12350723Scg	sbchan_setblocksize,
12450723Scg	sbchan_trigger,
12550723Scg	sbchan_getptr,
12650723Scg	sbchan_getcaps,
12750723Scg};
12829415Sjmg
12950925Scgstatic pcm_channel ess_chantemplate = {
13050925Scg	sbchan_init,
13150925Scg	esschan_setdir,
13250925Scg	esschan_setformat,
13350925Scg	esschan_setspeed,
13450925Scg	esschan_setblocksize,
13550925Scg	esschan_trigger,
13650925Scg	esschan_getptr,
13750925Scg	esschan_getcaps,
13850925Scg};
13950723Scg#define PLAIN_SB16(x) ((((x)->bd_flags) & (BD_F_SB16|BD_F_SB16X)) == BD_F_SB16)
14029415Sjmg
14150723Scgstruct sb_info;
14229415Sjmg
14350723Scgstruct sb_chinfo {
14450723Scg	struct sb_info *parent;
14550723Scg	pcm_channel *channel;
14650723Scg	snd_dbuf *buffer;
14750723Scg	int dir;
14850723Scg	u_int32_t fmt;
14950925Scg	int ess_dma_started;
15050723Scg};
15129415Sjmg
15250723Scgstruct sb_info {
15350723Scg    	struct resource *io_base;	/* I/O address for the board */
15450723Scg    	struct resource *irq;
15554462Scg   	struct resource *drq1;
15654462Scg    	struct resource *drq2;
15750723Scg    	bus_dma_tag_t    parent_dmat;
15829415Sjmg
15950723Scg    	int bd_id;
16050723Scg    	u_long bd_flags;       /* board-specific flags */
16150723Scg    	struct sb_chinfo pch, rch;
16250723Scg};
16350723Scg
16450723Scgstatic int sb_rd(struct sb_info *sb, int reg);
16550723Scgstatic void sb_wr(struct sb_info *sb, int reg, u_int8_t val);
16650723Scgstatic int sb_dspready(struct sb_info *sb);
16750723Scgstatic int sb_cmd(struct sb_info *sb, u_char val);
16850723Scgstatic int sb_cmd1(struct sb_info *sb, u_char cmd, int val);
16950723Scgstatic int sb_cmd2(struct sb_info *sb, u_char cmd, int val);
17050723Scgstatic u_int sb_get_byte(struct sb_info *sb);
17150723Scgstatic void sb_setmixer(struct sb_info *sb, u_int port, u_int value);
17250723Scgstatic int sb_getmixer(struct sb_info *sb, u_int port);
17354462Scgstatic int sb_reset_dsp(struct sb_info *sb);
17429415Sjmg
17550723Scgstatic void sb_intr(void *arg);
17650723Scgstatic int sb_format(struct sb_chinfo *ch, u_int32_t format);
17750723Scgstatic int sb_speed(struct sb_chinfo *ch, int speed);
17850723Scgstatic int sb_start(struct sb_chinfo *ch);
17950723Scgstatic int sb_stop(struct sb_chinfo *ch);
18050723Scg
18154462Scgstatic int ess_write(struct sb_info *sb, u_char reg, int val);
18254462Scgstatic int ess_read(struct sb_info *sb, u_char reg);
18354462Scgstatic void ess_intr(void *arg);
18450925Scgstatic int ess_format(struct sb_chinfo *ch, u_int32_t format);
18550925Scgstatic int ess_speed(struct sb_chinfo *ch, int speed);
18650925Scgstatic int ess_start(struct sb_chinfo *ch);
18750925Scgstatic int ess_stop(struct sb_chinfo *ch);
18850925Scgstatic int ess_abort(struct sb_chinfo *ch);
18954462Scg
19050723Scgstatic int sbmix_init(snd_mixer *m);
19150723Scgstatic int sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right);
19250723Scgstatic int sbmix_setrecsrc(snd_mixer *m, u_int32_t src);
19350723Scg
19450723Scgstatic snd_mixer sb_mixer = {
19550723Scg    "SoundBlaster mixer",
19650723Scg    sbmix_init,
19750723Scg    sbmix_set,
19850723Scg    sbmix_setrecsrc,
19950723Scg};
20050723Scg
20150723Scgstatic devclass_t pcm_devclass;
20250723Scg
20329415Sjmg/*
20450723Scg * Common code for the midi and pcm functions
20529415Sjmg *
20650723Scg * sb_cmd write a single byte to the CMD port.
20750723Scg * sb_cmd1 write a CMD + 1 byte arg
20850723Scg * sb_cmd2 write a CMD + 2 byte arg
20950723Scg * sb_get_byte returns a single byte from the DSP data port
21050723Scg *
21150723Scg * ess_write is actually sb_cmd1
21250723Scg * ess_read access ext. regs via sb_cmd(0xc0, reg) followed by sb_get_byte
21329415Sjmg */
21429415Sjmg
21529415Sjmgstatic int
21650723Scgport_rd(struct resource *port, int off)
21729415Sjmg{
21850723Scg	return bus_space_read_1(rman_get_bustag(port),
21950723Scg				rman_get_bushandle(port),
22050723Scg				off);
22150723Scg}
22229415Sjmg
22350723Scgstatic void
22450723Scgport_wr(struct resource *port, int off, u_int8_t data)
22550723Scg{
22650723Scg	return bus_space_write_1(rman_get_bustag(port),
22750723Scg				 rman_get_bushandle(port),
22850723Scg				 off, data);
22929415Sjmg}
23029415Sjmg
23129415Sjmgstatic int
23250723Scgsb_rd(struct sb_info *sb, int reg)
23329415Sjmg{
23450723Scg	return port_rd(sb->io_base, reg);
23550723Scg}
23629415Sjmg
23750723Scgstatic void
23850723Scgsb_wr(struct sb_info *sb, int reg, u_int8_t val)
23950723Scg{
24050723Scg	port_wr(sb->io_base, reg, val);
24129415Sjmg}
24229415Sjmg
24350723Scgstatic int
24450723Scgsb_dspready(struct sb_info *sb)
24550723Scg{
24650723Scg	return ((sb_rd(sb, SBDSP_STATUS) & 0x80) == 0);
24750723Scg}
24829415Sjmg
24929415Sjmgstatic int
25050723Scgsb_dspwr(struct sb_info *sb, u_char val)
25129415Sjmg{
25250723Scg    	int  i;
25329415Sjmg
25450723Scg    	for (i = 0; i < 1000; i++) {
25550723Scg		if (sb_dspready(sb)) {
25650723Scg	    		sb_wr(sb, SBDSP_CMD, val);
25750723Scg	    		return 1;
25850723Scg		}
25950723Scg		if (i > 10) DELAY((i > 100)? 1000 : 10);
26050723Scg    	}
26150723Scg    	printf("sb_dspwr(0x%02x) timed out.\n", val);
26250723Scg    	return 0;
26350723Scg}
26429415Sjmg
26550723Scgstatic int
26650723Scgsb_cmd(struct sb_info *sb, u_char val)
26750723Scg{
26850723Scg#if 0
26950723Scg	printf("sb_cmd: %x\n", val);
27050723Scg#endif
27150723Scg    	return sb_dspwr(sb, val);
27250723Scg}
27329415Sjmg
27450723Scgstatic int
27550723Scgsb_cmd1(struct sb_info *sb, u_char cmd, int val)
27650723Scg{
27750723Scg#if 0
27850723Scg    	printf("sb_cmd1: %x, %x\n", cmd, val);
27950723Scg#endif
28050723Scg    	if (sb_dspwr(sb, cmd)) {
28150723Scg		return sb_dspwr(sb, val & 0xff);
28250723Scg    	} else return 0;
28350723Scg}
28429415Sjmg
28550723Scgstatic int
28650723Scgsb_cmd2(struct sb_info *sb, u_char cmd, int val)
28750723Scg{
28850723Scg#if 0
28950723Scg    	printf("sb_cmd2: %x, %x\n", cmd, val);
29050723Scg#endif
29150723Scg    	if (sb_dspwr(sb, cmd)) {
29250723Scg		return sb_dspwr(sb, val & 0xff) &&
29350723Scg		       sb_dspwr(sb, (val >> 8) & 0xff);
29450723Scg    	} else return 0;
29550723Scg}
29629415Sjmg
29750723Scg/*
29850723Scg * in the SB, there is a set of indirect "mixer" registers with
29950723Scg * address at offset 4, data at offset 5
30050723Scg */
30150723Scgstatic void
30250723Scgsb_setmixer(struct sb_info *sb, u_int port, u_int value)
30350723Scg{
30450723Scg    	u_long   flags;
30529415Sjmg
30650723Scg    	flags = spltty();
30750723Scg    	sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
30850723Scg    	DELAY(10);
30950723Scg    	sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff));
31050723Scg    	DELAY(10);
31150723Scg    	splx(flags);
31250723Scg}
31331361Sjmg
31450723Scgstatic int
31550723Scgsb_getmixer(struct sb_info *sb, u_int port)
31650723Scg{
31750723Scg    	int val;
31850723Scg    	u_long flags;
31929415Sjmg
32050723Scg    	flags = spltty();
32150723Scg    	sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
32250723Scg    	DELAY(10);
32350723Scg    	val = sb_rd(sb, SB_MIX_DATA);
32450723Scg    	DELAY(10);
32550723Scg    	splx(flags);
32629415Sjmg
32750723Scg    	return val;
32850723Scg}
32929415Sjmg
33050723Scgstatic u_int
33150723Scgsb_get_byte(struct sb_info *sb)
33250723Scg{
33350723Scg    	int i;
33429415Sjmg
33550723Scg    	for (i = 1000; i > 0; i--) {
33650723Scg		if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80)
33750723Scg			return sb_rd(sb, DSP_READ);
33850723Scg		else
33950723Scg			DELAY(20);
34050723Scg    	}
34150723Scg    	return 0xffff;
34250723Scg}
34329415Sjmg
34450723Scgstatic int
34550723Scgess_write(struct sb_info *sb, u_char reg, int val)
34650723Scg{
34750723Scg    	return sb_cmd1(sb, reg, val);
34829415Sjmg}
34929415Sjmg
35029415Sjmgstatic int
35150723Scgess_read(struct sb_info *sb, u_char reg)
35229415Sjmg{
35350723Scg    	return (sb_cmd(sb, 0xc0) && sb_cmd(sb, reg))? sb_get_byte(sb) : 0xffff;
35429415Sjmg}
35529415Sjmg
35629415Sjmgstatic int
35750723Scgsb_reset_dsp(struct sb_info *sb)
35829415Sjmg{
35950723Scg    	sb_wr(sb, SBDSP_RST, 3);
36050723Scg    	DELAY(100);
36150723Scg    	sb_wr(sb, SBDSP_RST, 0);
36250723Scg    	if (sb_get_byte(sb) != 0xAA) {
36350723Scg        	DEB(printf("sb_reset_dsp 0x%lx failed\n",
36450723Scg			   rman_get_start(d->io_base)));
36550723Scg		return ENXIO;	/* Sorry */
36650723Scg    	}
36750723Scg    	if (sb->bd_flags & BD_F_ESS) sb_cmd(sb, 0xc6);
36850723Scg    	return 0;
36929415Sjmg}
37029415Sjmg
37129415Sjmgstatic void
37250723Scgsb_release_resources(struct sb_info *sb, device_t dev)
37329415Sjmg{
37450723Scg    	/* should we bus_teardown_intr here? */
37550723Scg    	if (sb->irq) {
37654462Scg		bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq);
37750723Scg		sb->irq = 0;
37850723Scg    	}
37950723Scg    	if (sb->drq1) {
38054462Scg		bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1);
38150723Scg		sb->drq1 = 0;
38250723Scg    	}
38350723Scg    	if (sb->drq2) {
38454462Scg		bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2);
38550723Scg		sb->drq2 = 0;
38650723Scg    	}
38750723Scg    	if (sb->io_base) {
38854462Scg		bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base);
38950723Scg		sb->io_base = 0;
39050723Scg    	}
39150723Scg    	free(sb, M_DEVBUF);
39250723Scg}
39329415Sjmg
39450723Scgstatic int
39550723Scgsb_alloc_resources(struct sb_info *sb, device_t dev)
39650723Scg{
39754462Scg	int rid;
39854462Scg
39954462Scg	rid = 0;
40050723Scg	if (!sb->io_base)
40150723Scg    		sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
40254462Scg						 &rid, 0, ~0, 1,
40350723Scg						 RF_ACTIVE);
40454462Scg	rid = 0;
40550723Scg	if (!sb->irq)
40650723Scg    		sb->irq = bus_alloc_resource(dev, SYS_RES_IRQ,
40754462Scg					     &rid, 0, ~0, 1,
40850723Scg					     RF_ACTIVE);
40954462Scg	rid = 0;
41050723Scg	if (!sb->drq1)
41150723Scg    		sb->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ,
41254462Scg					      &rid, 0, ~0, 1,
41350723Scg					      RF_ACTIVE);
41454462Scg	rid = 1;
41554462Scg	if (!sb->drq2)
41650723Scg        	sb->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ,
41754462Scg					      &rid, 0, ~0, 1,
41850723Scg					      RF_ACTIVE);
41929415Sjmg
42050723Scg    	if (sb->io_base && sb->drq1 && sb->irq) {
42154462Scg		isa_dma_acquire(rman_get_start(sb->drq1));
42254462Scg		isa_dmainit(rman_get_start(sb->drq1), DSP_BUFFSIZE);
42329415Sjmg
42450723Scg		if (sb->drq2) {
42554462Scg			isa_dma_acquire(rman_get_start(sb->drq2));
42654462Scg			isa_dmainit(rman_get_start(sb->drq2), DSP_BUFFSIZE);
42754462Scg		}
42850723Scg
42950723Scg		return 0;
43050723Scg	} else return ENXIO;
43129415Sjmg}
43229415Sjmg
43354462Scgstatic void
43454462Scgsb16_swap(void *v, int dir)
43529415Sjmg{
43654462Scg	struct sb_info *sb = v;
43754462Scg	int pb = sb->pch.buffer->dl;
43854462Scg	int rb = sb->rch.buffer->dl;
43954462Scg	int pc = sb->pch.buffer->chan;
44054462Scg	int rc = sb->rch.buffer->chan;
44154462Scg	int swp = 0;
44229415Sjmg
44354462Scg	if (!pb && !rb) {
44454462Scg		if (dir == PCMDIR_PLAY && pc < 4) swp = 1;
44554462Scg		else if (dir == PCMDIR_REC && rc < 4) swp = 1;
44654462Scg		if (sb->bd_flags & BD_F_SB16X) swp = !swp;
44754462Scg		if (swp) {
44854462Scg			int t;
44929415Sjmg
45054462Scg			t = sb->pch.buffer->chan;
45154462Scg			sb->pch.buffer->chan = sb->rch.buffer->chan;
45254462Scg			sb->rch.buffer->chan = t;
45354462Scg			sb->pch.buffer->dir = B_WRITE;
45454462Scg			sb->rch.buffer->dir = B_READ;
45531361Sjmg		}
45654462Scg	}
45750723Scg}
45841653Sbrian
45950723Scgstatic int
46050723Scgsb_doattach(device_t dev, struct sb_info *sb)
46129415Sjmg{
46250723Scg    	snddev_info *d = device_get_softc(dev);
46350723Scg    	void *ih;
46450723Scg    	char status[SND_STATUSLEN];
46529415Sjmg
46650723Scg    	if (sb_alloc_resources(sb, dev)) goto no;
46754462Scg    	if (sb_reset_dsp(sb)) goto no;
46854462Scg    	mixer_init(d, &sb_mixer, sb);
46929415Sjmg
47050925Scg	if (sb->bd_flags & BD_F_ESS)
47150925Scg		bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, ess_intr, sb, &ih);
47250925Scg	else
47350925Scg		bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &ih);
47454462Scg    	if ((sb->bd_flags & BD_F_SB16) && !(sb->bd_flags & BD_F_SB16X))
47554462Scg		pcm_setswap(dev, sb16_swap);
47654462Scg    	if (!sb->drq2)
47754462Scg		pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
47829415Sjmg
47950723Scg    	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
48050723Scg			/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
48150723Scg			/*highaddr*/BUS_SPACE_MAXADDR,
48250723Scg			/*filter*/NULL, /*filterarg*/NULL,
48350723Scg			/*maxsize*/DSP_BUFFSIZE, /*nsegments*/1,
48450723Scg			/*maxsegz*/0x3ffff,
48550723Scg			/*flags*/0, &sb->parent_dmat) != 0) {
48650723Scg		device_printf(dev, "unable to create dma tag\n");
48750723Scg		goto no;
48850723Scg    	}
48929415Sjmg
49054462Scg    	snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld",
49150723Scg    	     	rman_get_start(sb->io_base), rman_get_start(sb->irq),
49254462Scg		rman_get_start(sb->drq1));
49354462Scg    	if (sb->drq2) snprintf(status + strlen(status),	SND_STATUSLEN - strlen(status),
49454462Scg		":%ld", rman_get_start(sb->drq2));
49529415Sjmg
49650723Scg    	if (pcm_register(dev, sb, 1, 1)) goto no;
49750925Scg	if (sb->bd_flags & BD_F_ESS) {
49850925Scg		pcm_addchan(dev, PCMDIR_REC, &ess_chantemplate, sb);
49950925Scg		pcm_addchan(dev, PCMDIR_PLAY, &ess_chantemplate, sb);
50050925Scg	} else {
50150925Scg		pcm_addchan(dev, PCMDIR_REC, &sb_chantemplate, sb);
50250925Scg		pcm_addchan(dev, PCMDIR_PLAY, &sb_chantemplate, sb);
50350925Scg	}
50450723Scg    	pcm_setstatus(dev, status);
50529415Sjmg
50650723Scg    	return 0;
50729415Sjmg
50850723Scgno:
50950723Scg    	sb_release_resources(sb, dev);
51050723Scg    	return ENXIO;
51150723Scg}
51229415Sjmg
51350723Scgstatic void
51450723Scgsb_intr(void *arg)
51550723Scg{
51650723Scg    	struct sb_info *sb = (struct sb_info *)arg;
51750723Scg    	int reason = 3, c;
51829415Sjmg
51950723Scg    	/*
52050723Scg     	* SB < 4.0 is half duplex and has only 1 bit for int source,
52150723Scg     	* so we fake it. SB 4.x (SB16) has the int source in a separate
52250723Scg     	* register.
52350723Scg     	* The Vibra16X has separate flags for 8 and 16 bit transfers, but
52450723Scg     	* I have no idea how to tell capture from playback interrupts...
52550723Scg     	*/
52650723Scg    	if (sb->bd_flags & BD_F_SB16) {
52750723Scg    		c = sb_getmixer(sb, IRQ_STAT);
52850723Scg    		/* this tells us if the source is 8-bit or 16-bit dma. We
52950723Scg     		* have to check the io channel to map it to read or write...
53050723Scg     		*/
53150723Scg    		reason = 0;
53250723Scg    		if (c & 1) { /* 8-bit dma */
53350723Scg			if (sb->pch.fmt & AFMT_U8) reason |= 1;
53450723Scg			if (sb->rch.fmt & AFMT_U8) reason |= 2;
53550723Scg    		}
53650723Scg    		if (c & 2) { /* 16-bit dma */
53750723Scg			if (sb->pch.fmt & AFMT_S16_LE) reason |= 1;
53850723Scg			if (sb->rch.fmt & AFMT_S16_LE) reason |= 2;
53950723Scg    		}
54050723Scg    	} else c = 1;
54150723Scg#if 0
54250723Scg    	printf("sb_intr: reason=%d c=0x%x\n", reason, c);
54350723Scg#endif
54450723Scg    	if ((reason & 1) && (sb->pch.buffer->dl > 0))
54550723Scg		chn_intr(sb->pch.channel);
54650723Scg    	if ((reason & 2) && (sb->rch.buffer->dl > 0))
54750723Scg		chn_intr(sb->rch.channel);
54850723Scg    	if (c & 1) sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */
54950723Scg    	if (c & 2) sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */
55050723Scg}
55131361Sjmg
55250925Scgstatic void
55350925Scgess_intr(void *arg)
55450925Scg{
55550925Scg    struct sb_info *sb = (struct sb_info *)arg;
55650925Scg    sb_rd(sb, DSP_DATA_AVAIL); /* int ack */
55750925Scg#ifdef notyet
55850925Scg    /*
55950925Scg     * XXX
56050925Scg     * for full-duplex mode:
56150925Scg     * should read port 0x6 to identify where interrupt came from.
56250925Scg     */
56350925Scg#endif
56450925Scg    /*
56550925Scg     * We are transferring data in DSP normal mode,
56650925Scg     * so clear the dl to indicate the DMA is stopped.
56750925Scg     */
56850925Scg    if (sb->pch.buffer->dl > 0) {
56950925Scg	sb->pch.buffer->dl = -1;
57050925Scg	chn_intr(sb->pch.channel);
57150925Scg    }
57250925Scg    if (sb->rch.buffer->dl > 0) {
57350925Scg	sb->rch.buffer->dl = -1;
57450925Scg	chn_intr(sb->rch.channel);
57550925Scg    }
57650925Scg}
57751768Scg
57850723Scgstatic int
57950723Scgsb_format(struct sb_chinfo *ch, u_int32_t format)
58050723Scg{
58150723Scg	ch->fmt = format;
58250723Scg	return 0;
58329415Sjmg}
58429415Sjmg
58550723Scgstatic int
58650723Scgsb_speed(struct sb_chinfo *ch, int speed)
58729415Sjmg{
58850723Scg    	struct sb_info *sb = ch->parent;
58950723Scg    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
59050723Scg    	int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
59129415Sjmg
59250723Scg    	if (sb->bd_flags & BD_F_SB16) {
59350723Scg		RANGE(speed, 5000, 45000);
59450723Scg		sb_cmd(sb, 0x42 - play);
59550723Scg    		sb_cmd(sb, speed >> 8);
59650723Scg		sb_cmd(sb, speed & 0xff);
59750723Scg    	} else {
59850723Scg		u_char tconst;
59950723Scg		int max_speed = 45000, tmp;
60050723Scg        	u_long flags;
60129415Sjmg
60250723Scg    		/* here enforce speed limitations - max 22050 on sb 1.x*/
60350723Scg    		if (sb->bd_id <= 0x200) max_speed = 22050;
60429415Sjmg
60550723Scg    		/*
60650723Scg     	 	* SB models earlier than SB Pro have low limit for the
60750723Scg     	 	* input rate. Note that this is only for input, but since
60850723Scg     	 	* we do not support separate values for rec & play....
60950723Scg     	 	*/
61050723Scg		if (!play) {
61150723Scg    			if (sb->bd_id <= 0x200) max_speed = 13000;
61250723Scg    			else if (sb->bd_id < 0x300) max_speed = 15000;
61350723Scg		}
61450723Scg    		RANGE(speed, 4000, max_speed);
61550723Scg    		if (stereo) speed <<= 1;
61629415Sjmg
61750723Scg    		/*
61850723Scg     	 	* Now the speed should be valid. Compute the value to be
61950723Scg     	 	* programmed into the board.
62050723Scg     	 	*/
62150723Scg    		if (speed > 22050) { /* High speed mode on 2.01/3.xx */
62250723Scg			tconst = (u_char)
62350723Scg				((65536 - ((256000000 + speed / 2) / speed))
62450723Scg				>> 8);
62550723Scg			sb->bd_flags |= BD_F_HISPEED;
62650723Scg			tmp = 65536 - (tconst << 8);
62750723Scg			speed = (256000000 + tmp / 2) / tmp;
62850723Scg    		} else {
62950723Scg			sb->bd_flags &= ~BD_F_HISPEED;
63050723Scg			tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
63150723Scg			tmp = 256 - tconst;
63250723Scg			speed = (1000000 + tmp / 2) / tmp;
63350723Scg    		}
63450723Scg		flags = spltty();
63550723Scg		sb_cmd1(sb, 0x40, tconst); /* set time constant */
63650723Scg		splx(flags);
63750723Scg    		if (stereo) speed >>= 1;
63850723Scg    	}
63950723Scg    	return speed;
64029415Sjmg}
64129415Sjmg
64250723Scgstatic int
64350723Scgsb_start(struct sb_chinfo *ch)
64450723Scg{
64550723Scg	struct sb_info *sb = ch->parent;
64650723Scg    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
64750723Scg    	int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0;
64850723Scg    	int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
64950723Scg	int l = ch->buffer->dl;
65054462Scg	int dh = ch->buffer->chan > 3;
65154791Scg	u_char i1, i2;
65229415Sjmg
65354791Scg	if (b16 || dh) l >>= 1;
65450723Scg	l--;
65550723Scg	if (play) sb_cmd(sb, DSP_CMD_SPKON);
65650723Scg	if (sb->bd_flags & BD_F_SB16) {
65750723Scg	    i1 = DSP_F16_AUTO | DSP_F16_FIFO_ON |
65850723Scg	         (play? DSP_F16_DAC : DSP_F16_ADC);
65954462Scg	    i1 |= (b16 || dh)? DSP_DMA16 : DSP_DMA8;
66050723Scg	    i2 = (stereo? DSP_F16_STEREO : 0) | (b16? DSP_F16_SIGNED : 0);
66150723Scg	    sb_cmd(sb, i1);
66250723Scg	    sb_cmd2(sb, i2, l);
66350723Scg	} else {
66450723Scg	    if (sb->bd_flags & BD_F_HISPEED) i1 = play? 0x90 : 0x98;
66550723Scg	    else i1 = play? 0x1c : 0x2c;
66650723Scg	    sb_setmixer(sb, 0x0e, stereo? 2 : 0);
66750723Scg	    /* an ESS extension -- they can do 16 bits */
66850723Scg	    if (b16) i1 |= 1;
66950723Scg	    sb_cmd2(sb, 0x48, l);
67050723Scg	    sb_cmd(sb, i1);
67150723Scg	}
67250723Scg	sb->bd_flags |= BD_F_DMARUN << b16;
67350723Scg	return 0;
67450723Scg}
67550723Scg
67650723Scgstatic int
67750723Scgsb_stop(struct sb_chinfo *ch)
67829415Sjmg{
67950723Scg	struct sb_info *sb = ch->parent;
68050723Scg    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
68150723Scg    	int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0;
68229415Sjmg
68350723Scg    	if (sb->bd_flags & BD_F_HISPEED) sb_reset_dsp(sb);
68450723Scg	else {
68550723Scg		sb_cmd(sb, b16? DSP_CMD_DMAPAUSE_16 : DSP_CMD_DMAPAUSE_8);
68650723Scg	       /*
68750723Scg		* The above seems to have the undocumented side effect of
68850723Scg		* blocking the other side as well. If the other
68950723Scg		* channel was active (SB16) I have to re-enable it :(
69050723Scg		*/
69150723Scg		if (sb->bd_flags & (BD_F_DMARUN << (1 - b16)))
69250723Scg			sb_cmd(sb, b16? 0xd4 : 0xd6 );
69329415Sjmg	}
69450723Scg	if (play) sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */
69550723Scg	sb->bd_flags &= ~(BD_F_DMARUN << b16);
69650723Scg	return 0;
69750723Scg}
69829415Sjmg
69950925Scg/* utility functions for ESS */
70050925Scgstatic int
70150925Scgess_format(struct sb_chinfo *ch, u_int32_t format)
70250925Scg{
70350925Scg	struct sb_info *sb = ch->parent;
70450925Scg	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
70553126Sdfr	int b16 = (format & AFMT_S16_LE)? 1 : 0;
70653126Sdfr	int stereo = (format & AFMT_STEREO)? 1 : 0;
70750925Scg	u_char c;
70850925Scg	ch->fmt = format;
70950925Scg	sb_reset_dsp(sb);
71050925Scg	/* normal DMA mode */
71150925Scg	ess_write(sb, 0xb8, play ? 0x00 : 0x0a);
71250925Scg	/* mono/stereo */
71350925Scg	c = (ess_read(sb, 0xa8) & ~0x03) | 1;
71450925Scg	if (!stereo) c++;
71550925Scg	ess_write(sb, 0xa8, c);
71650925Scg	/* demand mode, 4 bytes/xfer */
71750925Scg	ess_write(sb, 0xb9, 2);
71850925Scg	/* setup dac/adc */
71950925Scg	if (play) ess_write(sb, 0xb6, b16? 0x00 : 0x80);
72050925Scg	ess_write(sb, 0xb7, 0x51 | (b16? 0x20 : 0x00));
72150925Scg	ess_write(sb, 0xb7, 0x98 + (b16? 0x24 : 0x00) + (stereo? 0x00 : 0x38));
72250925Scg	/* irq/drq control */
72350925Scg	ess_write(sb, 0xb1, (ess_read(sb, 0xb1) & 0x0f) | 0x50);
72450925Scg	ess_write(sb, 0xb2, (ess_read(sb, 0xb2) & 0x0f) | 0x50);
72550925Scg	return 0;
72650925Scg}
72750925Scg
72850925Scgstatic int
72950925Scgess_speed(struct sb_chinfo *ch, int speed)
73050925Scg{
73150925Scg	struct sb_info *sb = ch->parent;
73250925Scg	int t;
73350925Scg	RANGE (speed, 5000, 49000);
73450925Scg	if (speed > 22000) {
73550925Scg		t = (795500 + speed / 2) / speed;
73650925Scg		speed = (795500 + t / 2) / t;
73753126Sdfr		t = (256 - t ) | 0x80;
73850925Scg	} else {
73950925Scg		t = (397700 + speed / 2) / speed;
74050925Scg		speed = (397700 + t / 2) / t;
74150925Scg		t = 128 - t;
74250925Scg	}
74350925Scg	ess_write(sb, 0xa1, t); /* set time constant */
74450925Scg#if 0
74550925Scg	d->play_speed = d->rec_speed = speed;
74650925Scg	speed = (speed * 9 ) / 20;
74750925Scg#endif
74850925Scg	t = 256 - 7160000 / ((speed * 9 / 20) * 82);
74950925Scg	ess_write(sb, 0xa2, t);
75050925Scg	return speed;
75150925Scg}
75250925Scg
75350925Scgstatic int
75450925Scgess_start(struct sb_chinfo *ch)
75550925Scg{
75650925Scg	struct sb_info *sb = ch->parent;
75750925Scg    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
75850925Scg	short c = - ch->buffer->dl;
75950925Scg	u_char c1;
76050925Scg	/*
76150925Scg	 * clear bit 0 of register B8h
76250925Scg	 */
76350925Scg#if 1
76450925Scg	c1 = play ? 0x00 : 0x0a;
76550925Scg	ess_write(sb, 0xb8, c1++);
76650925Scg#else
76750925Scg	c1 = ess_read(sb, 0xb8) & 0xfe;
76850925Scg	ess_write(sb, 0xb8, c1++);
76950925Scg#endif
77050925Scg	/*
77150925Scg	 * update ESS Transfer Count Register
77250925Scg	 */
77350925Scg	ess_write(sb, 0xa4, (u_char)((u_short)c & 0xff));
77450925Scg	ess_write(sb, 0xa5, (u_char)(((u_short)c >> 8) & 0xff));
77550925Scg	/*
77650925Scg	 * set bit 0 of register B8h
77750925Scg	 */
77850925Scg	ess_write(sb, 0xb8, c1);
77950925Scg	if (play)
78050925Scg		sb_cmd(sb, DSP_CMD_SPKON);
78150925Scg	return 0;
78250925Scg}
78350925Scg
78450925Scgstatic int
78550925Scgess_stop(struct sb_chinfo *ch)
78650925Scg{
78750925Scg	struct sb_info *sb = ch->parent;
78850925Scg	/*
78950925Scg	 * no need to send a stop command if the DMA has already stopped.
79050925Scg	 */
79150925Scg	if (ch->buffer->dl > 0) {
79250925Scg		sb_cmd(sb, DSP_CMD_DMAPAUSE_8); /* pause dma. */
79350925Scg	}
79450925Scg	return 0;
79550925Scg}
79650925Scg
79750925Scgstatic int
79850925Scgess_abort(struct sb_chinfo *ch)
79950925Scg{
80050925Scg	struct sb_info *sb = ch->parent;
80150925Scg    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
80250925Scg	if (play) sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */
80350925Scg	sb_reset_dsp(sb);
80450925Scg	ess_format(ch, ch->fmt);
80550925Scg	ess_speed(ch, ch->channel->speed);
80650925Scg	return 0;
80750925Scg}
80850925Scg
80950723Scg/* channel interface */
81050723Scgstatic void *
81150723Scgsbchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
81250723Scg{
81350723Scg	struct sb_info *sb = devinfo;
81450723Scg	struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch;
81554791Scg	int dch, dl, dh;
81650723Scg
81750723Scg	ch->parent = sb;
81850723Scg	ch->channel = c;
81950723Scg	ch->buffer = b;
82050723Scg	ch->buffer->bufsize = DSP_BUFFSIZE;
82150723Scg	if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1) return NULL;
82254791Scg	dch = (dir == PCMDIR_PLAY)? 1 : 0;
82354791Scg	if (sb->bd_flags & BD_F_SB16X) dch = !dch;
82454791Scg	dl = rman_get_start(sb->drq1);
82554791Scg	if (sb->drq2) dh = rman_get_start(sb->drq2); else dh = dl;
82654791Scg	ch->buffer->chan = dch? dh : dl;
82750723Scg	return ch;
82829415Sjmg}
82929415Sjmg
83050723Scgstatic int
83150723Scgsbchan_setdir(void *data, int dir)
83229415Sjmg{
83350723Scg	struct sb_chinfo *ch = data;
83450723Scg	ch->dir = dir;
83529415Sjmg	return 0;
83629415Sjmg}
83729415Sjmg
83850723Scgstatic int
83950723Scgsbchan_setformat(void *data, u_int32_t format)
84029415Sjmg{
84150723Scg	struct sb_chinfo *ch = data;
84250723Scg	sb_format(ch, format);
84329415Sjmg	return 0;
84429415Sjmg}
84529415Sjmg
84650723Scgstatic int
84750723Scgsbchan_setspeed(void *data, u_int32_t speed)
84829415Sjmg{
84950723Scg	struct sb_chinfo *ch = data;
85050723Scg	return sb_speed(ch, speed);
85129415Sjmg}
85229415Sjmg
85350723Scgstatic int
85450723Scgsbchan_setblocksize(void *data, u_int32_t blocksize)
85550723Scg{
85650723Scg	return blocksize;
85750723Scg}
85829415Sjmg
85950723Scgstatic int
86050723Scgsbchan_trigger(void *data, int go)
86133474Sscrappy{
86250723Scg	struct sb_chinfo *ch = data;
86350723Scg	buf_isadma(ch->buffer, go);
86450723Scg	if (go == PCMTRIG_START) sb_start(ch); else sb_stop(ch);
86550723Scg	return 0;
86633474Sscrappy}
86733474Sscrappy
86850723Scgstatic int
86950723Scgsbchan_getptr(void *data)
87039899Sluigi{
87150723Scg	struct sb_chinfo *ch = data;
87250723Scg	return buf_isadmaptr(ch->buffer);
87339899Sluigi}
87433474Sscrappy
87550723Scgstatic pcmchan_caps *
87650723Scgsbchan_getcaps(void *data)
87739899Sluigi{
87850723Scg	struct sb_chinfo *ch = data;
87950723Scg	int p = (ch->dir == PCMDIR_PLAY)? 1 : 0;
88054462Scg	if (ch->parent->bd_id < 0x300)
88150723Scg		return p? &sb_playcaps : &sb_reccaps;
88254462Scg	else if (ch->parent->bd_id < 0x400)
88354462Scg		return p? &sbpro_playcaps : &sbpro_reccaps;
88454462Scg	else if (ch->parent->bd_flags & BD_F_SB16X)
88554462Scg		return &sb16x_caps;
88650723Scg	else
88754462Scg		return (ch->buffer->chan >= 4)? &sb16_hcaps : &sb16_lcaps;
88839899Sluigi}
88950925Scg/* channel interface for ESS18xx */
89050925Scg#ifdef notyet
89150925Scgstatic void *
89250925Scgesschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
89350925Scg{
89450925Scg	/* the same as sbchan_init()? */
89550925Scg}
89650925Scg#endif
89733474Sscrappy
89850925Scgstatic int
89950925Scgesschan_setdir(void *data, int dir)
90050925Scg{
90150925Scg	struct sb_chinfo *ch = data;
90250925Scg	ch->dir = dir;
90350925Scg	return 0;
90450925Scg}
90550925Scg
90650925Scgstatic int
90750925Scgesschan_setformat(void *data, u_int32_t format)
90850925Scg{
90950925Scg	struct sb_chinfo *ch = data;
91050925Scg	ess_format(ch, format);
91150925Scg	return 0;
91250925Scg}
91350925Scg
91450925Scgstatic int
91550925Scgesschan_setspeed(void *data, u_int32_t speed)
91650925Scg{
91750925Scg	struct sb_chinfo *ch = data;
91850925Scg	return ess_speed(ch, speed);
91950925Scg}
92050925Scg
92150925Scgstatic int
92250925Scgesschan_setblocksize(void *data, u_int32_t blocksize)
92350925Scg{
92450925Scg	return blocksize;
92550925Scg}
92650925Scg
92750925Scgstatic int
92850925Scgesschan_trigger(void *data, int go)
92950925Scg{
93050925Scg	struct sb_chinfo *ch = data;
93150925Scg	switch (go) {
93250925Scg	case PCMTRIG_START:
93350925Scg		if (!ch->ess_dma_started)
93450925Scg			buf_isadma(ch->buffer, go);
93550925Scg		ch->ess_dma_started = 1;
93650925Scg		ess_start(ch);
93750925Scg		break;
93850925Scg	case PCMTRIG_STOP:
93950925Scg		if (ch->buffer->dl >= 0) {
94050925Scg			buf_isadma(ch->buffer, go);
94150925Scg			ch->ess_dma_started = 0;
94250925Scg			ess_stop(ch);
94350925Scg		}
94450925Scg		break;
94550925Scg	case PCMTRIG_ABORT:
94650925Scg	default:
94750925Scg		ch->ess_dma_started = 0;
94850925Scg		ess_abort(ch);
94950925Scg		buf_isadma(ch->buffer, go);
95050925Scg		break;
95150925Scg	}
95250925Scg	return 0;
95350925Scg}
95450925Scg
95550925Scgstatic int
95650925Scgesschan_getptr(void *data)
95750925Scg{
95850925Scg	struct sb_chinfo *ch = data;
95950925Scg	return buf_isadmaptr(ch->buffer);
96050925Scg}
96150925Scg
96250925Scgstatic pcmchan_caps *
96350925Scgesschan_getcaps(void *data)
96450925Scg{
96550925Scg	struct sb_chinfo *ch = data;
96650925Scg	return (ch->dir == PCMDIR_PLAY)? &ess_playcaps : &ess_reccaps;
96750925Scg}
96850925Scg
96950723Scg/************************************************************/
97039899Sluigi
97129415Sjmgstatic int
97250723Scgsbmix_init(snd_mixer *m)
97329415Sjmg{
97450723Scg    	struct sb_info *sb = mix_getdevinfo(m);
97529415Sjmg
97650723Scg    	switch (sb->bd_flags & BD_F_MIX_MASK) {
97750723Scg    	case BD_F_MIX_CT1345: /* SB 3.0 has 1345 mixer */
97850723Scg		mix_setdevs(m, SBPRO_MIXER_DEVICES);
97950723Scg		mix_setrecdevs(m, SBPRO_RECORDING_DEVICES);
98050723Scg		sb_setmixer(sb, 0, 1); /* reset mixer */
98150723Scg		sb_setmixer(sb, MIC_VOL, 0x6); /* mic volume max */
98250723Scg		sb_setmixer(sb, RECORD_SRC, 0x0); /* mic source */
98350723Scg		sb_setmixer(sb, FM_VOL, 0x0); /* no midi */
98450723Scg		break;
98531361Sjmg
98650723Scg    	case BD_F_MIX_CT1745: /* SB16 mixer ... */
98750723Scg		mix_setdevs(m, SB16_MIXER_DEVICES);
98850723Scg		mix_setrecdevs(m, SB16_RECORDING_DEVICES);
98950723Scg		sb_setmixer(sb, 0x3c, 0x1f); /* make all output active */
99050723Scg		sb_setmixer(sb, 0x3d, 0); /* make all inputs-l off */
99150723Scg		sb_setmixer(sb, 0x3e, 0); /* make all inputs-r off */
99250723Scg    	}
99350723Scg    	return 0;
99450723Scg}
99531361Sjmg
99650723Scgstatic int
99750723Scgsbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
99850723Scg{
99950723Scg    	struct sb_info *sb = mix_getdevinfo(m);
100050723Scg    	int regoffs;
100150723Scg    	u_char   val;
100250723Scg    	mixer_tab *iomap;
100329415Sjmg
100450723Scg    	switch (sb->bd_flags & BD_F_MIX_MASK) {
100550723Scg    	case BD_F_MIX_CT1345:
100653126Sdfr		if (sb->bd_flags & BD_F_ESS)
100753126Sdfr			iomap = &ess_mix;
100853126Sdfr		else
100953126Sdfr			iomap = &sbpro_mix;
101050723Scg		break;
101129415Sjmg
101250723Scg    	case BD_F_MIX_CT1745:
101350723Scg		iomap = &sb16_mix;
101450723Scg		break;
101529415Sjmg
101650723Scg    	default:
101750723Scg        	return -1;
101850723Scg    	/* XXX how about the SG NX Pro, iomap = sgnxpro_mix */
101950723Scg    	}
102053126Sdfr
102153126Sdfr	/* Change left channel */
102250723Scg    	regoffs = (*iomap)[dev][LEFT_CHN].regno;
102353126Sdfr    	if (regoffs != 0) {
102453126Sdfr		val = sb_getmixer(sb, regoffs);
102553126Sdfr		change_bits(iomap, &val, dev, LEFT_CHN, left);
102653126Sdfr		sb_setmixer(sb, regoffs, val);
102753126Sdfr	}
102853126Sdfr
102953126Sdfr	/* Change right channel */
103053126Sdfr	regoffs = (*iomap)[dev][RIGHT_CHN].regno;
103153126Sdfr	if (regoffs != 0) {
103253126Sdfr		val = sb_getmixer(sb, regoffs); /* Read the new one */
103353126Sdfr		change_bits(iomap, &val, dev, RIGHT_CHN, right);
103453126Sdfr		sb_setmixer(sb, regoffs, val);
103553126Sdfr	} else
103653126Sdfr		right = left;
103753126Sdfr
103850723Scg    	return left | (right << 8);
103929415Sjmg}
104029415Sjmg
104150723Scgstatic int
104250723Scgsbmix_setrecsrc(snd_mixer *m, u_int32_t src)
104329415Sjmg{
104450723Scg    	struct sb_info *sb = mix_getdevinfo(m);
104550723Scg    	u_char recdev;
104629415Sjmg
104750723Scg    	switch (sb->bd_flags & BD_F_MIX_MASK) {
104850723Scg    	case BD_F_MIX_CT1345:
104950723Scg		if      (src == SOUND_MASK_LINE) 	recdev = 0x06;
105050723Scg		else if (src == SOUND_MASK_CD) 		recdev = 0x02;
105150723Scg		else { /* default: mic */
105250723Scg	    		src = SOUND_MASK_MIC;
105350723Scg	    		recdev = 0;
105450723Scg		}
105550723Scg		sb_setmixer(sb, RECORD_SRC, recdev |
105650723Scg			    (sb_getmixer(sb, RECORD_SRC) & ~0x07));
105750723Scg		break;
105829415Sjmg
105950723Scg    	case BD_F_MIX_CT1745: /* sb16 */
106050723Scg		recdev = 0;
106150723Scg		if (src & SOUND_MASK_MIC)   recdev |= 0x01; /* mono mic */
106250723Scg		if (src & SOUND_MASK_CD)    recdev |= 0x06; /* l+r cd */
106350723Scg		if (src & SOUND_MASK_LINE)  recdev |= 0x18; /* l+r line */
106450723Scg		if (src & SOUND_MASK_SYNTH) recdev |= 0x60; /* l+r midi */
106550723Scg		sb_setmixer(sb, SB16_IMASK_L, recdev);
106650723Scg		sb_setmixer(sb, SB16_IMASK_R, recdev);
106750723Scg		/*
106850723Scg	 	* since the same volume controls apply to the input and
106950723Scg	 	* output sections, the best approach to have a consistent
107050723Scg	 	* behaviour among cards would be to disable the output path
107150723Scg	 	* on devices which are used to record.
107250723Scg	 	* However, since users like to have feedback, we only disable
107350723Scg	 	* the mic -- permanently.
107450723Scg	 	*/
107550723Scg        	sb_setmixer(sb, SB16_OMASK, 0x1f & ~1);
107650723Scg		break;
107751768Scg       	}
107850723Scg    	return src;
107929415Sjmg}
108029415Sjmg
108129415Sjmgstatic int
108253553Stanimurasbsbc_probe(device_t dev)
108353553Stanimura{
108454462Scg    	char buf[64];
108554791Scg	u_int32_t func, ver, r, f;
108653553Stanimura
108753553Stanimura	/* The parent device has already been probed. */
108854462Scg	r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func);
108954462Scg	if (func != SCF_PCM)
109053553Stanimura		return (ENXIO);
109153553Stanimura
109254462Scg	r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
109354791Scg	f = (ver & 0xffff0000) >> 16;
109454462Scg	ver &= 0x0000ffff;
109554791Scg	snprintf(buf, sizeof buf, "SB DSP %d.%02d%s", ver >> 8, ver & 0xff,
109654791Scg		(f & BD_F_ESS)? " (ESS mode)" : "");
109754462Scg    	device_set_desc_copy(dev, buf);
109853553Stanimura
109953553Stanimura	return 0;
110053553Stanimura}
110153553Stanimura
110253553Stanimurastatic int
110353553Stanimurasbsbc_attach(device_t dev)
110453553Stanimura{
110553553Stanimura    	struct sb_info *sb;
110654462Scg	u_int32_t ver;
110753553Stanimura
110853553Stanimura    	sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
110953553Stanimura    	if (!sb) return ENXIO;
111053553Stanimura    	bzero(sb, sizeof *sb);
111153553Stanimura
111254462Scg	BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
111354462Scg	sb->bd_id = ver & 0x0000ffff;
111454462Scg	sb->bd_flags = (ver & 0xffff0000) >> 16;
111554462Scg
111653553Stanimura    	return sb_doattach(dev, sb);
111753553Stanimura}
111853553Stanimura
111953553Stanimurastatic device_method_t sbsbc_methods[] = {
112053553Stanimura	/* Device interface */
112153553Stanimura	DEVMETHOD(device_probe,		sbsbc_probe),
112253553Stanimura	DEVMETHOD(device_attach,	sbsbc_attach),
112353553Stanimura
112453553Stanimura	{ 0, 0 }
112553553Stanimura};
112653553Stanimura
112753553Stanimurastatic driver_t sbsbc_driver = {
112853553Stanimura	"pcm",
112953553Stanimura	sbsbc_methods,
113053553Stanimura	sizeof(snddev_info),
113153553Stanimura};
113253553Stanimura
113353553StanimuraDRIVER_MODULE(sbsbc, sbc, sbsbc_driver, pcm_devclass, 0, 0);
113453553Stanimura
113554462Scg
113654462Scg
1137