📄 if_snnew.c
字号:
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 + -