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

📄 if_snnew.c

📁 T-kernel Tcp/ip Protocol Stack Sample
💻 C
📖 第 1 页 / 共 5 页
字号:
	    if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
	        ifp->if_flags &= ~IFF_RUNNING;
	        snstop();
	        break;
	    } else {
	        /* reinitialize card on any parameter change */
	        sninit(0);
	        break;
	    }
	    break;

#ifdef notdef
	  case SIOCGHWADDR:
	    bcopy((caddr_t) sc->sc_addr, (caddr_t) & ifr->ifr_data,
	          sizeof(sc->sc_addr));
	    break;
#endif

	    case SIOCSIFMTU:

	            /*
	             * Set the interface MTU.
	             */
	            if (ifr->ifr_mtu > ETHERMTU) {
	                    error = EINVAL;
	            } else {
	                    ifp->if_mtu = ifr->ifr_mtu;
	            }
	            break;

	  default:
	            error = EINVAL;
	}

	splx(s);

	return (error);
}

void
snreset(void)
{
	int s;

	s = splimp();
	snstop();
	sninit(0);
	splx(s);
}

void
snwatchdog(struct ifnet *dummy)
{
	int s;

	s = splimp();
	snintr_sc();
	splx(s);
}

/* 1. zero the interrupt mask
 * 2. clear the enable receive flag
 * 3. clear the enable xmit flags
 */
void
snstop(void)
{
	struct sn_softc *sc = &sn_softc0;
	struct ifnet *ifp = &sc->arpcom.ac_if;
	
	/* Clear interrupt mask; disable all interrupts.
	 */
	SMC_SELECT_BANK( 2 );
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	/* cannot access with byte length */
	outw( BASE + INTR_MASK_REG_W, 0x0000 );
#else
	outb( BASE + INTR_MASK_REG_B, 0x00 );
#endif

	/* Disable transmitter and Receiver
	 */
	SMC_SELECT_BANK( 0 );
	outw( BASE + RECV_CONTROL_REG_W, 0x0000 );
	outw( BASE + TXMIT_CONTROL_REG_W, 0x0000 );

	/* Cancel watchdog.
	 */
	ifp->if_timer = 0;
}

/*
 * Function: smc_probe( int ioaddr )
 *
 * Purpose:
 *	  Tests to see if a given ioaddr points to an SMC9xxx chip.
 *	  Tries to cause as little damage as possible if it's not a SMC chip.
 *	  Returns a 0 on success
 *
 * Algorithm:
 *	  (1) see if the high byte of BANK_SELECT is 0x33
 *	  (2) compare the ioaddr with the base register's address
 *	  (3) see if I recognize the chip ID in the appropriate register
 *
 *
 */
static int smc_probe(int ioaddr)
{
	u_short bank;
	u_short revision_register;
	u_short base_address_register;

	/* First, see if the high byte is 0x33
	 */
	bank = inw( ioaddr + BANK_SELECT_REG_W );
	if ( (bank & BSR_DETECT_MASK) != BSR_DETECT_VALUE ) {
	    return -ENODEV;
	}

	/* The above MIGHT indicate a device, but I need to write to further
	 * test this.  Go to bank 0, then test that the register still reports
	 * the high byte is 0x33.
	 */
	outw( ioaddr + BANK_SELECT_REG_W, 0x0000 );
	bank = inw( ioaddr + BANK_SELECT_REG_W );
	if ( (bank & BSR_DETECT_MASK) != BSR_DETECT_VALUE ) {
	    return -ENODEV;
	}

#if BASE_ADDR_SET /* EEPROM is cleared. So we don't need */
	/* well, we've already written once, so hopefully another time won't
	 * hurt.  This time, I need to switch the bank register to bank 1,
	 * so I can access the base address register.  The contents of
	 * the BASE_ADDR_REG_W register, after some jiggery pokery, is
	 * expected to match the I/O port address where the adapter is being
	 * probed.
	 */
	outw( ioaddr + BANK_SELECT_REG_W, 0x0001 );
	base_address_register = inw( ioaddr + BASE_ADDR_REG_W );
	if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) )  {

	    /* Well, the base address register didn't match.  Must not have
	     * been a SMC chip after all.
	     */
#ifdef PRINTON
	     printf("sn: ioaddr %x doesn't match card configuration (%x)\n",
	        ioaddr, base_address_register >> 3 & 0x3E0 ); 
#endif
	    return -ENODEV;
	}

	/* Check if the revision register is something that I recognize.
	 * These might need to be added to later, as future revisions
	 * could be added.
	 */
	outw( ioaddr + BANK_SELECT_REG_W, 0x3 );
	revision_register  = inw( ioaddr + REVISION_REG_W );
	if ( !chip_ids[ ( revision_register  >> 4 ) & 0xF  ] ) {

	    /* I don't regonize this chip, so...
	     */
#ifdef PRINTON
	    printf("sn: ioaddr %x unrecognized revision register: %x\n",
	        ioaddr, revision_register ); 
#endif
	    return -ENODEV;
	}
