📄 smc91111.c
字号:
static void smc_set_multicast_list(struct net_device *dev)
{
short ioaddr = dev->base_addr;
PRINTK2("%s:smc_set_multicast_list\n", dev->name);
SMC_SELECT_BANK(0);
if ( dev->flags & IFF_PROMISC )
{
PRINTK2("%s:smc_set_multicast_list:RCR_PRMS\n", dev->name);
outw( inw(ioaddr + RCR_REG ) | RCR_PRMS, ioaddr + RCR_REG );
}
/* BUG? I never disable promiscuous mode if multicasting was turned on.
Now, I turn off promiscuous mode, but I don't do anything to multicasting
when promiscuous mode is turned on.
*/
/* Here, I am setting this to accept all multicast packets.
I don't need to zero the multicast table, because the flag is
checked before the table is
*/
else if (dev->flags & IFF_ALLMULTI)
{
outw( inw(ioaddr + RCR_REG ) | RCR_ALMUL, ioaddr + RCR_REG );
PRINTK2("%s:smc_set_multicast_list:RCR_ALMUL\n", dev->name);
}
/* We just get all multicast packets even if we only want them
. from one source. This will be changed at some future
. point. */
else if (dev->mc_count ) {
/* support hardware multicasting */
/* be sure I get rid of flags I might have set */
outw( inw( ioaddr + RCR_REG ) & ~(RCR_PRMS | RCR_ALMUL),
ioaddr + RCR_REG );
/* NOTE: this has to set the bank, so make sure it is the
last thing called. The bank is set to zero at the top */
smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list );
} else {
PRINTK2("%s:smc_set_multicast_list:~(RCR_PRMS|RCR_ALMUL)\n",
dev->name);
outw( inw( ioaddr + RCR_REG ) & ~(RCR_PRMS | RCR_ALMUL),
ioaddr + RCR_REG );
/*
since I'm disabling all multicast entirely, I need to
clear the multicast list
*/
SMC_SELECT_BANK( 3 );
outw( 0, ioaddr + MCAST_REG1 );
outw( 0, ioaddr + MCAST_REG2 );
outw( 0, ioaddr + MCAST_REG3 );
outw( 0, ioaddr + MCAST_REG4 );
}
}
#ifdef MODULE
static struct net_device devSMC91111;
int io = 0;
int irq = 0;
int nowait = 0;
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(nowait, "i");
/*------------------------------------------------------------
. Module initialization function
.-------------------------------------------------------------*/
int init_module(void)
{
int result;
PRINTK2("CARDNAME:init_module\n");
if (io == 0)
printk(KERN_WARNING
CARDNAME": You shouldn't use auto-probing with insmod!\n" );
/* copy the parameters from insmod into the device structure */
devSMC91111.base_addr = io;
devSMC91111.irq = irq;
devSMC91111.dma = nowait; // Use DMA field for nowait
devSMC91111.init = smc_init;/* Kernel 2.4 Changes - Pramod */
if ((result = register_netdev(&devSMC91111)) != 0)
return result;
return 0;
}
/*------------------------------------------------------------
. Cleanup when module is removed with rmmod
.-------------------------------------------------------------*/
void cleanup_module(void)
{
/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
unregister_netdev(&devSMC91111);
free_irq(devSMC91111.irq, &devSMC91111);
release_region(devSMC91111.base_addr, SMC_IO_EXTENT);
if (devSMC91111.priv)
kfree(devSMC91111.priv); /* Kernel 2.4 Changes - Pramod */
}
#endif /* MODULE */
#ifdef CONFIG_SYSCTL
/*------------------------------------------------------------
. Modify a bit in the LAN91C111 register set
.-------------------------------------------------------------*/
static word smc_modify_regbit(int bank, int ioaddr, int reg,
unsigned int bit, int val)
{
word regval;
SMC_SELECT_BANK( bank );
regval = inw( ioaddr+reg );
if (val)
regval |= bit;
else
regval &= ~bit;
outw( regval, ioaddr );
return(regval);
}
/*------------------------------------------------------------
. Retrieve a bit in the LAN91C111 register set
.-------------------------------------------------------------*/
static int smc_get_regbit(int bank, int ioaddr, int reg, unsigned int bit)
{
SMC_SELECT_BANK( bank );
if ( inw( ioaddr+reg ) & bit)
return(1);
else
return(0);
}
/*------------------------------------------------------------
. Modify a LAN91C111 register (word access only)
.-------------------------------------------------------------*/
static void smc_modify_reg(int bank, int ioaddr, int reg, word val)
{
SMC_SELECT_BANK( bank );
outw( val, ioaddr+reg );
}
/*------------------------------------------------------------
. Retrieve a LAN91C111 register (word access only)
.-------------------------------------------------------------*/
static int smc_get_reg(int bank, int ioaddr, int reg)
{
SMC_SELECT_BANK( bank );
return(inw( ioaddr+reg ));
}
static const char smc_info_string[] =
"\n"
"info Provides this information blurb\n"
"swver Prints the software version information of this driver\n"
"autoneg Auto-negotiate Mode = 1\n"
"rspeed Requested Speed, 100=100Mbps, 10=10Mpbs\n"
"rfduplx Requested Full Duplex Operation\n"
"aspeed Actual Speed, 100=100Mbps, 10=10Mpbs\n"
"afduplx Actual Full Duplex Operation\n"
"lnkfail PHY Link Failure when 1\n"
"miiop External MII when 1, Internal PHY when 0\n"
"swfdup Switched Full Duplex Mode (allowed only in MII operation)\n"
"ephloop EPH Block Loopback\n"
"forcol Force a collision\n"
"filtcar Filter leading edge of carrier sense for 12 bit times\n"
"freemem Free buffer memory in bytes\n"
"totmem Total buffer memory in bytes\n"
"leda Output of LED-A (green)\n"
"ledb Output of LED-B (yellow)\n"
"chiprev Revision ID of the LAN91C111 chip\n"
"";
/*------------------------------------------------------------
. Sysctl handler for all integer parameters
.-------------------------------------------------------------*/
static int smc_sysctl_handler(ctl_table *ctl, int write, struct file * filp,
void *buffer, size_t *lenp)
{
struct net_device *dev = (struct net_device*)ctl->extra1;
struct smc_local *lp = (struct smc_local *)ctl->extra2;
int ioaddr = dev->base_addr;
int *valp = ctl->data;
int val;
int ret;
// Update parameters from the real registers
switch (ctl->ctl_name)
{
case CTL_SMC_FORCOL:
*valp = smc_get_regbit(0, ioaddr, TCR_REG, TCR_FORCOL);
break;
case CTL_SMC_FREEMEM:
*valp = ( (word)smc_get_reg(0, ioaddr, MIR_REG) >> 8 )
* LAN91C111_MEMORY_MULTIPLIER;
break;
case CTL_SMC_TOTMEM:
*valp = ( smc_get_reg(0, ioaddr, MIR_REG) & (word)0x00ff )
* LAN91C111_MEMORY_MULTIPLIER;
break;
case CTL_SMC_CHIPREV:
*valp = smc_get_reg(3, ioaddr, REV_REG);
break;
case CTL_SMC_AFDUPLX:
*valp = (lp->lastPhy18 & PHY_INT_DPLXDET) ? 1 : 0;
break;
case CTL_SMC_ASPEED:
*valp = (lp->lastPhy18 & PHY_INT_SPDDET) ? 100 : 10;
break;
case CTL_SMC_LNKFAIL:
*valp = (lp->lastPhy18 & PHY_INT_LNKFAIL) ? 1 : 0;
break;
case CTL_SMC_LEDA:
*valp = (lp->rpc_cur_mode >> RPC_LSXA_SHFT) & (word)0x0007;
break;
case CTL_SMC_LEDB:
*valp = (lp->rpc_cur_mode >> RPC_LSXB_SHFT) & (word)0x0007;
break;
case CTL_SMC_MIIOP:
*valp = smc_get_regbit(1, ioaddr, CONFIG_REG, CONFIG_EXT_PHY);
break;
#ifdef SMC_DEBUG
case CTL_SMC_REG_BSR: // Bank Select
*valp = smc_get_reg(0, ioaddr, BSR_REG);
break;
case CTL_SMC_REG_TCR: // Transmit Control
*valp = smc_get_reg(0, ioaddr, TCR_REG);
break;
case CTL_SMC_REG_ESR: // EPH Status
*valp = smc_get_reg(0, ioaddr, EPH_STATUS_REG);
break;
case CTL_SMC_REG_RCR: // Receive Control
*valp = smc_get_reg(0, ioaddr, RCR_REG);
break;
case CTL_SMC_REG_CTRR: // Counter
*valp = smc_get_reg(0, ioaddr, COUNTER_REG);
break;
case CTL_SMC_REG_MIR: // Memory Information
*valp = smc_get_reg(0, ioaddr, MIR_REG);
break;
case CTL_SMC_REG_RPCR: // Receive/Phy Control
*valp = smc_get_reg(0, ioaddr, RPC_REG);
break;
case CTL_SMC_REG_CFGR: // Configuration
*valp = smc_get_reg(1, ioaddr, CONFIG_REG);
break;
case CTL_SMC_REG_BAR: // Base Address
*valp = smc_get_reg(1, ioaddr, BASE_REG);
break;
case CTL_SMC_REG_IAR0: // Individual Address
*valp = smc_get_reg(1, ioaddr, ADDR0_REG);
break;
case CTL_SMC_REG_IAR1: // Individual Address
*valp = smc_get_reg(1, ioaddr, ADDR1_REG);
break;
case CTL_SMC_REG_IAR2: // Individual Address
*valp = smc_get_reg(1, ioaddr, ADDR2_REG);
break;
case CTL_SMC_REG_GPR: // General Purpose
*valp = smc_get_reg(1, ioaddr, GP_REG);
break;
case CTL_SMC_REG_CTLR: // Control
*valp = smc_get_reg(1, ioaddr, CTL_REG);
break;
case CTL_SMC_REG_MCR: // MMU Command
*valp = smc_get_reg(2, ioaddr, MMU_CMD_REG);
break;
case CTL_SMC_REG_PNR: // Packet Number
*valp = smc_get_reg(2, ioaddr, PN_REG);
break;
case CTL_SMC_REG_FPR: // Allocation Result/FIFO Ports
*valp = smc_get_reg(2, ioaddr, RXFIFO_REG);
break;
case CTL_SMC_REG_PTR: // Pointer
*valp = smc_get_reg(2, ioaddr, PTR_REG);
break;
case CTL_SMC_REG_DR: // Data
*valp = smc_get_reg(2, ioaddr, DATA_REG);
break;
case CTL_SMC_REG_ISR: // Interrupt Status/Mask
*valp = smc_get_reg(2, ioaddr, INT_REG);
break;
case CTL_SMC_REG_MTR1: // Multicast Table Entry 1
*valp = smc_get_reg(3, ioaddr, MCAST_REG1);
break;
case CTL_SMC_REG_MTR2: // Multicast Table Entry 2
*valp = smc_get_reg(3, ioaddr, MCAST_REG2);
break;
case CTL_SMC_REG_MTR3: // Multicast Table Entry 3
*valp = smc_get_reg(3, ioaddr, MCAST_REG3);
break;
case CTL_SMC_REG_MTR4: // Multicast Table Entry 4
*valp = smc_get_reg(3, ioaddr, MCAST_REG4);
break;
case CTL_SMC_REG_MIIR: // Management Interface
*valp = smc_get_reg(3, ioaddr, MII_REG);
break;
case CTL_SMC_REG_REVR: // Revision
*valp = smc_get_reg(3, ioaddr, REV_REG);
break;
case CTL_SMC_REG_ERCVR: // Early RCV
*valp = smc_get_reg(3, ioaddr, ERCV_REG);
break;
case CTL_SMC_REG_EXTR: // External
*valp = smc_get_reg(7, ioaddr, EXT_REG);
break;
case CTL_SMC_PHY_CTRL:
*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
PHY_CNTL_REG);
break;
case CTL_SMC_PHY_STAT:
*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
PHY_STAT_REG);
break;
case CTL_SMC_PHY_ID1:
*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
PHY_ID1_REG);
break;
case CTL_SMC_PHY_ID2:
*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
PHY_ID2_REG);
break;
case CTL_SMC_PHY_ADC:
*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
PHY_AD_REG);
break;
case CTL_SMC_PHY_REMC:
*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
PHY_RMT_REG);
break;
case CTL_SMC_PHY_CFG1:
*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
PHY_CFG1_REG);
break;
case CTL_SMC_PHY_CFG2:
*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
PHY_CFG2_REG);
break;
case CTL_SMC_PHY_INT:
*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
PHY_INT_REG);
break;
case CTL_SMC_PHY_MASK:
*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
PHY_MASK_REG);
break;
#endif // SMC_DEBUG
default:
// Just ignore unsupported parameters
break;
}
// Save old state
val = *valp;
// Perform the generic integer operation
if ((ret = proc_dointvec(ctl, write, filp, buffer, lenp)) != 0)
return(ret);
// Write changes out to the registers
if (write && *valp != val) {
val = *valp;
switch (ctl->ctl_name) {
case CTL_SMC_SWFDUP:
if (val)
lp->tcr_cur_mode |= TCR_SWFDUP;
else
lp->tcr_cur_mode &= ~TCR_SWFDUP;
smc_modify_regbit(0, ioaddr, TCR_REG, TCR_SWFDUP, val);
break;
case CTL_SMC_EPHLOOP:
if (val)
lp->tcr_cur_mode |= TCR_EPH_LOOP;
else
lp->tcr_cur_mode &= ~TCR_EPH_LOOP;
smc_modify_regbit(0, ioaddr, TCR_REG, TCR_EPH_LOOP, val);
break;
case CTL_SMC_FORCOL:
if (val)
lp->tcr_cur_mode |= TCR_FORCOL;
else
lp->tcr_cur_mode &= ~TCR_FORCOL;
// Update the EPH block
smc_modify_regbit(0, ioaddr, TCR_REG, TCR_FORCOL, val);
break;
case CTL_SMC_FILTCAR:
if (val)
lp->rcr_cur_mode |= RCR_FILT_CAR;
else
lp->rcr_cur_mode &= ~RCR_FILT_CAR;
// Update the EPH block
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -