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

📄 sdla.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * SDLA		An implementation of a driver for the Sangoma S502/S508 series *		multi-protocol PC interface card.  Initial offering is with  *		the DLCI driver, providing Frame Relay support for linux. * *		Global definitions for the Frame relay interface. * * Version:	@(#)sdla.c   0.30	12 Sep 1996 * * Credits:	Sangoma Technologies, for the use of 2 cards for an extended *			period of time. *		David Mandelstam <dm@sangoma.com> for getting me started on  *			this project, and incentive to complete it. *		Gene Kozen <74604.152@compuserve.com> for providing me with *			important information about the cards. * * Author:	Mike McLagan <mike.mclagan@linux.org> * * Changes: *		0.15	Mike McLagan	Improved error handling, packet dropping *		0.20	Mike McLagan	New transmit/receive flags for config *					If in FR mode, don't accept packets from *					non DLCI devices. *		0.25	Mike McLagan	Fixed problem with rejecting packets *					from non DLCI devices. *		0.30	Mike McLagan	Fixed kernel panic when used with modified *					ifconfig * *		This program is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. */#include <linux/config.h> /* for CONFIG_DLCI_MAX */#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/skbuff.h>#include <linux/if_arp.h>#include <linux/if_frad.h>#include <linux/sdla.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/uaccess.h>static const char* version = "SDLA driver v0.30, 12 Sep 1996, mike.mclagan@linux.org";static unsigned int valid_port[] __initdata = { 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390};static unsigned int valid_mem[]  __initdata = {				    0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,                                     0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,                                    0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,                                    0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000,                                    0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000}; static spinlock_t sdla_lock = SPIN_LOCK_UNLOCKED;/********************************************************* * * these are the core routines that access the card itself  * *********************************************************/#define SDLA_WINDOW(dev,addr) outb((((addr) >> 13) & 0x1F), (dev)->base_addr + SDLA_REG_Z80_WINDOW)static void __sdla_read(struct net_device *dev, int addr, void *buf, short len){	char          *temp;	const void    *base;	int           offset, bytes;	temp = buf;	while(len)	{			offset = addr & SDLA_ADDR_MASK;		bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;		base = (const void *) (dev->mem_start + offset);		SDLA_WINDOW(dev, addr);		memcpy(temp, base, bytes);		addr += bytes;		temp += bytes;		len  -= bytes;	}  }static void sdla_read(struct net_device *dev, int addr, void *buf, short len){	unsigned long flags;	spin_lock_irqsave(&sdla_lock, flags);	__sdla_read(dev, addr, buf, len);	spin_unlock_irqrestore(&sdla_lock, flags);}static void __sdla_write(struct net_device *dev, int addr, 			 const void *buf, short len){	const char    *temp;	void 	      *base;	int           offset, bytes;	temp = buf;	while(len)	{		offset = addr & SDLA_ADDR_MASK;		bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;		base = (void *) (dev->mem_start + offset);		SDLA_WINDOW(dev, addr);		memcpy(base, temp, bytes);		addr += bytes;		temp += bytes;		len  -= bytes;	}}static void sdla_write(struct net_device *dev, int addr, 		       const void *buf, short len){	unsigned long flags;	spin_lock_irqsave(&sdla_lock, flags);	__sdla_write(dev, addr, buf, len);	spin_unlock_irqrestore(&sdla_lock, flags);}static void sdla_clear(struct net_device *dev){	unsigned long flags;	char          *base;	int           len, addr, bytes;	len = 65536;		addr = 0;	bytes = SDLA_WINDOW_SIZE;	base = (void *) dev->mem_start;	spin_lock_irqsave(&sdla_lock, flags);	while(len)	{		SDLA_WINDOW(dev, addr);		memset(base, 0, bytes);		addr += bytes;		len  -= bytes;	}	spin_unlock_irqrestore(&sdla_lock, flags);}static char sdla_byte(struct net_device *dev, int addr){	unsigned long flags;	char          byte, *temp;	temp = (void *) (dev->mem_start + (addr & SDLA_ADDR_MASK));	spin_lock_irqsave(&sdla_lock, flags);	SDLA_WINDOW(dev, addr);	byte = *temp;	spin_unlock_irqrestore(&sdla_lock, flags);	return(byte);}void sdla_stop(struct net_device *dev){	struct frad_local *flp;	flp = dev->priv;	switch(flp->type)	{		case SDLA_S502A:			outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);			flp->state = SDLA_HALT;			break;		case SDLA_S502E:			outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);			outb(SDLA_S502E_ENABLE, dev->base_addr + SDLA_REG_CONTROL);			flp->state = SDLA_S502E_ENABLE;			break;		case SDLA_S507:			flp->state &= ~SDLA_CPUEN;			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);			break;		case SDLA_S508:			flp->state &= ~SDLA_CPUEN;			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);			break;	}}void sdla_start(struct net_device *dev){	struct frad_local *flp;	flp = dev->priv;	switch(flp->type)	{		case SDLA_S502A:			outb(SDLA_S502A_NMI, dev->base_addr + SDLA_REG_CONTROL);			outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);			flp->state = SDLA_S502A_START;			break;		case SDLA_S502E:			outb(SDLA_S502E_CPUEN, dev->base_addr + SDLA_REG_Z80_CONTROL);			outb(0x00, dev->base_addr + SDLA_REG_CONTROL);			flp->state = 0;			break;		case SDLA_S507:			flp->state |= SDLA_CPUEN;			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);			break;		case SDLA_S508:			flp->state |= SDLA_CPUEN;			outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);			break;	}}/**************************************************** * * this is used for the S502A/E cards to determine * the speed of the onboard CPU.  Calibration is * necessary for the Frame Relay code uploaded  * later.  Incorrect results cause timing problems * with link checks & status messages * ***************************************************/int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char resp1, char resp2){	unsigned long start, done, now;	char          resp, *temp;	start = now = jiffies;	done = jiffies + jiffs;	temp = (void *)dev->mem_start;	temp += z80_addr & SDLA_ADDR_MASK;		resp = ~resp1;	while (time_before(jiffies, done) && (resp != resp1) && (!resp2 || (resp != resp2)))	{		if (jiffies != now)		{			SDLA_WINDOW(dev, z80_addr);			now = jiffies;			resp = *temp;		}	}	return(time_before(jiffies, done) ? jiffies - start : -1);}/* constants for Z80 CPU speed */#define Z80_READY 		'1'	/* Z80 is ready to begin */#define LOADER_READY 		'2'	/* driver is ready to begin */#define Z80_SCC_OK 		'3'	/* SCC is on board */#define Z80_SCC_BAD	 	'4'	/* SCC was not found */static int sdla_cpuspeed(struct net_device *dev, struct ifreq *ifr){	int  jiffs;	char data;	sdla_start(dev);	if (sdla_z80_poll(dev, 0, 3*HZ, Z80_READY, 0) < 0)		return(-EIO);	data = LOADER_READY;	sdla_write(dev, 0, &data, 1);	if ((jiffs = sdla_z80_poll(dev, 0, 8*HZ, Z80_SCC_OK, Z80_SCC_BAD)) < 0)		return(-EIO);	sdla_stop(dev);	sdla_read(dev, 0, &data, 1);	if (data == Z80_SCC_BAD)	{		printk("%s: SCC bad\n", dev->name);		return(-EIO);	}	if (data != Z80_SCC_OK)		return(-EINVAL);	if (jiffs < 165)		ifr->ifr_mtu = SDLA_CPU_16M;	else if (jiffs < 220)		ifr->ifr_mtu = SDLA_CPU_10M;	else if (jiffs < 258)		ifr->ifr_mtu = SDLA_CPU_8M;	else if (jiffs < 357)		ifr->ifr_mtu = SDLA_CPU_7M;	else if (jiffs < 467)		ifr->ifr_mtu = SDLA_CPU_5M;	else		ifr->ifr_mtu = SDLA_CPU_3M; 	return(0);}/************************************************ * *  Direct interaction with the Frame Relay code  *  starts here. * ************************************************/struct _dlci_stat {	short dlci		__attribute__((packed));	char  flags		__attribute__((packed));};struct _frad_stat {	char    flags;	struct _dlci_stat dlcis[SDLA_MAX_DLCI];};static void sdla_errors(struct net_device *dev, int cmd, int dlci, int ret, int len, void *data) {	struct _dlci_stat *pstatus;	short             *pdlci;	int               i;	char              *state, line[30];	switch (ret)	{		case SDLA_RET_MODEM:			state = data;			if (*state & SDLA_MODEM_DCD_LOW)				printk(KERN_INFO "%s: Modem DCD unexpectedly low!\n", dev->name);			if (*state & SDLA_MODEM_CTS_LOW)				printk(KERN_INFO "%s: Modem CTS unexpectedly low!\n", dev->name);			/* I should probably do something about this! */			break;		case SDLA_RET_CHANNEL_OFF:			printk(KERN_INFO "%s: Channel became inoperative!\n", dev->name);			/* same here */			break;		case SDLA_RET_CHANNEL_ON:			printk(KERN_INFO "%s: Channel became operative!\n", dev->name);			/* same here */			break;		case SDLA_RET_DLCI_STATUS:			printk(KERN_INFO "%s: Status change reported by Access Node.\n", dev->name);			len /= sizeof(struct _dlci_stat);			for(pstatus = data, i=0;i < len;i++,pstatus++)			{				if (pstatus->flags & SDLA_DLCI_NEW)					state = "new";				else if (pstatus->flags & SDLA_DLCI_DELETED)					state = "deleted";				else if (pstatus->flags & SDLA_DLCI_ACTIVE)					state = "active";				else				{					sprintf(line, "unknown status: %02X", pstatus->flags);					state = line;				}				printk(KERN_INFO "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state);				/* same here */			}			break;		case SDLA_RET_DLCI_UNKNOWN:			printk(KERN_INFO "%s: Received unknown DLCIs:", dev->name);			len /= sizeof(short);			for(pdlci = data,i=0;i < len;i++,pdlci++)				printk(" %i", *pdlci);			printk("\n");			break;		case SDLA_RET_TIMEOUT:			printk(KERN_ERR "%s: Command timed out!\n", dev->name);			break;		case SDLA_RET_BUF_OVERSIZE:			printk(KERN_INFO "%s: Bc/CIR overflow, acceptable size is %i\n", dev->name, len);			break;		case SDLA_RET_BUF_TOO_BIG:			printk(KERN_INFO "%s: Buffer size over specified max of %i\n", dev->name, len);			break;		case SDLA_RET_CHANNEL_INACTIVE:		case SDLA_RET_DLCI_INACTIVE:		case SDLA_RET_CIR_OVERFLOW:		case SDLA_RET_NO_BUFS:			if (cmd == SDLA_INFORMATION_WRITE)				break;		default: 			printk(KERN_DEBUG "%s: Cmd 0x%2.2X generated return code 0x%2.2X\n", dev->name, cmd, ret);			/* Further processing could be done here */			break;	}}static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags,                         void *inbuf, short inlen, void *outbuf, short *outlen){	static struct _frad_stat status;	struct frad_local        *flp;	struct sdla_cmd          *cmd_buf;	unsigned long            pflags;	unsigned long		 jiffs;	int                      ret, waiting, len;	long                     window;	flp = dev->priv;	window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF;	cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK));	ret = 0;	len = 0;	jiffs = jiffies + HZ;  /* 1 second is plenty */	spin_lock_irqsave(&sdla_lock, pflags);	SDLA_WINDOW(dev, window);	cmd_buf->cmd = cmd;	cmd_buf->dlci = dlci;	cmd_buf->flags = flags;	if (inbuf)		memcpy(cmd_buf->data, inbuf, inlen);	cmd_buf->length = inlen;	cmd_buf->opp_flag = 1;	spin_unlock_irqrestore(&sdla_lock, pflags);	waiting = 1;	len = 0;	while (waiting && time_before_eq(jiffies, jiffs))	{		if (waiting++ % 3) 		{			spin_lock_irqsave(&sdla_lock, pflags);			SDLA_WINDOW(dev, window);			waiting = ((volatile int)(cmd_buf->opp_flag));			spin_unlock_irqrestore(&sdla_lock, pflags);		}	}		if (!waiting)	{		spin_lock_irqsave(&sdla_lock, pflags);		SDLA_WINDOW(dev, window);		ret = cmd_buf->retval;		len = cmd_buf->length;		if (outbuf && outlen)		{			*outlen = *outlen >= len ? len : *outlen;			if (*outlen)				memcpy(outbuf, cmd_buf->data, *outlen);		}		/* This is a local copy that's used for error handling */		if (ret)			memcpy(&status, cmd_buf->data, len > sizeof(status) ? sizeof(status) : len);		spin_unlock_irqrestore(&sdla_lock, pflags);	}	else		ret = SDLA_RET_TIMEOUT;	if (ret != SDLA_RET_OK)	   	sdla_errors(dev, cmd, dlci, ret, len, &status);	return(ret);}/*********************************************** * * these functions are called by the DLCI driver  * ***********************************************/static int sdla_reconfig(struct net_device *dev);int sdla_activate(struct net_device *slave, struct net_device *master){	struct frad_local *flp;	int i;	flp = slave->priv;	for(i=0;i<CONFIG_DLCI_MAX;i++)		if (flp->master[i] == master)			break;	if (i == CONFIG_DLCI_MAX)		return(-ENODEV);	flp->dlci[i] = abs(flp->dlci[i]);	if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE))		sdla_cmd(slave, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);	return(0);}int sdla_deactivate(struct net_device *slave, struct net_device *master){	struct frad_local *flp;	int               i;	flp = slave->priv;	for(i=0;i<CONFIG_DLCI_MAX;i++)		if (flp->master[i] == master)			break;	if (i == CONFIG_DLCI_MAX)		return(-ENODEV);	flp->dlci[i] = -abs(flp->dlci[i]);	if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE))		sdla_cmd(slave, SDLA_DEACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);	return(0);}int sdla_assoc(struct net_device *slave, struct net_device *master){	struct frad_local *flp;	int               i;	if (master->type != ARPHRD_DLCI)		return(-EINVAL);

⌨️ 快捷键说明

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