sb16.c revision 30869
129415Sjmg/*
229415Sjmg * sound/sb_dsp.c
329415Sjmg *
429415Sjmg * driver for the SoundBlaster and clones.
529415Sjmg *
629415Sjmg * Copyright 1997 Luigi Rizzo.
729415Sjmg *
829415Sjmg * Derived from files in the Voxware 3.5 distribution,
929415Sjmg * Copyright by Hannu Savolainen 1994, under the same copyright
1029415Sjmg * conditions.
1129415Sjmg *
1229415Sjmg * Redistribution and use in source and binary forms, with or without
1329415Sjmg * modification, are permitted provided that the following conditions
1430869Sjmg * are met:
1530869Sjmg * 1. Redistributions of source code must retain the above copyright
1630869Sjmg *    notice, this list of conditions and the following disclaimer.
1730869Sjmg * 2. Redistributions in binary form must reproduce the above copyright
1830869Sjmg *    notice, this list of conditions and the following disclaimer in
1930869Sjmg *    the documentation and/or other materials provided with the
2030869Sjmg *    distribution.
2130869Sjmg *
2229415Sjmg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
2329415Sjmg * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2429415Sjmg * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
2529415Sjmg * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
2629415Sjmg * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2729415Sjmg * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2829415Sjmg * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
2929415Sjmg * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
3029415Sjmg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3129415Sjmg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3229415Sjmg * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3329415Sjmg * POSSIBILITY OF SUCH DAMAGE.
3429415Sjmg *
3529415Sjmg */
3629415Sjmg
3729415Sjmg/*
3829415Sjmg * use this as a template file for board-specific drivers.
3929415Sjmg * The next two lines (and the final #endif) are in all drivers:
4029415Sjmg */
4129415Sjmg
4229415Sjmg#include <i386/isa/snd/sound.h>
4329415Sjmg#if NPCM > 0
4429415Sjmg
4529415Sjmg/*
4629415Sjmg * Begin with the board-specific include files...
4729415Sjmg */
4829415Sjmg
4929415Sjmg#define __SB_MIXER_C__	/* XXX warning... */
5029415Sjmg#include  <i386/isa/snd/sbcard.h>
5129415Sjmg
5229415Sjmg/*
5329415Sjmg * then prototypes of functions which go in the snddev_info
5429415Sjmg * (usually static, unless they are shared by other modules)...
5529415Sjmg */
5629415Sjmg
5729415Sjmgstatic	int sb_probe(struct isa_device *dev);
5829415Sjmgstatic	int sb_attach(struct isa_device *dev);
5929415Sjmg
6029415Sjmgstatic	d_open_t	sb_dsp_open;
6129415Sjmgstatic	d_close_t	sb_dsp_close;
6229415Sjmgstatic	d_ioctl_t	sb_dsp_ioctl;
6329415Sjmgstatic	irq_proc_t	sbintr;
6429415Sjmgstatic	snd_callback_t	sb_callback;
6529415Sjmg
6629415Sjmg/*
6729415Sjmg * and prototypes for other private functions defined in this module.
6829415Sjmg */
6929415Sjmg
7029415Sjmgstatic	void sb_dsp_init(snddev_info *d, struct isa_device *dev);
7129415Sjmgstatic	void sb_mix_init(snddev_info *d);
7229415Sjmgstatic int sb_mixer_set(snddev_info *d, int dev, int value);
7329415Sjmgstatic int dsp_speed(snddev_info *d);
7429415Sjmgstatic void sb_mixer_reset(snddev_info *d);
7529415Sjmg
7629415Sjmgu_int sb_get_byte(int io_base);
7729415Sjmg
7829415Sjmg/*
7929415Sjmg * Then put here the descriptors for the various boards supported
8029415Sjmg * by this module, properly initialized.
8129415Sjmg */
8229415Sjmg
8329415Sjmgsnddev_info sb_op_desc = {
8429415Sjmg    "basic soundblaster",
8529415Sjmg
8629415Sjmg    SNDCARD_SB,
8729415Sjmg    sb_probe,
8829415Sjmg    sb_attach,
8929415Sjmg
9029415Sjmg    sb_dsp_open,
9129415Sjmg    sb_dsp_close /* sb_close */,
9229415Sjmg    NULL /* use generic sndread */,
9329415Sjmg    NULL /* use generic sndwrite */,
9429415Sjmg    sb_dsp_ioctl,
9529565Sjmg    sndpoll,
9629415Sjmg
9729415Sjmg    sbintr,
9829415Sjmg    sb_callback,
9929415Sjmg
10029415Sjmg    DSP_BUFFSIZE,	/* bufsize */
10129415Sjmg
10229415Sjmg    AFMT_STEREO | AFMT_U8,		/* audio format */
10329415Sjmg
10429415Sjmg} ;
10529415Sjmg
10629415Sjmg/*
10729415Sjmg * Then the file continues with the body of all functions
10829415Sjmg * directly referenced in the descriptor.
10929415Sjmg */
11029415Sjmg
11129415Sjmg/*
11229415Sjmg * the probe routine for the SoundBlaster only consists in
11329415Sjmg * resetting the dsp and testing if it is there.
11429415Sjmg * Version detection etc. will be done at attach time.
11529415Sjmg *
11630869Sjmg * Remember, ISA probe routines are supposed to return the
11729415Sjmg * size of io space used.
11829415Sjmg */
11929415Sjmg
12029415Sjmgstatic int
12129415Sjmgsb_probe(struct isa_device *dev)
12229415Sjmg{
12329565Sjmg    bzero(&pcm_info[dev->id_unit], sizeof(pcm_info[dev->id_unit]) );
12429415Sjmg    if (dev->id_iobase == -1) {
12529415Sjmg	dev->id_iobase = 0x220;
12629415Sjmg	printf("sb_probe: no address supplied, try defaults (0x220,0x240)\n");
12729415Sjmg        if (snd_conflict(dev->id_iobase))
12829415Sjmg	    dev->id_iobase = 0x240;
12929415Sjmg    }
13029415Sjmg    if (snd_conflict(dev->id_iobase))
13129415Sjmg	return 0 ;
13229415Sjmg
13329415Sjmg    if (sb_reset_dsp(dev->id_iobase))
13429415Sjmg	return 16 ; /* the SB uses 16 registers... */
13529415Sjmg    else
13629415Sjmg	return 0;
13729415Sjmg}
13829415Sjmg
13929415Sjmgstatic int
14029415Sjmgsb_attach(struct isa_device *dev)
14129415Sjmg{
14229415Sjmg    snddev_info *d = &pcm_info[dev->id_unit] ;
14329415Sjmg
14430869Sjmg    dev->id_alive = 16 ; /* number of io ports */
14530869Sjmg    /* should be already set but just in case... */
14629415Sjmg    sb_dsp_init(d, dev);
14729415Sjmg    return 0 ;
14829415Sjmg}
14929415Sjmg
15029415Sjmg/*
15129415Sjmg * here are the main routines from the switches.
15229415Sjmg */
15329415Sjmg
15429415Sjmgstatic int
15529415Sjmgsb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
15629415Sjmg{
15729415Sjmg    snddev_info *d;
15829415Sjmg    int unit ;
15929415Sjmg
16029415Sjmg    dev = minor(dev);
16129415Sjmg    unit = dev >> 4 ;
16229415Sjmg    d = &pcm_info[unit] ;
16329415Sjmg
16429415Sjmg    DEB(printf("<%s>%d : open\n", d->name, unit));
16529415Sjmg
16629415Sjmg    if (d->flags & SND_F_BUSY) {
16729415Sjmg	printf("<%s>%d open: device busy\n", d->name, unit);
16829415Sjmg	return EBUSY ;
16929415Sjmg    }
17029415Sjmg
17129415Sjmg    d->wsel.si_pid = 0;
17229415Sjmg    d->wsel.si_flags = 0;
17329415Sjmg
17429415Sjmg    d->rsel.si_pid = 0;
17529415Sjmg    d->rsel.si_flags = 0;
17629415Sjmg
17729415Sjmg    d->flags = 0 ;
17829415Sjmg    d->bd_flags &= ~BD_F_HISPEED ;
17929415Sjmg
18029415Sjmg    switch ( dev & 0xf ) {
18129415Sjmg    case SND_DEV_DSP16 :
18229415Sjmg	if ((d->audio_fmt & AFMT_S16_LE) == 0) {
18329415Sjmg	    printf("sorry, 16-bit not supported on SB %d.%02d\n",
18429415Sjmg		(d->bd_id >>8) & 0xff, d->bd_id & 0xff);
18529415Sjmg	    return ENXIO;
18629415Sjmg	}
18729415Sjmg	d->play_fmt = d->rec_fmt = AFMT_S16_LE ;
18829415Sjmg	break;
18929415Sjmg    case SND_DEV_AUDIO :
19029415Sjmg	d->play_fmt = d->rec_fmt = AFMT_MU_LAW ;
19129415Sjmg	break ;
19229415Sjmg    case SND_DEV_DSP :
19329415Sjmg	d->play_fmt = d->rec_fmt = AFMT_U8 ;
19429415Sjmg	break ;
19529415Sjmg    }
19629415Sjmg
19729415Sjmg    d->flags |= SND_F_BUSY ;
19829415Sjmg    d->play_speed = d->rec_speed = DSP_DEFAULT_SPEED ;
19929415Sjmg
20029415Sjmg    if (flags & O_NONBLOCK)
20129415Sjmg	d->flags |= SND_F_NBIO ;
20229415Sjmg
20329415Sjmg    sb_reset_dsp(d->io_base);
20429415Sjmg    ask_init(d);
20529415Sjmg
20629415Sjmg    return 0;
20729415Sjmg}
20829415Sjmg
20929415Sjmgstatic int
21029415Sjmgsb_dsp_close(dev_t dev, int flags, int mode, struct proc * p)
21129415Sjmg{
21229415Sjmg    int unit;
21329415Sjmg    snddev_info *d;
21429415Sjmg    u_long s;
21529415Sjmg
21629415Sjmg    dev = minor(dev);
21729415Sjmg    unit = dev >> 4 ;
21829415Sjmg    d = &pcm_info[unit] ;
21929415Sjmg
22029415Sjmg    s = spltty();
22129415Sjmg    d->flags |= SND_F_CLOSING ;
22229415Sjmg    splx(s);
22329415Sjmg    snd_flush(d);
22429415Sjmg
22529415Sjmg    sb_cmd(d->io_base, DSP_CMD_SPKOFF ); /* XXX useless ? */
22629415Sjmg
22729415Sjmg    d->flags = 0 ;
22829415Sjmg    return 0 ;
22929415Sjmg}
23029415Sjmg
23129415Sjmgstatic int
23229415Sjmgsb_dsp_ioctl(dev_t dev, int cmd, caddr_t arg, int mode, struct proc * p)
23329415Sjmg{
23429415Sjmg    int unit;
23529415Sjmg    snddev_info *d;
23629415Sjmg
23729415Sjmg    dev = minor(dev);
23829415Sjmg    unit = dev >> 4 ;
23929415Sjmg    d = &pcm_info[unit] ;
24029415Sjmg
24129415Sjmg    /*
24229415Sjmg     * handle mixer calls first. Reads are in the default handler,
24329415Sjmg     * so do not bother about them.
24429415Sjmg     */
24529415Sjmg    if ( (cmd & MIXER_WRITE(0)) == MIXER_WRITE(0) )
24629415Sjmg	return sb_mixer_set(d, cmd & 0xff, *(int *)arg) ;
24729415Sjmg
24829415Sjmg    /*
24929415Sjmg     * for the remaining functions, use the default handler.
25029415Sjmg     */
25129415Sjmg
25229415Sjmg    return ENOSYS ;
25329415Sjmg}
25429415Sjmg
25529415Sjmgstatic void
25629415Sjmgsbintr(int unit)
25729415Sjmg{
25829415Sjmg    snddev_info *d = &pcm_info[unit];
25929415Sjmg    int reason = 3, c=1, io_base = d->io_base;
26029415Sjmg
26129565Sjmg    DEB(printf("got sbintr for unit %d, flags 0x%08lx\n", unit, d->flags));
26229415Sjmg
26329415Sjmg    /*
26429415Sjmg     * SB < 4.0 is half duplex and has only 1 bit for int source,
26529415Sjmg     * so we fake it. SB 4.x (SB16) has the int source in a separate
26629415Sjmg     * register.
26729415Sjmg     */
26829415Sjmgagain:
26929415Sjmg    if (d->bd_flags & BD_F_SB16) {
27029415Sjmg	c = sb_getmixer(io_base, IRQ_STAT);
27129415Sjmg	/* this tells us if the source is 8-bit or 16-bit dma. We
27229415Sjmg	 * have to check the io channel to map it to read or write...
27329415Sjmg	 */
27429415Sjmg	reason = 0 ;
27529415Sjmg	if ( c & 1 ) { /* 8-bit dma */
27629415Sjmg	    if (d->dma1 < 4)
27729415Sjmg		reason |= 1;
27829415Sjmg	    if (d->dma2 < 4)
27929415Sjmg		reason |= 2;
28029415Sjmg	}
28129415Sjmg	if ( c & 2 ) { /* 16-bit dma */
28229415Sjmg	    if (d->dma1 >= 4)
28329415Sjmg		reason |= 1;
28429415Sjmg	    if (d->dma2 >= 4)
28529415Sjmg		reason |= 2;
28629415Sjmg	}
28729415Sjmg    }
28830869Sjmg    /* XXX previous location of ack... */
28930869Sjmg    DEB(printf("sbintr, flags 0x%08lx reason %d\n", d->flags, reason));
29030869Sjmg    if ( d->dbuf_out.dl && (reason & 1) )
29130869Sjmg	dsp_wrintr(d);
29230869Sjmg    if ( d->dbuf_in.dl && (reason & 2) )
29330869Sjmg	dsp_rdintr(d);
29430869Sjmg
29529415Sjmg    if ( c & 2 )
29629415Sjmg	inb(DSP_DATA_AVL16); /* 16-bit int ack */
29729415Sjmg    if (c & 1)
29829415Sjmg	inb(DSP_DATA_AVAIL);	/* 8-bit int ack */
29929415Sjmg
30029415Sjmg    /*
30129415Sjmg     * the sb16 might have multiple sources etc.
30229415Sjmg     */
30329415Sjmg    if (d->bd_flags & BD_F_SB16 && (c & 3) )
30429415Sjmg	goto again;
30529415Sjmg}
30629415Sjmg
30729415Sjmg/*
30829415Sjmg * device-specific function called back from the dma module.
30929415Sjmg * The reason of the callback is the second argument.
31029415Sjmg * NOTE: during operations, some ioctl can be done to change
31129415Sjmg * settings (e.g. speed, channels, format), and the default
31229415Sjmg * ioctl handler will just record the change and set the
31329415Sjmg * flag SND_F_INIT. The callback routine is in charge of applying
31429415Sjmg * the changes at the next convenient time (typically, at the
31529415Sjmg * start of operations). For full duplex devices, in some cases the
31629415Sjmg * init requires both channels to be idle.
31729415Sjmg */
31829415Sjmgstatic int
31929415Sjmgsb_callback(snddev_info *d, int reason)
32029415Sjmg{
32129415Sjmg    int rd = reason & SND_CB_RD ;
32230869Sjmg    int l = (rd) ? d->dbuf_in.dl : d->dbuf_out.dl ;
32329415Sjmg
32429415Sjmg    switch (reason & SND_CB_REASON_MASK) {
32529415Sjmg    case SND_CB_INIT : /* called with int enabled and no pending io */
32629415Sjmg	dsp_speed(d);
32729415Sjmg	snd_set_blocksize(d);
32829415Sjmg	if (d->play_fmt & AFMT_MU_LAW)
32929415Sjmg	    d->flags |= SND_F_XLAT8 ;
33029415Sjmg	else
33129415Sjmg	    d->flags &= ~SND_F_XLAT8 ;
33230869Sjmg	reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
33330869Sjmg	reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
33429415Sjmg	return 1;
33530869Sjmg	break;
33629415Sjmg
33729415Sjmg    case SND_CB_START : /* called with int disabled */
33829415Sjmg	if (d->bd_flags & BD_F_SB16) {
33929415Sjmg	    /* the SB16 can do full duplex using one 16-bit channel
34029415Sjmg	     * and one 8-bit channel. It needs to be programmed to
34129415Sjmg	     * use split format though.
34230869Sjmg	     * We use the following algorithm:
34330869Sjmg	     * 1. check which direction(s) are active;
34430869Sjmg	     * 2. check if we should swap dma channels
34530869Sjmg	     * 3. check if we can do the swap.
34629415Sjmg	     */
34730869Sjmg	    int swap = 1 ; /* default... */
34829415Sjmg
34930869Sjmg	    if (rd) {
35030869Sjmg		if (d->flags & SND_F_WRITING || d->dbuf_out.dl)
35130869Sjmg		    swap = 0;
35230869Sjmg		if (d->rec_fmt == AFMT_S16_LE && d->dma2 >=4)
35330869Sjmg		    swap = 0;
35430869Sjmg		if (d->rec_fmt != AFMT_S16_LE && d->dma2 <4)
35530869Sjmg		    swap = 0;
35629415Sjmg	    } else {
35730869Sjmg		if (d->flags & SND_F_READING || d->dbuf_in.dl)
35830869Sjmg		    swap = 0;
35930869Sjmg		if (d->play_fmt == AFMT_S16_LE && d->dma1 >=4)
36030869Sjmg		    swap = 0;
36130869Sjmg		if (d->play_fmt != AFMT_S16_LE && d->dma1 <4)
36230869Sjmg		    swap = 0;
36329415Sjmg	    }
36430869Sjmg
36529415Sjmg	    if (swap) {
36629415Sjmg	        int c = d->dma2 ;
36729415Sjmg		d->dma2 = d->dma1;
36829415Sjmg		d->dma1 = c ;
36930869Sjmg		reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
37030869Sjmg		reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
37130869Sjmg		DEB(printf("START dma chan: play %d, rec %d\n",
37230869Sjmg		    d->dma1, d->dma2));
37329415Sjmg	    }
37429415Sjmg	}
37530869Sjmg	if (!rd)
37630869Sjmg	    sb_cmd(d->io_base, DSP_CMD_SPKON);
37730869Sjmg
37829415Sjmg	if (d->bd_flags & BD_F_SB16) {
37929415Sjmg	    u_char c, c1 ;
38029415Sjmg
38129415Sjmg	    if (rd) {
38229415Sjmg		c = ((d->dma2 > 3) ? DSP_DMA16 : DSP_DMA8) |
38330869Sjmg			DSP_F16_AUTO |
38429415Sjmg			DSP_F16_FIFO_ON | DSP_F16_ADC ;
38530869Sjmg		c1 = (d->rec_fmt == AFMT_U8) ? 0 : DSP_F16_SIGNED ;
38630869Sjmg		if (d->rec_fmt == AFMT_MU_LAW) c1 = 0 ;
38729415Sjmg		if (d->rec_fmt == AFMT_S16_LE)
38829415Sjmg		    l /= 2 ;
38929415Sjmg	    } else {
39029415Sjmg		c = ((d->dma1 > 3) ? DSP_DMA16 : DSP_DMA8) |
39130869Sjmg			DSP_F16_AUTO |
39229415Sjmg			DSP_F16_FIFO_ON | DSP_F16_DAC ;
39330869Sjmg		c1 = (d->play_fmt == AFMT_U8) ? 0 : DSP_F16_SIGNED ;
39429415Sjmg		if (d->play_fmt == AFMT_MU_LAW) c1 = 0 ;
39529415Sjmg		if (d->play_fmt == AFMT_S16_LE)
39629415Sjmg		    l /= 2 ;
39729415Sjmg	    }
39829415Sjmg
39929415Sjmg	    if (d->flags & SND_F_STEREO)
40029415Sjmg		c1 |= DSP_F16_STEREO ;
40129415Sjmg
40229415Sjmg	    sb_cmd(d->io_base, c );
40329415Sjmg	    sb_cmd3(d->io_base, c1 , l - 1) ;
40429415Sjmg	} else {
40530869Sjmg	    /* code for the SB2 and SB3 */
40629415Sjmg	    u_char c ;
40729415Sjmg	    if (d->bd_flags & BD_F_HISPEED)
40830869Sjmg		c = (rd) ? DSP_CMD_HSADC_AUTO : DSP_CMD_HSDAC_AUTO ;
40929415Sjmg	    else
41030869Sjmg		c = (rd) ? DSP_CMD_ADC8_AUTO : DSP_CMD_DAC8_AUTO ;
41129415Sjmg	    sb_cmd3(d->io_base, c , l - 1) ;
41229415Sjmg	}
41329415Sjmg	break;
41429415Sjmg
41530869Sjmg    case SND_CB_ABORT : /* XXX */
41629415Sjmg    case SND_CB_STOP :
41730869Sjmg	{
41830869Sjmg	    int cmd = DSP_CMD_DMAPAUSE_8 ; /* default: halt 8 bit chan */
41930869Sjmg	    if (d->bd_flags & BD_F_SB16) {
42030869Sjmg		if ( (rd && d->dbuf_in.chan>4) || (!rd && d->dbuf_out.chan>4) )
42130869Sjmg		    cmd = DSP_CMD_DMAPAUSE_16 ;
42230869Sjmg	    }
42330869Sjmg	    if (d->bd_flags & BD_F_HISPEED) {
42430869Sjmg		sb_reset_dsp(d->io_base);
42530869Sjmg		d->flags |= SND_F_INIT ;
42630869Sjmg	    } else {
42730869Sjmg		sb_cmd(d->io_base, cmd); /* pause dma. */
42830869Sjmg	       /*
42930869Sjmg		* This seems to have the side effect of blocking the other
43030869Sjmg		* side as well so I have to re-enable it :(
43130869Sjmg		*/
43230869Sjmg		if ( (rd && d->dbuf_out.dl) ||
43330869Sjmg		     (!rd && d->dbuf_in.dl) )
43430869Sjmg		    sb_cmd(d->io_base, cmd == DSP_CMD_DMAPAUSE_8 ?
43530869Sjmg			0xd6 : 0xd4); /* continue other dma */
43630869Sjmg	    }
43730869Sjmg	}
43830869Sjmg	DEB( sb_cmd(d->io_base, DSP_CMD_SPKOFF) ); /* speaker off */
43929415Sjmg	break ;
44029415Sjmg
44129415Sjmg    }
44229415Sjmg    return 0 ;
44329415Sjmg}
44429415Sjmg
44529415Sjmg/*
44629415Sjmg * The second part of the file contains all functions specific to
44729415Sjmg * the board and (usually) not exported to other modules.
44829415Sjmg */
44929415Sjmg
45029415Sjmgint
45129415Sjmgsb_reset_dsp(int io_base)
45229415Sjmg{
45329415Sjmg    int loopc;
45429415Sjmg
45529415Sjmg    outb(DSP_RESET, 1);
45629415Sjmg    DELAY(100);
45729415Sjmg    outb(DSP_RESET, 0);
45829415Sjmg    for (loopc = 0; loopc<100 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++)
45929415Sjmg	DELAY(30);
46029415Sjmg
46129415Sjmg    if (inb(DSP_READ) != 0xAA) {
46230869Sjmg        DEB(printf("sb_reset_dsp 0x%x failed\n", io_base));
46329415Sjmg	return 0;	/* Sorry */
46429415Sjmg    }
46529415Sjmg    return 1;
46629415Sjmg}
46729415Sjmg
46829415Sjmg/*
46929415Sjmg * only used in sb_attach from here.
47029415Sjmg */
47129415Sjmg
47229415Sjmgstatic void
47329415Sjmgsb_dsp_init(snddev_info *d, struct isa_device *dev)
47429415Sjmg{
47529415Sjmg    int i, x;
47629415Sjmg    char *fmt = NULL ;
47729415Sjmg    int	io_base = dev->id_iobase ;
47829415Sjmg
47929415Sjmg    d->bd_id = 0 ;
48029415Sjmg
48129415Sjmg    sb_reset_dsp(io_base);
48229415Sjmg    sb_cmd(io_base, DSP_CMD_GETVER);	/* Get version */
48329415Sjmg
48429415Sjmg    for (i = 10000; i; i--) { /* perhaps wait longer on a fast machine ? */
48529415Sjmg	if (inb(DSP_DATA_AVAIL) & 0x80) { /* wait for Data Ready */
48629415Sjmg	    if ( (d->bd_id & 0xff00) == 0)
48729415Sjmg		d->bd_id = inb(DSP_READ) << 8; /* major */
48829415Sjmg	    else {
48929415Sjmg		d->bd_id |= inb(DSP_READ); /* minor */
49029415Sjmg		break;
49129415Sjmg	    }
49229415Sjmg	} else
49329415Sjmg	    DELAY(20);
49429415Sjmg    }
49529415Sjmg
49629415Sjmg    /*
49729415Sjmg     * now do various initializations depending on board id.
49829415Sjmg     */
49929415Sjmg
50029415Sjmg    fmt = "SoundBlaster %d.%d" ; /* default */
50129415Sjmg
50229415Sjmg    switch ( d->bd_id >> 8 ) {
50329415Sjmg    case 0 :
50429415Sjmg	printf("\n\nFailed to get SB version (%x) - possible I/O conflict\n\n",
50529415Sjmg	       inb(DSP_DATA_AVAIL));
50629415Sjmg	d->bd_id = 0x100;
50729415Sjmg    case 1 : /* old sound blaster has nothing... */
50829415Sjmg	break ;
50929415Sjmg
51029415Sjmg    case 2 :
51129415Sjmg	d->dma2 = d->dma1 ; /* half duplex */
51229415Sjmg	d->bd_flags |= BD_F_DUP_MIDI ;
51329415Sjmg
51429415Sjmg	if (d->bd_id == 0x200)
51529415Sjmg	    break ; /* no mixer on the 2.0 */
51629415Sjmg	d->bd_flags &= ~BD_F_MIX_MASK ;
51729415Sjmg	d->bd_flags |= BD_F_MIX_CT1335 ;
51829415Sjmg
51929415Sjmg	break ;
52029415Sjmg    case 4 :
52129415Sjmg	fmt = "SoundBlaster 16 %d.%d";
52229415Sjmg	d->audio_fmt |= AFMT_FULLDUPLEX | AFMT_WEIRD | AFMT_S8 | AFMT_S16_LE;
52329415Sjmg	d->bd_flags |= BD_F_SB16;
52429415Sjmg	d->bd_flags &= ~BD_F_MIX_MASK ;
52529415Sjmg	d->bd_flags |= BD_F_MIX_CT1745 ;
52629415Sjmg
52729415Sjmg	/* soft irq/dma configuration */
52829415Sjmg	x = -1 ;
52929415Sjmg	if (d->irq == 5) x = 2;
53029415Sjmg	else if (d->irq == 7) x = 4;
53129415Sjmg	else if (d->irq == 9) x = 1;
53229415Sjmg	else if (d->irq == 10) x = 8;
53329415Sjmg	if (x == -1)
53429415Sjmg	    printf("<%s>%d: bad irq %d (only 5,7,9,10 allowed)\n",
53529415Sjmg		d->name, dev->id_unit, d->irq);
53629415Sjmg	else
53729415Sjmg	    sb_setmixer(io_base, IRQ_NR, x);
53829415Sjmg
53929415Sjmg	sb_setmixer(io_base, DMA_NR, (1 << d->dma1) | (1 << d->dma2));
54029415Sjmg	break ;
54129415Sjmg
54229415Sjmg    case 3 :
54329415Sjmg	d->dma2 = d->dma1 ; /* half duplex */
54429415Sjmg	fmt = "SoundBlaster Pro %d.%d";
54529415Sjmg	d->bd_flags |= BD_F_DUP_MIDI ;
54629415Sjmg	d->bd_flags &= ~BD_F_MIX_MASK ;
54729415Sjmg	d->bd_flags |= BD_F_MIX_CT1345 ;
54829415Sjmg	if (d->bd_id == 0x301) {
54929415Sjmg	    int ess_major = 0, ess_minor = 0;
55029415Sjmg
55129415Sjmg	    /*
55229415Sjmg	     * Try to detect ESS chips.
55329415Sjmg	     */
55429415Sjmg
55529415Sjmg	    sb_cmd(io_base, DSP_CMD_GETID);	/* Return ident. bytes. */
55629415Sjmg
55729415Sjmg	    for (i = 1000; i; i--) {
55829415Sjmg		if (inb(DSP_DATA_AVAIL) & 0x80) { /* wait for Data Ready */
55929415Sjmg		    if (ess_major == 0)
56029415Sjmg			ess_major = inb(DSP_READ);
56129415Sjmg		    else {
56229415Sjmg			ess_minor = inb(DSP_READ);
56329415Sjmg			break;
56429415Sjmg		    }
56529415Sjmg		}
56629415Sjmg	    }
56729415Sjmg
56829415Sjmg	    if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80)
56929415Sjmg		printf("Hmm... Could this be an ESS488 based card (rev %d)\n",
57029415Sjmg		   ess_minor & 0x0f);
57129415Sjmg	    else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
57229415Sjmg		printf("Hmm... Could this be an ESS688 based card (rev %d)\n",
57329415Sjmg		   ess_minor & 0x0f);
57429415Sjmg	}
57529415Sjmg
57629415Sjmg	if (d->bd_flags & BD_F_JAZZ16) {
57729415Sjmg	    if (d->bd_flags & BD_F_JAZZ16_2)
57829415Sjmg		fmt = "SoundMan Wave %d.%d";
57929415Sjmg	    else
58029415Sjmg		fmt = "MV Jazz16 %d.%d";
58129415Sjmg	    d->audio_fmt |= AFMT_S16_LE;	/* 16 bits */
58229415Sjmg	}
58329415Sjmg    }
58429415Sjmg
58529415Sjmg    sprintf(d->name, fmt, (d->bd_id >> 8) &0xff, d->bd_id & 0xff);
58629415Sjmg
58729415Sjmg    sb_mix_init(d);
58829415Sjmg}
58929415Sjmg
59029415Sjmgstatic void
59129415Sjmgsb_mix_init(snddev_info *d)
59229415Sjmg{
59329415Sjmg    switch (d->bd_flags & BD_F_MIX_MASK) {
59429415Sjmg    case BD_F_MIX_CT1345 : /* SB 3.0 has 1345 mixer */
59529415Sjmg
59629415Sjmg	d->mix_devs = SBPRO_MIXER_DEVICES ;
59729415Sjmg	d->mix_rec_devs = SBPRO_RECORDING_DEVICES ;
59829415Sjmg	d->mix_recsrc = SOUND_MASK_MIC ;
59929415Sjmg
60029415Sjmg	sb_setmixer(d->io_base, 0, 1 ); /* reset mixer */
60129415Sjmg	sb_setmixer(d->io_base, MIC_VOL , 0x6 ); /* mic volume max */
60229415Sjmg	sb_setmixer(d->io_base, RECORD_SRC , 0x0 ); /* mic source */
60329415Sjmg	sb_setmixer(d->io_base, FM_VOL , 0x0 ); /* no midi */
60429415Sjmg	break ;
60529415Sjmg
60629415Sjmg    case BD_F_MIX_CT1745 : /* SB16 mixer ... */
60729415Sjmg
60829415Sjmg	d->mix_devs = SB16_MIXER_DEVICES ;
60929415Sjmg	d->mix_rec_devs = SB16_RECORDING_DEVICES ;
61029415Sjmg	d->mix_recsrc = SOUND_MASK_MIC ;
61129415Sjmg    }
61229415Sjmg    sb_mixer_reset(d);
61329415Sjmg}
61429415Sjmg
61529415Sjmg/*
61629415Sjmg * Common code for the midi and pcm functions
61729415Sjmg */
61829415Sjmg
61929415Sjmgint
62029415Sjmgsb_cmd(int io_base, u_char val)
62129415Sjmg{
62229415Sjmg    int  i;
62329415Sjmg
62429415Sjmg    for (i = 0; i < 1000 ; i++) {
62529415Sjmg	if ((inb(DSP_STATUS) & 0x80) == 0) {
62629415Sjmg	    outb(DSP_COMMAND, val);
62729415Sjmg	    return 1;
62829415Sjmg	}
62929415Sjmg	if (i > 10)
63029415Sjmg	    DELAY (i > 100 ? 1000 : 10 );
63129415Sjmg    }
63229415Sjmg
63329415Sjmg    printf("SoundBlaster: DSP Command(0x%02x) timeout. IRQ conflict ?\n", val);
63429415Sjmg    return 0;
63529415Sjmg}
63629415Sjmg
63729415Sjmgint
63829415Sjmgsb_cmd3(int io_base, u_char cmd, int val)
63929415Sjmg{
64029415Sjmg    if (sb_cmd(io_base, cmd)) {
64129415Sjmg	sb_cmd(io_base, val & 0xff );
64229415Sjmg	sb_cmd(io_base, (val>>8) & 0xff );
64329415Sjmg	return 1 ;
64429415Sjmg    } else
64529415Sjmg	return 0;
64629415Sjmg}
64729415Sjmg
64829415Sjmgint
64929415Sjmgsb_cmd2(int io_base, u_char cmd, int val)
65029415Sjmg{
65129415Sjmg    if (sb_cmd(io_base, cmd)) {
65229415Sjmg	sb_cmd(io_base, val & 0xff );
65329415Sjmg	return 1 ;
65429415Sjmg    } else
65529415Sjmg	return 0;
65629415Sjmg}
65729415Sjmg
65829415Sjmgvoid
65929415Sjmgsb_setmixer(int io_base, u_int port, u_int value)
66029415Sjmg{
66129415Sjmg    u_long   flags;
66229415Sjmg
66329415Sjmg    flags = spltty();
66429415Sjmg    outb(MIXER_ADDR, (u_char) (port & 0xff));   /* Select register */
66529415Sjmg    DELAY(10);
66629415Sjmg    outb(MIXER_DATA, (u_char) (value & 0xff));
66729415Sjmg    DELAY(10);
66829415Sjmg    splx(flags);
66929415Sjmg}
67029415Sjmg
67129415Sjmgu_int
67229415Sjmgsb_get_byte(int io_base)
67329415Sjmg{
67429415Sjmg    int             i;
67529415Sjmg
67629415Sjmg    for (i = 1000; i; i--)
67729415Sjmg	if (inb(DSP_DATA_AVAIL) & 0x80)
67829415Sjmg	    return inb(DSP_READ);
67929415Sjmg	else
68029415Sjmg	    DELAY(20);
68129415Sjmg    return 0xffff;
68229415Sjmg}
68329415Sjmg
68429415Sjmgint
68529415Sjmgsb_getmixer(int io_base, u_int port)
68629415Sjmg{
68729415Sjmg    int             val;
68829415Sjmg    u_long   flags;
68929415Sjmg
69029415Sjmg    flags = spltty();
69129415Sjmg    outb(MIXER_ADDR, (u_char) (port & 0xff));   /* Select register */
69229415Sjmg    DELAY(10);
69329415Sjmg    val = inb(MIXER_DATA);
69429415Sjmg    DELAY(10);
69529415Sjmg    splx(flags);
69629415Sjmg
69729415Sjmg    return val;
69829415Sjmg}
69929415Sjmg
70029415Sjmg
70129415Sjmg/*
70229415Sjmg * various utility functions for the DSP
70329415Sjmg */
70429415Sjmg
70529415Sjmg/*
70629415Sjmg * dsp_speed updates the speed setting from the descriptor. make sure
70729415Sjmg * it is called at spltty().
70829415Sjmg * Besides, it takes care of stereo setting.
70929415Sjmg */
71029415Sjmgstatic int
71129415Sjmgdsp_speed(snddev_info *d)
71229415Sjmg{
71329415Sjmg    u_char   tconst;
71429415Sjmg    u_long   flags;
71529415Sjmg    int max_speed = 44100, speed = d->play_speed ;
71629415Sjmg
71729415Sjmg    if (d->bd_flags & BD_F_SB16) {
71829415Sjmg	RANGE (speed, 5000, 45000);
71929415Sjmg	d->play_speed = d->rec_speed = speed ;
72029415Sjmg	sb_cmd(d->io_base, 0x41);
72129415Sjmg	sb_cmd(d->io_base, d->play_speed >> 8 );
72229415Sjmg	sb_cmd(d->io_base, d->play_speed & 0xff );
72329415Sjmg	sb_cmd(d->io_base, 0x42);
72429415Sjmg	sb_cmd(d->io_base, d->rec_speed >> 8 );
72529415Sjmg	sb_cmd(d->io_base, d->rec_speed & 0xff );
72629415Sjmg	return speed ;
72729415Sjmg    }
72829415Sjmg    /*
72929415Sjmg     * only some models can do stereo, and only if not
73029415Sjmg     * simultaneously using midi.
73129415Sjmg     */
73229415Sjmg    if ( (d->bd_id & 0xff00) < 0x300 || d->bd_flags & BD_F_MIDIBUSY)
73329415Sjmg	d->flags &= ~SND_F_STEREO;
73429415Sjmg
73529415Sjmg    /*
73629415Sjmg     * here enforce speed limitations.
73729415Sjmg     */
73829415Sjmg    if (d->bd_id <= 0x200)
73929415Sjmg	max_speed = 22050; /* max 22050 on SB 1.X */
74029415Sjmg
74129415Sjmg    /*
74229415Sjmg     * SB models earlier than SB Pro have low limit for the
74329415Sjmg     * input rate. Note that this is only for input, but since
74429415Sjmg     * we do not support separate values for rec & play....
74529415Sjmg     */
74629415Sjmg    if (d->bd_id <= 0x200)
74729415Sjmg	max_speed = 13000;
74829415Sjmg    else if (d->bd_id < 0x300)
74929415Sjmg	max_speed = 15000;
75029415Sjmg
75129415Sjmg    RANGE(speed, 4000, max_speed);
75229415Sjmg
75329415Sjmg    /*
75429415Sjmg     * Logitech SoundMan Games and Jazz16 cards can support 44.1kHz
75529415Sjmg     * stereo
75629415Sjmg     */
75729415Sjmg#if !defined (SM_GAMES)
75829415Sjmg    /*
75929415Sjmg     * Max. stereo speed is 22050
76029415Sjmg     */
76129415Sjmg    if (d->flags & SND_F_STEREO && speed > 22050 && !(d->bd_flags & BD_F_JAZZ16))
76229415Sjmg	speed = 22050;
76329415Sjmg#endif
76429415Sjmg
76529415Sjmg    if (d->flags & SND_F_STEREO)
76629415Sjmg	speed *= 2;
76729415Sjmg
76829415Sjmg    /*
76929415Sjmg     * Now the speed should be valid. Compute the value to be
77029415Sjmg     * programmed into the board.
77129565Sjmg     *
77230869Sjmg     * XXX stereo init is still missing...
77329415Sjmg     */
77429415Sjmg
77529415Sjmg    if (speed > 22050) { /* High speed mode on 2.01/3.xx */
77629415Sjmg	int tmp;
77729415Sjmg
77830869Sjmg	tconst = (u_char) ((65536 - ((256000000 + speed / 2) / speed)) >> 8) ;
77929415Sjmg	d->bd_flags |= BD_F_HISPEED ;
78029415Sjmg
78129415Sjmg	flags = spltty();
78229415Sjmg	sb_cmd2(d->io_base, DSP_CMD_TCONST, tconst);
78329415Sjmg	splx(flags);
78429415Sjmg
78529415Sjmg	tmp = 65536 - (tconst << 8);
78629415Sjmg	speed = (256000000 + tmp / 2) / tmp;
78729415Sjmg    } else {
78829415Sjmg	int             tmp;
78929415Sjmg
79029415Sjmg	d->bd_flags &= ~BD_F_HISPEED ;
79129415Sjmg	tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
79229415Sjmg
79329415Sjmg	flags = spltty();
79429415Sjmg	sb_cmd2(d->io_base, DSP_CMD_TCONST, tconst);
79529415Sjmg	splx(flags);
79629415Sjmg
79729415Sjmg	tmp = 256 - tconst;
79829415Sjmg	speed = (1000000 + tmp / 2) / tmp;
79929415Sjmg    }
80029415Sjmg
80129415Sjmg    if (d->flags & SND_F_STEREO)
80229415Sjmg	speed /= 2;
80329415Sjmg
80429415Sjmg    d->play_speed = d->rec_speed = speed;
80529415Sjmg    return speed;
80629415Sjmg}
80729415Sjmg
80829415Sjmg/*
80929415Sjmg * mixer support, originally in sb_mixer.c
81029415Sjmg */
81129415Sjmg
81229415Sjmgstatic void
81329415Sjmgsb_set_recsrc(snddev_info *d, int mask)
81429415Sjmg{
81529415Sjmg    u_char recdev ;
81629415Sjmg
81729415Sjmg    mask &= d->mix_rec_devs;
81829415Sjmg    switch (d->bd_flags & BD_F_MIX_MASK) {
81929415Sjmg    case BD_F_MIX_CT1345 :
82029415Sjmg	if (mask == SOUND_MASK_LINE)
82129415Sjmg	    recdev = 6 ;
82229415Sjmg	else if (mask == SOUND_MASK_CD)
82329415Sjmg	    recdev = 2 ;
82429415Sjmg	else { /* default: mic */
82529415Sjmg	    mask =  SOUND_MASK_MIC ;
82629415Sjmg	    recdev = 0 ;
82729415Sjmg	}
82829415Sjmg	sb_setmixer(d->io_base, RECORD_SRC,
82929415Sjmg	    recdev | (sb_getmixer(d->io_base, RECORD_SRC) & ~7 ));
83029415Sjmg	break ;
83129415Sjmg    case BD_F_MIX_CT1745 : /* sb16 */
83229415Sjmg	if (mask == 0)
83329415Sjmg	    mask = SOUND_MASK_MIC ; /* XXX For compatibility. Bug ? */
83429415Sjmg	recdev = 0 ;
83529415Sjmg	if (mask & SOUND_MASK_MIC)
83629415Sjmg	    recdev |= 1 ;
83729415Sjmg	if (mask & SOUND_MASK_CD)
83829415Sjmg	    recdev |= 6 ; /* l+r cd */
83929415Sjmg	if (mask & SOUND_MASK_LINE)
84029415Sjmg	    recdev |= 0x18 ; /* l+r line */
84129415Sjmg	if (mask & SOUND_MASK_SYNTH)
84229415Sjmg	    recdev |= 0x60 ; /* l+r midi */
84329415Sjmg	sb_setmixer(d->io_base, SB16_IMASK_L, recdev);
84429415Sjmg	sb_setmixer(d->io_base, SB16_IMASK_R, recdev);
84529415Sjmg	/*
84629415Sjmg	 * since the same volume controls apply to the input and
84729415Sjmg	 * output sections, the best approach to have a consistent
84829415Sjmg	 * behaviour among cards would be to disable the output path
84929415Sjmg	 * on devices which are used to record.
85029415Sjmg	 * However, since users like to have feedback, we only disable
85129415Sjmg	 * the mike -- permanently.
85229415Sjmg	 */
85329415Sjmg        sb_setmixer(d->io_base, SB16_OMASK, 0x1f & ~1);
85429415Sjmg	break ;
85529415Sjmg    }
85629415Sjmg    d->mix_recsrc = mask;
85729415Sjmg}
85829415Sjmg
85929415Sjmgstatic void
86029415Sjmgsb_mixer_reset(snddev_info *d)
86129415Sjmg{
86229415Sjmg    int             i;
86329415Sjmg
86429415Sjmg    for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
86529415Sjmg	sb_mixer_set(d, i, levels[i]);
86629415Sjmg    if (d->bd_flags & BD_F_SB16) {
86729415Sjmg	sb_setmixer(d->io_base, 0x3c, 0x1f); /* make all output active */
86829415Sjmg	sb_setmixer(d->io_base, 0x3d, 0); /* make all inputs-l off */
86929415Sjmg	sb_setmixer(d->io_base, 0x3e, 0); /* make all inputs-r off */
87029415Sjmg    }
87129415Sjmg    sb_set_recsrc(d, SOUND_MASK_MIC);
87229415Sjmg}
87329415Sjmg
87429415Sjmgstatic int
87529415Sjmgsb_mixer_set(snddev_info *d, int dev, int value)
87629415Sjmg{
87729415Sjmg    int left = value & 0x000000ff;
87829415Sjmg    int right = (value & 0x0000ff00) >> 8;
87929415Sjmg    int regoffs;
88029415Sjmg    u_char   val;
88129415Sjmg    mixer_tab *iomap;
88229415Sjmg
88329415Sjmg#ifdef JAZZ16
88429415Sjmg    if (d->bd_flags & BD_F_JAZZ16 && d->bd_flags & BD_F_JAZZ16_2)
88529415Sjmg        return smw_mixer_set(dev, value);
88629415Sjmg#endif
88729415Sjmg
88829415Sjmg    if (dev == SOUND_MIXER_RECSRC) {
88929415Sjmg	sb_set_recsrc(d, value);
89029415Sjmg	return 0 ;
89129415Sjmg    }
89229415Sjmg    if (left > 100)
89329415Sjmg        left = 100;
89429415Sjmg    if (right > 100)
89529415Sjmg        right = 100;
89629415Sjmg
89729415Sjmg    if (dev > 31)
89829415Sjmg        return EINVAL ;
89929415Sjmg
90029415Sjmg    if (!(d->mix_devs & (1 << dev)))      /* Not supported */
90129415Sjmg        return EINVAL;
90229415Sjmg
90329415Sjmg    switch ( d->bd_flags & BD_F_MIX_MASK ) {
90429415Sjmg    default:
90529415Sjmg	/* mixer unknown, fail... */
90629415Sjmg	return EINVAL ;/* XXX change this */
90729415Sjmg    case BD_F_MIX_CT1345 :
90829415Sjmg	iomap = &sbpro_mix ;
90929415Sjmg	break;
91029415Sjmg    case BD_F_MIX_CT1745 :
91129415Sjmg	iomap = &sb16_mix ;
91229415Sjmg	break;
91329415Sjmg    /* XXX how about the SG NX Pro, iomap = sgnxpro_mix */
91429415Sjmg    }
91529415Sjmg    regoffs = (*iomap)[dev][LEFT_CHN].regno;
91629415Sjmg    if (regoffs == 0)
91729415Sjmg        return EINVAL;
91829415Sjmg
91929415Sjmg    val = sb_getmixer(d->io_base, regoffs);
92029415Sjmg
92129415Sjmg    change_bits(iomap, &val, dev, LEFT_CHN, left);
92229415Sjmg
92329415Sjmg    d->mix_levels[dev] = left | (left << 8);
92429415Sjmg
92529415Sjmg    if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) {    /* Change register */
92629415Sjmg        sb_setmixer(d->io_base, regoffs, val);     /* Save the old one */
92729415Sjmg        regoffs = (*iomap)[dev][RIGHT_CHN].regno;
92829415Sjmg
92929415Sjmg        if (regoffs == 0)
93029415Sjmg            return 0 ;  /* Just left channel present */
93129415Sjmg
93229415Sjmg        val = sb_getmixer(d->io_base, regoffs);    /* Read the new one */
93329415Sjmg    }
93429415Sjmg    change_bits(iomap, &val, dev, RIGHT_CHN, right);
93529415Sjmg
93629415Sjmg    sb_setmixer(d->io_base, regoffs, val);
93729415Sjmg
93829415Sjmg    d->mix_levels[dev] = left | (right << 8);
93929415Sjmg    return 0 ; /* ok */
94029415Sjmg}
94129415Sjmg
94229415Sjmg/*
94329415Sjmg * now support for some PnP boards.
94429415Sjmg */
94529415Sjmg
94629415Sjmg#if NPNP > 0
94729415Sjmgstatic char *opti925_probe(u_long csn, u_long vend_id);
94829415Sjmgstatic void opti925_attach(u_long csn, u_long vend_id, char *name,
94929415Sjmg        struct isa_device *dev);
95029415Sjmg
95129415Sjmgstatic struct pnp_device opti925 = {
95229415Sjmg        "opti925",
95329415Sjmg        opti925_probe,
95429415Sjmg        opti925_attach,
95529415Sjmg        &nsnd,  /* use this for all sound cards */
95629415Sjmg        &tty_imask      /* imask */
95729415Sjmg};
95829415SjmgDATA_SET (pnpdevice_set, opti925);
95929415Sjmg
96029415Sjmgstatic char *
96129415Sjmgopti925_probe(u_long csn, u_long vend_id)
96229415Sjmg{
96329415Sjmg    if (vend_id == 0x2509143e) {
96429415Sjmg	struct pnp_cinfo d ;
96529415Sjmg	read_pnp_parms ( &d , 1 ) ;
96629415Sjmg	if (d.enable == 0) {
96729415Sjmg	    printf("This is an OPTi925, but LDN 1 is disabled\n");
96829415Sjmg	    return NULL;
96929415Sjmg	}
97029415Sjmg        return "OPTi925" ;
97129415Sjmg    }
97229415Sjmg    return NULL ;
97329415Sjmg}
97429415Sjmg
97529415Sjmgstatic void
97629415Sjmgopti925_attach(u_long csn, u_long vend_id, char *name,
97729415Sjmg        struct isa_device *dev)
97829415Sjmg{
97929415Sjmg    struct pnp_cinfo d ;
98029415Sjmg    snddev_info tmp_d ; /* patched copy of the basic snddev_info */
98129415Sjmg    int the_irq = 0 ;
98229415Sjmg
98329415Sjmg    tmp_d = sb_op_desc;
98429415Sjmg    snddev_last_probed = &tmp_d;
98529415Sjmg
98629415Sjmg    read_pnp_parms ( &d , 3 );  /* disable LDN 3 */
98729415Sjmg    the_irq = d.irq[0];
98829415Sjmg    d.port[0] = 0 ;
98929415Sjmg    d.enable = 0 ;
99029415Sjmg    write_pnp_parms ( &d , 3 );
99129415Sjmg
99229415Sjmg    read_pnp_parms ( &d , 2 ); /* disable LDN 2 */
99329415Sjmg    d.port[0] = 0 ;
99429415Sjmg    d.enable = 0 ;
99529415Sjmg    write_pnp_parms ( &d , 2 );
99629415Sjmg
99729415Sjmg    read_pnp_parms ( &d , 1 ) ;
99829415Sjmg    d.irq[0] = the_irq ;
99929415Sjmg    dev->id_iobase = d.port[0];
100029415Sjmg    write_pnp_parms ( &d , 1 );
100129415Sjmg    enable_pnp_card();
100229415Sjmg
100329415Sjmg    tmp_d.conf_base = d.port[3];
100429415Sjmg
100529415Sjmg    dev->id_drq = d.drq[0] ; /* primary dma */
100629415Sjmg    dev->id_irq = (1 << d.irq[0] ) ;
100729415Sjmg    dev->id_intr = pcmintr ;
100829415Sjmg    dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ;
100929415Sjmg
101029415Sjmg    snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
101129415Sjmg
101229415Sjmg    pcmattach(dev);
101329415Sjmg
101429415Sjmg}
101529415Sjmg
101629415Sjmg/*
101729415Sjmg * A driver for some SB16pnp and compatibles...
101829415Sjmg *
101929415Sjmg * Avance Asound 100 -- 0x01009305
102029415Sjmg * xxx               -- 0x2b008c0e
102129415Sjmg *
102229415Sjmg */
102329415Sjmg
102429415Sjmgstatic char *sb16pnp_probe(u_long csn, u_long vend_id);
102529415Sjmgstatic void sb16pnp_attach(u_long csn, u_long vend_id, char *name,
102629415Sjmg        struct isa_device *dev);
102729415Sjmg
102829415Sjmgstatic struct pnp_device sb16pnp = {
102929415Sjmg        "SB16pnp",
103029415Sjmg        sb16pnp_probe,
103129415Sjmg        sb16pnp_attach,
103229415Sjmg        &nsnd,  /* use this for all sound cards */
103329415Sjmg        &tty_imask      /* imask */
103429415Sjmg};
103529415SjmgDATA_SET (pnpdevice_set, sb16pnp);
103629415Sjmg
103729415Sjmgstatic char *
103829415Sjmgsb16pnp_probe(u_long csn, u_long vend_id)
103929415Sjmg{
104029415Sjmg    char *s = NULL ;
104130869Sjmg
104229415Sjmg    /*
104330869Sjmg     * The SB16/AWExx cards seem to differ in the fourth byte of
104429415Sjmg     * the vendor id, so I have just masked it for the time being...
104529415Sjmg     * Reported values are:
104629415Sjmg     * SB16 Value PnP:	0x2b008c0e
104729415Sjmg     * SB AWE64 PnP:	0x39008c0e 0x9d008c0e 0xc3008c0e
104829415Sjmg     */
104929415Sjmg    if ( (vend_id & 0xffffff)  == (0x9d008c0e & 0xffffff) )
105030869Sjmg	s = "SB16 PnP";
105130869Sjmg    else if (vend_id == 0x01009305)
105230869Sjmg        s = "Avance Asound 100" ;
105329415Sjmg    if (s) {
105429415Sjmg	struct pnp_cinfo d;
105529415Sjmg	read_pnp_parms(&d, 0);
105629415Sjmg	if (d.enable == 0) {
105729415Sjmg	    printf("This is a %s, but LDN 0 is disabled\n", s);
105829415Sjmg	    return NULL ;
105929415Sjmg	}
106029415Sjmg	return s ;
106129415Sjmg    }
106229415Sjmg    return NULL ;
106329415Sjmg}
106429415Sjmg
106529415Sjmgstatic void
106629415Sjmgsb16pnp_attach(u_long csn, u_long vend_id, char *name,
106729415Sjmg        struct isa_device *dev)
106829415Sjmg{
106929415Sjmg    struct pnp_cinfo d ;
107029415Sjmg    snddev_info tmp_d ; /* patched copy of the basic snddev_info */
107129415Sjmg
107229415Sjmg    tmp_d = sb_op_desc;
107329415Sjmg    snddev_last_probed = &tmp_d;
107429415Sjmg
107529415Sjmg    read_pnp_parms ( &d , 0 ) ;
107629415Sjmg    d.port[1] = 0 ; /* only the first address is used */
107729415Sjmg    dev->id_iobase = d.port[0];
107829415Sjmg    write_pnp_parms ( &d , 0 );
107929415Sjmg    enable_pnp_card();
108029415Sjmg
108129415Sjmg    dev->id_drq = d.drq[0] ; /* primary dma */
108229415Sjmg    dev->id_irq = (1 << d.irq[0] ) ;
108329415Sjmg    dev->id_intr = pcmintr ;
108429415Sjmg    dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ;
108529415Sjmg
108629415Sjmg    pcm_info[dev->id_unit] = tmp_d;
108729415Sjmg    snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
108829415Sjmg
108929415Sjmg    pcmattach(dev);
109029415Sjmg}
109129415Sjmg#endif /* NPNP */
109229415Sjmg
109329415Sjmg#endif
1094