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

📄 smc91x.c

📁 LUBBOCK板的BLOB
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------
 . smc91x.c
 . This is a driver for SMSC's 9196/91C111 single-chip Ethernet device.
 .
 . Copyright (C) 2003, Intel corporation (yu.tang@intel.com)
 .
 . (C) Copyright 2002
 . Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 . Rolf Offermanns <rof@sysgo.de>
 .
 . Copyright (C) 2001 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
 .
 . author:
 . 	Erik Stahlman				( erik@vt.edu )
 . 	Daris A Nevil				( dnevil@snmc.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:
 .	10/17/01  Marco Hasewinkel Modify for DNP/1110
 .	07/25/01  Woojung Huh      Modify for ADS Bitsy
 .	04/25/01  Daris A Nevil    Initial public release through SMSC
 .	03/16/01  Daris A Nevil    Modified smc9194.c for use with LAN91C111
 ----------------------------------------------------------------------------*/

#ifdef HAVE_CONFIG_H
# include <blob/config.h>
#endif

#include <blob/arch.h>
#include <blob/types.h>
#include <blob/init.h>
#include <blob/serial.h>
#include <blob/util.h>
#include <blob/time.h>

#include "net.h"
#include "smc91x.h"

// Use power-down feature of the chip
#define POWER_DOWN	0

#define NO_AUTOPROBE

static const char version[] =
	"smc91x.c:v1.0 04/25/01 by Daris A Nevil (dnevil@snmc.com)\n";


#define SMC_DEBUG 0


/*------------------------------------------------------------------------
 .
 . Configuration options, for the experienced user to change.
 .
 -------------------------------------------------------------------------*/

/*
 . 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


#if (SMC_DEBUG > 2 )
#define PRINTK3(args...) printf(args)
#else
#define PRINTK3(args...)
#endif

#if SMC_DEBUG > 1
#define PRINTK2(args...) printf(args)
#else
#define PRINTK2(args...)
#endif

#ifdef SMC_DEBUG
#define PRINTK(args...) printf(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 "LAN91X"

// Memory sizing constant
#define LAN91C111_MEMORY_MULTIPLIER	(1024*2)

#define SMC_BASE_ADDRESS CONFIG_SMC91X_BASE 
#define SMC_DEV_NAME "SMC91X"
#define SMC_PHY_ADDR 0x0000
#define SMC_ALLOC_MAX_TRY 5
#define SMC_TX_TIMEOUT 30

#define SMC_PHY_CLOCK_DELAY 1

#define ETH_ZLEN 60

/*-----------------------------------------------------------------
 .
 .  The driver can be entered at any of the following entry points.
 .
 .------------------------------------------------------------------  */

extern int eth_init();
extern void eth_halt(void);
extern int eth_rx(void);
extern int eth_xmit(struct mybuf *packet);





/*
 . 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(void);

/*
 . This is called by  unregister_netdev().  It is responsible for
 . cleaning up before the driver is finally unregistered and discarded.
*/
void smc_destructor(void);

/*
 . The kernel calls this function when someone wants to use the device,
 . typically 'ifconfig ethX up'.
*/
static int smc_open(void);


/*
 . 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(void);

/*
 . Configures the PHY through the MII Management interface
*/
static void smc_phy_configure(void);

/*
 . This is a separate procedure to handle the receipt of a packet, to
 . leave the interrupt code looking slightly cleaner
*/
static int smc_rcv(void);



/*
 ------------------------------------------------------------
 .
 . Internal routines
 .
 ------------------------------------------------------------
*/

/** This is hardcoded for now.
 * Once the flash works correctly the mac addr. can be
 * fetched from FLASHBLOCK 1 / OFFSET 0x10 using 
 * smc_get_macaddr( smc_mac_addr );
 */
unsigned char eth_mac_addr[6] = {0x08, 0x00, 0x3e, 0x26, 0x0a, 0x5b};

/*
void smc_get_macaddr( byte *addr ) {
	// MAC ADDRESS AT FLASHBLOCK 1 / OFFSET 0x10 
        unsigned char *dnp1110_mac = (unsigned char *) (0xE8000000 + 0x20010);
	int i;


        for (i=0; i<6; i++) {
            addr[0] = *(dnp1110_mac+0);
            addr[1] = *(dnp1110_mac+1);
            addr[2] = *(dnp1110_mac+2);
            addr[3] = *(dnp1110_mac+3);
            addr[4] = *(dnp1110_mac+4);
            addr[5] = *(dnp1110_mac+5);
        }
}
*/

/***********************************************
 * Show available memory                       *
 ***********************************************/
void dump_memory_info(void)
{
        word mem_info;
        word old_bank;

        old_bank = SMC_inw(BANK_SELECT)&0xF;

        SMC_SELECT_BANK(0);
        mem_info = SMC_inw( MIR_REG );
        PRINTK2("Memory: %4d available\n", (mem_info >> 8)*2048);

        SMC_SELECT_BANK(old_bank);
}
/*
 . 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 does a soft reset on the device */
static void smc_reset( void );

/* Enable Interrupts, Receive, and Transmit */
static void smc_enable( void );

/* this puts the device in an inactive state */
static void smc_shutdown( void );

/* Routines to Read and Write the PHY Registers across the
   MII Management Interface
*/

static word smc_read_phy_register(byte phyreg);
static void smc_write_phy_register(byte phyreg, word phydata);

/*
 . Function: smc_reset( void )
 . Purpose:
 .  	This sets the SMC9196/91111 chip to its normal state, hopefully from whatever
 . 	mess that any other DOS driver has put it in.
 .
 . Maybe I should reset more registers to defaults in here?  SOFTRST  should
 . do that for me.
 .
 . Method:
 .	1.  send a SOFT RESET
 .	2.  wait for it to finish
 .	3.  enable autorelease mode
 .	4.  reset the memory management unit
 .	5.  clear all interrupts
 .
*/
static void smc_reset( void )
{
	PRINTK2("%s:smc_reset\n", SMC_DEV_NAME);

	/* This resets the registers mostly to defaults, but doesn't
	   affect EEPROM.  That seems unnecessary */
	SMC_SELECT_BANK( 0 );
	SMC_outw( RCR_SOFTRST, RCR_REG );

	/* Setup the Configuration Register */
	/* This is necessary because the CONFIG_REG is not affected */
	/* by a soft reset */

	SMC_SELECT_BANK( 1 );
//#if defined(CONFIG_SMC91111_EXT_PHY)
//	SMC_outw( CONFIG_DEFAULT | CONFIG_EXT_PHY, CONFIG_REG);
//#else
	SMC_outw( CONFIG_DEFAULT, CONFIG_REG);
//#endif


	/* Release from possible power-down state */
	/* Configuration register is not affected by Soft Reset */
	SMC_outw( SMC_inw( CONFIG_REG ) | CONFIG_EPH_POWER_EN, CONFIG_REG  );

	SMC_SELECT_BANK( 0 );

	/* this should pause enough for the chip to be happy */
	msleep(1);

	/* Disable transmit and receive functionality */
	SMC_outw( RCR_CLEAR, RCR_REG );
	SMC_outw( TCR_CLEAR, TCR_REG );

	/* set the control register */
	SMC_SELECT_BANK( 1 );
	//SMC_outw( CTL_DEFAULT, CTL_REG );
	// Enable AUTO_RELEASE
	SMC_outw( SMC_inw(CTL_REG) | CTL_AUTO_RELEASE, CTL_REG);

	/* Reset the MMU */
	SMC_SELECT_BANK( 2 );
	SMC_outw( MC_RESET, MMU_CMD_REG );
	while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY )
		msleep(1); // Wait until not busy

	/* Note:  It doesn't seem that waiting for the MMU busy is needed here,
	   but this is a place where future chipsets _COULD_ break.  Be wary
 	   of issuing another MMU command right after this */

	/* Disable all interrupts */
	SMC_outb( 0, IM_REG );
}

/*
 . Function: smc_enable
 . Purpose: let the chip talk to the outside work
 . Method:
 .	1.  Enable the transmitter
 .	2.  Enable the receiver
 .	3.  Enable interrupts
*/
static void smc_enable()
{
	PRINTK2("%s:smc_enable\n", SMC_DEV_NAME);
	SMC_SELECT_BANK( 0 );
	/* see the header file for options in TCR/RCR DEFAULT*/
	SMC_outw( TCR_DEFAULT, TCR_REG );
	SMC_outw( RCR_DEFAULT, RCR_REG );

	/* clear MII_DIS */
//	smc_write_phy_register(PHY_CNTL_REG, 0x0000);
}

/*
 . Function: smc_shutdown
 . Purpose:  closes down the SMC91xxx chip.
 . Method:
 .	1. zero the interrupt mask
 .	2. clear the enable receive flag
 .	3. clear the enable xmit flags
 .
 . TODO:
 .   (1) maybe utilize power down mode.
 .	Why not yet?  Because while the chip will go into power down mode,
 .	the manual says that it will wake up in response to any I/O requests
 .	in the register space.   Empirical results do not show this working.
*/
static void smc_shutdown()
{
	PRINTK2(CARDNAME ":smc_shutdown\n");

	/* no more interrupts for me */
	SMC_SELECT_BANK( 2 );
	SMC_outb( 0, IM_REG );

	/* and tell the card to stay away from that nasty outside world */
	SMC_SELECT_BANK( 0 );
	SMC_outb( RCR_CLEAR, RCR_REG );
	SMC_outb( TCR_CLEAR, TCR_REG );
}


/*
 . Function:  smc_hardware_send_packet(struct net_device * )
 . Purpose:
 .	This sends the actual packet to the SMC9xxx chip.
 .
 . Algorithm:
 . 	First, see if a saved_skb is available.
 .		( this should NOT be called if there is no 'saved_skb'
 .	Now, find the packet number that the chip allocated
 .	Point the data pointers at it in memory
 .	Set the length word in the chip's memory
 .	Dump the packet to chip memory
 .	Check if a last byte is needed ( odd length packet )
 .		if so, set the control flag right
 . 	Tell the card to send it
 .	Enable the transmit interrupt, so I know if it failed
 . 	Free the kernel data if I actually sent it.
*/
static int smc_send_packet(volatile void *packet, int packet_length)
{
	byte	 		packet_no;
	unsigned long		ioaddr;
	byte			* buf;
	int			length;
	int			numPages;
	int			try = 0;
	int			time_out;
	byte			status;


	PRINTK3("%s:smc_hardware_send_packet\n", SMC_DEV_NAME);

	length = ETH_ZLEN < packet_length ? packet_length : ETH_ZLEN;
	
	/* allocate memory
	** The MMU wants the number of pages to be the number of 256 bytes
	** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
	**
	** The 91C111 ignores the size bits, but the code is left intact
	** for backwards and future compatibility.
	**
	** Pkt size for allocating is data length +6 (for additional status
	** words, length and ctl!)
	**
	** If odd size then last byte is included in this header.
	*/
	numPages =   ((length & 0xfffe) + 6);
	numPages >>= 8; // Divide by 256

	if (numPages > 7 ) {
		printf("%s: Far too big packet error. \n", SMC_DEV_NAME);
		return 0;
	}

again:
	/* now, try to allocate the memory */
	SMC_SELECT_BANK( 2 );
	SMC_outw( MC_ALLOC | numPages, MMU_CMD_REG );

	try++;
	time_out = MEMORY_WAIT_TIME;
	do {

⌨️ 快捷键说明

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