sb16.c revision 55706
192512Sphk/*
292512Sphk * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
392512Sphk * Copyright 1997,1998 Luigi Rizzo.
492512Sphk *
592512Sphk * Derived from files in the Voxware 3.5 distribution,
692512Sphk * Copyright by Hannu Savolainen 1994, under the same copyright
792512Sphk * conditions.
892512Sphk * All rights reserved.
992512Sphk *
1092512Sphk * Redistribution and use in source and binary forms, with or without
1192512Sphk * modification, are permitted provided that the following conditions
1292512Sphk * are met:
1392512Sphk * 1. Redistributions of source code must retain the above copyright
1492512Sphk *    notice, this list of conditions and the following disclaimer.
1592512Sphk * 2. Redistributions in binary form must reproduce the above copyright
1692512Sphk *    notice, this list of conditions and the following disclaimer in the
1792512Sphk *    documentation and/or other materials provided with the distribution.
1892512Sphk *
1992512Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2092512Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2192512Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2292512Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2392512Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2492512Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2592512Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2692512Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2792512Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2892512Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2992512Sphk * SUCH DAMAGE.
3092512Sphk *
3192512Sphk * $FreeBSD: head/sys/dev/sound/isa/sb16.c 55706 2000-01-10 03:22:28Z cg $
3292512Sphk */
3392512Sphk
3492512Sphk#include <dev/sound/pcm/sound.h>
3592512Sphk
3692512Sphk#include "sbc.h"
3792512Sphk
3892512Sphk#define __SB_MIXER_C__	/* XXX warning... */
3992512Sphk#include  <dev/sound/isa/sb.h>
4092512Sphk#include  <dev/sound/chip.h>
4192512Sphk
4292512Sphk#define ESS_BUFFSIZE (65536 - 256)
4392512Sphk#define PLAIN_SB16(x) ((((x)->bd_flags) & (BD_F_SB16|BD_F_SB16X)) == BD_F_SB16)
4492512Sphk
4592512Sphk/* channel interface */
4692512Sphkstatic void *sbchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
4792512Sphkstatic int sbchan_setdir(void *data, int dir);
4892512Sphkstatic int sbchan_setformat(void *data, u_int32_t format);
4992512Sphkstatic int sbchan_setspeed(void *data, u_int32_t speed);
5092512Sphkstatic int sbchan_setblocksize(void *data, u_int32_t blocksize);
5192512Sphkstatic int sbchan_trigger(void *data, int go);
5292512Sphkstatic int sbchan_getptr(void *data);
5392512Sphkstatic pcmchan_caps *sbchan_getcaps(void *data);
5492512Sphk
5592512Sphk/* channel interface for ESS */
5692512Sphkstatic void *esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
5792512Sphkstatic int esschan_setdir(void *data, int dir);
5892512Sphkstatic int esschan_setformat(void *data, u_int32_t format);
5992512Sphkstatic int esschan_setspeed(void *data, u_int32_t speed);
6092512Sphkstatic int esschan_setblocksize(void *data, u_int32_t blocksize);
6192512Sphkstatic int esschan_trigger(void *data, int go);
6292512Sphkstatic int esschan_getptr(void *data);
6392512Sphkstatic pcmchan_caps *esschan_getcaps(void *data);
6492512Sphk
6592512Sphkstatic pcmchan_caps sb_playcaps = {
6692512Sphk	4000, 22050,
6792512Sphk	AFMT_U8,
6892512Sphk	AFMT_U8
6992512Sphk};
7092512Sphk
7192512Sphkstatic pcmchan_caps sb_reccaps = {
7292512Sphk	4000, 13000,
7392512Sphk	AFMT_U8,
7492512Sphk	AFMT_U8
7592512Sphk};
7692512Sphk
7792512Sphkstatic pcmchan_caps sbpro_playcaps = {
7892512Sphk	4000, 45000,
7992512Sphk	AFMT_STEREO | AFMT_U8,
8092512Sphk	AFMT_STEREO | AFMT_U8
8192512Sphk};
8292512Sphk
8392512Sphkstatic pcmchan_caps sbpro_reccaps = {
8492512Sphk	4000, 15000,
8592512Sphk	AFMT_STEREO | AFMT_U8,
8692512Sphk	AFMT_STEREO | AFMT_U8
8792512Sphk};
8892512Sphk
8992512Sphkstatic pcmchan_caps sb16_hcaps = {
9092512Sphk	5000, 45000,
9192512Sphk	AFMT_STEREO | AFMT_S16_LE,
9292512Sphk	AFMT_STEREO | AFMT_S16_LE
9392512Sphk};
9492512Sphk
9592512Sphkstatic pcmchan_caps sb16_lcaps = {
9692512Sphk	5000, 45000,
9792512Sphk	AFMT_STEREO | AFMT_U8,
9892512Sphk	AFMT_STEREO | AFMT_U8
9992512Sphk};
10092512Sphk
10192512Sphkstatic pcmchan_caps sb16x_caps = {
10292512Sphk	5000, 49000,
10392512Sphk	AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
10492512Sphk	AFMT_STEREO | AFMT_S16_LE
10592512Sphk};
10692512Sphk
10792512Sphkstatic pcmchan_caps ess_playcaps = {
10892512Sphk	5000, 49000,
10992512Sphk	AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
11092512Sphk	AFMT_STEREO | AFMT_S16_LE
11192512Sphk};
11292512Sphk
11392512Sphkstatic pcmchan_caps ess_reccaps = {
11492512Sphk	5000, 49000,
11592512Sphk	AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
11692512Sphk	AFMT_STEREO | AFMT_S16_LE
11792512Sphk};
11892512Sphk
11992512Sphkstatic pcm_channel sb_chantemplate = {
12092512Sphk	sbchan_init,
12192512Sphk	sbchan_setdir,
12292512Sphk	sbchan_setformat,
12392512Sphk	sbchan_setspeed,
12492512Sphk	sbchan_setblocksize,
12592512Sphk	sbchan_trigger,
12692512Sphk	sbchan_getptr,
12792512Sphk	sbchan_getcaps,
12892512Sphk};
12992512Sphk
13092512Sphkstatic pcm_channel ess_chantemplate = {
13192512Sphk	esschan_init,
13292512Sphk	esschan_setdir,
13392512Sphk	esschan_setformat,
13492512Sphk	esschan_setspeed,
13592512Sphk	esschan_setblocksize,
13692512Sphk	esschan_trigger,
13792512Sphk	esschan_getptr,
13892512Sphk	esschan_getcaps,
13992512Sphk};
14092512Sphk
14192512Sphkstruct sb_info;
14292512Sphk
14392512Sphkstruct sb_chinfo {
14492512Sphk	struct sb_info *parent;
14592512Sphk	pcm_channel *channel;
14692512Sphk	snd_dbuf *buffer;
14792512Sphk	int dir;
14892512Sphk	u_int32_t fmt, spd;
14992512Sphk	int ess_dma_started;
15092512Sphk};
15192512Sphk
15292512Sphkstruct sb_info {
15392512Sphk    	struct resource *io_base;	/* I/O address for the board */
15492512Sphk    	struct resource *irq;
15592512Sphk   	struct resource *drq1;
15692512Sphk    	struct resource *drq2;
15792512Sphk    	bus_dma_tag_t parent_dmat;
15892512Sphk
15992512Sphk    	int bd_id;
16092512Sphk    	u_long bd_flags;       /* board-specific flags */
16192512Sphk    	struct sb_chinfo pch, rch;
16292512Sphk};
16392512Sphk
16492512Sphkstatic int sb_rd(struct sb_info *sb, int reg);
16592512Sphkstatic void sb_wr(struct sb_info *sb, int reg, u_int8_t val);
16692512Sphkstatic int sb_dspready(struct sb_info *sb);
16792512Sphkstatic int sb_cmd(struct sb_info *sb, u_char val);
16892512Sphkstatic int sb_cmd1(struct sb_info *sb, u_char cmd, int val);
16992512Sphkstatic int sb_cmd2(struct sb_info *sb, u_char cmd, int val);
17092512Sphkstatic u_int sb_get_byte(struct sb_info *sb);
17192512Sphkstatic void sb_setmixer(struct sb_info *sb, u_int port, u_int value);
17292512Sphkstatic int sb_getmixer(struct sb_info *sb, u_int port);
17392512Sphkstatic int sb_reset_dsp(struct sb_info *sb);
17492512Sphk
17592512Sphkstatic void sb_intr(void *arg);
17692512Sphkstatic int sb_speed(struct sb_chinfo *ch);
17792512Sphkstatic int sb_start(struct sb_chinfo *ch);
17892512Sphkstatic int sb_stop(struct sb_chinfo *ch);
17992512Sphk
18092512Sphkstatic int ess_write(struct sb_info *sb, u_char reg, int val);
18192512Sphkstatic int ess_read(struct sb_info *sb, u_char reg);
18292512Sphkstatic void ess_intr(void *arg);
18392512Sphkstatic int ess_format(struct sb_chinfo *ch, u_int32_t format);
18492512Sphkstatic int ess_speed(struct sb_chinfo *ch, int speed);
18592512Sphkstatic int ess_start(struct sb_chinfo *ch);
18692512Sphkstatic int ess_stop(struct sb_chinfo *ch);
18792512Sphkstatic int ess_abort(struct sb_chinfo *ch);
18892512Sphk
18992512Sphkstatic int sbmix_init(snd_mixer *m);
19092512Sphkstatic int sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right);
19192512Sphkstatic int sbmix_setrecsrc(snd_mixer *m, u_int32_t src);
19292512Sphk
19392512Sphkstatic snd_mixer sb_mixer = {
19492512Sphk    "SoundBlaster mixer",
19592512Sphk    sbmix_init,
19692512Sphk    sbmix_set,
19792512Sphk    sbmix_setrecsrc,
19892512Sphk};
19992512Sphk
20092512Sphkstatic devclass_t pcm_devclass;
20192512Sphk
20292512Sphk/*
20392512Sphk * Common code for the midi and pcm functions
20492512Sphk *
20592512Sphk * sb_cmd write a single byte to the CMD port.
20692512Sphk * sb_cmd1 write a CMD + 1 byte arg
20792512Sphk * sb_cmd2 write a CMD + 2 byte arg
20892512Sphk * sb_get_byte returns a single byte from the DSP data port
20992512Sphk *
21092512Sphk * ess_write is actually sb_cmd1
21192512Sphk * ess_read access ext. regs via sb_cmd(0xc0, reg) followed by sb_get_byte
21292512Sphk */
21392512Sphk
21492512Sphkstatic int
21592512Sphkport_rd(struct resource *port, int off)
21692512Sphk{
21792512Sphk	return bus_space_read_1(rman_get_bustag(port),
21892512Sphk				rman_get_bushandle(port),
21992512Sphk				off);
22092512Sphk}
22192512Sphk
22292512Sphkstatic void
22392512Sphkport_wr(struct resource *port, int off, u_int8_t data)
22492512Sphk{
22592512Sphk	return bus_space_write_1(rman_get_bustag(port),
22692512Sphk				 rman_get_bushandle(port),
22792512Sphk				 off, data);
22892512Sphk}
22992512Sphk
23092512Sphkstatic int
23192512Sphksb_rd(struct sb_info *sb, int reg)
23292512Sphk{
23392512Sphk	return port_rd(sb->io_base, reg);
23492512Sphk}
23592512Sphk
23692512Sphkstatic void
23792512Sphksb_wr(struct sb_info *sb, int reg, u_int8_t val)
23892512Sphk{
23992512Sphk	port_wr(sb->io_base, reg, val);
24092512Sphk}
24192512Sphk
24292512Sphkstatic int
24392512Sphksb_dspready(struct sb_info *sb)
24492512Sphk{
24592512Sphk	return ((sb_rd(sb, SBDSP_STATUS) & 0x80) == 0);
24692512Sphk}
24792512Sphk
24892512Sphkstatic int
24992512Sphksb_dspwr(struct sb_info *sb, u_char val)
25092512Sphk{
25192512Sphk    	int  i;
25292512Sphk
25392512Sphk    	for (i = 0; i < 1000; i++) {
25492512Sphk		if (sb_dspready(sb)) {
25592512Sphk	    		sb_wr(sb, SBDSP_CMD, val);
25692512Sphk	    		return 1;
25792512Sphk		}
25892512Sphk		if (i > 10) DELAY((i > 100)? 1000 : 10);
25992512Sphk    	}
26092512Sphk    	printf("sb_dspwr(0x%02x) timed out.\n", val);
26192512Sphk    	return 0;
26292512Sphk}
26392512Sphk
26492512Sphkstatic int
26592512Sphksb_cmd(struct sb_info *sb, u_char val)
26692512Sphk{
26792512Sphk#if 0
26892512Sphk	printf("sb_cmd: %x\n", val);
26992512Sphk#endif
27092512Sphk    	return sb_dspwr(sb, val);
27192512Sphk}
27292512Sphk
27392512Sphkstatic int
27492512Sphksb_cmd1(struct sb_info *sb, u_char cmd, int val)
27592512Sphk{
27692512Sphk#if 0
27792512Sphk    	printf("sb_cmd1: %x, %x\n", cmd, val);
27892512Sphk#endif
27992512Sphk    	if (sb_dspwr(sb, cmd)) {
28092512Sphk		return sb_dspwr(sb, val & 0xff);
28192512Sphk    	} else return 0;
28292512Sphk}
28392512Sphk
28492512Sphkstatic int
28592512Sphksb_cmd2(struct sb_info *sb, u_char cmd, int val)
28692512Sphk{
28792512Sphk#if 0
28892512Sphk    	printf("sb_cmd2: %x, %x\n", cmd, val);
28992512Sphk#endif
29092512Sphk    	if (sb_dspwr(sb, cmd)) {
29192512Sphk		return sb_dspwr(sb, val & 0xff) &&
29292512Sphk		       sb_dspwr(sb, (val >> 8) & 0xff);
29392512Sphk    	} else return 0;
29492512Sphk}
29592512Sphk
29692512Sphk/*
29792512Sphk * in the SB, there is a set of indirect "mixer" registers with
29892512Sphk * address at offset 4, data at offset 5
29992512Sphk */
30092512Sphkstatic void
30192512Sphksb_setmixer(struct sb_info *sb, u_int port, u_int value)
30292512Sphk{
30392512Sphk    	u_long   flags;
30492512Sphk
30592512Sphk    	flags = spltty();
30692512Sphk    	sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
30792512Sphk    	DELAY(10);
30892512Sphk    	sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff));
30992512Sphk    	DELAY(10);
31092512Sphk    	splx(flags);
31192512Sphk}
31292512Sphk
31392512Sphkstatic int
31492512Sphksb_getmixer(struct sb_info *sb, u_int port)
31592512Sphk{
31692512Sphk    	int val;
31792512Sphk    	u_long flags;
31892512Sphk
31992512Sphk    	flags = spltty();
32092512Sphk    	sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
32192512Sphk    	DELAY(10);
32292512Sphk    	val = sb_rd(sb, SB_MIX_DATA);
32392512Sphk    	DELAY(10);
32492512Sphk    	splx(flags);
32592512Sphk
32692512Sphk    	return val;
32792512Sphk}
32892512Sphk
32992512Sphkstatic u_int
33092512Sphksb_get_byte(struct sb_info *sb)
33192512Sphk{
33292512Sphk    	int i;
33392512Sphk
33492512Sphk    	for (i = 1000; i > 0; i--) {
33592512Sphk		if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80)
33692512Sphk			return sb_rd(sb, DSP_READ);
33792512Sphk		else
33892512Sphk			DELAY(20);
33992512Sphk    	}
34092512Sphk    	return 0xffff;
34192512Sphk}
34292512Sphk
34392512Sphkstatic int
34492512Sphkess_write(struct sb_info *sb, u_char reg, int val)
34592512Sphk{
34692512Sphk    	return sb_cmd1(sb, reg, val);
34792512Sphk}
34892512Sphk
34992512Sphkstatic int
35092512Sphkess_read(struct sb_info *sb, u_char reg)
35192512Sphk{
35292512Sphk    	return (sb_cmd(sb, 0xc0) && sb_cmd(sb, reg))? sb_get_byte(sb) : 0xffff;
35392512Sphk}
35492512Sphk
35592512Sphkstatic int
35692512Sphksb_reset_dsp(struct sb_info *sb)
35792512Sphk{
35892512Sphk    	sb_wr(sb, SBDSP_RST, 3);
35992512Sphk    	DELAY(100);
36092512Sphk    	sb_wr(sb, SBDSP_RST, 0);
36192512Sphk    	if (sb_get_byte(sb) != 0xAA) {
36292512Sphk        	DEB(printf("sb_reset_dsp 0x%lx failed\n",
36392512Sphk			   rman_get_start(d->io_base)));
36492512Sphk		return ENXIO;	/* Sorry */
36592512Sphk    	}
36692512Sphk    	if (sb->bd_flags & BD_F_ESS)
36792512Sphk		sb_cmd(sb, 0xc6);
36892512Sphk    	return 0;
36992512Sphk}
37092512Sphk
37192512Sphkstatic void
37292512Sphksb_release_resources(struct sb_info *sb, device_t dev)
37392512Sphk{
37492512Sphk    	/* should we bus_teardown_intr here? */
37592512Sphk    	if (sb->irq) {
37692512Sphk		bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq);
37792512Sphk		sb->irq = 0;
37892512Sphk    	}
37992512Sphk    	if (sb->drq1) {
38092512Sphk		bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1);
38192512Sphk		sb->drq1 = 0;
38292512Sphk    	}
38392512Sphk    	if (sb->drq2) {
38492512Sphk		bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2);
38592512Sphk		sb->drq2 = 0;
38692512Sphk    	}
38792512Sphk    	if (sb->io_base) {
38892512Sphk		bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base);
38992512Sphk		sb->io_base = 0;
39092512Sphk    	}
39192512Sphk    	free(sb, M_DEVBUF);
39292512Sphk}
39392512Sphk
39492512Sphkstatic int
39592512Sphksb_alloc_resources(struct sb_info *sb, device_t dev)
39692512Sphk{
39792512Sphk	int rid;
39892512Sphk
39992512Sphk	rid = 0;
40092512Sphk	if (!sb->io_base)
40192512Sphk    		sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
40292512Sphk						 &rid, 0, ~0, 1,
40392512Sphk						 RF_ACTIVE);
40492512Sphk	rid = 0;
40592512Sphk	if (!sb->irq)
40692512Sphk    		sb->irq = bus_alloc_resource(dev, SYS_RES_IRQ,
40792512Sphk					     &rid, 0, ~0, 1,
40892512Sphk					     RF_ACTIVE);
40992512Sphk	rid = 0;
41092512Sphk	if (!sb->drq1)
41192512Sphk    		sb->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ,
41292512Sphk					      &rid, 0, ~0, 1,
41392512Sphk					      RF_ACTIVE);
41492512Sphk	rid = 1;
41592512Sphk	if (!sb->drq2 && !(sb->bd_flags & BD_F_ESS))
41692512Sphk        	sb->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ,
41792512Sphk					      &rid, 0, ~0, 1,
41892512Sphk					      RF_ACTIVE);
41992512Sphk
42092512Sphk    	if (sb->io_base && sb->drq1 && sb->irq) {
42192512Sphk		int bs = (sb->bd_flags & BD_F_ESS)? ESS_BUFFSIZE : DSP_BUFFSIZE;
42292512Sphk
42392512Sphk		isa_dma_acquire(rman_get_start(sb->drq1));
42492512Sphk		isa_dmainit(rman_get_start(sb->drq1), bs);
42592512Sphk
42692512Sphk		if (sb->drq2) {
42792512Sphk			isa_dma_acquire(rman_get_start(sb->drq2));
42892512Sphk			isa_dmainit(rman_get_start(sb->drq2), bs);
42992512Sphk		}
43092512Sphk
43192512Sphk		return 0;
43292512Sphk	} else return ENXIO;
43392512Sphk}
43492512Sphk
43592512Sphkstatic void
43692512Sphksb16_swap(void *v, int dir)
437{
438	struct sb_info *sb = v;
439	int pb = sb->pch.buffer->dl;
440	int rb = sb->rch.buffer->dl;
441	int pc = sb->pch.buffer->chan;
442	int rc = sb->rch.buffer->chan;
443	int swp = 0;
444
445	if (!pb && !rb) {
446		if (dir == PCMDIR_PLAY && pc < 4)
447			swp = 1;
448		else
449			if (dir == PCMDIR_REC && rc < 4)
450				swp = 1;
451		if (sb->bd_flags & BD_F_SB16X)
452			swp = !swp;
453		if (swp) {
454			int t;
455
456			t = sb->pch.buffer->chan;
457			sb->pch.buffer->chan = sb->rch.buffer->chan;
458			sb->rch.buffer->chan = t;
459			sb->pch.buffer->dir = B_WRITE;
460			sb->rch.buffer->dir = B_READ;
461		}
462	}
463}
464
465static int
466sb_doattach(device_t dev, struct sb_info *sb)
467{
468    	snddev_info *d = device_get_softc(dev);
469    	void *ih;
470    	char status[SND_STATUSLEN];
471	int bs = (sb->bd_flags & BD_F_ESS)? ESS_BUFFSIZE : DSP_BUFFSIZE;
472
473    	if (sb_alloc_resources(sb, dev))
474		goto no;
475    	if (sb_reset_dsp(sb))
476		goto no;
477    	mixer_init(d, &sb_mixer, sb);
478
479	if (sb->bd_flags & BD_F_ESS)
480		bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, ess_intr, sb, &ih);
481	else
482		bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &ih);
483    	if ((sb->bd_flags & BD_F_SB16) && !(sb->bd_flags & BD_F_SB16X))
484		pcm_setswap(dev, sb16_swap);
485    	if (!sb->drq2)
486		pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
487
488    	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
489			/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
490			/*highaddr*/BUS_SPACE_MAXADDR,
491			/*filter*/NULL, /*filterarg*/NULL,
492			/*maxsize*/bs, /*nsegments*/1,
493			/*maxsegz*/0x3ffff,
494			/*flags*/0, &sb->parent_dmat) != 0) {
495		device_printf(dev, "unable to create dma tag\n");
496		goto no;
497    	}
498
499    	snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld",
500    	     	rman_get_start(sb->io_base), rman_get_start(sb->irq),
501		rman_get_start(sb->drq1));
502    	if (sb->drq2)
503		snprintf(status + strlen(status), SND_STATUSLEN - strlen(status),
504			":%ld", rman_get_start(sb->drq2));
505
506    	if (pcm_register(dev, sb, 1, 1))
507		goto no;
508	if (sb->bd_flags & BD_F_ESS) {
509		pcm_addchan(dev, PCMDIR_REC, &ess_chantemplate, sb);
510		pcm_addchan(dev, PCMDIR_PLAY, &ess_chantemplate, sb);
511	} else {
512		pcm_addchan(dev, PCMDIR_REC, &sb_chantemplate, sb);
513		pcm_addchan(dev, PCMDIR_PLAY, &sb_chantemplate, sb);
514	}
515    	pcm_setstatus(dev, status);
516
517    	return 0;
518
519no:
520    	sb_release_resources(sb, dev);
521    	return ENXIO;
522}
523
524static void
525sb_intr(void *arg)
526{
527    	struct sb_info *sb = (struct sb_info *)arg;
528    	int reason = 3, c;
529
530    	/*
531     	* SB < 4.0 is half duplex and has only 1 bit for int source,
532     	* so we fake it. SB 4.x (SB16) has the int source in a separate
533     	* register.
534     	* The Vibra16X has separate flags for 8 and 16 bit transfers, but
535     	* I have no idea how to tell capture from playback interrupts...
536     	*/
537    	if (sb->bd_flags & BD_F_SB16) {
538    		c = sb_getmixer(sb, IRQ_STAT);
539    		/* this tells us if the source is 8-bit or 16-bit dma. We
540     		* have to check the io channel to map it to read or write...
541     		*/
542    		reason = 0;
543    		if (c & 1) { /* 8-bit dma */
544			if (sb->pch.fmt & AFMT_U8)
545				reason |= 1;
546			if (sb->rch.fmt & AFMT_U8)
547				reason |= 2;
548    		}
549    		if (c & 2) { /* 16-bit dma */
550			if (sb->pch.fmt & AFMT_S16_LE)
551				reason |= 1;
552			if (sb->rch.fmt & AFMT_S16_LE)
553				reason |= 2;
554    		}
555    	} else c = 1;
556#if 0
557    	printf("sb_intr: reason=%d c=0x%x\n", reason, c);
558#endif
559    	if ((reason & 1) && (sb->pch.buffer->dl > 0))
560		chn_intr(sb->pch.channel);
561    	if ((reason & 2) && (sb->rch.buffer->dl > 0))
562		chn_intr(sb->rch.channel);
563    	if (c & 1)
564		sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */
565    	if (c & 2)
566		sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */
567}
568
569static void
570ess_intr(void *arg)
571{
572    	struct sb_info *sb = (struct sb_info *)arg;
573
574    	sb_rd(sb, DSP_DATA_AVAIL); /* int ack */
575#ifdef notyet
576    	/*
577     	* XXX
578     	* for full-duplex mode:
579     	* should read port 0x6 to identify where interrupt came from.
580     	*/
581#endif
582    	/*
583     	* We are transferring data in DSP normal mode,
584     	* so clear the dl to indicate the DMA is stopped.
585     	*/
586    	if (sb->pch.buffer->dl > 0) {
587		sb->pch.buffer->dl = -1;
588		chn_intr(sb->pch.channel);
589    	}
590    	if (sb->rch.buffer->dl > 0) {
591		sb->rch.buffer->dl = -1;
592		chn_intr(sb->rch.channel);
593    	}
594}
595
596static int
597sb_speed(struct sb_chinfo *ch)
598{
599    	struct sb_info *sb = ch->parent;
600    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
601    	int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
602	int speed = ch->spd;
603
604    	if (sb->bd_flags & BD_F_SB16) {
605		RANGE(speed, 5000, 45000);
606		sb_cmd(sb, 0x42 - play);
607    		sb_cmd(sb, speed >> 8);
608		sb_cmd(sb, speed & 0xff);
609    	} else {
610		u_char tconst;
611		int max_speed = 45000, tmp;
612        	u_long flags;
613
614    		/* here enforce speed limitations - max 22050 on sb 1.x*/
615    		if (sb->bd_id <= 0x200)
616			max_speed = 22050;
617
618    		/*
619     	 	* SB models earlier than SB Pro have low limit for the
620     	 	* input rate. Note that this is only for input, but since
621     	 	* we do not support separate values for rec & play....
622     	 	*/
623		if (!play) {
624    			if (sb->bd_id <= 0x200)
625				max_speed = 13000;
626    			else
627				if (sb->bd_id < 0x300)
628					max_speed = 15000;
629		}
630    		RANGE(speed, 4000, max_speed);
631    		if (stereo)
632			speed <<= 1;
633
634    		/*
635     	 	* Now the speed should be valid. Compute the value to be
636     	 	* programmed into the board.
637     	 	*/
638    		if (speed > 22050) { /* High speed mode on 2.01/3.xx */
639			tconst = (u_char)
640				((65536 - ((256000000 + speed / 2) / speed))
641				>> 8);
642			sb->bd_flags |= BD_F_HISPEED;
643			tmp = 65536 - (tconst << 8);
644			speed = (256000000 + tmp / 2) / tmp;
645    		} else {
646			sb->bd_flags &= ~BD_F_HISPEED;
647			tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
648			tmp = 256 - tconst;
649			speed = (1000000 + tmp / 2) / tmp;
650    		}
651		flags = spltty();
652		sb_cmd1(sb, 0x40, tconst); /* set time constant */
653		splx(flags);
654    		if (stereo)
655			speed >>= 1;
656    	}
657	ch->spd = speed;
658    	return speed;
659}
660
661static int
662sb_start(struct sb_chinfo *ch)
663{
664	struct sb_info *sb = ch->parent;
665    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
666    	int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0;
667    	int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
668	int l = ch->buffer->dl;
669	int dh = ch->buffer->chan > 3;
670	u_char i1, i2;
671
672	if (b16 || dh)
673		l >>= 1;
674	l--;
675
676	if (play)
677		sb_cmd(sb, DSP_CMD_SPKON);
678
679	if (sb->bd_flags & BD_F_SB16) {
680	    	i1 = DSP_F16_AUTO | DSP_F16_FIFO_ON;
681	        i1 |= play? DSP_F16_DAC : DSP_F16_ADC;
682	    	i1 |= (b16 || dh)? DSP_DMA16 : DSP_DMA8;
683	    	i2 = (stereo? DSP_F16_STEREO : 0) | (b16? DSP_F16_SIGNED : 0);
684	    	sb_cmd(sb, i1);
685	    	sb_cmd2(sb, i2, l);
686	} else {
687	    	if (sb->bd_flags & BD_F_HISPEED)
688			i1 = play? 0x90 : 0x98;
689	    	else
690			i1 = play? 0x1c : 0x2c;
691	    	sb_setmixer(sb, 0x0e, stereo? 2 : 0);
692	    	sb_cmd2(sb, 0x48, l);
693       	    	sb_cmd(sb, i1);
694	}
695	sb->bd_flags |= BD_F_DMARUN << b16;
696	return 0;
697}
698
699static int
700sb_stop(struct sb_chinfo *ch)
701{
702	struct sb_info *sb = ch->parent;
703    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
704    	int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0;
705
706    	if (sb->bd_flags & BD_F_HISPEED)
707		sb_reset_dsp(sb);
708	else {
709		sb_cmd(sb, b16? DSP_CMD_DMAPAUSE_16 : DSP_CMD_DMAPAUSE_8);
710	       /*
711		* The above seems to have the undocumented side effect of
712		* blocking the other side as well. If the other
713		* channel was active (SB16) I have to re-enable it :(
714		*/
715		if (sb->bd_flags & (BD_F_DMARUN << (1 - b16)))
716			sb_cmd(sb, b16? 0xd4 : 0xd6 );
717	}
718	if (play)
719		sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */
720	sb->bd_flags &= ~(BD_F_DMARUN << b16);
721	return 0;
722}
723
724/* channel interface */
725static void *
726sbchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
727{
728	struct sb_info *sb = devinfo;
729	struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch;
730	int dch, dl, dh;
731
732	ch->parent = sb;
733	ch->channel = c;
734	ch->buffer = b;
735	ch->buffer->bufsize = DSP_BUFFSIZE;
736	if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1)
737		return NULL;
738	dch = (dir == PCMDIR_PLAY)? 1 : 0;
739	if (sb->bd_flags & BD_F_SB16X)
740		dch = !dch;
741	dl = rman_get_start(sb->drq1);
742	dh = sb->drq2? rman_get_start(sb->drq2) : dl;
743	ch->buffer->chan = dch? dh : dl;
744	return ch;
745}
746
747static int
748sbchan_setdir(void *data, int dir)
749{
750	struct sb_chinfo *ch = data;
751
752	ch->dir = dir;
753	return 0;
754}
755
756static int
757sbchan_setformat(void *data, u_int32_t format)
758{
759	struct sb_chinfo *ch = data;
760
761	ch->fmt = format;
762	return 0;
763}
764
765static int
766sbchan_setspeed(void *data, u_int32_t speed)
767{
768	struct sb_chinfo *ch = data;
769
770	ch->spd = speed;
771	return sb_speed(ch);
772}
773
774static int
775sbchan_setblocksize(void *data, u_int32_t blocksize)
776{
777	return blocksize;
778}
779
780static int
781sbchan_trigger(void *data, int go)
782{
783	struct sb_chinfo *ch = data;
784
785	if (go == PCMTRIG_EMLDMAWR)
786		return 0;
787
788	buf_isadma(ch->buffer, go);
789	if (go == PCMTRIG_START)
790		sb_start(ch);
791	else
792		sb_stop(ch);
793	return 0;
794}
795
796static int
797sbchan_getptr(void *data)
798{
799	struct sb_chinfo *ch = data;
800
801	return buf_isadmaptr(ch->buffer);
802}
803
804static pcmchan_caps *
805sbchan_getcaps(void *data)
806{
807	struct sb_chinfo *ch = data;
808	int p = (ch->dir == PCMDIR_PLAY)? 1 : 0;
809
810	if (ch->parent->bd_id < 0x300)
811		return p? &sb_playcaps : &sb_reccaps;
812	else if (ch->parent->bd_id < 0x400)
813		return p? &sbpro_playcaps : &sbpro_reccaps;
814	else if (ch->parent->bd_flags & BD_F_SB16X)
815		return &sb16x_caps;
816	else
817		return (ch->buffer->chan >= 4)? &sb16_hcaps : &sb16_lcaps;
818}
819
820/* utility functions for ESS */
821static int
822ess_format(struct sb_chinfo *ch, u_int32_t format)
823{
824	struct sb_info *sb = ch->parent;
825	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
826	int b16 = (format & AFMT_S16_LE)? 1 : 0;
827	int stereo = (format & AFMT_STEREO)? 1 : 0;
828	u_char c;
829
830	ch->fmt = format;
831	sb_reset_dsp(sb);
832	/* auto-init DMA mode */
833	ess_write(sb, 0xb8, play ? 0x04 : 0x0e);
834	/* mono/stereo */
835	c = (ess_read(sb, 0xa8) & ~0x03) | 1;
836	if (!stereo)
837		c++;
838	ess_write(sb, 0xa8, c);
839	/* demand mode, 4 bytes/xfer */
840	ess_write(sb, 0xb9, 2);
841	/* setup dac/adc */
842	if (play)
843		ess_write(sb, 0xb6, b16? 0x00 : 0x80);
844	ess_write(sb, 0xb7, 0x51 | (b16? 0x20 : 0x00));
845	ess_write(sb, 0xb7, 0x98 + (b16? 0x24 : 0x00) + (stereo? 0x00 : 0x38));
846	/* irq/drq control */
847	ess_write(sb, 0xb1, (ess_read(sb, 0xb1) & 0x0f) | 0x50);
848	ess_write(sb, 0xb2, (ess_read(sb, 0xb2) & 0x0f) | 0x50);
849	return 0;
850}
851
852static int
853ess_speed(struct sb_chinfo *ch, int speed)
854{
855	struct sb_info *sb = ch->parent;
856	int t;
857
858	RANGE (speed, 5000, 49000);
859	if (speed > 22000) {
860		t = (795500 + speed / 2) / speed;
861		speed = (795500 + t / 2) / t;
862		t = (256 - t ) | 0x80;
863	} else {
864		t = (397700 + speed / 2) / speed;
865		speed = (397700 + t / 2) / t;
866		t = 128 - t;
867	}
868	ess_write(sb, 0xa1, t); /* set time constant */
869#if 0
870	d->play_speed = d->rec_speed = speed;
871	speed = (speed * 9 ) / 20;
872#endif
873	t = 256 - 7160000 / ((speed * 9 / 20) * 82);
874	ess_write(sb, 0xa2, t);
875	return speed;
876}
877
878static int
879ess_start(struct sb_chinfo *ch)
880{
881	struct sb_info *sb = ch->parent;
882    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
883	short c = - ch->buffer->dl;
884	u_char c1;
885
886	/*
887	 * clear bit 0 of register B8h
888	 */
889#if 1
890	c1 = play ? 0x04 : 0x0e;
891	ess_write(sb, 0xb8, c1++);
892#else
893	c1 = ess_read(sb, 0xb8) & 0xfe;
894	ess_write(sb, 0xb8, c1++);
895#endif
896	/*
897	 * update ESS Transfer Count Register
898	 */
899	ess_write(sb, 0xa4, (u_char)((u_short)c & 0xff));
900	ess_write(sb, 0xa5, (u_char)(((u_short)c >> 8) & 0xff));
901	/*
902	 * set bit 0 of register B8h
903	 */
904	ess_write(sb, 0xb8, c1);
905	if (play)
906		sb_cmd(sb, DSP_CMD_SPKON);
907	return 0;
908}
909
910static int
911ess_stop(struct sb_chinfo *ch)
912{
913	struct sb_info *sb = ch->parent;
914	/*
915	 * no need to send a stop command if the DMA has already stopped.
916	 */
917	if (ch->buffer->dl > 0) {
918		sb_cmd(sb, DSP_CMD_DMAPAUSE_8); /* pause dma. */
919	}
920	return 0;
921}
922
923static int
924ess_abort(struct sb_chinfo *ch)
925{
926	struct sb_info *sb = ch->parent;
927    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
928
929	if (play)
930		sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */
931	sb_reset_dsp(sb);
932	ess_format(ch, ch->fmt);
933	ess_speed(ch, ch->channel->speed);
934	return 0;
935}
936
937/* channel interface for ESS18xx */
938static void *
939esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
940{
941	struct sb_info *sb = devinfo;
942	struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch;
943
944	ch->parent = sb;
945	ch->channel = c;
946	ch->buffer = b;
947	ch->buffer->bufsize = ESS_BUFFSIZE;
948	if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1)
949		return NULL;
950	ch->buffer->chan = rman_get_start(sb->drq1);
951	return ch;
952}
953
954static int
955esschan_setdir(void *data, int dir)
956{
957	struct sb_chinfo *ch = data;
958
959	ch->dir = dir;
960	return 0;
961}
962
963static int
964esschan_setformat(void *data, u_int32_t format)
965{
966	struct sb_chinfo *ch = data;
967
968	ess_format(ch, format);
969	return 0;
970}
971
972static int
973esschan_setspeed(void *data, u_int32_t speed)
974{
975	struct sb_chinfo *ch = data;
976
977	return ess_speed(ch, speed);
978}
979
980static int
981esschan_setblocksize(void *data, u_int32_t blocksize)
982{
983	return blocksize;
984}
985
986static int
987esschan_trigger(void *data, int go)
988{
989	struct sb_chinfo *ch = data;
990
991	if (go == PCMTRIG_EMLDMAWR)
992		return 0;
993	switch (go) {
994	case PCMTRIG_START:
995		if (!ch->ess_dma_started)
996			buf_isadma(ch->buffer, go);
997		ch->ess_dma_started = 1;
998		ess_start(ch);
999		break;
1000	case PCMTRIG_STOP:
1001		if (ch->buffer->dl >= 0) {
1002			buf_isadma(ch->buffer, go);
1003			ch->ess_dma_started = 0;
1004			ess_stop(ch);
1005		}
1006		break;
1007	case PCMTRIG_ABORT:
1008	default:
1009		ch->ess_dma_started = 0;
1010		ess_abort(ch);
1011		buf_isadma(ch->buffer, go);
1012		break;
1013	}
1014	return 0;
1015}
1016
1017static int
1018esschan_getptr(void *data)
1019{
1020	struct sb_chinfo *ch = data;
1021
1022	return buf_isadmaptr(ch->buffer);
1023}
1024
1025static pcmchan_caps *
1026esschan_getcaps(void *data)
1027{
1028	struct sb_chinfo *ch = data;
1029
1030	return (ch->dir == PCMDIR_PLAY)? &ess_playcaps : &ess_reccaps;
1031}
1032
1033/************************************************************/
1034
1035static int
1036sbmix_init(snd_mixer *m)
1037{
1038    	struct sb_info *sb = mix_getdevinfo(m);
1039
1040    	switch (sb->bd_flags & BD_F_MIX_MASK) {
1041    	case BD_F_MIX_CT1345: /* SB 3.0 has 1345 mixer */
1042		mix_setdevs(m, SBPRO_MIXER_DEVICES);
1043		mix_setrecdevs(m, SBPRO_RECORDING_DEVICES);
1044		sb_setmixer(sb, 0, 1); /* reset mixer */
1045		if (!(sb->bd_flags & BD_F_ESS))
1046			sb_setmixer(sb, MIC_VOL, 0x6); /* mic volume max */
1047		sb_setmixer(sb, RECORD_SRC, 0x0); /* mic source */
1048		sb_setmixer(sb, FM_VOL, 0x0); /* no midi */
1049		break;
1050
1051    	case BD_F_MIX_CT1745: /* SB16 mixer ... */
1052		mix_setdevs(m, SB16_MIXER_DEVICES);
1053		mix_setrecdevs(m, SB16_RECORDING_DEVICES);
1054		sb_setmixer(sb, 0x3c, 0x1f); /* make all output active */
1055		sb_setmixer(sb, 0x3d, 0); /* make all inputs-l off */
1056		sb_setmixer(sb, 0x3e, 0); /* make all inputs-r off */
1057    	}
1058    	return 0;
1059}
1060
1061static int
1062sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1063{
1064    	struct sb_info *sb = mix_getdevinfo(m);
1065    	int regoffs;
1066    	u_char   val;
1067    	mixer_tab *iomap;
1068
1069    	switch (sb->bd_flags & BD_F_MIX_MASK) {
1070    	case BD_F_MIX_CT1345:
1071		if (sb->bd_flags & BD_F_ESS)
1072			iomap = &ess_mix;
1073		else
1074			iomap = &sbpro_mix;
1075		break;
1076
1077    	case BD_F_MIX_CT1745:
1078		iomap = &sb16_mix;
1079		break;
1080
1081    	default:
1082        	return -1;
1083    	}
1084
1085	/* Change left channel */
1086    	regoffs = (*iomap)[dev][LEFT_CHN].regno;
1087    	if (regoffs != 0) {
1088		val = sb_getmixer(sb, regoffs);
1089		change_bits(iomap, &val, dev, LEFT_CHN, left);
1090		sb_setmixer(sb, regoffs, val);
1091	}
1092
1093	/* Change right channel */
1094	regoffs = (*iomap)[dev][RIGHT_CHN].regno;
1095	if (regoffs != 0) {
1096		val = sb_getmixer(sb, regoffs); /* Read the new one */
1097		change_bits(iomap, &val, dev, RIGHT_CHN, right);
1098		sb_setmixer(sb, regoffs, val);
1099	} else
1100		right = left;
1101
1102    	return left | (right << 8);
1103}
1104
1105static int
1106sbmix_setrecsrc(snd_mixer *m, u_int32_t src)
1107{
1108    	struct sb_info *sb = mix_getdevinfo(m);
1109    	u_char recdev;
1110
1111    	switch (sb->bd_flags & BD_F_MIX_MASK) {
1112    	case BD_F_MIX_CT1345:
1113		if      (src == SOUND_MASK_LINE)
1114			recdev = 0x06;
1115		else if (src == SOUND_MASK_CD)
1116			recdev = 0x02;
1117		else { /* default: mic */
1118	    		src = SOUND_MASK_MIC;
1119	    		recdev = 0;
1120		}
1121		sb_setmixer(sb, RECORD_SRC, recdev |
1122			    (sb_getmixer(sb, RECORD_SRC) & ~0x07));
1123		break;
1124
1125    	case BD_F_MIX_CT1745: /* sb16 */
1126		recdev = 0;
1127		if (src & SOUND_MASK_MIC)
1128			recdev |= 0x01; /* mono mic */
1129		if (src & SOUND_MASK_CD)
1130			recdev |= 0x06; /* l+r cd */
1131		if (src & SOUND_MASK_LINE)
1132			recdev |= 0x18; /* l+r line */
1133		if (src & SOUND_MASK_SYNTH)
1134			recdev |= 0x60; /* l+r midi */
1135		sb_setmixer(sb, SB16_IMASK_L, recdev);
1136		sb_setmixer(sb, SB16_IMASK_R, recdev);
1137		/*
1138	 	* since the same volume controls apply to the input and
1139	 	* output sections, the best approach to have a consistent
1140	 	* behaviour among cards would be to disable the output path
1141	 	* on devices which are used to record.
1142	 	* However, since users like to have feedback, we only disable
1143	 	* the mic -- permanently.
1144	 	*/
1145        	sb_setmixer(sb, SB16_OMASK, 0x1f & ~1);
1146		break;
1147       	}
1148    	return src;
1149}
1150
1151static int
1152sbsbc_probe(device_t dev)
1153{
1154    	char buf[64];
1155	uintptr_t func, ver, r, f;
1156
1157	/* The parent device has already been probed. */
1158	r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func);
1159	if (func != SCF_PCM)
1160		return (ENXIO);
1161
1162	r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
1163	f = (ver & 0xffff0000) >> 16;
1164	ver &= 0x0000ffff;
1165	snprintf(buf, sizeof buf, "SB DSP %d.%02d%s%s", (int) ver >> 8, (int) ver & 0xff,
1166		(f & BD_F_ESS)? " (ESS mode)" : "",
1167		(f & BD_F_SB16X)? " (ViBRA16X)" : "");
1168    	device_set_desc_copy(dev, buf);
1169
1170	return 0;
1171}
1172
1173static int
1174sbsbc_attach(device_t dev)
1175{
1176    	struct sb_info *sb;
1177	uintptr_t ver;
1178
1179    	sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
1180    	if (!sb)
1181		return ENXIO;
1182    	bzero(sb, sizeof *sb);
1183
1184	BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
1185	sb->bd_id = ver & 0x0000ffff;
1186	sb->bd_flags = (ver & 0xffff0000) >> 16;
1187
1188    	return sb_doattach(dev, sb);
1189}
1190
1191static device_method_t sbsbc_methods[] = {
1192	/* Device interface */
1193	DEVMETHOD(device_probe,		sbsbc_probe),
1194	DEVMETHOD(device_attach,	sbsbc_attach),
1195
1196	{ 0, 0 }
1197};
1198
1199static driver_t sbsbc_driver = {
1200	"pcm",
1201	sbsbc_methods,
1202	sizeof(snddev_info),
1203};
1204
1205DRIVER_MODULE(sbsbc, sbc, sbsbc_driver, pcm_devclass, 0, 0);
1206
1207
1208
1209