📄 smc91111.c
字号:
/*------------------------------------------------------------------------
. smc91111.c
. This is a driver for SMSC's 91C111 single-chip Ethernet device.
.
. Copyright (C) 2001-2004 Standard Microsystems Corporation (SMSC)
. Developed by Simple Network Magic Corporation (SNMC)
. Copyright (C) 1996 by Erik Stahlman (ES)
.
. 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.
.
. 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
.
. Information contained in this file was obtained from the LAN91C111
. manual from SMC. To get a copy, if you really want one, you can find
. information under www.smsc.com.
.
.
. "Features" of the SMC chip:
. Integrated PHY/MAC for 10/100BaseT Operation
. Supports internal and external MII
. Integrated 8K packet memory
. EEPROM interface for configuration
.
. Arguments:
. io = for the base address
. irq = for the IRQ
. nowait = 0 for normal wait states, 1 eliminates additional wait states
.
. author:
. Erik Stahlman ( erik@vt.edu )
. Daris A Nevil ( dnevil@snmc.com )
. Pramod B Bhardwaj (pramod.bhardwaj@smsc.com)
. M David Gelbman (david.gelbman@smsc.com)
.
.
. Hardware multicast code from Peter Cammaert ( pc@denkart.be )
.
. Sources:
. o SMSC LAN91C111 databook (www.smsc.com)
. o smc9194.c by Erik Stahlman
. o skeleton.c by Donald Becker ( becker@cesdis.gsfc.nasa.gov )
.
. History:
. 17/08/06 (v2.02) by Frank Meisenbach (f.meisenbach@cbl.de)
. - Bugs fixed to improve the stability
. --> Sometimes the system hung up, e.g. under heavy broadcast load condition
. - Added the function eth_change_mtu()
. - Added support for RevC
. --> smc_recv() was buggy, RevC was handled as RevA
. - Modified smc_timeout()
. --> The interface will have the same behavior as before (PROMISC, MULTICAST)
. 06/23/06 M David Gelbman add "insmod" link_mode parameter
. 11/03/05 M David Gelbman Added support for RevC of LAN91C111
. 12/13/04 Steven Chew, Added code to reset PHY upon link down
. 09/24/01 Pramod B Bhardwaj, Added the changes for Kernel 2.4
. 08/21/01 Pramod B Bhardwaj Added support for RevB of LAN91C111
. 04/25/01 Daris A Nevil Initial public release through SMSC
. 03/16/01 Daris A Nevil Modified smc9194.c for use with LAN91C111
----------------------------------------------------------------------------*/
// Use power-down feature of the chip
#define POWER_DOWN 1
static const char version[] =
"SMSC LAN91C111 Driver (v2.03), (Linux Kernel 2.4 + Support for Odd Byte) 09/08/2006\n\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/slab.h>
#include <linux/string.h>
#include <linux/init.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
//#include <linux/kcomp.h>
#ifdef CONFIG_SYSCTL
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#endif
#include "smc91111.h"
/*------------------------------------------------------------------------
.
. Configuration options, for the experienced user to change.
.
-------------------------------------------------------------------------*/
#define LINK_OFF (0x00)
#define LINK_SPEED_10HD (0x01)
#define LINK_SPEED_10FD (0x02)
#define LINK_SPEED_100HD (0x04)
#define LINK_SPEED_100FD (0x08)
#define LINK_AUTO_NEGOTIATE (0x40)
#define LINK_MODE_INIT (LINK_SPEED_10HD|LINK_SPEED_10FD|LINK_SPEED_100HD|LINK_SPEED_100FD|LINK_AUTO_NEGOTIATE)
/*
. Do you want to use 32 bit xfers? This should work on all chips, as
. the chipset is designed to accommodate them.
*/
#define USE_32_BIT 1
/*
.the LAN91C111 can be at any of the following port addresses. To change,
.for a slightly different card, you can add it to the array. Keep in
.mind that the array must end in zero.
*/
static unsigned int smc_portlist[] __initdata =
{ 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0};
/*
. Wait time for memory to be free. This probably shouldn't be
. tuned that much, as waiting for this means nothing else happens
. in the system
*/
#define MEMORY_WAIT_TIME 16
/*
. DEBUGGING LEVELS
.
. 0 for normal operation
. 1 for slightly more details
. >2 for various levels of increasingly useless information
. 2 for interrupt tracking, status flags
. 3 for packet info
. 4 for complete packet dumps
*/
//#define SMC_DEBUG 3 // Must be defined in makefile
#if (SMC_DEBUG > 2 )
#define PRINTK3(args...) printk(args)
#else
#define PRINTK3(args...)
#endif
#if SMC_DEBUG > 1
#define PRINTK2(args...) printk(args)
#else
#define PRINTK2(args...)
#endif
#ifdef SMC_DEBUG
#define PRINTK(args...) printk(args)
#else
#define PRINTK(args...)
#endif
/*------------------------------------------------------------------------
.
. The internal workings of the driver. If you are changing anything
. here with the SMC stuff, you should have the datasheet and know
. what you are doing.
.
-------------------------------------------------------------------------*/
#define CARDNAME "LAN91C111"
// Memory sizing constant
#define LAN91C111_MEMORY_MULTIPLIER (1024*2)
/* store this information for the driver.. */
struct smc_local {
// these are things that the kernel wants me to keep, so users
// can find out semi-useless statistics of how well the card is
// performing
struct net_device_stats stats;
// If I have to wait until memory is available to send
// a packet, I will store the skbuff here, until I get the
// desired memory. Then, I'll send it out and free it.
struct sk_buff * saved_skb;
// This keeps track of how many packets that I have
// sent out. When an TX_EMPTY interrupt comes, I know
// that all of these have been sent.
int packets_waiting;
// Set to true during the auto-negotiation sequence
int autoneg_active;
// Address of our PHY port
word phyaddr;
// Type of PHY
word phytype;
// Last contents of PHY Register 18
word lastPhy18;
// Contains the current active transmission mode
word tcr_cur_mode;
// Contains the current active receive mode
word rcr_cur_mode;
// Contains the current active receive/phy mode
word rpc_cur_mode;
/* => Pramod, Odd Byte issue */
// Contains the Current ChipID
unsigned short ChipID;
//Contains the Current ChipRevision
unsigned short ChipRev;
/* <= Pramod, Odd Byte issue */
#ifdef CONFIG_SYSCTL
// Root directory /proc/sys/dev
// Second entry must be null to terminate the table
ctl_table root_table[2];
// Directory for this device /proc/sys/dev/ethX
// Again the second entry must be zero to terminate
ctl_table eth_table[2];
// This is the parameters (file) table
ctl_table param_table[CTL_SMC_LAST_ENTRY];
// Saves the sysctl header returned by register_sysctl_table()
// we send this to unregister_sysctl_table()
struct ctl_table_header *sysctl_header;
// Parameter variables (files) go here
char ctl_info[1024];
int ctl_swfdup;
int ctl_ephloop;
int ctl_miiop;
int ctl_autoneg;
int ctl_rfduplx;
int ctl_rspeed;
int ctl_afduplx;
int ctl_aspeed;
int ctl_lnkfail;
int ctl_forcol;
int ctl_filtcar;
int ctl_freemem;
int ctl_totmem;
int ctl_leda;
int ctl_ledb;
int ctl_chiprev;
#ifdef SMC_DEBUG
int ctl_reg_bsr;
int ctl_reg_tcr;
int ctl_reg_esr;
int ctl_reg_rcr;
int ctl_reg_ctrr;
int ctl_reg_mir;
int ctl_reg_rpcr;
int ctl_reg_cfgr;
int ctl_reg_bar;
int ctl_reg_iar0;
int ctl_reg_iar1;
int ctl_reg_iar2;
int ctl_reg_gpr;
int ctl_reg_ctlr;
int ctl_reg_mcr;
int ctl_reg_pnr;
int ctl_reg_fpr;
int ctl_reg_ptr;
int ctl_reg_dr;
int ctl_reg_isr;
int ctl_reg_mtr1;
int ctl_reg_mtr2;
int ctl_reg_mtr3;
int ctl_reg_mtr4;
int ctl_reg_miir;
int ctl_reg_revr;
int ctl_reg_ercvr;
int ctl_reg_extr;
int ctl_phy_ctrl;
int ctl_phy_stat;
int ctl_phy_id1;
int ctl_phy_id2;
int ctl_phy_adc;
int ctl_phy_remc;
int ctl_phy_cfg1;
int ctl_phy_cfg2;
int ctl_phy_int;
int ctl_phy_mask;
#endif // SMC_DEBUG
#endif // CONFIG_SYSCTL
};
MODULE_LICENSE("GPL");
/*-----------------------------------------------------------------
.
. The driver can be entered at any of the following entry points.
.
.------------------------------------------------------------------ */
/*
. This is called by register_netdev(). It is responsible for
. checking the portlist for the SMC9000 series chipset. If it finds
. one, then it will initialize the device, find the hardware information,
. and sets up the appropriate device parameters.
. NOTE: Interrupts are *OFF* when this procedure is called.
.
. NB:This shouldn't be static since it is referred to externally.
*/
int smc_init(struct net_device *dev);
/*
. This is called by unregister_netdev(). It is responsible for
. cleaning up before the driver is finally unregistered and discarded.
*/
void smc_destructor(struct net_device *dev);
/*
. The kernel calls this function when someone wants to use the net_device,
. typically 'ifconfig ethX up'.
*/
static int smc_open(struct net_device *dev);
/*
. This is called by the kernel to send a packet out into the net. it's
. responsible for doing a best-effort send, but if it's simply not possible
. to send it, the packet gets dropped.
*/
static void smc_timeout (struct net_device *dev);
/*
. This is called by the kernel in response to 'ifconfig ethX down'. It
. is responsible for cleaning up everything that the open routine
. does, and maybe putting the card into a powerdown state.
*/
static int smc_close(struct net_device *dev);
/*
. This routine allows the proc file system to query the driver's
. statistics.
*/
static struct net_device_stats * smc_query_statistics( struct net_device *dev);
/*
. Finally, a call to set promiscuous mode ( for TCPDUMP and related
. programs ) and multicast modes.
*/
static void smc_set_multicast_list(struct net_device *dev);
/*
. Configures the PHY through the MII Management interface
*/
static void smc_phy_configure(struct net_device* dev);
/*---------------------------------------------------------------
.
. Interrupt level calls..
.
----------------------------------------------------------------*/
/*
. Handles the actual interrupt
*/
static void smc_interrupt(int irq, void *, struct pt_regs *regs);
/*
. This is a separate procedure to handle the receipt of a packet, to
. leave the interrupt code looking slightly cleaner
*/
inline static void smc_rcv( struct net_device *dev );
/*
. This handles a TX interrupt, which is only called when an error
. relating to a packet is sent.
*/
inline static void smc_tx( struct net_device * dev );
/*
. This handles interrupts generated from PHY register 18
*/
static void smc_phy_interrupt(struct net_device* dev);
/*
. Kicks the PHY out of invalid states
*/
static void smc_phy_reset(struct net_device* dev);
/*
------------------------------------------------------------
.
. Internal routines
.
------------------------------------------------------------
*/
/*
. Test if a given location contains a chip, trying to cause as
. little damage as possible if it's not a SMC chip.
*/
static int smc_probe(struct net_device *dev, int ioaddr);
/*
. A rather simple routine to print out a packet for debugging purposes.
*/
#if SMC_DEBUG > 2
static void print_packet( byte *, int );
#endif
#define tx_done(dev) 1
/* this is called to actually send the packet to the chip */
static void smc_hardware_send_packet( struct net_device * dev );
/* Since I am not sure if I will have enough room in the chip's ram
. to store the packet, I call this routine, which either sends it
. now, or generates an interrupt when the card is ready for the
. packet */
static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev );
/* this does a soft reset on the device */
static void smc_reset( struct net_device* dev );
/* Enable Interrupts, Receive, and Transmit */
static void smc_enable( struct net_device *dev );
/* this puts the device in an inactive state */
static void smc_shutdown( int ioaddr );
#ifndef NO_AUTOPROBE
/* This routine will find the IRQ of the driver if one is not
. specified in the input to the device. */
static int smc_findirq( int ioaddr );
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -