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

📄 sktr.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  sktr.c: A network driver for the SysKonnect Token Ring ISA/PCI Adapters. * *  Written 1997 by Christoph Goos * *  A fine result of the Linux Systems Network Architecture Project. *  http://samba.anu.edu.au/linux-sna/ * *  This software may be used and distributed according to the terms *  of the GNU Public License, incorporated herein by reference. * *  This device driver works with the following SysKonnect adapters: *	- SysKonnect TR4/16(+) ISA	(SK-4190) *	- SysKonnect TR4/16(+) PCI	(SK-4590) *	- SysKonnect TR4/16 PCI		(SK-4591) * *  Sources: *  	- The hardware related parts of this driver are take from *  	  the SysKonnect Token Ring driver for Windows NT. *  	- I used the IBM Token Ring driver 'ibmtr.c' as a base for this *  	  driver, as well as the 'skeleton.c' driver by Donald Becker. *  	- Also various other drivers in the linux source tree were taken *  	  as samples for some tasks. * *  Maintainer(s): *    JS        Jay Schulist            jschlst@samba.anu.edu.au *    CG	Christoph Goos		cgoos@syskonnect.de * *  Modification History: *	29-Aug-97	CG	Created *	04-Apr-98	CG	Fixed problems caused by tok_timer_check *	10-Apr-98	CG	Fixed lockups at cable disconnection *	27-May-98	JS	Formated to Linux Kernel Format *	31-May-98	JS	Hacked in PCI support *	16-Jun-98	JS	Modulized for multiple cards with one driver * *  To do: *    1. Selectable 16 Mbps or 4Mbps *    2. Multi/Broadcast packet handling * */static const char *version = "sktr.c: v1.01 08/29/97 by Christoph Goos\n";#ifdef MODULE#include <linux/module.h>#include <linux/version.h>#endif#include <linux/kernel.h>#include <linux/sched.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/malloc.h>#include <linux/string.h>#include <linux/time.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/irq.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/trdevice.h>#include "sktr.h"		/* Our Stuff */#include "sktr_firmware.h"	/* SysKonnect adapter firmware *//* A zero-terminated list of I/O addresses to be probed. */static unsigned int sktr_portlist[] __initdata = {	0x0A20, 0x1A20, 0x0B20, 0x1B20, 0x0980, 0x1980, 0x0900, 0x1900,	0};/* A zero-terminated list of IRQs to be probed.  * Used again after initial probe for sktr_chipset_init, called from sktr_open. */static unsigned short sktr_irqlist[] = {	3, 5, 9, 10, 11, 12, 15,	0};/* A zero-terminated list of DMAs to be probed. */static int sktr_dmalist[] __initdata = {	5, 6, 7,	0};/* Card names */static char *pci_cardname = "SK NET TR 4/16 PCI\0";static char *isa_cardname = "SK NET TR 4/16 ISA\0";static char *AdapterName;/* Use 0 for production, 1 for verification, 2 for debug, and * 3 for very verbose debug. */#ifndef SKTR_DEBUG#define SKTR_DEBUG 1#endifstatic unsigned int sktr_debug = SKTR_DEBUG;/* The number of low I/O ports used by the tokencard. */#define SKTR_IO_EXTENT 32/* Index to functions, as function prototypes. * Alphabetical by function name. *//* "B" */static int      sktr_bringup_diags(struct device *dev);/* "C" */static void	sktr_cancel_tx_queue(struct net_local* tp);static int 	sktr_chipset_init(struct device *dev);static void 	sktr_chk_irq(struct device *dev);static unsigned char sktr_chk_frame(struct device *dev, unsigned char *Addr);static void 	sktr_chk_outstanding_cmds(struct device *dev);static void 	sktr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr);static unsigned char sktr_chk_ssb(struct net_local *tp, unsigned short IrqType);static int 	sktr_close(struct device *dev);static void 	sktr_cmd_status_irq(struct device *dev);/* "D" */static void 	sktr_disable_interrupts(struct device *dev);static void 	sktr_dump(unsigned char *Data, int length);/* "E" */static void 	sktr_enable_interrupts(struct device *dev);static void 	sktr_exec_cmd(struct device *dev, unsigned short Command);static void 	sktr_exec_sifcmd(struct device *dev, unsigned int WriteValue);/* "F" */static unsigned char *sktr_fix_srouting(unsigned char *buf, short *FrameLen);/* "G" */static struct enet_statistics *sktr_get_stats(struct device *dev);/* "H" */static void 	sktr_hardware_send_packet(struct device *dev,			struct net_local* tp);/* "I" */static int 	sktr_init_adapter(struct device *dev);static int 	sktr_init_card(struct device *dev);static void 	sktr_init_ipb(struct net_local *tp);static void 	sktr_init_net_local(struct device *dev);static void 	sktr_init_opb(struct net_local *tp);static void 	sktr_interrupt(int irq, void *dev_id, struct pt_regs *regs);static int 	sktr_isa_chk_card(struct device *dev, int ioaddr);static int      sktr_isa_chk_ioaddr(int ioaddr);/* "O" */static int 	sktr_open(struct device *dev);static void	sktr_open_adapter(struct device *dev);/* "P" */static int 	sktr_pci_chk_card(struct device *dev);int 		sktr_probe(struct device *dev);static int 	sktr_probe1(struct device *dev, int ioaddr);/* "R" */static void 	sktr_rcv_status_irq(struct device *dev);static void 	sktr_read_addr(struct device *dev, unsigned char *Address);static void 	sktr_read_ptr(struct device *dev);static void 	sktr_read_ram(struct device *dev, unsigned char *Data,			unsigned short Address, int Length);static int 	sktr_reset_adapter(struct device *dev);static void 	sktr_reset_interrupt(struct device *dev);static void 	sktr_ring_status_irq(struct device *dev);/* "S" */static int 	sktr_send_packet(struct sk_buff *skb, struct device *dev);static void 	sktr_set_multicast_list(struct device *dev);/* "T" */static void 	sktr_timer_chk(unsigned long data);static void 	sktr_timer_end_wait(unsigned long data);static void 	sktr_tx_status_irq(struct device *dev);/* "U" */static void 	sktr_update_rcv_stats(struct net_local *tp,			unsigned char DataPtr[], unsigned int Length);/* "W" */static void 	sktr_wait(unsigned long time);static void 	sktr_write_rpl_status(RPL *rpl, unsigned int Status);static void 	sktr_write_tpl_status(TPL *tpl, unsigned int Status);/* * Check for a network adapter of this type, and return '0' if one exists. * If dev->base_addr == 0, probe all likely locations. * If dev->base_addr == 1, always return failure. */__initfunc(int sktr_probe(struct device *dev)){	int i;	int base_addr = dev ? dev->base_addr : 0;	if(base_addr > 0x1ff)    /* Check a single specified location. */		return (sktr_probe1(dev, base_addr));	else if(base_addr != 0)  /* Don't probe at all. */		return (-ENXIO);	for(i = 0; sktr_portlist[i]; i++)	{		int ioaddr = sktr_portlist[i];		if(check_region(ioaddr, SKTR_IO_EXTENT))			continue;		if(sktr_probe1(dev, ioaddr))		{#ifndef MODULE                        tr_freedev(dev);#endif                }		else			return (0);	}	return (-ENODEV);}/* * Detect and setup the PCI SysKonnect TR cards in slot order. */__initfunc(static int sktr_pci_chk_card(struct device *dev)){	static int pci_index = 0;	unsigned char pci_bus, pci_device_fn;	if(!pci_present())		return (-1);	/* No PCI present. */	for(; pci_index < 0xff; pci_index++)	{		unsigned int pci_irq_line;		struct pci_dev *pdev;		unsigned short pci_command, new_command, vendor, device;		unsigned int pci_ioaddr;		if(pcibios_find_class(PCI_CLASS_NETWORK_TOKEN_RING << 8,			pci_index, &pci_bus, &pci_device_fn)			!= PCIBIOS_SUCCESSFUL)		{			break;		}		pcibios_read_config_word(pci_bus, pci_device_fn,						PCI_VENDOR_ID, &vendor);		pcibios_read_config_word(pci_bus, pci_device_fn,						PCI_DEVICE_ID, &device);		pdev		= pci_find_slot(pci_bus, pci_device_fn);		pci_irq_line 	= pdev->irq;		pci_ioaddr 	= pdev->base_address[0];		pcibios_read_config_word(pci_bus, pci_device_fn,						PCI_COMMAND, &pci_command);		/* Remove I/O space marker in bit 0. */		pci_ioaddr &= ~3;		if(vendor != PCI_VENDOR_ID_SK)			continue;		if(device != PCI_DEVICE_ID_SK_TR)			continue;		if(check_region(pci_ioaddr, SKTR_IO_EXTENT))			continue;		request_region(pci_ioaddr, SKTR_IO_EXTENT, pci_cardname);		if(request_irq(pdev->irq, sktr_interrupt, SA_SHIRQ,				pci_cardname, dev))			return (-ENODEV); /* continue; ?? */		AdapterName = pci_cardname;		new_command = (pci_command|PCI_COMMAND_MASTER|PCI_COMMAND_IO);		if(pci_command != new_command)		{			printk("The PCI BIOS has not enabled this"				"device! Updating PCI command %4.4x->%4.4x.\n",			  	pci_command, new_command);			pcibios_write_config_word(pci_bus, pci_device_fn,				PCI_COMMAND, new_command);		}		/* At this point we have found a valid PCI TR card. */		dev->base_addr	= pci_ioaddr;		dev->irq 	= pci_irq_line;		dev->dma	= 0;		printk("%s: %s found at %#4x, using IRQ %d.\n",			dev->name, AdapterName, pci_ioaddr, dev->irq);		return (0);	}	return (-1);}/* * Detect and setup the ISA SysKonnect TR cards. */__initfunc(static int sktr_isa_chk_card(struct device *dev, int ioaddr)){	int i, err;	unsigned long flags;	err = sktr_isa_chk_ioaddr(ioaddr);	if(err < 0)		return (-ENODEV);        if(virt_to_bus((void*)((unsigned long)dev->priv+sizeof(struct net_local)))		> ISA_MAX_ADDRESS)        {                printk("%s: Memory not accessible for DMA\n", dev->name);                kfree(dev->priv);                return (-EAGAIN);        }	AdapterName = isa_cardname;        /* Grab the region so that no one else tries to probe our ioports. */        request_region(ioaddr, SKTR_IO_EXTENT, AdapterName);        dev->base_addr = ioaddr;        /* Autoselect IRQ and DMA if dev->irq == 0 */        if(dev->irq == 0)        {                for(i = 0; sktr_irqlist[i] != 0; i++)                {                        dev->irq = sktr_irqlist[i];                        err = request_irq(dev->irq, &sktr_interrupt, 0, AdapterName, dev);                        if(!err)				break;                }                if(sktr_irqlist[i] == 0)                {                        printk("%s: AutoSelect no IRQ available\n", dev->name);                        return (-EAGAIN);                }        }        else        {                err = request_irq(dev->irq, &sktr_interrupt, 0, AdapterName, dev);		if(err)                {                        printk("%s: Selected IRQ not available\n", dev->name);                        return (-EAGAIN);                }        }        /* Always allocate the DMA channel after IRQ and clean up on failure */        if(dev->dma == 0)        {                for(i = 0; sktr_dmalist[i] != 0; i++)                {			dev->dma = sktr_dmalist[i];                        err = request_dma(dev->dma, AdapterName);                        if(!err)                                break;                }                if(dev->dma == 0)                {                        printk("%s: AutoSelect no DMA available\n", dev->name);                        free_irq(dev->irq, NULL);                        return (-EAGAIN);                }        }        else        {                err = request_dma(dev->dma, AdapterName);                if(err)                {                        printk("%s: Selected DMA not available\n", dev->name);                        free_irq(dev->irq, NULL);                        return (-EAGAIN);                }        }	flags=claim_dma_lock();	disable_dma(dev->dma);        set_dma_mode(dev->dma, DMA_MODE_CASCADE);        enable_dma(dev->dma);        release_dma_lock(flags);	printk("%s: %s found at %#4x, using IRQ %d and DMA %d.\n",                dev->name, AdapterName, ioaddr, dev->irq, dev->dma);	return (0);}__initfunc(static int sktr_probe1(struct device *dev, int ioaddr)){	static unsigned version_printed = 0;	struct net_local *tp;	int err;	if(sktr_debug && version_printed++ == 0)		printk("%s", version);#ifndef MODULE	dev = init_trdev(dev, 0);	if(dev == NULL)		return (-ENOMEM);#endif	err = sktr_pci_chk_card(dev);	if(err < 0)	{		err = sktr_isa_chk_card(dev, ioaddr);		if(err < 0)			return (-ENODEV);	}	/* Setup this devices private information structure */	tp = (struct net_local *)kmalloc(sizeof(struct net_local), GFP_KERNEL | GFP_DMA);	if(tp == NULL)		return (-ENOMEM);	memset(tp, 0, sizeof(struct net_local));	dev->priv		= tp;	dev->init               = sktr_init_card;        dev->open               = sktr_open;        dev->stop               = sktr_close;        dev->hard_start_xmit    = sktr_send_packet;        dev->get_stats          = sktr_get_stats;        dev->set_multicast_list = &sktr_set_multicast_list;        return (0);}/* Dummy function */__initfunc(static int sktr_init_card(struct device *dev)){	if(sktr_debug > 3)		printk("%s: sktr_init_card\n", dev->name);	return (0);}/* * This function tests if an adapter is really installed at the * given I/O address. Return negative if no adapter at IO addr. */__initfunc(static int sktr_isa_chk_ioaddr(int ioaddr)){	unsigned char old, chk1, chk2;	old = inb(ioaddr + SIFADR);	/* Get the old SIFADR value */	chk1 = 0;	/* Begin with check value 0 */	do {		/* Write new SIFADR value */		outb(chk1, ioaddr + SIFADR);		/* Read, invert and write */		chk2 = inb(ioaddr + SIFADD);		chk2 ^= 0x0FE;		outb(chk2, ioaddr + SIFADR);		/* Read, invert and compare */		chk2 = inb(ioaddr + SIFADD);		chk2 ^= 0x0FE;		if(chk1 != chk2)			return (-1);	/* No adapter */		chk1 -= 2;	} while(chk1 != 0);	/* Repeat 128 times (all byte values) */    	/* Restore the SIFADR value */	outb(old, ioaddr + SIFADR);	return (0);}/* * Open/initialize the board. This is called sometime after * booting when the 'ifconfig' program is run. * * This routine should set everything up anew at each open, even * registers that "should" only need to be set once at boot, so that * there is non-reboot way to recover if something goes wrong. */static int sktr_open(struct device *dev){	struct net_local *tp = (struct net_local *)dev->priv;	int err;	/* Reset the hardware here. Don't forget to set the station address. */	err = sktr_chipset_init(dev);	if(err)	{		printk(KERN_INFO "%s: Chipset initialization error\n", 			dev->name);		return (-1);	}	dev->addr_len = 6;	sktr_read_addr(dev, (unsigned char*)dev->dev_addr);	init_timer(&tp->timer);	tp->timer.expires	= jiffies + 30*HZ;	tp->timer.function	= sktr_timer_end_wait;	tp->timer.data		= (unsigned long)dev;	tp->timer.next		= NULL;	tp->timer.prev		= NULL;	add_timer(&tp->timer);	sktr_read_ptr(dev);	sktr_enable_interrupts(dev);	sktr_open_adapter(dev);	dev->tbusy = 0;	dev->interrupt = 0;	dev->start = 0;

⌨️ 快捷键说明

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