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

📄 drv_lan91c111.c

📁 91c111的驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*---------------------------------------------------------------
*	Developed By Signal Process, synergy Co.,Ltd.
*	Copyright (c) 2006-2008 synergy Co.,Ltd.
*	All Right Reserved.
*
*	$Author Zhaoww (Zhaoww@synergy.com.cn)
*	$Version: Alpha
*	$Since 2006.4.11
*	$Log
*
*	DESCRIPTION
*		 This is a driver for SMSC's LAN91C111
*			single-chip Ethernet device
*
*---------------------------------------------------------------*/
#define		_DRV_91C111_GLOBALS_
#include "includes.h"
#include "drv_int.h"
#include "drv_lan91c111.h"
#include "tasksystem.h"

INT8U smc_mac_addr[] = { 0xc0, 0x00, 0x00, 0x1b, 0x62, 0x9d};

			
void SMC_outb(INT16U d,INT16U r)
{
	INT16U __d = (INT8U)(d); 
	INT16U __w = SMC_inw((r)&~1);

	
	__w &= ((r)&1) ? 0x00FF : 0xFF00;
	__w |= ((r)&1) ? __d<<8 : __d;
	SMC_outw(__w,(r)&~1);
}
void SMC_insw(INT8U r,INT8U *b,INT32U l)
{
	int __i ; 
	INT16U *__b2;  
	__b2 = (INT16U *) b;  
	for (__i = 0; __i < l; __i++) 
	{ 
		  *(__b2 + __i) = SMC_inw(r);  
		  SMC_inw(0);  
	};  
}
void SMC_outsw(INT8U r,INT8U *b,INT32U l)
{
	int __i; 
	INT16U *__b2; 
	__b2 = (INT16U *) b; 
	for (__i = 0; __i < l; __i++) 
	{
	    SMC_outw( *(__b2 + __i), r); 
	}
}
static int poll4int (INT8U mask, INT32U timeout)
{
	INT16U old_bank = SMC_inw (BSR_REG);

	OS_DEBUGF(DEV_91C111_DEBUG,("Polling...\r\n"));

	SMC_SELECT_BANK (2);
	while ((SMC_inw (SMC91111_INT_REG) & mask) == 0) {}

	/* restore old bank selection */
	SMC_SELECT_BANK (old_bank);
	return 0;
}
/* Only one release command at a time, please */
static inline void smc_wait_mmu_release_complete (void)
{
	int count = 0;

	/* assume bank 2 selected */
	while (SMC_inw (MMU_CMD_REG) & MC_BUSY) {
		udelay (10);	/* Wait until not busy */
		if (++count > 200)
			break;
	}
}
/*
 . Function: smc_reset( void )
 . Purpose:
 .	This sets the SMC91111 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)
{
	
	/* 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);
	SMC_outw (CONFIG_DEFAULT, CONFIG_REG);



	/* 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 */
	//udelay( 50 );
	OSTimeDly( OS_DELAY_TIME(dSYSTEM_TIME_120MS));

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

	/* Reset the MMU */
	SMC_SELECT_BANK (2);
	smc_wait_mmu_release_complete ();
	SMC_outw (MC_RESET, MMU_CMD_REG);
	while (SMC_inw (MMU_CMD_REG) & MC_BUSY)
		udelay (10);	/* 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()
{
	
	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 );

	SMC_SELECT_BANK( 2 );
	SMC_outb( IM_RCV_INT, IM_REG );

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


static INT16U smc_read_phy_register (INT8U phyreg)
{
	INT32U 	oldBank;
	INT32U	i;
	INT8U	mask;
	INT16U	mii_reg;
	INT8U 	bits[64];
	INT32U	clk_idx = 0;
	INT32U	input_idx;
	INT16U	phydata;
	INT8U	phyaddr = SMC_PHY_ADDR;

	/* 32 consecutive ones on MDO to establish sync */
	for (i = 0; i < 32; ++i)
		bits[clk_idx++] = MII_MDOE | MII_MDO;

	/* Start code <01> */
	bits[clk_idx++] = MII_MDOE;
	bits[clk_idx++] = MII_MDOE | MII_MDO;

	/* Read command <10> */
	bits[clk_idx++] = MII_MDOE | MII_MDO;
	bits[clk_idx++] = MII_MDOE;

	/* Output the PHY address, msb first */
	mask = (INT8U) 0x10;
	for (i = 0; i < 5; ++i) {
		if (phyaddr & mask)
			bits[clk_idx++] = MII_MDOE | MII_MDO;
		else
			bits[clk_idx++] = MII_MDOE;

		/* Shift to next lowest bit */
		mask >>= 1;
	}

	/* Output the phy register number, msb first */
	mask = (INT8U) 0x10;
	for (i = 0; i < 5; ++i) {
		if (phyreg & mask)
			bits[clk_idx++] = MII_MDOE | MII_MDO;
		else
			bits[clk_idx++] = MII_MDOE;

		/* Shift to next lowest bit */
		mask >>= 1;
	}

	/* Tristate and turnaround (2 bit times) */
	bits[clk_idx++] = 0;
	/*bits[clk_idx++] = 0; */

	/* Input starts at this bit time */
	input_idx = clk_idx;

	/* Will input 16 bits */
	for (i = 0; i < 16; ++i)
		bits[clk_idx++] = 0;

	/* Final clock bit */
	bits[clk_idx++] = 0;

	/* Save the current bank */
	oldBank = SMC_inw (BANK_SELECT);

	/* Select bank 3 */
	SMC_SELECT_BANK (3);

	/* Get the current MII register value */
	mii_reg = SMC_inw (MII_REG);

	/* Turn off all MII Interface bits */
	mii_reg &= ~(MII_MDOE | MII_MCLK | MII_MDI | MII_MDO);

	/* Clock all 64 cycles */
	for (i = 0; i < sizeof bits; ++i) {
		/* Clock Low - output data */
		SMC_outw (mii_reg | bits[i], MII_REG);
		udelay (SMC_PHY_CLOCK_DELAY);


		/* Clock Hi - input data */
		SMC_outw (mii_reg | bits[i] | MII_MCLK, MII_REG);
		udelay (SMC_PHY_CLOCK_DELAY);
		bits[i] |= SMC_inw (MII_REG) & MII_MDI;
	}

	/* Return to idle state */
	/* Set clock to low, data to low, and output tristated */
	SMC_outw (mii_reg, MII_REG);
	udelay (SMC_PHY_CLOCK_DELAY);

	/* Restore original bank select */
	SMC_SELECT_BANK (oldBank);

	/* Recover input data */
	phydata = 0;
	for (i = 0; i < 16; ++i) {
		phydata <<= 1;

		if (bits[input_idx++] & MII_MDI)
			phydata |= 0x0001;
	}

	return (phydata);
}

