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

📄 sb_dsp.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
    for (i = 1000; i; i--)	if (inb(DSP_DATA_AVAIL) & 0x80)	    return inb(DSP_READ);	else	    DELAY(20);    return 0xffff;}intess_write(int io_base, u_char reg, int val){    return sb_cmd2(io_base, reg, val);}intess_read(int io_base, u_char reg){    if (!sb_cmd(io_base, 0xc0) || !sb_cmd(io_base, reg) )	return 0xffff ;    return sb_get_byte(io_base);}/* * various utility functions for the DSP *//* * dsp_speed updates the speed setting from the descriptor. make sure * it is called at spltty(). * Besides, it takes care of stereo setting. */static intdsp_speed(snddev_info *d){    u_char   tconst;    u_long   flags;    int max_speed = 44100, speed = d->play_speed ;    /*     * special code for the SB16     */    if (d->bd_flags & BD_F_SB16) {	RANGE (speed, 5000, 45000);	d->play_speed = d->rec_speed = speed ;	sb_cmd(d->io_base, 0x41);	sb_cmd(d->io_base, d->play_speed >> 8 );	sb_cmd(d->io_base, d->play_speed & 0xff );	sb_cmd(d->io_base, 0x42);	sb_cmd(d->io_base, d->rec_speed >> 8 );	sb_cmd(d->io_base, d->rec_speed & 0xff );	return speed ;    }    /*     * special code for the ESS ...     */    if (d->bd_flags & BD_F_ESS) {	int t;	RANGE (speed, 5000, 49000);	if (speed > 22000) {	    t = (795500 + speed / 2) / speed;	    speed = (795500 + t / 2) / t ;	    t = (256 - t ) | 0x80 ;	} else {	    t = (397700 + speed / 2) / speed;	    speed = (397700 + t / 2) / t ;	    t = 128 - t ;	}	ess_write(d->io_base, 0xa1, t); /* set time constant */	d->play_speed = d->rec_speed = speed ;	speed = (speed * 9 ) / 20 ;	t = 256-7160000/(speed*82);	ess_write(d->io_base,0xa2,t);	return speed ;    }    /*     * This is code for the SB3.x and lower.     * Only some models can do stereo, and only if not     * simultaneously using midi.     * At the moment we do not support either...     */#if 0    d->flags &= ~SND_F_STEREO;#endif    /*     * here enforce speed limitations.     */    if (d->bd_id <= 0x200)	max_speed = 22050; /* max 22050 on SB 1.X */    /*     * SB models earlier than SB Pro have low limit for the     * input rate. Note that this is only for input, but since     * we do not support separate values for rec & play....     */    if (d->bd_id <= 0x200)	max_speed = 13000;    else if (d->bd_id < 0x300)	max_speed = 15000;    RANGE(speed, 4000, max_speed);    if (d->flags & SND_F_STEREO) /* really unused right now... */	speed *= 2;    /*     * Now the speed should be valid. Compute the value to be     * programmed into the board.     */    if (speed > 22050) { /* High speed mode on 2.01/3.xx */	int tmp;	tconst = (u_char) ((65536 - ((256000000 + speed / 2) / speed)) >> 8) ;	d->bd_flags |= BD_F_HISPEED ;	flags = spltty();	sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */	splx(flags);	tmp = 65536 - (tconst << 8);	speed = (256000000 + tmp / 2) / tmp;    } else {	int             tmp;	d->bd_flags &= ~BD_F_HISPEED ;	tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;	flags = spltty();	sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */	splx(flags);	tmp = 256 - tconst;	speed = (1000000 + tmp / 2) / tmp;    }    if (d->flags & SND_F_STEREO) /* really unused right now... */	speed /= 2;    d->play_speed = d->rec_speed = speed;    return speed;}/* * mixer support, originally in sb_mixer.c */static voidsb_set_recsrc(snddev_info *d, int mask){    u_char recdev ;    mask &= d->mix_rec_devs;    switch (d->bd_flags & BD_F_MIX_MASK) {    case BD_F_MIX_CT1345 :	if (mask == SOUND_MASK_LINE)	    recdev = 6 ;	else if (mask == SOUND_MASK_CD)	    recdev = 2 ;	else { /* default: mic */	    mask =  SOUND_MASK_MIC ;	    recdev = 0 ;	}	sb_setmixer(d->io_base, RECORD_SRC,	    recdev | (sb_getmixer(d->io_base, RECORD_SRC) & ~7 ));	break ;    case BD_F_MIX_CT1745 : /* sb16 */	if (mask == 0)	    mask = SOUND_MASK_MIC ; /* XXX For compatibility. Bug ? */	recdev = 0 ;	if (mask & SOUND_MASK_MIC)	    recdev |= 1 ;	if (mask & SOUND_MASK_CD)	    recdev |= 6 ; /* l+r cd */	if (mask & SOUND_MASK_LINE)	    recdev |= 0x18 ; /* l+r line */	if (mask & SOUND_MASK_SYNTH)	    recdev |= 0x60 ; /* l+r midi */	sb_setmixer(d->io_base, SB16_IMASK_L, recdev);	sb_setmixer(d->io_base, SB16_IMASK_R, recdev);	/*	 * since the same volume controls apply to the input and	 * output sections, the best approach to have a consistent	 * behaviour among cards would be to disable the output path	 * on devices which are used to record.	 * However, since users like to have feedback, we only disable	 * the mike -- permanently.	 */        sb_setmixer(d->io_base, SB16_OMASK, 0x1f & ~1);	break ;    }    d->mix_recsrc = mask;}static voidsb_mixer_reset(snddev_info *d){    int             i;    for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)	sb_mixer_set(d, i, levels[i]);    if (d->bd_flags & BD_F_SB16) {	sb_setmixer(d->io_base, 0x3c, 0x1f); /* make all output active */	sb_setmixer(d->io_base, 0x3d, 0); /* make all inputs-l off */	sb_setmixer(d->io_base, 0x3e, 0); /* make all inputs-r off */    }    sb_set_recsrc(d, SOUND_MASK_MIC);}static intsb_mixer_set(snddev_info *d, int dev, int value){    int left = value & 0x000000ff;    int right = (value & 0x0000ff00) >> 8;    int regoffs;    u_char   val;    mixer_tab *iomap;#ifdef JAZZ16    if (d->bd_flags & BD_F_JAZZ16 && d->bd_flags & BD_F_JAZZ16_2)        return smw_mixer_set(dev, value);#endif    if (dev == SOUND_MIXER_RECSRC) {	sb_set_recsrc(d, value);	return 0 ;    }    if (left > 100)        left = 100;    if (right > 100)        right = 100;    if (dev > 31)        return EINVAL ;    if (!(d->mix_devs & (1 << dev)))      /* Not supported */        return EINVAL;    switch ( d->bd_flags & BD_F_MIX_MASK ) {    default:	/* mixer unknown, fail... */	return EINVAL ;/* XXX change this */    case BD_F_MIX_CT1345 :	iomap = &sbpro_mix ;	break;    case BD_F_MIX_CT1745 :	iomap = &sb16_mix ;	break;    /* XXX how about the SG NX Pro, iomap = sgnxpro_mix */    }    regoffs = (*iomap)[dev][LEFT_CHN].regno;    if (regoffs == 0)        return EINVAL;    val = sb_getmixer(d->io_base, regoffs);    change_bits(iomap, &val, dev, LEFT_CHN, left);    d->mix_levels[dev] = left | (left << 8);    if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) {    /* Change register */        sb_setmixer(d->io_base, regoffs, val);     /* Save the old one */        regoffs = (*iomap)[dev][RIGHT_CHN].regno;        if (regoffs == 0)            return 0 ;  /* Just left channel present */        val = sb_getmixer(d->io_base, regoffs);    /* Read the new one */    }    change_bits(iomap, &val, dev, RIGHT_CHN, right);    sb_setmixer(d->io_base, regoffs, val);    d->mix_levels[dev] = left | (right << 8);    return 0 ; /* ok */}/* * now support for some PnP boards. */#if NPNP > 0static char *ess1868_probe(u_long csn, u_long vend_id);static void ess1868_attach(u_long csn, u_long vend_id, char *name,        struct isa_device *dev);static struct pnp_device ess1868 = {        "ESS1868",        ess1868_probe,        ess1868_attach,        &nsnd,  /* use this for all sound cards */        &tty_imask      /* imask */};DATA_SET (pnpdevice_set, ess1868);    static char *ess1868_probe(u_long csn, u_long vend_id){       /*     * pnp X 1 os enable drq0 3 irq0 12 port0 0x240     */    if (vend_id == 0x68187316) {	struct pnp_cinfo d ;	read_pnp_parms ( &d , 1 ) ;	if (d.enable == 0) {	    printf("This is an ESS1868, but LDN 1 is disabled\n");	    return NULL;	}        return "ESS1868" ;    }    return NULL ;}static voidess1868_attach(u_long csn, u_long vend_id, char *name,        struct isa_device *dev){       struct pnp_cinfo d ;    snddev_info tmp_d ; /* patched copy of the basic snddev_info */    int the_irq = 0 ;         tmp_d = sb_op_desc;    snddev_last_probed = &tmp_d;#if 0    read_pnp_parms ( &d , 3 );  /* disable LDN 3 */    d.port[0] = 0 ;    d.enable = 0 ;    write_pnp_parms ( &d , 3 );        read_pnp_parms ( &d , 2 ); /* disable LDN 2 */    d.port[0] = 0 ;    d.enable = 0 ;    write_pnp_parms ( &d , 2 );    read_pnp_parms ( &d , 0 ); /* read config base */    tmp_d.conf_base = d.port[0];    write_pnp_parms ( &d , 0 );#endif      read_pnp_parms ( &d , 1 ) ;    dev->id_iobase = d.port[0];    d.port[1] = 0 ;    d.port[2] = 0 ;    write_pnp_parms ( &d , 1 );    enable_pnp_card();    dev->id_drq = d.drq[0] ; /* primary dma */    dev->id_irq = (1 << d.irq[0] ) ;    dev->id_intr = (inthand2_t *)pcmintr ;     dev->id_flags = 0 /* DV_F_DUAL_DMA | (d.drq[1] ) */;#if 0    snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */#endif    pcmattach(dev); }/* * A driver for some SB16pnp and compatibles... * * Avance Asound 100 -- 0x01009305 * Avance Logic ALS100+ -- 0x10019305 * xxx               -- 0x2b008c0e * */static char *sb16pnp_probe(u_long csn, u_long vend_id);static void sb16pnp_attach(u_long csn, u_long vend_id, char *name,        struct isa_device *dev);static struct pnp_device sb16pnp = {        "SB16pnp",        sb16pnp_probe,        sb16pnp_attach,        &nsnd,  /* use this for all sound cards */        &tty_imask      /* imask */};DATA_SET (pnpdevice_set, sb16pnp);    static char *sb16pnp_probe(u_long csn, u_long vend_id){       char *s = NULL ;    /*     * The SB16/AWExx cards seem to differ in the fourth byte of     * the vendor id, so I have just masked it for the time being...     * Reported values are:     * SB16 Value PnP:	0x2b008c0e     * SB AWExx PnP:	0x39008c0e 0x9d008c0e 0xc3008c0e     * Vibra16X:        0xf0008c0e     */    if (vend_id == 0xf0008c0e)	s = "Vibra16X" ;    else if ( (vend_id & 0xffffff)  == (0x9d008c0e & 0xffffff) )	s = "SB16 PnP";    else if (vend_id == 0x01009305)          s = "Avance Asound 100" ;    else if (vend_id == 0x10019305)        s = "Avance Logic 100+" ; /* Vibra16X-class */    if (s) {	struct pnp_cinfo d; 	read_pnp_parms(&d, 0); 	if (d.enable == 0) {	    printf("This is a %s, but LDN 0 is disabled\n", s);	    return NULL ;	}	return s ;    }    return NULL ;}    static voidsb16pnp_attach(u_long csn, u_long vend_id, char *name,        struct isa_device *dev){       struct pnp_cinfo d ;    snddev_info tmp_d ; /* patched copy of the basic snddev_info */        tmp_d = sb_op_desc;    snddev_last_probed = &tmp_d;    read_pnp_parms ( &d , 0 ) ;    d.port[1] = 0 ; /* only the first address is used */    dev->id_iobase = d.port[0];    tmp_d.synth_base = d.port[2];    write_pnp_parms ( &d , 0 );    enable_pnp_card();    dev->id_drq = d.drq[0] ; /* primary dma */    dev->id_irq = (1 << d.irq[0] ) ;    dev->id_intr = (inthand2_t *)pcmintr ;     dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ;    pcm_info[dev->id_unit] = tmp_d; /* pcm_info[] will be reinitialized after */    snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */        if (vend_id == 0x10019305 || vend_id == 0xf0008c0e) {	/*	 * XXX please add here the vend_id for other vibra16X cards...	 * And remember, must change tmp_d, not 	 */	tmp_d.bd_flags |= BD_F_SB16X ;    }    pcmattach(dev); }#endif /* NPNP */    #endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -