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

📄 sm_wss.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* --------------------------------------------------------------------- */static int wss_close(struct net_device *dev, struct sm_state *sm) {	if (!dev || !sm)		return -EINVAL;	/*	 * disable interrupts	 */	disable_dma(dev->dma);        write_codec(dev, 9, 0xc); /* disable codec */	free_irq(dev->irq, dev);		free_dma(dev->dma);		release_region(dev->base_addr, WSS_EXTENT);	kfree(sm->dma.obuf);	return 0;}/* --------------------------------------------------------------------- */static int wss_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;	int i, j;	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 ((i = wss_srate_index((*mtp)->srate)) < 0) 			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) &&			    ((j = wss_srate_index((*mrp)->srate)) >= 0)) {				sm->mode_tx = *mtp;				sm->mode_rx = *mrp;				SCSTATE->fmt[0] = j;				SCSTATE->fmt[1] = i;				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;				/* prefer same data format if possible to minimize switching times */				sm->dma.i16bit = sm->dma.o16bit = 2;				if (sm->mode_rx->srate == sm->mode_tx->srate) {					if (sm->mode_rx->demodulator_s16 && sm->mode_tx->modulator_s16)						sm->dma.i16bit = sm->dma.o16bit = 1;					else if (sm->mode_rx->demodulator_u8 && sm->mode_tx->modulator_u8)						sm->dma.i16bit = sm->dma.o16bit = 0;				}				if (sm->dma.i16bit == 2) {					if (sm->mode_rx->demodulator_s16)						sm->dma.i16bit = 1;					else if (sm->mode_rx->demodulator_u8)						sm->dma.i16bit = 0;				}				if (sm->dma.o16bit == 2) {					if (sm->mode_tx->modulator_s16)						sm->dma.o16bit = 1;					else if (sm->mode_tx->modulator_u8)						sm->dma.o16bit = 0;				}				if (sm->dma.i16bit == 2 ||  sm->dma.o16bit == 2) {					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;				}#ifdef __BIG_ENDIAN				/* big endian 16bit only works on crystal cards... */				if (sm->dma.i16bit) {					SCSTATE->fmt[0] |= 0xc0;					sm->dma.ifragsz <<= 1;				}				if (sm->dma.o16bit) {					SCSTATE->fmt[1] |= 0xc0;					sm->dma.ofragsz <<= 1;				}#else /* __BIG_ENDIAN */				if (sm->dma.i16bit) {					SCSTATE->fmt[0] |= 0x40;					sm->dma.ifragsz <<= 1;				}				if (sm->dma.o16bit) {					SCSTATE->fmt[1] |= 0x40;					sm->dma.ofragsz <<= 1;				}#endif /* __BIG_ENDIAN */				return 0;			}		}	}	return -EINVAL;}/* --------------------------------------------------------------------- */static int wss_ioctl(struct net_device *dev, struct sm_state *sm, struct ifreq *ifr, 		     struct hdlcdrv_ioctl *hi, int cmd){	struct sm_ioctl bi;	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 = SCSTATE->crystal ? 			SM_MIXER_CRYSTAL : SM_MIXER_AD1848;		if (((SCSTATE->crystal ? 0x2c0c20fflu: 0x20fflu) 		     >> bi.data.mix.reg) & 1) {			bi.data.mix.data = read_codec(dev, bi.data.mix.reg);			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;		if ((bi.data.mix.mixer_type != SM_MIXER_CRYSTAL || 		     !SCSTATE->crystal) &&		    (bi.data.mix.mixer_type != SM_MIXER_AD1848 ||		     bi.data.mix.reg >= 0x10))			return -EINVAL;		if (!((0x2c0c20fflu >> bi.data.mix.reg) & 1))			return -EACCES;		write_codec(dev, bi.data.mix.reg, bi.data.mix.data);		return 0;			}	if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi)))		return -EFAULT;	return 0;}/* --------------------------------------------------------------------- */const struct hardware_info sm_hw_wss = {	"wss", sizeof(struct sc_state_wss), 	wss_open, wss_close, wss_ioctl, wss_sethw};/* --------------------------------------------------------------------- */static void setup_fdx_dma_wss(struct net_device *dev, struct sm_state *sm){        unsigned long flags;	unsigned char oldcodecmode, codecdma;	long abrt;	unsigned int osamps, isamps;	        save_flags(flags);        cli();	/*	 * perform the final DMA sequence to disable the codec request	 */	oldcodecmode = read_codec(dev, 9);        write_codec(dev, 9, 0); /* disable codec DMA */	wss_ack_int(dev);	if ((codecdma = read_codec(dev, 11)) & 0x10) {		dma_setup(sm, 1, dev->dma);		dma_setup(sm, 0, sm->hdrv.ptt_out.dma2);		abrt = 0;		while (((codecdma = read_codec(dev, 11)) & 0x10) || ((++abrt) >= 0x10000));	}       	wss_set_codec_fmt(dev, sm, SCSTATE->fmt[1], SCSTATE->fmt[0], 1, 1);	osamps = dma_setup(sm, 1, dev->dma) - 1;	isamps = dma_setup(sm, 0, sm->hdrv.ptt_out.dma2) - 1;	write_codec(dev, 15, osamps & 0xff);	write_codec(dev, 14, osamps >> 8);	if (SCSTATE->crystal) {		write_codec(dev, 31, isamps & 0xff);		write_codec(dev, 30, isamps >> 8);	}	write_codec(dev, 9, 3);        restore_flags(flags);}/* --------------------------------------------------------------------- */static void wssfdx_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 long flags;	unsigned char cry_int_src;	unsigned icfrag, ocfrag, isamps, osamps;	if (!dev || !sm || !sm->mode_rx || !sm->mode_tx || 	    sm->hdrv.magic != HDLCDRV_MAGIC)		return;	save_flags(flags);	cli();	if (SCSTATE->crystal) { 		/* Crystal has an essentially different interrupt handler! */		cry_int_src = read_codec(dev, 0x18);		wss_ack_int(dev);		if (cry_int_src & 0x10) {       /* playback interrupt */			disable_dma(dev->dma);			clear_dma_ff(dev->dma);			osamps = dma_ptr(sm, 1, dev->dma, &ocfrag)-1;			write_codec(dev, 15, osamps & 0xff);			write_codec(dev, 14, osamps >> 8);			enable_dma(dev->dma);		}		if (cry_int_src & 0x20) {       /* capture interrupt */			disable_dma(sm->hdrv.ptt_out.dma2);			clear_dma_ff(sm->hdrv.ptt_out.dma2);			isamps = dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag)-1;			write_codec(dev, 31, isamps & 0xff);			write_codec(dev, 30, isamps >> 8);			enable_dma(sm->hdrv.ptt_out.dma2);		}		restore_flags(flags);		sm_int_freq(sm);		sti();		if (cry_int_src & 0x10) {			if (dma_end_transmit(sm, ocfrag))				dma_clear_transmit(sm);			dma_transmit(sm);		}		if (cry_int_src & 0x20) { 			dma_receive(sm, icfrag);			hdlcdrv_arbitrate(dev, &sm->hdrv);		}		sm_output_status(sm);		hdlcdrv_transmitter(dev, &sm->hdrv);		hdlcdrv_receiver(dev, &sm->hdrv);		return;	}	wss_ack_int(dev);	disable_dma(dev->dma);	disable_dma(sm->hdrv.ptt_out.dma2);	clear_dma_ff(dev->dma);	clear_dma_ff(sm->hdrv.ptt_out.dma2);	osamps = dma_ptr(sm, 1, dev->dma, &ocfrag)-1;	isamps = dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag)-1;	write_codec(dev, 15, osamps & 0xff);	write_codec(dev, 14, osamps >> 8);	if (SCSTATE->crystal) {		write_codec(dev, 31, isamps & 0xff);		write_codec(dev, 30, isamps >> 8);	}	enable_dma(dev->dma);	enable_dma(sm->hdrv.ptt_out.dma2);	restore_flags(flags);	sm_int_freq(sm);	sti();	if (dma_end_transmit(sm, ocfrag))		dma_clear_transmit(sm);	dma_transmit(sm);	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 wssfdx_open(struct net_device *dev, struct sm_state *sm) {	if (!dev || !sm || !sm->mode_rx || !sm->mode_tx)		return -ENXIO;	if (dev->base_addr <= 0 || dev->base_addr > 0x1000-WSS_EXTENT || 	    dev->irq < 2 || dev->irq > 15 || dev->dma > 3)		return -ENXIO;	if (check_region(dev->base_addr, WSS_EXTENT))		return -EACCES;	/*	 * check if a card is available	 */	if (wss_init_codec(dev, sm, 1, 1, 1, 0, 0, -45, -45))		return -ENODEV;	/*	 * 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, wssfdx_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, WSS_EXTENT, sm->hwdrv->hw_name);	setup_fdx_dma_wss(dev, sm);	return 0;}/* --------------------------------------------------------------------- */static int wssfdx_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);        write_codec(dev, 9, 0xc); /* disable codec */	free_irq(dev->irq, dev);		free_dma(dev->dma);		free_dma(sm->hdrv.ptt_out.dma2);		release_region(dev->base_addr, WSS_EXTENT);	kfree(sm->dma.ibuf);	kfree(sm->dma.obuf);	return 0;}/* --------------------------------------------------------------------- */static int wssfdx_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;	int i;	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 ((i = wss_srate_index((*mtp)->srate)) < 0) 			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 == (*mrp)->srate) {				sm->mode_tx = *mtp;				sm->mode_rx = *mrp;				SCSTATE->fmt[0] = SCSTATE->fmt[1] = i;				sm->dma.ifragsz = sm->dma.ofragsz = (sm->mode_rx->srate + 50)/100;				if (sm->dma.ifragsz < sm->mode_rx->overlap)					sm->dma.ifragsz = sm->mode_rx->overlap;				sm->dma.i16bit = sm->dma.o16bit = 2;				if (sm->mode_rx->demodulator_s16) {					sm->dma.i16bit = 1;					sm->dma.ifragsz <<= 1;#ifdef __BIG_ENDIAN    /* big endian 16bit only works on crystal cards... */					SCSTATE->fmt[0] |= 0xc0;#else /* __BIG_ENDIAN */					SCSTATE->fmt[0] |= 0x40;#endif /* __BIG_ENDIAN */				} else if (sm->mode_rx->demodulator_u8)					sm->dma.i16bit = 0;				if (sm->mode_tx->modulator_s16) {					sm->dma.o16bit = 1;					sm->dma.ofragsz <<= 1;#ifdef __BIG_ENDIAN    /* big endian 16bit only works on crystal cards... */					SCSTATE->fmt[1] |= 0xc0;#else /* __BIG_ENDIAN */					SCSTATE->fmt[1] |= 0x40;#endif /* __BIG_ENDIAN */				} else if (sm->mode_tx->modulator_u8)					sm->dma.o16bit = 0;				if (sm->dma.i16bit == 2 ||  sm->dma.o16bit == 2) {					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 wssfdx_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 wss_ioctl(dev, sm, ifr, hi, cmd);}/* --------------------------------------------------------------------- */const struct hardware_info sm_hw_wssfdx = {	"wssfdx", sizeof(struct sc_state_wss), 	wssfdx_open, wssfdx_close, wssfdx_ioctl, wssfdx_sethw};/* --------------------------------------------------------------------- */#undef SCSTATE

⌨️ 快捷键说明

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