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

📄 scc.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	scc_discard_buffers(scc);	return 0;}/* ----> receive frame, called from scc_rxint() <---- */static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb){	if (skb->len == 0) {		dev_kfree_skb_irq(skb);		return;	}			scc->dev_stat.rx_packets++;	skb->dev      = scc->dev;	skb->protocol = htons(ETH_P_AX25);	skb->mac.raw  = skb->data;	skb->pkt_type = PACKET_HOST;		netif_rx(skb);	return;}/* ----> transmit frame <---- */static int scc_net_tx(struct sk_buff *skb, struct net_device *dev){	struct scc_channel *scc = (struct scc_channel *) dev->priv;	unsigned long flags;	char kisscmd;	if (skb->len > scc->stat.bufsize || skb->len < 2) {		scc->dev_stat.tx_dropped++;	/* bogus frame */		dev_kfree_skb(skb);		return 0;	}		scc->dev_stat.tx_packets++;	scc->stat.txframes++;		kisscmd = *skb->data & 0x1f;	skb_pull(skb, 1);	if (kisscmd) {		scc_set_param(scc, kisscmd, *skb->data);		dev_kfree_skb(skb);		return 0;	}	save_flags(flags);	cli();		if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len) {		struct sk_buff *skb_del;		skb_del = skb_dequeue(&scc->tx_queue);		dev_kfree_skb(skb_del);	}	skb_queue_tail(&scc->tx_queue, skb);	dev->trans_start = jiffies;		/*	 * Start transmission if the trx state is idle or	 * t_idle hasn't expired yet. Use dwait/persistance/slottime	 * algorithm for normal halfduplex operation.	 */	if(scc->stat.tx_state == TXS_IDLE || scc->stat.tx_state == TXS_IDLE2) {		scc->stat.tx_state = TXS_BUSY;		if (scc->kiss.fulldup == KISS_DUPLEX_HALF)			scc_start_tx_timer(scc, t_dwait, scc->kiss.waittime);		else			scc_start_tx_timer(scc, t_dwait, 0);	}	restore_flags(flags);		return 0;}/* ----> ioctl functions <---- *//* * SIOCSCCCFG		- configure driver	arg: (struct scc_hw_config *) arg * SIOCSCCINI		- initialize driver	arg: --- * SIOCSCCCHANINI	- initialize channel	arg: (struct scc_modem *) arg * SIOCSCCSMEM		- set memory		arg: (struct scc_mem_config *) arg * SIOCSCCGKISS		- get level 1 parameter	arg: (struct scc_kiss_cmd *) arg * SIOCSCCSKISS		- set level 1 parameter arg: (struct scc_kiss_cmd *) arg * SIOCSCCGSTAT		- get driver status	arg: (struct scc_stat *) arg * SIOCSCCCAL		- send calib. pattern	arg: (struct scc_calibrate *) arg */static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){	struct scc_kiss_cmd kiss_cmd;	struct scc_mem_config memcfg;	struct scc_hw_config hwcfg;	struct scc_calibrate cal;	int chan;	unsigned char device_name[10];	void *arg;	struct scc_channel *scc;		scc = (struct scc_channel *) dev->priv;	arg = (void *) ifr->ifr_data;		if (!Driver_Initialized)	{		if (cmd == SIOCSCCCFG)		{			int found = 1;			if (!capable(CAP_SYS_RAWIO)) return -EPERM;			if (!arg) return -EFAULT;			if (Nchips >= SCC_MAXCHIPS) 				return -EINVAL;			if (copy_from_user(&hwcfg, arg, sizeof(hwcfg)))				return -EFAULT;			if (hwcfg.irq == 2) hwcfg.irq = 9;			if (hwcfg.irq <0 || hwcfg.irq > NR_IRQS)				return -EINVAL;							if (!Ivec[hwcfg.irq].used && hwcfg.irq)			{				if (request_irq(hwcfg.irq, scc_isr, SA_INTERRUPT, "AX.25 SCC", NULL))					printk(KERN_WARNING "z8530drv: warning, cannot get IRQ %d\n", hwcfg.irq);				else					Ivec[hwcfg.irq].used = 1;			}			if (hwcfg.vector_latch && !Vector_Latch) {				if (!request_region(hwcfg.vector_latch, 1, "scc vector latch"))					printk(KERN_WARNING "z8530drv: warning, cannot reserve vector latch port 0x%lx\n, disabled.", hwcfg.vector_latch);				else					Vector_Latch = hwcfg.vector_latch;			}			if (hwcfg.clock == 0)				hwcfg.clock = SCC_DEFAULT_CLOCK;#ifndef SCC_DONT_CHECK			disable_irq(hwcfg.irq);			check_region(scc->ctrl, 1);			Outb(hwcfg.ctrl_a, 0);			OutReg(hwcfg.ctrl_a, R9, FHWRES);			udelay(100);			OutReg(hwcfg.ctrl_a,R13,0x55);		/* is this chip really there? */			udelay(5);			if (InReg(hwcfg.ctrl_a,R13) != 0x55)				found = 0;			enable_irq(hwcfg.irq);#endif			if (found)			{				SCC_Info[2*Nchips  ].ctrl = hwcfg.ctrl_a;				SCC_Info[2*Nchips  ].data = hwcfg.data_a;				SCC_Info[2*Nchips  ].irq  = hwcfg.irq;				SCC_Info[2*Nchips+1].ctrl = hwcfg.ctrl_b;				SCC_Info[2*Nchips+1].data = hwcfg.data_b;				SCC_Info[2*Nchips+1].irq  = hwcfg.irq;							SCC_ctrl[Nchips].chan_A = hwcfg.ctrl_a;				SCC_ctrl[Nchips].chan_B = hwcfg.ctrl_b;				SCC_ctrl[Nchips].irq    = hwcfg.irq;			}			for (chan = 0; chan < 2; chan++)			{				sprintf(device_name, "%s%i", SCC_DriverName, 2*Nchips+chan);				SCC_Info[2*Nchips+chan].special = hwcfg.special;				SCC_Info[2*Nchips+chan].clock = hwcfg.clock;				SCC_Info[2*Nchips+chan].brand = hwcfg.brand;				SCC_Info[2*Nchips+chan].option = hwcfg.option;				SCC_Info[2*Nchips+chan].enhanced = hwcfg.escc;#ifdef SCC_DONT_CHECK				printk(KERN_INFO "%s: data port = 0x%3.3x  control port = 0x%3.3x\n",					device_name, 					SCC_Info[2*Nchips+chan].data, 					SCC_Info[2*Nchips+chan].ctrl);#else				printk(KERN_INFO "%s: data port = 0x%3.3lx  control port = 0x%3.3lx -- %s\n",					device_name,					chan? hwcfg.data_b : hwcfg.data_a, 					chan? hwcfg.ctrl_b : hwcfg.ctrl_a,					found? "found" : "missing");#endif				if (found)				{					request_region(SCC_Info[2*Nchips+chan].ctrl, 1, "scc ctrl");					request_region(SCC_Info[2*Nchips+chan].data, 1, "scc data");					if (Nchips+chan != 0)						scc_net_setup(&SCC_Info[2*Nchips+chan], device_name, 1);				}			}						if (found) Nchips++;						return 0;		}				if (cmd == SIOCSCCINI)		{			if (!capable(CAP_SYS_RAWIO))				return -EPERM;							if (Nchips == 0)				return -EINVAL;			z8530_init();			return 0;		}				return -EINVAL;	/* confuse the user */	}		if (!scc->init)	{		if (cmd == SIOCSCCCHANINI)		{			if (!capable(CAP_NET_ADMIN)) return -EPERM;			if (!arg) return -EINVAL;						scc->stat.bufsize   = SCC_BUFSIZE;			if (copy_from_user(&scc->modem, arg, sizeof(struct scc_modem)))				return -EINVAL;						/* default KISS Params */					if (scc->modem.speed < 4800)			{				scc->kiss.txdelay = 36;		/* 360 ms */				scc->kiss.persist = 42;		/* 25% persistence */			/* was 25 */				scc->kiss.slottime = 16;	/* 160 ms */				scc->kiss.tailtime = 4;		/* minimal reasonable value */				scc->kiss.fulldup = 0;		/* CSMA */				scc->kiss.waittime = 50;	/* 500 ms */				scc->kiss.maxkeyup = 10;	/* 10 s */				scc->kiss.mintime = 3;		/* 3 s */				scc->kiss.idletime = 30;	/* 30 s */				scc->kiss.maxdefer = 120;	/* 2 min */				scc->kiss.softdcd = 0;		/* hardware dcd */			} else {				scc->kiss.txdelay = 10;		/* 100 ms */				scc->kiss.persist = 64;		/* 25% persistence */			/* was 25 */				scc->kiss.slottime = 8;		/* 160 ms */				scc->kiss.tailtime = 1;		/* minimal reasonable value */				scc->kiss.fulldup = 0;		/* CSMA */				scc->kiss.waittime = 50;	/* 500 ms */				scc->kiss.maxkeyup = 7;		/* 7 s */				scc->kiss.mintime = 3;		/* 3 s */				scc->kiss.idletime = 30;	/* 30 s */				scc->kiss.maxdefer = 120;	/* 2 min */				scc->kiss.softdcd = 0;		/* hardware dcd */			}						scc->tx_buff = NULL;			skb_queue_head_init(&scc->tx_queue);			scc->init = 1;						return 0;		}				return -EINVAL;	}		switch(cmd)	{		case SIOCSCCRESERVED:			return -ENOIOCTLCMD;		case SIOCSCCSMEM:			if (!capable(CAP_SYS_RAWIO)) return -EPERM;			if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg)))				return -EINVAL;			scc->stat.bufsize   = memcfg.bufsize;			return 0;				case SIOCSCCGSTAT:			if (!arg || copy_to_user(arg, &scc->stat, sizeof(scc->stat)))				return -EINVAL;			return 0;				case SIOCSCCGKISS:			if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd)))				return -EINVAL;			kiss_cmd.param = scc_get_param(scc, kiss_cmd.command);			if (copy_to_user(arg, &kiss_cmd, sizeof(kiss_cmd)))				return -EINVAL;			return 0;				case SIOCSCCSKISS:			if (!capable(CAP_NET_ADMIN)) return -EPERM;			if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd)))				return -EINVAL;			return scc_set_param(scc, kiss_cmd.command, kiss_cmd.param);				case SIOCSCCCAL:			if (!capable(CAP_SYS_RAWIO)) return -EPERM;			if (!arg || copy_from_user(&cal, arg, sizeof(cal)) || cal.time == 0)				return -EINVAL;			scc_start_calibrate(scc, cal.time, cal.pattern);			return 0;		default:			return -ENOIOCTLCMD;			}		return -EINVAL;}/* ----> set interface callsign <---- */static int scc_net_set_mac_address(struct net_device *dev, void *addr){	struct sockaddr *sa = (struct sockaddr *) addr;	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);	return 0;}/* ----> get statistics <---- */static struct net_device_stats *scc_net_get_stats(struct net_device *dev){	struct scc_channel *scc = (struct scc_channel *) dev->priv;		scc->dev_stat.rx_errors = scc->stat.rxerrs + scc->stat.rx_over;	scc->dev_stat.tx_errors = scc->stat.txerrs + scc->stat.tx_under;	scc->dev_stat.rx_fifo_errors = scc->stat.rx_over;	scc->dev_stat.tx_fifo_errors = scc->stat.tx_under;	return &scc->dev_stat;}/* ******************************************************************** *//* *		dump statistics to /proc/net/z8530drv		      * *//* ******************************************************************** */static int scc_net_get_info(char *buffer, char **start, off_t offset, int length){	struct scc_channel *scc;	struct scc_kiss *kiss;	struct scc_stat *stat;	int len = 0;	off_t pos = 0;	off_t begin = 0;	int k;	len += sprintf(buffer, "z8530drv-"VERSION"\n");	if (!Driver_Initialized)	{		len += sprintf(buffer+len, "not initialized\n");		goto done;	}	if (!Nchips)	{		len += sprintf(buffer+len, "chips missing\n");		goto done;	}	for (k = 0; k < Nchips*2; k++)	{		scc = &SCC_Info[k];		stat = &scc->stat;		kiss = &scc->kiss;		if (!scc->init)			continue;		/* dev	data ctrl irq clock brand enh vector special option 		 *	baud nrz clocksrc softdcd bufsize		 *	rxints txints exints spints		 *	rcvd rxerrs over / xmit txerrs under / nospace bufsize		 *	txd pers slot tail ful wait min maxk idl defr txof grp		 *	W ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##		 *	R ## ## XX ## ## ## ## ## XX ## ## ## ## ## ## ##		 */		len += sprintf(buffer+len, "%s\t%3.3lx %3.3lx %d %lu %2.2x %d %3.3lx %3.3lx %d\n",				scc->dev->name,				scc->data, scc->ctrl, scc->irq, scc->clock, scc->brand,				scc->enhanced, Vector_Latch, scc->special,				scc->option);		len += sprintf(buffer+len, "\t%lu %d %d %d %d\n",				scc->modem.speed, scc->modem.nrz,				scc->modem.clocksrc, kiss->softdcd,				stat->bufsize);		len += sprintf(buffer+len, "\t%lu %lu %lu %lu\n",				stat->rxints, stat->txints, stat->exints, stat->spints);		len += sprintf(buffer+len, "\t%lu %lu %d / %lu %lu %d / %d %d\n",				stat->rxframes, stat->rxerrs, stat->rx_over,				stat->txframes, stat->txerrs, stat->tx_under,				stat->nospace,  stat->tx_state);#define K(x) kiss->x		len += sprintf(buffer+len, "\t%d %d %d %d %d %d %d %d %d %d %d %d\n",				K(txdelay), K(persist), K(slottime), K(tailtime),				K(fulldup), K(waittime), K(mintime), K(maxkeyup),				K(idletime), K(maxdefer), K(tx_inhibit), K(group));#undef K#ifdef SCC_DEBUG		{			int reg;		len += sprintf(buffer+len, "\tW ");			for (reg = 0; reg < 16; reg++)				len += sprintf(buffer+len, "%2.2x ", scc->wreg[reg]);			len += sprintf(buffer+len, "\n");					len += sprintf(buffer+len, "\tR %2.2x %2.2x XX ", InReg(scc->ctrl,R0), InReg(scc->ctrl,R1));			for (reg = 3; reg < 8; reg++)				len += sprintf(buffer+len, "%2.2x ", InReg(scc->ctrl, reg));			len += sprintf(buffer+len, "XX ");			for (reg = 9; reg < 16; reg++)				len += sprintf(buffer+len, "%2.2x ", InReg(scc->ctrl, reg));			len += sprintf(buffer+len, "\n");		}#endif		len += sprintf(buffer+len, "\n");                pos = begin + len;                if (pos < offset) {                        len   = 0;                        begin = pos;                }                if (pos > offset + length)                        break;	}done:        *start = buffer + (offset - begin);        len   -= (offset - begin);        if (len > length) len = length;        return len;} /* ******************************************************************** *//* * 			Init SCC driver 			      * *//* ******************************************************************** */static int __init scc_init_driver (void){	int result;	char devname[10];		printk(banner);		sprintf(devname,"%s0", SCC_DriverName);		result = scc_net_setup(SCC_Info, devname, 0);	if (result)	{		printk(KERN_ERR "z8530drv: cannot initialize module\n");		return result;	}	proc_net_create("z8530drv", 0, scc_net_get_info);	return 0;}static void __exit scc_cleanup_driver(void){	unsigned long flags;	io_port ctrl;	int k;	struct scc_channel *scc;		save_flags(flags); 	cli();	if (Nchips == 0)	{		unregister_netdev(SCC_Info[0].dev);		kfree(SCC_Info[0].dev);	}	for (k = 0; k < Nchips; k++)		if ( (ctrl = SCC_ctrl[k].chan_A) )		{			Outb(ctrl, 0);			OutReg(ctrl,R9,FHWRES);	/* force hardware reset */			udelay(50);		}			for (k = 0; k < Nchips*2; k++)	{		scc = &SCC_Info[k];		if (scc->ctrl)		{			release_region(scc->ctrl, 1);			release_region(scc->data, 1);		}		if (scc->dev)		{			unregister_netdev(scc->dev);			kfree(scc->dev);		}	}		for (k=0; k < NR_IRQS ; k++)		if (Ivec[k].used) free_irq(k, NULL);			if (Vector_Latch)		release_region(Vector_Latch, 1);	restore_flags(flags);	proc_net_remove("z8530drv");}MODULE_AUTHOR("Joerg Reuter <jreuter@yaina.de>");MODULE_DESCRIPTION("AX.25 Device Driver for Z8530 based HDLC cards");MODULE_SUPPORTED_DEVICE("Z8530 based SCC cards for Amateur Radio");MODULE_LICENSE("GPL");module_init(scc_init_driver);module_exit(scc_cleanup_driver);

⌨️ 快捷键说明

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