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

📄 ncr885e.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  An Ethernet driver for the dual-function NCR 53C885 SCSI/Ethernet *  controller. * * *  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. * */static const char *version ="ncr885e.c:v1.0 02/10/00 dan@synergymicro.com, cort@fsmlabs.com\n";#include <linux/module.h>#include <linux/version.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/ptrace.h>#include <linux/malloc.h>#include <linux/netdevice.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/errno.h>#include <linux/init.h>#include <asm/io.h>#include <asm/dbdma.h>#include <asm/uaccess.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include "ncr885e.h"#include "ncr885_debug.h"static const char *chipname = "ncr885e";#define NCR885E_DEBUG   0/* The 885's Ethernet PCI device id. */#ifndef PCI_DEVICE_ID_NCR_53C885_ETHERNET#define PCI_DEVICE_ID_NCR_53C885_ETHERNET  0x0701#endif#define NR_RX_RING    8#define NR_TX_RING    8#define MAX_TX_ACTIVE (NR_TX_RING-1)#define NCMDS_TX      NR_TX_RING#define RX_BUFLEN     (ETH_FRAME_LEN + 8)#define TX_TIMEOUT    5*HZ#define NCR885E_TOTAL_SIZE 0xe0#define TXSR          (1<<6)   /* tx: xfer status written */#define TXABORT       (1<<7)   /* tx: abort */#define EOP           (1<<7)   /* rx: end of packet written to buffer */int ncr885e_debug = NCR885E_DEBUG;static int print_version = 0;struct ncr885e_private {	/* preserve a 1-1 marking with buffs */	struct dbdma_cmd *head;	struct dbdma_cmd *tx_cmds;	struct dbdma_cmd *rx_cmds;	struct dbdma_cmd *stop_cmd;	struct sk_buff *tx_skbufs[NR_TX_RING];	struct sk_buff *rx_skbufs[NR_RX_RING];	int rx_current;	int rx_dirty;	int tx_dirty;	int tx_current;	unsigned short tx_status[NR_TX_RING];	unsigned char tx_fullup;	unsigned char tx_active;  	struct net_device_stats  stats;	struct net_device *dev;	struct timer_list tx_timeout;	int timeout_active;	spinlock_t lock;};static struct net_device *root_dev = NULL;static int ncr885e_open( struct net_device *dev );static int ncr885e_close( struct net_device *dev );static void ncr885e_rx( struct net_device *dev );static void ncr885e_tx( struct net_device *dev );static int ncr885e_probe1( unsigned long ioaddr, unsigned char irq );static int ncr885e_xmit_start( struct sk_buff *skb, struct net_device *dev );static struct net_device_stats *ncr885e_stats( struct net_device *dev );static void ncr885e_set_multicast( struct net_device *dev );static void ncr885e_config( struct net_device *dev );static int ncr885e_set_address( struct net_device *dev, void *addr );static void ncr885e_interrupt( int irq, void *dev_id, struct pt_regs *regs );static void show_dbdma_cmd( volatile struct dbdma_cmd *cmd );#if 0static int read_eeprom( unsigned int ioadddr, int location );#endif#ifdef NCR885E_DEBUG_MIIstatic void show_mii( unsigned long ioaddr );static int read_mii( unsigned long ioaddr, int reg );static void write_mii( unsigned long ioaddr, int reg, int data );#endif /* NCR885E_DEBUG_MII */#define TX_RESET_FLAGS    (TX_CHANNEL_RUN|TX_CHANNEL_PAUSE|TX_CHANNEL_WAKE)#define RX_RESET_FLAGS    (RX_CHANNEL_RUN|RX_CHANNEL_PAUSE|RX_CHANNEL_WAKE)static struct pci_device_id ncr885e_pci_tbl[] __initdata = {	{ PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885_ETHERNET, PCI_ANY_ID, PCI_ANY_ID, },	{ }			/* Terminating entry */};MODULE_DEVICE_TABLE(pci, ncr885e_pci_tbl);#if 0static intdebug_ioctl( struct net_device *dev, struct ifreq *req, int cmd ){	unsigned long ioaddr = dev->base_addr;	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;	struct ncr885e_private *data;	struct ncr885e_regs *regs;	unsigned long flags;	union {		struct ncr885e_regs dump;		struct ncr885e_private priv;    	} temp;	switch( cmd ) {		/* dump the rx ring status */	case NCR885E_GET_PRIV:		data = (struct ncr885e_private *) &req->ifr_data;    		if ( verify_area(VERIFY_WRITE, &req->ifr_data,				 sizeof( struct ncr885e_private )))			return -EFAULT;		memcpy((char *) &temp.priv, sp, sizeof( struct ncr885e_private ));		copy_to_user( data, (char *) &temp.priv, sizeof( struct ncr885e_private));		break;	case NCR885E_GET_REGS:		regs = (struct ncr885e_regs *) &req->ifr_data;  		if ( verify_area( VERIFY_WRITE, &req->ifr_data,				  sizeof( struct ncr885e_regs )))			return -EFAULT;		spin_lock_irqsave( &sp->lock, flags ); 		temp.dump.tx_status = inl( ioaddr + TX_CHANNEL_STATUS );		temp.dump.rx_status = inl( ioaddr + RX_CHANNEL_STATUS );		temp.dump.mac_config = inl( ioaddr + MAC_CONFIG );		temp.dump.tx_control = inl( ioaddr + TX_CHANNEL_CONTROL );		temp.dump.rx_control = inl( ioaddr + RX_CHANNEL_CONTROL );		temp.dump.tx_cmd_ptr = inl( ioaddr + TX_CMD_PTR_LO );		temp.dump.rx_cmd_ptr = inl( ioaddr + RX_CMD_PTR_LO );		temp.dump.int_status = inl( ioaddr + INTERRUPT_STATUS_REG );		spin_unlock_irqrestore( &sp->lock, flags );		copy_to_user( regs, (char *) &temp.dump, sizeof( struct ncr885e_regs ));		break;	default:		return -EOPNOTSUPP;	}	return 0;}#endif/*  Enable interrupts on the 53C885 */static inline voidncr885e_enable( struct net_device *dev ){	unsigned long ioaddr = dev->base_addr;	unsigned short reg;	reg = inw(ioaddr + INTERRUPT_ENABLE);	outw(reg | INTERRUPT_INTE, ioaddr + INTERRUPT_ENABLE);}/*  Disable interrupts on the 53c885 */static inline voidncr885e_disable( struct net_device *dev ){	unsigned long ioaddr = dev->base_addr;	unsigned short reg;	reg = inw( ioaddr + INTERRUPT_ENABLE );	outw( reg & ~INTERRUPT_INTE, ioaddr + INTERRUPT_ENABLE );}static inline voidncr885e_reset( struct net_device *dev ){	unsigned short reg;  	unsigned long cntl;	int i;	unsigned long ioaddr = dev->base_addr;	if (ncr885e_debug > 1)		printk( KERN_INFO "%s: Resetting 53C885...\n", dev->name );	/* disable interrupts on the 53C885 */	ncr885e_disable( dev );  	/* disable rx in the MAC */	reg = inw( ioaddr + MAC_CONFIG );	outw( reg & ~MAC_CONFIG_RXEN, ioaddr + MAC_CONFIG );  	for( i=0; i < 100; i++ ) {		if ( !(inw( ioaddr + MAC_CONFIG ) & MAC_CONFIG_RXEN ))			break;		udelay( 10 );	}  	reg = inw( ioaddr + MAC_CONFIG );	outw( reg | MAC_CONFIG_SRST, ioaddr + MAC_CONFIG );	outw( reg, ioaddr + MAC_CONFIG );	/* disable both rx and tx DBDMA channels */	outl( TX_DBDMA_ENABLE << 16, ioaddr + TX_CHANNEL_CONTROL );	outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL );	for( i=0; i < 100; i++ ) {    		if ( !(inw( ioaddr + TX_CHANNEL_STATUS ) & TX_DBDMA_ENABLE ) &&		     !(inw( ioaddr + RX_CHANNEL_STATUS ) & RX_DBDMA_ENABLE ))			break;		udelay( 10 );	}	/* perform a "software reset" */	cntl = inl( ioaddr + DBDMA_CONTROL );	outl( cntl | DBDMA_SRST, ioaddr + DBDMA_CONTROL );	for( i=0; i < 100; i++ ) {  		if ( !(inl( ioaddr + DBDMA_CONTROL ) & DBDMA_SRST ))			break;		udelay( 10 );	}	/* books says that a software reset should be done to the MAC, as	   well.  This true??? */	if (ncr885e_debug > 3) 		printk( KERN_INFO "%s: reset complete\n", dev->name );}/*  configure the 53C885 chip.    The DBDMA command descriptors on the 53C885 can be programmed to    branch, interrupt or pause conditionally or always by using the    interrupt, branch and wait select registers.  */static voidncr885e_config( struct net_device *dev ){	unsigned long ioaddr = dev->base_addr;	if (ncr885e_debug > 3)		printk( KERN_INFO "%s: Configuring 53C885.\n", dev->name );	ncr885e_reset( dev ); 	/* The 53C885 can be programmed to perform conditional DBDMA	   branches, interrupts or waits.  	   Neither channel makes use of "wait", as it requires that the	   DBDMA engine to be restarted.  Don't go there.  The rx channel	   will branch upon the successful reception of a packet ('EOP' in	   the xfer_status field).  The branch address is to the STOP	   DBDMA command descriptor, which shuts down the rx channel until	   the interrupt is serviced.   */     	/* cause tx channel to stop after "status received" */	outl( 0, ioaddr + TX_INT_SELECT );	outl( (TX_WAIT_STAT_RECV << 16) | TX_WAIT_STAT_RECV, 	      ioaddr + TX_WAIT_SELECT );	outl( 0, ioaddr + TX_BRANCH_SELECT );	/* cause rx channel to branch to the STOP descriptor on "End-of-Packet" */#if 0	outl( (RX_INT_SELECT_EOP << 16) | RX_INT_SELECT_EOP,	      ioaddr + RX_INT_SELECT );#else	outl( 0, ioaddr + RX_INT_SELECT );#endif#if 0	outl( 0, ioaddr + RX_WAIT_SELECT );#else	outl( (RX_WAIT_SELECT_EOP << 16) | RX_WAIT_SELECT_EOP, 	      ioaddr + RX_WAIT_SELECT );#endif#if 1	outl( 0, ioaddr + RX_BRANCH_SELECT );#else	outl( (RX_BRANCH_SELECT_EOP << 16) | RX_BRANCH_SELECT_EOP,	      ioaddr + RX_BRANCH_SELECT );#endif	/* configure DBDMA */	outl( (DBDMA_BE | DBDMA_DPMRLE | DBDMA_TDPCE |	       DBDMA_DDPE | DBDMA_TDPE |	       (DBDMA_BURST_4 << DBDMA_TX_BST_SHIFT) |	       (DBDMA_BURST_4 << DBDMA_RX_BST_SHIFT) |	       (DBDMA_TX_ARBITRATION_DEFAULT) |	       (DBDMA_RX_ARBITRATION_DEFAULT)), ioaddr + DBDMA_CONTROL );	outl( 0, ioaddr + TX_THRESHOLD );	/* disable MAC loopback */	outl( (MAC_CONFIG_ITXA | MAC_CONFIG_RXEN | MAC_CONFIG_RETRYL |	       MAC_CONFIG_PADEN | (0x18 << 16)),	      ioaddr + MAC_CONFIG );	/* configure MAC */	outl( (MAC_CONFIG_ITXA | MAC_CONFIG_RXEN | MAC_CONFIG_RETRYL |	       MAC_CONFIG_PADEN | ( 0x18 << 16)), ioaddr + MAC_CONFIG );	outw( (0x1018), ioaddr + NBTOB_INTP_GAP );	/* clear and enable interrupts */	inw( ioaddr + INTERRUPT_CLEAR );	ncr885e_enable( dev );	/* and enable them in the chip */	outl( (INTERRUPT_INTE|INTERRUPT_TX_MASK|INTERRUPT_RX_MASK)<<16,	      ioaddr + INTERRUPT_ENABLE - 2);	if (ncr885e_debug > 3)		printk( KERN_INFO "%s: 53C885 config complete.\n", dev->name );	return;}/*   transmit interrupt  */static voidncr885e_tx( struct net_device *dev ){	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;	volatile struct dbdma_cmd *cp, *dp;	unsigned short txbits, xfer;	int i;	del_timer( &sp->tx_timeout );	if (ncr885e_debug > 3)		printk( KERN_INFO "%s: ncr885e_tx: active=%d, dirty=%d, current=%d\n", 			dev->name, sp->tx_active, sp->tx_dirty, sp->tx_current );	sp->timeout_active = 0;	i = sp->tx_dirty;	cp = sp->tx_cmds + (i*3);	dp = cp+1;	sp->tx_active--;	xfer = inw( &dp->xfer_status );	txbits = inw( &sp->tx_status[i] );	if (ncr885e_debug > 4) {		show_dbdma_cmd( cp );		show_dbdma_cmd( dp );	}	/* get xmit result */	txbits = inw( &sp->tx_status[i] );	if (ncr885e_debug > 3)		printk( KERN_INFO "%s: tx xfer=%04x, txbits=%04x\n", dev->name,			xfer, txbits );	/* look for any channel status (?) */	if ( xfer ) {		dev_kfree_skb_irq( sp->tx_skbufs[i] );		if ( txbits & TX_STATUS_TXOK ) {			sp->stats.tx_packets++;			sp->stats.tx_bytes += inw( &cp->req_count );		}		/* dropped packets */		if ( txbits & (TX_STATUS_TDLC|TX_STATUS_TDEC) ) {			sp->stats.tx_dropped++;		}		/* add the collisions */		sp->stats.collisions += ( txbits & 0x04 );	}	netif_start_queue(dev);  	return;}/*  rx interrupt handling */static voidncr885e_rx( struct net_device *dev ){	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;	volatile struct dbdma_cmd *cp;	struct sk_buff *skb;	int i, nb;	unsigned short status;	unsigned char *data, *stats;	unsigned long rxbits, ioaddr = dev->base_addr;	i = sp->rx_current;	cp = sp->rx_cmds + (i*2);	if (ncr885e_debug > 3)		printk( KERN_INFO "%s: ncr885e_rx dirty=%d, current=%d (cp@%p)\n",			dev->name, sp->rx_dirty, sp->rx_current, cp );	nb = inw( &cp->req_count ) - inw( &cp->res_count );

⌨️ 快捷键说明

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