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

📄 scc.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
static int scc_net_tx(struct sk_buff *skb, struct device *dev){	struct scc_channel *scc = (struct scc_channel *) dev->priv;	unsigned long flags;	char kisscmd;		if (scc == NULL || scc->magic != SCC_MAGIC || dev->tbusy)	{		dev_kfree_skb(skb);		return 0;	}	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 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;	if (scc == NULL || scc->magic != SCC_MAGIC)		return -EINVAL;			arg = (void *) ifr->ifr_data;		if (!Driver_Initialized)	{		if (cmd == SIOCSCCCFG)		{			int found = 1;			if (!suser()) 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 (!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 = 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 (!suser())				return -EPERM;							if (Nchips == 0)				return -EINVAL;			z8530_init();			return 0;		}				return -EINVAL;	/* confuse the user */	}		if (!scc->init)	{		if (cmd == SIOCSCCCHANINI)		{			if (!suser()) 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 (!suser()) 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 (!suser()) 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 (!suser()) 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 device *dev, void *addr){	struct sockaddr *sa = (struct sockaddr *) addr;	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);	return 0;}/* ----> "hard" header <---- */static int  scc_net_header(struct sk_buff *skb, struct device *dev, 	unsigned short type, void *daddr, void *saddr, unsigned len){	return ax25_encapsulate(skb, dev, type, daddr, saddr, len);}/* ----> get statistics <---- */static struct net_device_stats *scc_net_get_stats(struct device *dev){	struct scc_channel *scc = (struct scc_channel *) dev->priv;		if (scc == NULL || scc->magic != SCC_MAGIC)		return NULL;			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, int dummy){	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;}#ifdef CONFIG_PROC_FSstruct proc_dir_entry scc_proc_dir_entry = { 	PROC_NET_Z8530, 8, "z8530drv", S_IFREG | S_IRUGO, 1, 0, 0, 0, 	&proc_net_inode_operations, scc_net_get_info };#define scc_net_procfs_init()   proc_net_register(&scc_proc_dir_entry);#define scc_net_procfs_remove() proc_net_unregister(PROC_NET_Z8530);#else#define scc_net_procfs_init()#define scc_net_procfs_remove()#endif  /* ******************************************************************** *//* * 			Init SCC driver 			      * *//* ******************************************************************** */__initfunc(int scc_init (void)){	int chip, chan, k, result;	char devname[10];		printk(KERN_INFO BANNER);		memset(&SCC_ctrl, 0, sizeof(SCC_ctrl));		/* pre-init channel information */		for (chip = 0; chip < SCC_MAXCHIPS; chip++)	{		memset((char *) &SCC_Info[2*chip  ], 0, sizeof(struct scc_channel));		memset((char *) &SCC_Info[2*chip+1], 0, sizeof(struct scc_channel));				for (chan = 0; chan < 2; chan++)			SCC_Info[2*chip+chan].magic = SCC_MAGIC;	}	for (k = 0; k < 16; k++) Ivec[k].used = 0;	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;	}	scc_net_procfs_init();	return 0;}/* ******************************************************************** *//* *			    Module support 			      * *//* ******************************************************************** */#ifdef MODULEint init_module(void){	int result = 0;		result = scc_init();	if (result == 0)		printk(KERN_INFO "Copyright 1993,1998 Joerg Reuter DL1BKE (jreuter@poboxes.com)\n");			return result;}void cleanup_module(void){	long flags;	io_port ctrl;	int k;	struct scc_channel *scc;		save_flags(flags); 	cli();	if (Nchips == 0)		unregister_netdev(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)		{			release_region(scc->ctrl, 1);			release_region(scc->data, 1);			if (scc->dev)			{				unregister_netdev(scc->dev);				kfree(scc->dev);			}		}	}		for (k=0; k < 16 ; k++)		if (Ivec[k].used) free_irq(k, NULL);			restore_flags(flags);	scc_net_procfs_remove();}#endif

⌨️ 快捷键说明

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