#endif /* BASE_ADDR_SET */
	/* at this point I'll assume that the chip is an SMC9xxx.
	 * It might be prudent to check a listing of MAC addresses
	 * against the hardware address, or do some other tests.
	 */
	return 0;
}

/*** PHY Access functions ***/
int phy_init(void)
{
	struct sn_softc *sc = &sn_softc0;
	u_short ret;
	u_char phy,regno;
	u_short wdata;
	volatile int i, j;

	/* PHY address */
	phy = PHY_ADDR;

	/* PHY Control Register */
	regno = PHY_CNTL_REG;

	/* Reset PHY */
	wdata = PHY_CNTL_RST;	/* RST */
	ret = phy_access(phy,regno,OPWrite,wdata);
	while(1) {
#if defined(LAN91C111)
#ifdef _MIC_SH7145_
		// for (i=0;i<2*1000*1000;i++);	/* BUSY wait */
		// for (i=0;i<1*1000*1000;i++);	/* BUSY wait */
		for (i=0;i<WAIT_UNIT;i++);	/* BUSY wait */
#else
		// for (i=0;i<10*1000*1000;i++);	/* BUSY wait */
		for (i=0;i<WAIT_UNIT;i++);	/* BUSY wait */
#endif // _MIC_SH7145
#else
		for (i=0;i<0x100;i++);	/* BUSY wait */
#endif
		ret = phy_access(phy,regno,OPRead,wdata);
		if ((ret & PHY_CNTL_RST) == 0)
			break;
	}
	for (i=0;i<100*1000;i++);	/* 50ms BUSY wait */

#if defined(LAN91C111)
	/* Clear MII_DIS for chip bug */
	ret = phy_access(phy,regno,OPRead,wdata);
	if (ret & PHY_CNTL_MII_DIS) {
		wdata = 0x0000;
		ret = phy_access(phy,regno,OPWrite,wdata);
		while(1) {
			for (i=0;i<100*1000;i++);	/* 50ms BUSY wait */
			ret = phy_access(phy,regno,OPRead,wdata);
			if ((ret & PHY_CNTL_MII_DIS) == 0)
				break;
		}
	}
	for (i=0;i<100*1000;i++);	/* 50ms BUSY wait */
#endif

#if defined(LAN91C111)
	/* Save PHY Status Output */
	regno = PHY_INT_REG;
	sc->lastPhy18 = phy_access(phy,regno,OPRead,wdata);
	for (i=0;i<100*1000;i++);	/* 50ms BUSY wait */
	
	/* Enable PHY interrupts for MLNKFAIL */
	regno = PHY_MASK_REG;
	wdata = PHY_INT_LOSSSYNC|PHY_INT_CWRD|PHY_INT_SSD|PHY_INT_ESD
		|PHY_INT_RPOL|PHY_INT_JAB|PHY_INT_SPDDET|PHY_INT_DPLXDET;
	ret = phy_access(phy,regno,OPWrite,wdata);
	for (i=0;i<100*1000;i++);	/* 50ms BUSY wait */
#endif

	/* Set the Receive/Phy Control Reg. */
	SMC_SELECT_BANK( 0 );
	wdata = inw( BASE + PHY_CONTROL_REG_W );

#if defined(OLD)
	outw( BASE + PHY_CONTROL_REG_W, wdata | RPCR_LS2A );
#else
	/* also set Auto-Negotiation mode(ANEG) */
	outw( BASE + PHY_CONTROL_REG_W, wdata | RPCR_DEFAULT );
#endif

	/* PHY Control Register */
	regno = PHY_CNTL_REG;

#if defined(OLD)
	/***  Now use 10baseT half duplex mode  ***/
	wdata = 0x0;
	ret = phy_access(phy,regno,OPWrite,wdata);
	for (i=0;i<0x10000;i++);	/* BUSY wait */
#else
	/* Restart Auto-Negotiation process */
	wdata = ( PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST
		| PHY_CNTL_SPEED | PHY_CNTL_DPLX );
	ret = phy_access(phy,regno,OPWrite,wdata);

	/* Wait for the auto-negotiation to initiate */
	ret = phy_access(phy,regno,OPRead,wdata);
	while (1) {
		for (i=0;i<100*1000;i++);	/* 50ms BUSY wait */
		ret = phy_access(phy,regno,OPRead,wdata);
		if ((ret & PHY_CNTL_ANEG_RST) == 0) {
			break;
		}
	}
	for (i=0;i<100*1000;i++);	/* 50ms BUSY wait */
#endif /* OLD */

#if defined(OLD)
	/* BMCR value check */
	wdata = 0x0;
	ret = phy_access(phy,regno,OPRead,wdata);
	if (wdata != ret)
		return(-1);
#endif
	/* PHY Status Register */
	regno = PHY_STS_REG;
	ret = phy_access(phy,regno,OPRead,wdata);
	for (i=0;i<100*1000;i++);	/* 50ms BUSY wait */

#if defined(OLD)
	/* check 10baseT half duplex capable */
	if ((ret & 0x0800) == 0)
		return(-1);
#else
	/* check Auto-Negotiation capable */
	if ((ret & PHY_STS_CAP_ANEG) == 0)
		return(-1);
	/* check Auto-Negotiation Acknowlegment */
	j = 6;
	while (j--) {
#ifdef _MIC_SH7145_
		for (i=0;i<2*1000*1000;i++);	/* BUSY wait */
#else 
		for (i=0;i<WAIT_UNIT;i++);	/* BUSY wait */
#endif // _MIC_SH7145
		ret = phy_access(phy,regno,OPRead,wdata);
		if (ret & PHY_STS_ANEG_ACK) {
			break;
		}
		/* Restart Auto-Negotiation if remote fault */
		if (ret & PHY_STS_REM_FLT) {
			wdata = ( PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST
				| PHY_CNTL_SPEED | PHY_CNTL_DPLX );
			ret = phy_access(phy,regno,OPWrite,wdata);
		}
	}
#endif /* OLD */

#if defined(OLD)
	/* PHYSTS value check */
	regno = 0x10;
	ret = phy_access(phy,regno,OPRead,wdata);
	/* check if device ready,10BaseT mode,Link up */  
	if ((ret & 0x0803) == 0)
		return(-1);
#else
	/* check Link Status */
	regno = PHY_STS_REG;
	ret = phy_access(phy,regno,OPRead,wdata);
	if ((ret & PHY_STS_LINK) == 0)
		return(-1);
#endif /* OLD */

#if !defined(OLD)
	/* Update the Receive/Phy Control Reg. */
	SMC_SELECT_BANK( 0 );
	wdata = inw( BASE + PHY_CONTROL_REG_W );

	regno = PHY_INT_REG;	/* Status Output */
	ret = phy_access(phy,regno,OPRead,wdata);
	if (ret & PHY_INT_SPDDET) {
		wdata |= RPCR_SPEED;
	} else {
		wdata &= ~RPCR_SPEED;
	}
	if (ret & PHY_INT_DPLXDET) {
		wdata |= RPCR_DPLX;
	} else {
		wdata &= ~RPCR_DPLX;
	}
	outw( BASE + PHY_CONTROL_REG_W, wdata );
#endif /* !OLD */

	return(0);
}

