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

📄 3c59x.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	u32 next;					/* Last entry points to 0.   */	s32 status;	u32 addr;					/* Up to 63 addr/len pairs possible. */	s32 length;					/* Set LAST_FRAG to indicate last pair. */};/* Values for the Rx status entry. */enum rx_desc_status {	RxDComplete=0x00008000, RxDError=0x4000,	/* See boomerang_rx() for actual error bits */	IPChksumErr=1<<25, TCPChksumErr=1<<26, UDPChksumErr=1<<27,	IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31,};struct boom_tx_desc {	u32 next;					/* Last entry points to 0.   */	s32 status;					/* bits 0:12 length, others see below.  */	u32 addr;	s32 length;};/* Values for the Tx status entry. */enum tx_desc_status {	CRCDisable=0x2000, TxDComplete=0x8000,	AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000,	TxIntrUploaded=0x80000000,		/* IRQ when in FIFO, but maybe not sent. */};/* Chip features we care about in vp->capabilities, read from the EEPROM. */enum ChipCaps { CapBusMaster=0x20 };struct vortex_private {	/* The Rx and Tx rings should be quad-word-aligned. */	struct boom_rx_desc rx_ring[RX_RING_SIZE];	struct boom_tx_desc tx_ring[TX_RING_SIZE];	/* The addresses of transmit- and receive-in-place skbuffs. */	struct sk_buff* rx_skbuff[RX_RING_SIZE];	struct sk_buff* tx_skbuff[TX_RING_SIZE];	struct device *next_module;	void *priv_addr;	unsigned int cur_rx, cur_tx;		/* The next free ring entry */	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */	struct net_device_stats stats;	struct sk_buff *tx_skb;		/* Packet being eaten by bus master ctrl.  */	/* PCI configuration space information. */	u8 pci_bus, pci_devfn;		/* PCI bus location, for power management. */	char *cb_fn_base;			/* CardBus function status addr space. */	int chip_id;	/* The remainder are related to chip state, mostly media selection. */	unsigned long in_interrupt;	struct timer_list timer;	/* Media selection timer. */	int options;				/* User-settable misc. driver options. */	unsigned int media_override:3, 			/* Passed-in media type. */		default_media:4,				/* Read from the EEPROM/Wn3_Config. */		full_duplex:1, force_fd:1, autoselect:1,		bus_master:1,				/* Vortex can only do a fragment bus-m. */		full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */		hw_csums:1,				/* Has hardware checksums. */		tx_full:1;	u16 status_enable;	u16 intr_enable;	u16 available_media;				/* From Wn3_Options. */	u16 capabilities, info1, info2;		/* Various, from EEPROM. */	u16 advertising;					/* NWay media advertisement */	unsigned char phys[2];				/* MII device addresses. */};/* The action to take with a media selection timer tick.   Note that we deviate from the 3Com order by checking 10base2 before AUI. */enum xcvr_types {	XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,	XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10,};static struct media_table {	char *name;	unsigned int media_bits:16,		/* Bits to set in Wn4_Media register. */		mask:8,				/* The transceiver-present bit in Wn3_Config.*/		next:8;				/* The media type to try next. */	int wait;			/* Time before we check media status. */} media_tbl[] = {  {	"10baseT",   Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},  { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},  { "undefined", 0,			0x80, XCVR_10baseT, 10000},  { "10base2",   0,			0x10, XCVR_AUI,		(1*HZ)/10},  { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10},  { "100baseFX", Media_Lnk, 0x04, XCVR_MII,		(14*HZ)/10},  { "MII",		 0,			0x41, XCVR_10baseT, 3*HZ },  { "undefined", 0,			0x01, XCVR_10baseT, 10000},  { "Autonegotiate", 0,		0x41, XCVR_10baseT, 3*HZ},  { "MII-External",	 0,		0x41, XCVR_10baseT, 3*HZ },  { "Default",	 0,			0xFF, XCVR_10baseT, 10000},};#ifndef CARDBUSstatic int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]);#endifstatic int vortex_open(struct device *dev);static void mdio_sync(long ioaddr, int bits);static int mdio_read(long ioaddr, int phy_id, int location);static void mdio_write(long ioaddr, int phy_id, int location, int value);static void vortex_timer(unsigned long arg);static int vortex_start_xmit(struct sk_buff *skb, struct device *dev);static int boomerang_start_xmit(struct sk_buff *skb, struct device *dev);static int vortex_rx(struct device *dev);static int boomerang_rx(struct device *dev);static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs);static int vortex_close(struct device *dev);static void update_stats(long ioaddr, struct device *dev);static struct net_device_stats *vortex_get_stats(struct device *dev);static void set_rx_mode(struct device *dev);static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd);/* This driver uses 'options' to pass the media type, full-duplex flag, etc. *//* Option count limit only -- unlimited interfaces are supported. */#define MAX_UNITS 8static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};/* A list of all installed Vortex devices, for removing the driver module. */static struct device *root_vortex_dev = NULL;#ifdef MODULE#ifndef CARDBUS/* Variables to work-around the Compaq PCI BIOS32 problem. */static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;#endif#ifdef CARDBUS#include <pcmcia/driver_ops.h>static dev_node_t *vortex_attach(dev_locator_t *loc){	u16 dev_id, vendor_id;	u32 io;	u8 bus, devfn, irq;	struct device *dev;	int chip_idx;	if (loc->bus != LOC_PCI) return NULL;	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);	pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id);	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);	printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n",		   bus, devfn, dev_id);	io &= ~3;	if (io == 0 || irq == 0) {		printk(KERN_ERR "The 3Com CardBus Ethernet interface was not "			   "assigned an %s.\n" KERN_ERR "  It will not be activated.\n",			   io == 0 ? "I/O address" : "IRQ");		return NULL;	}	for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)		if (vendor_id == pci_tbl[chip_idx].vendor_id			&& (dev_id & pci_tbl[chip_idx].device_id_mask) ==			pci_tbl[chip_idx].device_id)			break;	if (pci_tbl[chip_idx].vendor_id == 0) { 		/* Compiled out! */		printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in "			   "vortex_attach().\n", vendor_id, dev_id);		return NULL;	}	dev = vortex_probe1(bus, devfn, NULL, io, irq, chip_idx, MAX_UNITS+1);	if (dev) {		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);		strcpy(node->dev_name, dev->name);		node->major = node->minor = 0;		node->next = NULL;		MOD_INC_USE_COUNT;		return node;	}	return NULL;}static void vortex_detach(dev_node_t *node){	struct device **devp, **next;	printk(KERN_INFO "vortex_detach(%s)\n", node->dev_name);	for (devp = &root_vortex_dev; *devp; devp = next) {		next = &((struct vortex_private *)(*devp)->priv)->next_module;		if (strcmp((*devp)->name, node->dev_name) == 0) break;	}	if (*devp) {		struct device *dev = *devp;		struct vortex_private *vp = dev->priv;		if (dev->flags & IFF_UP)			vortex_close(dev);		dev->flags &= ~(IFF_UP|IFF_RUNNING);		unregister_netdev(dev);		if (vp->cb_fn_base) iounmap(vp->cb_fn_base);		kfree(dev);		*devp = *next;		kfree(vp);		kfree(node);		MOD_DEC_USE_COUNT;	}}struct driver_operations vortex_ops = {	"3c575_cb", vortex_attach, NULL, NULL, vortex_detach};#endif  /* Cardbus support */int init_module(void){	if (vortex_debug)		printk(KERN_INFO "%s", version);#ifdef CARDBUS	register_driver(&vortex_ops);	return 0;#else	return vortex_scan(0, pci_tbl);#endif}#elseint tc59x_probe(struct device *dev){	static int scanned=0;	if(scanned++)		return -ENODEV;	printk(KERN_INFO "%s", version);	return vortex_scan(dev, pci_tbl);}#endif  /* not MODULE */#ifndef CARDBUSstatic int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]){	int cards_found = 0;	/* Allow an EISA-only driver. */#if defined(CONFIG_PCI) || (defined(MODULE) && !defined(NO_PCI))	/* Ideally we would detect all cards in slot order.  That would	   be best done a central PCI probe dispatch, which wouldn't work	   well with the current structure.  So instead we detect 3Com cards	   in slot order. */	if (pcibios_present()) {		static int pci_index = 0;		unsigned char pci_bus, pci_device_fn;		for (;pci_index < 0xff; pci_index++) {			u16 vendor, device, pci_command, new_command, pwr_cmd;			int chip_idx, irq;			long ioaddr;			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 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);			for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)				if (vendor == pci_tbl[chip_idx].vendor_id					&& (device & pci_tbl[chip_idx].device_id_mask) ==					pci_tbl[chip_idx].device_id)					break;			if (pci_tbl[chip_idx].vendor_id == 0) 		/* Compiled out! */				continue;			{#if LINUX_VERSION_CODE >= 0x20155				struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);				ioaddr = pdev->base_address[0] & ~3;				irq = pdev->irq;#else				u32 pci_ioaddr;				u8 pci_irq_line;				pcibios_read_config_byte(pci_bus, pci_device_fn,										 PCI_INTERRUPT_LINE, &pci_irq_line);				pcibios_read_config_dword(pci_bus, pci_device_fn,										  PCI_BASE_ADDRESS_0, &pci_ioaddr);				ioaddr = pci_ioaddr & ~3;;				irq = pci_irq_line;#endif			}			/* Power-up the card. */			pcibios_read_config_word(pci_bus, pci_device_fn,										 0xe0, &pwr_cmd);			if (pwr_cmd & 0x3) {				/* Save the ioaddr and IRQ info! */				printk(KERN_INFO "  A 3Com network adapter is powered down!"					   "  Setting the power state %4.4x->%4.4x.\n",					   pwr_cmd, pwr_cmd & ~3);				pcibios_write_config_word(pci_bus, pci_device_fn,										  0xe0, pwr_cmd & ~3);				printk(KERN_INFO "  Setting the IRQ to %d, IOADDR to %#lx.\n",					   irq, ioaddr);				pcibios_write_config_byte(pci_bus, pci_device_fn,										 PCI_INTERRUPT_LINE, irq);				pcibios_write_config_dword(pci_bus, pci_device_fn,										  PCI_BASE_ADDRESS_0, ioaddr);			}			if (ioaddr == 0) {				printk(KERN_WARNING "  A 3Com network adapter has been found, "					   "however it has not been assigned an I/O address.\n"					   "  You may need to power-cycle the machine for this "					   "device to work!\n");				continue;			}			if (check_region(ioaddr, pci_tbl[chip_idx].io_size))				continue;			/* Activate the card. */			pcibios_read_config_word(pci_bus, pci_device_fn,									 PCI_COMMAND, &pci_command);			new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;			if (pci_command != new_command) {				printk(KERN_INFO "  The PCI BIOS has not enabled the device "					   "at %d/%d. Updating PCI command %4.4x->%4.4x.\n",					   pci_bus, pci_device_fn, pci_command, new_command);				pcibios_write_config_word(pci_bus, pci_device_fn,										  PCI_COMMAND, new_command);			}			dev = vortex_probe1(pci_bus, pci_device_fn, dev, ioaddr, irq,								chip_idx, cards_found);			if (dev) {				/* Get and check the latency values.  On the 3c590 series				   the latency timer must be set to the maximum value to avoid				   data corruption that occurs when the timer expires during				   a transfer -- a bug in the Vortex chip only. */				u8 pci_latency;				u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32;								pcibios_read_config_byte(pci_bus, pci_device_fn,										 PCI_LATENCY_TIMER, &pci_latency);				if (pci_latency < new_latency) {					printk(KERN_INFO "%s: Overriding PCI latency"						   " timer (CFLT) setting of %d, new value is %d.\n",						   dev->name, pci_latency, new_latency);					pcibios_write_config_byte(pci_bus, pci_device_fn,											  PCI_LATENCY_TIMER, new_latency);				}				dev = 0;				cards_found++;			}		}	}#endif /* NO_PCI */	/* Now check all slots of the EISA bus. */	if (EISA_bus) {		static long ioaddr = 0x1000;		for ( ; ioaddr < 0x9000; ioaddr += 0x1000) {			int device_id;			if (check_region(ioaddr, VORTEX_TOTAL_SIZE))				continue;			/* Check the standard EISA ID register for an encoded '3Com'. */			if (inw(ioaddr + 0xC80) != 0x6d50)				continue;			/* Check for a product that we support, 3c59{2,7} any rev. */			device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);			if ((device_id & 0xFF00) != 0x5900)				continue;			vortex_probe1(0, 0, dev, ioaddr, inw(ioaddr + 0xC88) >> 12,						  4, cards_found);			dev = 0;			cards_found++;		}	}#ifdef MODULE	/* Special code to work-around the Compaq PCI BIOS32 problem. */	if (compaq_ioaddr) {		vortex_probe1(0, 0, dev, compaq_ioaddr, compaq_irq,					  compaq_device_id, cards_found++);		dev = 0;	}#endif	return cards_found ? 0 : -ENODEV;}#endif  /* ! Cardbus */

⌨️ 快捷键说明

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