/*------------------------------------------------------------
 . Writes a register to the MII Management serial interface
 .-------------------------------------------------------------*/
static void smc_write_phy_register (INT8U phyreg, INT16U phydata)
{
	INT32U	oldBank;
	INT32U	i;
	INT16U	mask;
	INT16U	mii_reg;
	INT8U	bits[65];
	INT32U	clk_idx = 0;
	INT8U	phyaddr = SMC_PHY_ADDR;

	/* 32 consecutive ones on MDO to establish sync */
	for (i = 0; i < 32; ++i)
		bits[clk_idx++] = MII_MDOE | MII_MDO;

	/* Start code <01> */
	bits[clk_idx++] = MII_MDOE;
	bits[clk_idx++] = MII_MDOE | MII_MDO;

	/* Write command <01> */
	bits[clk_idx++] = MII_MDOE;
	bits[clk_idx++] = MII_MDOE | MII_MDO;

	/* Output the PHY address, msb first */
	mask = (INT8U) 0x10;
	for (i = 0; i < 5; ++i) {
		if (phyaddr & mask)
			bits[clk_idx++] = MII_MDOE | MII_MDO;
		else
			bits[clk_idx++] = MII_MDOE;

		/* Shift to next lowest bit */
		mask >>= 1;
	}

	/* Output the phy register number, msb first */
	mask = (INT8U) 0x10;
	for (i = 0; i < 5; ++i) {
		if (phyreg & mask)
			bits[clk_idx++] = MII_MDOE | MII_MDO;
		else
			bits[clk_idx++] = MII_MDOE;

		/* Shift to next lowest bit */
		mask >>= 1;
	}

	/* Tristate and turnaround (2 bit times) */
	bits[clk_idx++] = 0;
	bits[clk_idx++] = 0;

	/* Write out 16 bits of data, msb first */
	mask = 0x8000;
	for (i = 0; i < 16; ++i) {
		if (phydata & mask)
			bits[clk_idx++] = MII_MDOE | MII_MDO;
		else
			bits[clk_idx++] = MII_MDOE;

		/* Shift to next lowest bit */
		mask >>= 1;
	}

	/* Final clock bit (tristate) */
	bits[clk_idx++] = 0;

	/* Save the current bank */
	oldBank = SMC_inw (BANK_SELECT);

	/* Select bank 3 */
	SMC_SELECT_BANK (3);

	/* Get the current MII register value */
	mii_reg = SMC_inw (MII_REG);

	/* Turn off all MII Interface bits */
	mii_reg &= ~(MII_MDOE | MII_MCLK | MII_MDI | MII_MDO);

	/* Clock all cycles */
	for (i = 0; i < sizeof bits; ++i) {
		/* Clock Low - output data */
		SMC_outw (mii_reg | bits[i], MII_REG);
		udelay (SMC_PHY_CLOCK_DELAY);


		/* Clock Hi - input data */
		SMC_outw (mii_reg | bits[i] | MII_MCLK, MII_REG);
		udelay (SMC_PHY_CLOCK_DELAY);
		bits[i] |= SMC_inw (MII_REG) & MII_MDI;
	}

	/* Return to idle state */
	/* Set clock to low, data to low, and output tristated */
	SMC_outw (mii_reg, MII_REG);
	udelay (SMC_PHY_CLOCK_DELAY);

	/* Restore original bank select */
	SMC_SELECT_BANK (oldBank);

}

