📄 sb_dsp.c
字号:
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 + -