⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sb_dsp.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
				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 + -