int phy_ints(void)
{
	struct sn_softc *sc = &sn_softc0;
	u_char phy,regno;
	u_short wdata=0;
	u_short phy18;

	/* PHY address */
	phy = PHY_ADDR;

	/* read PHY Status Output */
	regno = PHY_INT_REG;

	while (1) {
		phy18 = phy_access(phy,regno,OPRead,wdata);

		if (sc->lastPhy18 == phy18)
			break;
		sc->lastPhy18 = phy18;
	}

	return(0);
}

unsigned short phy_access(u_char phy_addr, u_char reg_addr, u_char opcode, unsigned short wdata)
{
	int i;
	unsigned short mgmt_val;

	phy_addr &= 0x1f;
	reg_addr &= 0x1f;
	opcode &= 0x03;

	/* Select BANK 3 */
	outw(SMC_LAN_BASEADDR + BANK_SELECT_REG_W, 3);

	mgmt_val = inw(SMC_LAN_BASEADDR + MGMT_REG_W) & (MALL ^ 0xffff);

	/* Output Preamble (32 '1's ) */
	for (i=0; i<32; i++)
		clkmdio(mgmt_val | MDOE | MDO);

	/* Output Start of frame ('01') */
	for (i=0; i<2; i++)
		clkmdio(mgmt_val | MDOE | i);

	/* Output Opcode ('01' for write or '10' for read) */
	for (i=1; i>=0; i--)
		clkmdio(mgmt_val | MDOE | ((opcode >>i) & 0x01));

	/* Output Phy address, MSB first */
	for (i=4; i>=0; i--)
		clkmdio(mgmt_val | MDOE | ((phy_addr >>i) & 0x01));

	/* Output Register address, MSB first */
	for (i=4; i>=0; i--)
		clkmdio(mgmt_val | MDOE | ((reg_addr >>i) & 0x01));

	if (opcode == OPRead) {
#if defined(LAN91C111)
		/* MDOE <- Hi-Z */
		outw(SMC_LAN_BASEADDR + MGMT_REG_W, mgmt_val);

		/* Turnaround */
		for (i=1; i>=0; i--)
			clkmdio(mgmt_val);
#else
		/* Turnaround */
		clkmdio(mgmt_val);

		/* Comment out for NS PHY (Bug),Leave for other PHY */
		/* clkmdio(mgmt_val | MDOE); */
#endif
		/* Read Data, MSB first */
		wdata = 0;

		for (i=15; i>=0; i--) {
#if !defined(LAN91C111)
			clkmdio(mgmt_val);
#endif
			wdata |= (((inw(SMC_LAN_BASEADDR + MGMT_REG_W) & MDI) >> 1) << i);
#if defined(LAN91C111)
			clkmdio(mgmt_val);
#endif
		}
	}
	else {
		/* Turnaround */
		for (i=1; i>=0; i--)
			clkmdio(mgmt_val | MDOE | ((2>>i) & 0x01));

		/* Write Data, MSB first */
		for (i=15; i>=0; i--)
			clkmdio(mgmt_val | MDOE | ((wdata>>i) & 0x01));

		wdata = 1;
	}
	return(wdata);
}

void clkmdio(unsigned short mngdata) /* use for BANK3 */
{
	outw(SMC_LAN_BASEADDR + MGMT_REG_W, mngdata);
	outw(SMC_LAN_BASEADDR + MGMT_REG_W, mngdata | MCLK);
#if defined(LAN91C111)
	outw(SMC_LAN_BASEADDR + MGMT_REG_W, mngdata);
#endif
}

/* EOF */

⌨️ 快捷键说明

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