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

📄 sm_sbc.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
			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 + -