#if 0
static void smc_wait_ms(unsigned int ms)
{
	udelay(ms*1000);
}
#endif
static void smc_phy_configure ()
{
	INT32U 	timeout;
	INT8U 	phyaddr;
	INT16U 	my_phy_caps;	/* My PHY capabilities */
	INT16U	my_ad_caps;	/* My Advertised capabilities */
	INT16U	status = 0;	/*;my status = 0 */
	
	

	/* Get the detected phy address */
	phyaddr = SMC_PHY_ADDR;
	
	phyaddr = phyaddr ;
	/* Reset the PHY, setting all other bits to zero */
	smc_write_phy_register (PHY_CNTL_REG, PHY_CNTL_RST);

	/* Wait for the reset to complete, or time out */
	timeout = 6;		/* Wait up to 3 seconds */
	while (timeout--) {
		if (!(smc_read_phy_register (PHY_CNTL_REG)
		      & PHY_CNTL_RST)) {
			/* reset complete */
			break;
		}

		//smc_wait_ms (500);	/* wait 500 millisecs */
		OSTimeDly( OS_DELAY_TIME(dSYSTEM_TIME_520MS));
		
	}

	if (timeout < 1) {

	OS_DEBUGF(DEV_91C111_DEBUG,("%s:PHY reset timed out\r\n", SMC_DEV_NAME));

		return;
	}

	/* Read PHY Register 18, Status Output */
	/* lp->lastPhy18 = smc_read_phy_register(PHY_INT_REG); */

	/* Enable PHY Interrupts (for register 18) */
	/* Interrupts listed here are disabled */
	smc_write_phy_register (PHY_MASK_REG, 0xffff);

	/* Configure the Receive/Phy Control register */
	SMC_SELECT_BANK (0);
	SMC_outw (RPC_DEFAULT, RPC_REG);

	/* Copy our capabilities from PHY_STAT_REG to PHY_AD_REG */
	my_phy_caps = smc_read_phy_register (PHY_STAT_REG);
	my_ad_caps = PHY_AD_CSMA;	/* I am CSMA capable */

	if (my_phy_caps & PHY_STAT_CAP_T4)
		my_ad_caps |= PHY_AD_T4;

	if (my_phy_caps & PHY_STAT_CAP_TXF)
		my_ad_caps |= PHY_AD_TX_FDX;

	if (my_phy_caps & PHY_STAT_CAP_TXH)
		my_ad_caps |= PHY_AD_TX_HDX;

	if (my_phy_caps & PHY_STAT_CAP_TF)
		my_ad_caps |= PHY_AD_10_FDX;

	if (my_phy_caps & PHY_STAT_CAP_TH)
		my_ad_caps |= PHY_AD_10_HDX;

	/* Update our Auto-Neg Advertisement Register */
	smc_write_phy_register (PHY_AD_REG, my_ad_caps);

	/* Read the register back.  Without this, it appears that when */
	/* auto-negotiation is restarted, sometimes it isn't ready and */
	/* the link does not come up. */
	smc_read_phy_register(PHY_AD_REG);

	OS_DEBUGF(DEV_91C111_DEBUG, ("%s:phy caps=%x\r\n", SMC_DEV_NAME, my_phy_caps));
	OS_DEBUGF(DEV_91C111_DEBUG,("%s:phy advertised caps=%x\r\n", SMC_DEV_NAME, my_ad_caps));

	/* Restart auto-negotiation process in order to advertise my caps */
 	
	
	smc_write_phy_register (PHY_CNTL_REG,
				PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST );

	/* Wait for the auto-negotiation to complete.  This may take from */
	/* 2 to 3 seconds. */
	/* Wait for the reset to complete, or time out */
	timeout = 20;		/* Wait up to 10 seconds */

⌨️ 快捷键说明

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