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

📄 lanstreamer.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *   lanstreamer.c -- driver for the IBM Auto LANStreamer PCI Adapter * *  Written By: Mike Sullivan, IBM Corporation * *  Copyright (C) 1999 IBM Corporation * *  Linux driver for IBM PCI tokenring cards based on the LanStreamer MPC *  chipset.  * *  This driver is based on the olympic driver for IBM PCI TokenRing cards (Pit/Pit-Phy/Olympic *  chipsets) written  by: *      1999 Peter De Schrijver All Rights Reserved *	1999 Mike Phillips (phillim@amtrak.com) * *  Base Driver Skeleton: *      Written 1993-94 by Donald Becker. * *      Copyright 1993 United States Government as represented by the *      Director, National Security Agency. * * 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.                                        *                                                                            * This program is distributed in the hope that it will be useful,            * but WITHOUT ANY WARRANTY; without even the implied warranty of             * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              * GNU General Public License for more details.                               *                                                                            * NO WARRANTY                                                                * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR         * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT       * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,       * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is     * solely responsible for determining the appropriateness of using and        * distributing the Program and assumes all risks associated with its         * exercise of rights under this Agreement, including but not limited to      * the risks and costs of program errors, damage to or loss of data,          * programs or equipment, and unavailability or interruption of operations.   *                                                                            * DISCLAIMER OF LIABILITY                                                    * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY    * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL         * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR      * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE     * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED   * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES              *                                                                            * You should have received a copy of the GNU General Public License          * along with this program; if not, write to the Free Software                * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  *                                                                            *  *  12/10/99 - Alpha Release 0.1.0 *            First release to the public *  03/03/00 - Merged to kernel, indented -kr -i8 -bri0, fixed some missing *		malloc free checks, reviewed code. <alan@redhat.com> *  03/13/00 - Added spinlocks for smp *   *  To Do: * *  1) Test Network Monitor Mode *  2) Add auto reset logic on adapter errors *  3) Test with varying options * *  If Problems do Occur *  Most problems can be rectified by either closing and opening the interface *  (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult *  if compiled into the kernel). *//* Change STREAMER_DEBUG to 1 to get verbose, and I mean really verbose, messages */#define STREAMER_DEBUG 0#define STREAMER_DEBUG_PACKETS 0/* Change STREAMER_NETWORK_MONITOR to receive mac frames through the arb channel. * Will also create a /proc/net/streamer_tr entry if proc_fs is compiled into the * kernel. * Intended to be used to create a ring-error reporting network module  * i.e. it will give you the source address of beaconers on the ring  */#define STREAMER_NETWORK_MONITOR 0#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/timer.h>#include <linux/in.h>#include <linux/ioport.h>#include <linux/string.h>#include <linux/proc_fs.h>#include <linux/ptrace.h>#include <linux/skbuff.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/trdevice.h>#include <linux/stddef.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/spinlock.h>#include <net/checksum.h>#include <asm/io.h>#include <asm/system.h>#include <asm/bitops.h>#include "lanstreamer.h"/* I've got to put some intelligence into the version number so that Peter and I know * which version of the code somebody has got.  * Version Number = a.b.c.d  where a.b.c is the level of code and d is the latest author. * So 0.0.1.pds = Peter, 0.0.1.mlp = Mike *  * Official releases will only have an a.b.c version number format. */static char *version = "LanStreamer.c v0.3.1 03/13/99 - Mike Sullivan";static char *open_maj_error[] = {	"No error", "Lobe Media Test", "Physical Insertion",	"Address Verification", "Neighbor Notification (Ring Poll)",	"Request Parameters", "FDX Registration Request",	"FDX Lobe Media Test", "FDX Duplicate Address Check",	"Unknown stage"};static char *open_min_error[] = {	"No error", "Function Failure", "Signal Lost", "Wire Fault",	"Ring Speed Mismatch", "Timeout", "Ring Failure", "Ring Beaconing",	"Duplicate Node Address", "Request Parameters", "Remove Received",	"Reserved", "Reserved", "No Monitor Detected for RPL",	"Monitor Contention failer for RPL", "FDX Protocol Error"};/* Module paramters *//* Ring Speed 0,4,16 * 0 = Autosense          * 4,16 = Selected speed only, no autosense * This allows the card to be the first on the ring * and become the active monitor. * * WARNING: Some hubs will allow you to insert * at the wrong speed */static int ringspeed[STREAMER_MAX_ADAPTERS] = { 0, };MODULE_PARM(ringspeed, "1-" __MODULE_STRING(STREAMER_MAX_ADAPTERS) "i");/* Packet buffer size */static int pkt_buf_sz[STREAMER_MAX_ADAPTERS] = { 0, };MODULE_PARM(pkt_buf_sz, "1-" __MODULE_STRING(STREAMER_MAX_ADAPTERS) "i");/* Message Level */static int message_level[STREAMER_MAX_ADAPTERS] = { 1, };MODULE_PARM(message_level,	    "1-" __MODULE_STRING(STREAMER_MAX_ADAPTERS) "i");static int streamer_scan(struct net_device *dev);static int streamer_init(struct net_device *dev);static int streamer_open(struct net_device *dev);static int streamer_xmit(struct sk_buff *skb, struct net_device *dev);static int streamer_close(struct net_device *dev);static void streamer_set_rx_mode(struct net_device *dev);static void streamer_interrupt(int irq, void *dev_id,			       struct pt_regs *regs);static struct net_device_stats *streamer_get_stats(struct net_device *dev);static int streamer_set_mac_address(struct net_device *dev, void *addr);static void streamer_arb_cmd(struct net_device *dev);static int streamer_change_mtu(struct net_device *dev, int mtu);static void streamer_srb_bh(struct net_device *dev);static void streamer_asb_bh(struct net_device *dev);#if STREAMER_NETWORK_MONITOR#ifdef CONFIG_PROC_FSstatic int sprintf_info(char *buffer, struct net_device *dev);#endif#endifint __init streamer_probe(struct net_device *dev){	int cards_found;	cards_found = streamer_scan(dev);	return cards_found ? 0 : -ENODEV;}static int __init streamer_scan(struct net_device *dev){	struct pci_dev *pci_device = NULL;	struct streamer_private *streamer_priv;	int card_no = 0;	if (pci_present()) 	{		while ((pci_device = pci_find_device(PCI_VENDOR_ID_IBM,	PCI_DEVICE_ID_IBM_TR, pci_device))) 		{			if (pci_enable_device(pci_device))				continue;			pci_set_master(pci_device);			/* Check to see if io has been allocated, if so, we've already done this card,			   so continue on the card discovery loop  */			if (check_region(pci_resource_start(pci_device,0), STREAMER_IO_SPACE)) 			{				card_no++;				continue;			}			streamer_priv = kmalloc(sizeof(struct streamer_private), GFP_KERNEL);			if(streamer_priv==NULL)			{				printk(KERN_ERR "lanstreamer: out of memory.\n");				break;			}			memset(streamer_priv, 0, sizeof(struct streamer_private));			init_waitqueue_head(&streamer_priv->srb_wait);			init_waitqueue_head(&streamer_priv->trb_wait);#ifndef MODULE			dev = init_trdev(dev, 0);			if(dev==NULL)			{				kfree(streamer_priv);				printk(KERN_ERR "lanstreamer: out of memory.\n");				break;			}#endif			dev->priv = (void *) streamer_priv;#if STREAMER_DEBUG			printk("pci_device: %p, dev:%p, dev->priv: %p\n",			       pci_device, dev, dev->priv);#endif			dev->irq = pci_device->irq;			dev->base_addr = pci_resource_start(pci_device, 0);			dev->init = &streamer_init;			streamer_priv->streamer_card_name = (char *)pci_device->resource[0].name;			streamer_priv->streamer_mmio = 				ioremap(pci_resource_start(pci_device, 1), 256);			if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000))				streamer_priv->pkt_buf_sz = PKT_BUF_SZ;			else				streamer_priv->pkt_buf_sz = pkt_buf_sz[card_no];			streamer_priv->streamer_ring_speed = ringspeed[card_no];			streamer_priv->streamer_message_level = message_level[card_no];			if (streamer_init(dev) == -1) {				unregister_netdevice(dev);				kfree(dev->priv);				return 0;			}			dev->open = &streamer_open;			dev->hard_start_xmit = &streamer_xmit;			dev->change_mtu = &streamer_change_mtu;			dev->stop = &streamer_close;			dev->do_ioctl = NULL;			dev->set_multicast_list = &streamer_set_rx_mode;			dev->get_stats = &streamer_get_stats;			dev->set_mac_address = &streamer_set_mac_address;			return 1;		}	}	return 0;}static int streamer_reset(struct net_device *dev){	struct streamer_private *streamer_priv;	__u8 *streamer_mmio;	unsigned long t;	unsigned int uaa_addr;	struct sk_buff *skb = 0;	__u16 misr;	streamer_priv = (struct streamer_private *) dev->priv;	streamer_mmio = streamer_priv->streamer_mmio;	writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL);	t = jiffies;	/* Hold soft reset bit for a while */	current->state = TASK_UNINTERRUPTIBLE;	schedule_timeout(HZ);		writew(readw(streamer_mmio + BCTL) & ~BCTL_SOFTRESET,	       streamer_mmio + BCTL);#if STREAMER_DEBUG	printk("BCTL: %x\n", readw(streamer_mmio + BCTL));	printk("GPR: %x\n", readw(streamer_mmio + GPR));	printk("SISRMASK: %x\n", readw(streamer_mmio + SISR_MASK));#endif	if (streamer_priv->streamer_ring_speed == 0) {	/* Autosense */		writew(readw(streamer_mmio + GPR) | GPR_AUTOSENSE,		       streamer_mmio + GPR);		if (streamer_priv->streamer_message_level)			printk(KERN_INFO "%s: Ringspeed autosense mode on\n",			       dev->name);	} else if (streamer_priv->streamer_ring_speed == 16) {		if (streamer_priv->streamer_message_level)			printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n",			       dev->name);		writew(GPR_16MBPS, streamer_mmio + GPR);	} else if (streamer_priv->streamer_ring_speed == 4) {		if (streamer_priv->streamer_message_level)			printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n",			       dev->name);		writew(0, streamer_mmio + GPR);	}	skb = dev_alloc_skb(streamer_priv->pkt_buf_sz);	if (!skb) {		printk(KERN_INFO "%s: skb allocation for diagnostics failed...proceeding\n",		       dev->name);	} else {	        struct streamer_rx_desc *rx_ring;                u8 *data;		rx_ring=(struct streamer_rx_desc *)skb->data;		data=((u8 *)skb->data)+sizeof(struct streamer_rx_desc);		rx_ring->forward=0;		rx_ring->status=0;		rx_ring->buffer=virt_to_bus(data);		rx_ring->framelen_buflen=512; 		writel(virt_to_bus(rx_ring),streamer_mmio+RXBDA);	}#if STREAMER_DEBUG	printk("GPR = %x\n", readw(streamer_mmio + GPR));#endif	/* start solo init */	writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);	while (!((readw(streamer_mmio + SISR)) & SISR_SRB_REPLY)) {		current->state = TASK_INTERRUPTIBLE;		schedule_timeout(HZ/10);		if (jiffies - t > 40 * HZ) {			printk(KERN_ERR			       "IBM PCI tokenring card not responding\n");			release_region(dev->base_addr, STREAMER_IO_SPACE);			return -1;		}	}	writew(~SISR_SRB_REPLY, streamer_mmio + SISR_RUM);	misr = readw(streamer_mmio + MISR_RUM);	writew(~misr, streamer_mmio + MISR_RUM);	if (skb)		dev_kfree_skb(skb);	/* release skb used for diagnostics */#if STREAMER_DEBUG	printk("LAPWWO: %x, LAPA: %x LAPE:  %x\n",	       readw(streamer_mmio + LAPWWO), readw(streamer_mmio + LAPA),	       readw(streamer_mmio + LAPE));#endif#if STREAMER_DEBUG	{		int i;		writew(readw(streamer_mmio + LAPWWO),		       streamer_mmio + LAPA);		printk("initialization response srb dump: ");		for (i = 0; i < 10; i++)			printk("%x:",			       ntohs(readw(streamer_mmio + LAPDINC)));		printk("\n");	}#endif	writew(readw(streamer_mmio + LAPWWO) + 6, streamer_mmio + LAPA);	if (readw(streamer_mmio + LAPD)) {		printk(KERN_INFO "tokenring card intialization failed. errorcode : %x\n",		       ntohs(readw(streamer_mmio + LAPD)));		release_region(dev->base_addr, STREAMER_IO_SPACE);		return -1;	}	writew(readw(streamer_mmio + LAPWWO) + 8, streamer_mmio + LAPA);	uaa_addr = ntohs(readw(streamer_mmio + LAPDINC));	readw(streamer_mmio + LAPDINC);	/* skip over Level.Addr field */	streamer_priv->streamer_addr_table_addr = ntohs(readw(streamer_mmio + LAPDINC));	streamer_priv->streamer_parms_addr = ntohs(readw(streamer_mmio + LAPDINC));#if STREAMER_DEBUG	printk("UAA resides at %x\n", uaa_addr);#endif	/* setup uaa area for access with LAPD */	{		int i;		__u16 addr;		writew(uaa_addr, streamer_mmio + LAPA);		for (i = 0; i < 6; i += 2) {		        addr=ntohs(readw(streamer_mmio+LAPDINC));			dev->dev_addr[i]= (addr >> 8) & 0xff;			dev->dev_addr[i+1]= addr & 0xff;		}#if STREAMER_DEBUG		printk("Adapter address: ");		for (i = 0; i < 6; i++) {			printk("%02x:", dev->dev_addr[i]);		}		printk("\n");#endif	}	return 0;}static int __init streamer_init(struct net_device *dev) {        struct streamer_private *streamer_priv;	__u8 *streamer_mmio;	int rc;  	streamer_priv=(struct streamer_private *)dev->priv;	streamer_mmio=streamer_priv->streamer_mmio;	spin_lock_init(&streamer_priv->streamer_lock);  	printk("%s \n", version);	printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name,	       streamer_priv->streamer_card_name,	       (unsigned int) dev->base_addr,	       streamer_priv->streamer_mmio, 	       dev->irq);	request_region(dev->base_addr, STREAMER_IO_SPACE, "streamer");	rc=streamer_reset(dev);	return rc;}  static int streamer_open(struct net_device *dev)

⌨️ 快捷键说明

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