📄 sb_dsp.c
字号:
ess_write(d->io_base, 0xb7, 0x71); ess_write(d->io_base, 0xb7, 0xbc); } else { /* 16 bit mono */ if (d->play_fmt) ess_write(d->io_base, 0xb6, 0x00); ess_write(d->io_base, 0xb7, 0x71); ess_write(d->io_base, 0xb7, 0xf4); } break; case AFMT_U8: if (d->flags & SND_F_STEREO) { /* 8 bit stereo */ if (d->play_fmt) ess_write(d->io_base, 0xb6, 0x80); ess_write(d->io_base, 0xb7, 0x51); ess_write(d->io_base, 0xb7, 0x98); } else { /* 8 bit mono */ if (d->play_fmt) ess_write(d->io_base, 0xb6, 0x80); ess_write(d->io_base, 0xb7, 0x51); ess_write(d->io_base, 0xb7, 0xd0); } break; } ess_write(d->io_base, 0xb1, ess_read(d->io_base, 0xb1) | 0x50); ess_write(d->io_base, 0xb2, ess_read(d->io_base, 0xb1) | 0x50); } reset_dbuf(& (d->dbuf_in), SND_CHAN_RD ); reset_dbuf(& (d->dbuf_out), SND_CHAN_WR ); break ; case SND_CB_START : /* called with int disabled */ if (d->bd_flags & BD_F_SB16) { u_char c, c1 ; if (d->bd_flags & BD_F_SB16X) { /* just a guess: on the Vibra16X, the first * op started takes the first dma channel, * the second one takes the next... * The default is to be ready for play. */ int swap = 0 ; DEB(printf("start %s -- now dma %d:%d\n", rd ? "rd" : "wr", d->dbuf_out.chan, d->dbuf_in.chan);); /* swap only if both channels are idle * play: dl=0, since there is no pause; * rec: rl=0 */ if ( rd && d->dbuf_out.dl == 0 && d->dbuf_in.rl == 0 ) { /* must swap channels, but also save dl */ int c = d->dbuf_in.chan ; int dl = d->dbuf_in.dl ; d->dbuf_in.chan = d->dbuf_out.chan; d->dbuf_out.chan = c ; reset_dbuf(& (d->dbuf_in), SND_CHAN_RD ); reset_dbuf(& (d->dbuf_out), SND_CHAN_WR ); d->dbuf_in.dl = dl ; printf("swapped -- now dma %d:%d\n", d->dbuf_out.chan, d->dbuf_in.chan); } } /* * XXX note: c1 and l should be set basing on d->rec_fmt, * but there is no choice once a 16 or 8-bit channel * is assigned. This means that if the application * tries to use a bad format, the sound will not be nice. */ if ( b->chan > 4 || (rd && d->rec_fmt == AFMT_S16_LE) || (!rd && d->play_fmt == AFMT_S16_LE) ) { c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA16 ; c1 = DSP_F16_SIGNED ; l /= 2 ; } else { c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA8 ; c1 = 0 ; } c |= (rd) ? DSP_F16_ADC : DSP_F16_DAC ; if (d->flags & SND_F_STEREO) c1 |= DSP_F16_STEREO ; sb_cmd(d->io_base, c ); sb_cmd3(d->io_base, c1 , l - 1) ; } else if (d->bd_flags & BD_F_ESS) { u_long fmt = rd ? d->rec_fmt : d->play_fmt; DEB(printf("SND_CB_START: %s (%d)\n", rd ? "rd" : "wr", l)); if (fmt == AFMT_S16_LE) l >>= 1; l--; if (!rd) sb_cmd(d->io_base, DSP_CMD_SPKON); ess_write(d->io_base, 0xa4, l); ess_write(d->io_base, 0xa5, l >> 8); ess_write(d->io_base, 0xb8, ess_read(d->io_base, 0xb8) | (rd ? 0x0f : 0x05)); } else { /* SBPro -- stereo not supported */ u_char c ; if (!rd) sb_cmd(d->io_base, DSP_CMD_SPKON); /* code for the SB2 and SB3, only MONO */ if (d->bd_flags & BD_F_HISPEED) c = (rd) ? 0x98 : 0x90 ; else c = (rd) ? 0x2c : 0x1c ; if (d->flags & SND_F_STEREO) sb_setmixer(d->io_base, 0xe, 2 ); else sb_setmixer(d->io_base, 0xe, 0 ); /* * some ESS extensions -- they can do 16 bits */ if ( (rd && d->rec_fmt == AFMT_S16_LE) || (!rd && d->play_fmt == AFMT_S16_LE) ) { c |= 1; l /= 2 ; } sb_cmd3(d->io_base, 0x48 , l - 1) ; sb_cmd(d->io_base, c ) ; } break; case SND_CB_ABORT : /* XXX */ case SND_CB_STOP : { int cmd = DSP_CMD_DMAPAUSE_8 ; /* default: halt 8 bit chan */ DEB(printf("SND_CB_XXX: reason 0x%x\n", reason)); if ( b->chan > 4 || (rd && d->rec_fmt == AFMT_S16_LE) || (!rd && d->play_fmt == AFMT_S16_LE) ) cmd = DSP_CMD_DMAPAUSE_16 ; if (d->bd_flags & BD_F_HISPEED) { sb_reset_dsp(d->io_base); if (d->bd_flags & BD_F_ESS) sb_cmd(d->io_base, 0xc6 ); /* enable extended ESS mode */ d->flags |= SND_F_INIT ; } else { sb_cmd(d->io_base, cmd); /* pause dma. */ /* * The above seems to have the undocumented side effect of * blocking the other side as well. If the other * channel was active (SB16) I have to re-enable it :( */ if ( (rd && d->dbuf_out.dl) || (!rd && d->dbuf_in.dl) ) sb_cmd(d->io_base, cmd == DSP_CMD_DMAPAUSE_8 ? 0xd6 : 0xd4); /* continue other dma */ } if (d->bd_flags & BD_F_SB16X) { /* restore possible swapped channels. * The default is to be ready for play. * XXX right now, it kills all input on overflow */ if ( rd && d->dbuf_out.dl == 0 ) { /* must swap channels ? */ int c = d->dbuf_in.chan ; d->dbuf_in.chan = d->dbuf_out.chan; d->dbuf_out.chan = c ; reset_dbuf(& (d->dbuf_in), SND_CHAN_RD ); reset_dbuf(& (d->dbuf_out), SND_CHAN_WR ); printf("restored -- now dma %d:%d\n", d->dbuf_out.chan, d->dbuf_in.chan); } } } DEB( sb_cmd(d->io_base, DSP_CMD_SPKOFF) ); /* speaker off */ break ; } return 0 ;}/* * The second part of the file contains all functions specific to * the board and (usually) not exported to other modules. */intsb_reset_dsp(int io_base){ int loopc; outb(io_base + SBDSP_RST, 3); DELAY(100); outb(io_base + SBDSP_RST, 0); for (loopc = 0; loopc<100 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++) DELAY(30); if (inb(DSP_READ) != 0xAA) { DEB(printf("sb_reset_dsp 0x%x failed\n", io_base)); return 0; /* Sorry */ } return 1;}/* * only used in sb_attach from here. */static voidsb_dsp_init(snddev_info *d, struct isa_device *dev){ int i, x; char *fmt = NULL ; int io_base = dev->id_iobase ; d->bd_id = 0 ; sb_reset_dsp(io_base); sb_cmd(io_base, DSP_CMD_GETVER); /* Get version */ for (i = 10000; i; i--) { /* perhaps wait longer on a fast machine ? */ if (inb(DSP_DATA_AVAIL) & 0x80) { /* wait for Data Ready */ if ( (d->bd_id & 0xff00) == 0) d->bd_id = inb(DSP_READ) << 8; /* major */ else { d->bd_id |= inb(DSP_READ); /* minor */ break; } } else DELAY(20); } /* * now do various initializations depending on board id. */ fmt = "SoundBlaster %d.%d" ; /* default */ switch ( d->bd_id >> 8 ) { case 0 : printf("\n\nFailed to get SB version (%x) - possible I/O conflict\n\n", inb(DSP_DATA_AVAIL)); d->bd_id = 0x100; case 1 : /* old sound blaster has nothing... */ break ; case 2 : d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */ d->bd_flags |= BD_F_DUP_MIDI ; if (d->bd_id == 0x200) break ; /* no mixer on the 2.0 */ d->bd_flags &= ~BD_F_MIX_MASK ; d->bd_flags |= BD_F_MIX_CT1335 ; break ; case 4 : fmt = "SoundBlaster 16 %d.%d"; d->audio_fmt |= AFMT_FULLDUPLEX | AFMT_WEIRD | AFMT_S8 | AFMT_S16_LE; d->bd_flags |= BD_F_SB16; d->bd_flags &= ~BD_F_MIX_MASK ; d->bd_flags |= BD_F_MIX_CT1745 ; /* soft irq/dma configuration */ x = -1 ; if (d->irq == 5) x = 2; else if (d->irq == 7) x = 4; else if (d->irq == 9) x = 1; else if (d->irq == 10) x = 8; if (x == -1) printf("<%s>%d: bad irq %d (only 5,7,9,10 allowed)\n", d->name, dev->id_unit, d->irq); else sb_setmixer(io_base, IRQ_NR, x); if (d->dbuf_out.chan == d->dbuf_in.chan) { printf("WARNING: sb: misconfigured secondary DMA channel\n"); } sb_setmixer(io_base, DMA_NR, (1 << d->dbuf_out.chan) | (1 << d->dbuf_in.chan)); break ; case 3 : d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */ fmt = "SoundBlaster Pro %d.%d"; d->bd_flags |= BD_F_DUP_MIDI ; d->bd_flags &= ~BD_F_MIX_MASK ; d->bd_flags |= BD_F_MIX_CT1345 ; if (d->bd_id == 0x301) { int ess_major = 0, ess_minor = 0; /* * Try to detect ESS chips. */ sb_cmd(io_base, DSP_CMD_GETID); /* Return ident. bytes. */ for (i = 1000; i; i--) { if (inb(DSP_DATA_AVAIL) & 0x80) { /* wait for Data Ready */ if (ess_major == 0) ess_major = inb(DSP_READ); else { ess_minor = inb(DSP_READ); break; } } else DELAY(20); } if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) { /* the ESS488 can be treated as an SBPRO */ printf("ESS488 (rev %d)\n", ess_minor & 0x0f); break ; } else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) { u_char cfg; u_char bits; int rev = ess_minor & 0xf; if (rev >= 8) printf("ESS1868 (rev %d)\n", rev); else printf("ESS688 (rev %d)\n", rev); d->bd_flags |= BD_F_ESS; d->audio_fmt |= AFMT_S16_LE; /* enable extended ESS mode */ sb_cmd(d->io_base, 0xc6); break; } else { printf("Unknown card 0x%x 0x%x -- hope it is SBPRO\n", ess_major, ess_minor); break ; } } } sprintf(d->name, fmt, (d->bd_id >> 8) &0xff, d->bd_id & 0xff); sb_mix_init(d);}static voidsb_mix_init(snddev_info *d){ switch (d->bd_flags & BD_F_MIX_MASK) { case BD_F_MIX_CT1345 : /* SB 3.0 has 1345 mixer */ d->mix_devs = SBPRO_MIXER_DEVICES ; d->mix_rec_devs = SBPRO_RECORDING_DEVICES ; d->mix_recsrc = SOUND_MASK_MIC ; sb_setmixer(d->io_base, 0, 1 ); /* reset mixer */ sb_setmixer(d->io_base, MIC_VOL , 0x6 ); /* mic volume max */ sb_setmixer(d->io_base, RECORD_SRC , 0x0 ); /* mic source */ sb_setmixer(d->io_base, FM_VOL , 0x0 ); /* no midi */ break ; case BD_F_MIX_CT1745 : /* SB16 mixer ... */ d->mix_devs = SB16_MIXER_DEVICES ; d->mix_rec_devs = SB16_RECORDING_DEVICES ; d->mix_recsrc = SOUND_MASK_MIC ; } sb_mixer_reset(d);}/* * Common code for the midi and pcm functions * * sb_cmd write a single byte to the CMD port. * sb_cmd2 write a CMD + 1 byte arg * sb_cmd3 write a CMD + 2 byte arg * sb_get_byte returns a single byte from the DSP data port * * ess_write is actually sb_cmd2 * ess_read access ext. regs via sb_cmd(0xc0, reg) followed by sb_get_byte */intsb_cmd(int io_base, u_char val){ int i; for (i = 0; i < 1000 ; i++) { if ((inb(io_base + SBDSP_STATUS) & 0x80) == 0) { outb(io_base + SBDSP_CMD, val); return 1; } if (i > 10) DELAY (i > 100 ? 1000 : 10 ); } printf("SoundBlaster: DSP Command(0x%02x) timeout. IRQ conflict ?\n", val); return 0;}intsb_cmd3(int io_base, u_char cmd, int val){ if (sb_cmd(io_base, cmd)) { sb_cmd(io_base, val & 0xff ); sb_cmd(io_base, (val>>8) & 0xff ); return 1 ; } else return 0;}intsb_cmd2(int io_base, u_char cmd, int val){ if (sb_cmd(io_base, cmd)) { sb_cmd(io_base, val & 0xff ); return 1 ; } else return 0;}/* * in the SB, there is a set of indirect "mixer" registers with * address at offset 4, data at offset 5 */voidsb_setmixer(int io_base, u_int port, u_int value){ u_long flags; flags = spltty(); outb(io_base + SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ DELAY(10); outb(io_base + SB_MIX_DATA, (u_char) (value & 0xff)); DELAY(10); splx(flags);}intsb_getmixer(int io_base, u_int port){ int val; u_long flags; flags = spltty(); outb(io_base + SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ DELAY(10); val = inb(io_base + SB_MIX_DATA); DELAY(10); splx(flags); return val;} u_intsb_get_byte(int io_base){ int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -