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