📄 sm_sbc.c
字号:
printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", sm_drvname, (*mtp)->name, (*mtp)->loc_storage); continue; } if (!(*mtp)->name || strcmp((*mtp)->name, mode)) continue; if ((*mtp)->srate < 5000 || (*mtp)->srate > 44100) continue; if (!(*mtp)->modulator_u8) continue; for (mrp = sm_modem_rx_table; *mrp; mrp++) { if ((*mrp)->loc_storage > sizeof(sm->d)) { printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", sm_drvname, (*mrp)->name, (*mrp)->loc_storage); continue; } if (!(*mrp)->demodulator_u8) continue; if ((*mrp)->name && !strcmp((*mrp)->name, cp) && (*mrp)->srate >= 5000 && (*mrp)->srate <= 44100) { sm->mode_tx = *mtp; sm->mode_rx = *mrp; SCSTATE->fmt[0] = 256-((1000000L+sm->mode_rx->srate/2)/ sm->mode_rx->srate); SCSTATE->fmt[1] = 256-((1000000L+sm->mode_tx->srate/2)/ sm->mode_tx->srate); sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100; sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100; if (sm->dma.ifragsz < sm->mode_rx->overlap) sm->dma.ifragsz = sm->mode_rx->overlap; sm->dma.i16bit = sm->dma.o16bit = 0; return 0; } } } return -EINVAL;}/* --------------------------------------------------------------------- */static int sbc_ioctl(struct net_device *dev, struct sm_state *sm, struct ifreq *ifr, struct hdlcdrv_ioctl *hi, int cmd){ struct sm_ioctl bi; unsigned long flags; int i; if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_SERIOBASE | HDLCDRV_PARMASK_PARIOBASE | HDLCDRV_PARMASK_MIDIIOBASE; if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) return -EFAULT; switch (bi.cmd) { default: return -ENOIOCTLCMD; case SMCTL_GETMIXER: i = 0; bi.data.mix.sample_rate = sm->mode_rx->srate; bi.data.mix.bit_rate = sm->hdrv.par.bitrate; bi.data.mix.mixer_type = SM_MIXER_INVALID; switch (SCSTATE->revhi) { case 2: bi.data.mix.mixer_type = SM_MIXER_CT1335; break; case 3: bi.data.mix.mixer_type = SM_MIXER_CT1345; break; case 4: bi.data.mix.mixer_type = SM_MIXER_CT1745; break; } if (bi.data.mix.mixer_type != SM_MIXER_INVALID && bi.data.mix.reg < 0x80) { save_flags(flags); cli(); outb(bi.data.mix.reg, DSP_MIXER_ADDR(dev->base_addr)); bi.data.mix.data = inb(DSP_MIXER_DATA(dev->base_addr)); restore_flags(flags); i = 1; } if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) return -EFAULT; return i; case SMCTL_SETMIXER: if (!capable(CAP_SYS_RAWIO)) return -EACCES; switch (SCSTATE->revhi) { case 2: if (bi.data.mix.mixer_type != SM_MIXER_CT1335) return -EINVAL; break; case 3: if (bi.data.mix.mixer_type != SM_MIXER_CT1345) return -EINVAL; break; case 4: if (bi.data.mix.mixer_type != SM_MIXER_CT1745) return -EINVAL; break; default: return -ENODEV; } if (bi.data.mix.reg >= 0x80) return -EACCES; save_flags(flags); cli(); outb(bi.data.mix.reg, DSP_MIXER_ADDR(dev->base_addr)); outb(bi.data.mix.data, DSP_MIXER_DATA(dev->base_addr)); restore_flags(flags); return 0; } if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) return -EFAULT; return 0;}/* --------------------------------------------------------------------- */const struct hardware_info sm_hw_sbc = { "sbc", sizeof(struct sc_state_sbc), sbc_open, sbc_close, sbc_ioctl, sbc_sethw};/* --------------------------------------------------------------------- */static void setup_dma_fdx_dsp(struct net_device *dev, struct sm_state *sm){ unsigned long flags; unsigned int isamps, osamps; if (!reset_dsp(dev)) { printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname); return; } save_flags(flags); cli(); sbc_int_ack_8bit(dev); sbc_int_ack_16bit(dev); /* should eventually change to set rates individually by SBC_SAMPLE_RATE_{IN/OUT} */ write_dsp(dev, SBC_SAMPLE_RATE_IN); write_dsp(dev, SCSTATE->sr[0] >> 8); write_dsp(dev, SCSTATE->sr[0] & 0xff); write_dsp(dev, SBC_SAMPLE_RATE_OUT); write_dsp(dev, SCSTATE->sr[1] >> 8); write_dsp(dev, SCSTATE->sr[1] & 0xff); write_dsp(dev, SBC_SPEAKER_ON); if (sm->dma.o16bit) { /* * DMA channel 1 (8bit) does input (capture), * DMA channel 2 (16bit) does output (playback) */ isamps = dma_setup(sm, 0, dev->dma) - 1; osamps = dma_setup(sm, 1, sm->hdrv.ptt_out.dma2) - 1; sbc_int_ack_8bit(dev); sbc_int_ack_16bit(dev); write_dsp(dev, SBC4_IN8_AI); write_dsp(dev, SBC4_MODE_UNS_MONO); write_dsp(dev, isamps & 0xff); write_dsp(dev, isamps >> 8); write_dsp(dev, SBC4_OUT16_AI); write_dsp(dev, SBC4_MODE_SIGN_MONO); write_dsp(dev, osamps & 0xff); write_dsp(dev, osamps >> 8); } else { /* * DMA channel 1 (8bit) does output (playback), * DMA channel 2 (16bit) does input (capture) */ isamps = dma_setup(sm, 0, sm->hdrv.ptt_out.dma2) - 1; osamps = dma_setup(sm, 1, dev->dma) - 1; sbc_int_ack_8bit(dev); sbc_int_ack_16bit(dev); write_dsp(dev, SBC4_OUT8_AI); write_dsp(dev, SBC4_MODE_UNS_MONO); write_dsp(dev, osamps & 0xff); write_dsp(dev, osamps >> 8); write_dsp(dev, SBC4_IN16_AI); write_dsp(dev, SBC4_MODE_SIGN_MONO); write_dsp(dev, isamps & 0xff); write_dsp(dev, isamps >> 8); } dma_init_receive(sm); dma_init_transmit(sm); restore_flags(flags);}/* --------------------------------------------------------------------- */static void sbcfdx_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *)dev_id; struct sm_state *sm = (struct sm_state *)dev->priv; unsigned char intsrc, pbint = 0, captint = 0; unsigned int ocfrag, icfrag; unsigned long flags; if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC) return; save_flags(flags); cli(); outb(0x82, DSP_MIXER_ADDR(dev->base_addr)); intsrc = inb(DSP_MIXER_DATA(dev->base_addr)); if (intsrc & 0x01) { sbc_int_ack_8bit(dev); if (sm->dma.o16bit) { captint = 1; disable_dma(dev->dma); clear_dma_ff(dev->dma); dma_ptr(sm, 0, dev->dma, &icfrag); enable_dma(dev->dma); } else { pbint = 1; disable_dma(dev->dma); clear_dma_ff(dev->dma); dma_ptr(sm, 1, dev->dma, &ocfrag); enable_dma(dev->dma); } } if (intsrc & 0x02) { sbc_int_ack_16bit(dev); if (sm->dma.o16bit) { pbint = 1; disable_dma(sm->hdrv.ptt_out.dma2); clear_dma_ff(sm->hdrv.ptt_out.dma2); dma_ptr(sm, 1, sm->hdrv.ptt_out.dma2, &ocfrag); enable_dma(sm->hdrv.ptt_out.dma2); } else { captint = 1; disable_dma(sm->hdrv.ptt_out.dma2); clear_dma_ff(sm->hdrv.ptt_out.dma2); dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag); enable_dma(sm->hdrv.ptt_out.dma2); } } restore_flags(flags); sm_int_freq(sm); sti(); if (pbint) { if (dma_end_transmit(sm, ocfrag)) dma_clear_transmit(sm); dma_transmit(sm); } if (captint) { dma_receive(sm, icfrag); hdlcdrv_arbitrate(dev, &sm->hdrv); } sm_output_status(sm); hdlcdrv_transmitter(dev, &sm->hdrv); hdlcdrv_receiver(dev, &sm->hdrv);}/* --------------------------------------------------------------------- */static int sbcfdx_open(struct net_device *dev, struct sm_state *sm) { int err; if (sizeof(sm->m) < sizeof(struct sc_state_sbc)) { printk(KERN_ERR "sm sbc: sbc state too big: %d > %d\n", sizeof(struct sc_state_sbc), sizeof(sm->m)); return -ENODEV; } if (!dev || !sm) return -ENXIO; if (dev->base_addr <= 0 || dev->base_addr > 0x1000-SBC_EXTENT || dev->irq < 2 || dev->irq > 15 || dev->dma > 3) return -ENXIO; if (check_region(dev->base_addr, SBC_EXTENT)) return -EACCES; /* * check if a card is available */ if (!reset_dsp(dev)) { printk(KERN_ERR "%s: sbc: no card at io address 0x%lx\n", sm_drvname, dev->base_addr); return -ENODEV; } write_dsp(dev, SBC_GET_REVISION); if (!read_dsp(dev, &SCSTATE->revhi) || !read_dsp(dev, &SCSTATE->revlo)) return -ENODEV; printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%d\n", sm_drvname, SCSTATE->revhi, SCSTATE->revlo); if (SCSTATE->revhi < 4) { printk(KERN_ERR "%s: at least DSP rev 4.00 required\n", sm_drvname); return -ENODEV; } if ((err = config_resources(dev, sm, 1))) { printk(KERN_ERR "%s: invalid IRQ and/or DMA specified\n", sm_drvname); return err; } /* * initialize some variables */ if (!(sm->dma.ibuf = kmalloc(sm->dma.ifragsz * (NUM_FRAGMENTS+1), GFP_KERNEL | GFP_DMA))) return -ENOMEM; if (!(sm->dma.obuf = kmalloc(sm->dma.ofragsz * NUM_FRAGMENTS, GFP_KERNEL | GFP_DMA))) { kfree(sm->dma.ibuf); return -ENOMEM; } dma_init_transmit(sm); dma_init_receive(sm); memset(&sm->m, 0, sizeof(sm->m)); memset(&sm->d, 0, sizeof(sm->d)); if (sm->mode_tx->init) sm->mode_tx->init(sm); if (sm->mode_rx->init) sm->mode_rx->init(sm); if (request_dma(dev->dma, sm->hwdrv->hw_name)) { kfree(sm->dma.ibuf); kfree(sm->dma.obuf); return -EBUSY; } if (request_dma(sm->hdrv.ptt_out.dma2, sm->hwdrv->hw_name)) { kfree(sm->dma.ibuf); kfree(sm->dma.obuf); free_dma(dev->dma); return -EBUSY; } if (request_irq(dev->irq, sbcfdx_interrupt, SA_INTERRUPT, sm->hwdrv->hw_name, dev)) { kfree(sm->dma.ibuf); kfree(sm->dma.obuf); free_dma(dev->dma); free_dma(sm->hdrv.ptt_out.dma2); return -EBUSY; } request_region(dev->base_addr, SBC_EXTENT, sm->hwdrv->hw_name); setup_dma_fdx_dsp(dev, sm); return 0;}/* --------------------------------------------------------------------- */static int sbcfdx_close(struct net_device *dev, struct sm_state *sm) { if (!dev || !sm) return -EINVAL; /* * disable interrupts */ disable_dma(dev->dma); disable_dma(sm->hdrv.ptt_out.dma2); reset_dsp(dev); free_irq(dev->irq, dev); free_dma(dev->dma); free_dma(sm->hdrv.ptt_out.dma2); release_region(dev->base_addr, SBC_EXTENT); kfree(sm->dma.ibuf); kfree(sm->dma.obuf); return 0;}/* --------------------------------------------------------------------- */static int sbcfdx_sethw(struct net_device *dev, struct sm_state *sm, char *mode){ char *cp = strchr(mode, '.'); const struct modem_tx_info **mtp = sm_modem_tx_table; const struct modem_rx_info **mrp; if (!strcmp(mode, "off")) { sm->mode_tx = NULL; sm->mode_rx = NULL; return 0; } if (cp) *cp++ = '\0'; else cp = mode; for (; *mtp; mtp++) { if ((*mtp)->loc_storage > sizeof(sm->m)) { printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", sm_drvname, (*mtp)->name, (*mtp)->loc_storage); continue; } if (!(*mtp)->name || strcmp((*mtp)->name, mode)) continue; if ((*mtp)->srate < 5000 || (*mtp)->srate > 44100) continue; for (mrp = sm_modem_rx_table; *mrp; mrp++) { if ((*mrp)->loc_storage > sizeof(sm->d)) { printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", sm_drvname, (*mrp)->name, (*mrp)->loc_storage); continue; } if ((*mrp)->name && !strcmp((*mrp)->name, cp) && (*mtp)->srate >= 5000 && (*mtp)->srate <= 44100 && (*mrp)->srate == (*mtp)->srate) { sm->mode_tx = *mtp; sm->mode_rx = *mrp; SCSTATE->sr[0] = sm->mode_rx->srate; SCSTATE->sr[1] = sm->mode_tx->srate; sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100; sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100; if (sm->dma.ifragsz < sm->mode_rx->overlap) sm->dma.ifragsz = sm->mode_rx->overlap; if (sm->mode_rx->demodulator_s16 && sm->mode_tx->modulator_u8) { sm->dma.i16bit = 1; sm->dma.o16bit = 0; sm->dma.ifragsz <<= 1; } else if (sm->mode_rx->demodulator_u8 && sm->mode_tx->modulator_s16) { sm->dma.i16bit = 0; sm->dma.o16bit = 1; sm->dma.ofragsz <<= 1; } else { printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname, sm->mode_rx->name, sm->mode_tx->name); sm->mode_tx = NULL; sm->mode_rx = NULL; return -EINVAL; } return 0; } } } return -EINVAL;}/* --------------------------------------------------------------------- */static int sbcfdx_ioctl(struct net_device *dev, struct sm_state *sm, struct ifreq *ifr, struct hdlcdrv_ioctl *hi, int cmd){ if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_DMA2 | HDLCDRV_PARMASK_SERIOBASE | HDLCDRV_PARMASK_PARIOBASE | HDLCDRV_PARMASK_MIDIIOBASE; return sbc_ioctl(dev, sm, ifr, hi, cmd);}/* --------------------------------------------------------------------- */const struct hardware_info sm_hw_sbcfdx = { "sbcfdx", sizeof(struct sc_state_sbc), sbcfdx_open, sbcfdx_close, sbcfdx_ioctl, sbcfdx_sethw};/* --------------------------------------------------------------------- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -