📄 dm9000x.c
字号:
/* Save previous register address */
reg_save = inb(db->ioaddr);
/* TX timeout check */
if (dev->trans_start&&((jiffies-dev->trans_start)>DMFE_TX_TIMEOUT)) {
//printk("TX timeout reset.\n");
db->device_wait_reset = 1;
db->reset_tx_timeout++;
}
/* DM9000 dynamic RESET check and do */
if (db->device_wait_reset) {
netif_stop_queue(dev);
db->reset_counter++;
db->device_wait_reset = 0;
dev->trans_start = 0;
dmfe_init_dm9000(dev);
netif_wake_queue(dev);
}
/* Auto Sense Media mode policy:
FastEthernet NIC: don't need to do anything.
Media Force mode: don't need to do anything.
HomeRun/LongRun NIC and AUTO_Mode:
INT_MII not link, select EXT_MII
EXT_MII not link, select INT_MII
*/
if ((db->nic_type != FASTETHER_NIC) & (db->op_mode == DM9000_AUTO))
{
tmp_reg = ior(db, 0x01); /* Got link status */
if ( !(tmp_reg & 0x40) ) { /* not link */
db->reg0 ^= 0x80;
iow(db, 0x00, db->reg0);
//printk(KERN_ERR "not link\n");
}
}
/* Restore previous register address */
outb(reg_save, db->ioaddr);
/* Set timer again */
db->timer.expires = DMFE_TIMER_WUT;
add_timer(&db->timer);
}
#if defined(AUTOMDIX)
static void dmfe_mdix_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
board_info_t *db = (board_info_t *)dev->priv;
/* support AUTO-MDIX */
db->mdix = ior(db, DM9000_GPR);
db->link_status = ior(db, DM9000_NSR);
db->link_status = test_bit(6, &db->link_status);
udelay(2000);
if (!db->link_status)
{
switch(db->mdix)
{
case 0x7c: //use parallel line change to cross line
if(netif_carrier_ok(dev))
netif_carrier_off(dev);
iow(db, DM9000_GPCR, 0x03);
iow(db, DM9000_GPR, 0x02);
break;
case 0x7e: // use cross line change to parallel line
if(netif_carrier_ok(dev))
netif_carrier_off(dev);
iow(db, DM9000_GPCR, 0x03);
iow(db, DM9000_GPR, 0x00);
break;
default:
break;
}
}
else{
if (!netif_carrier_ok(dev))
netif_carrier_on(dev);
}
/* Set timer again */
db->mdix_timer.expires = DMFE_TIMER_MDIX;
add_timer(&db->mdix_timer);
}
#endif
/*
Received a packet and pass to upper layer
*/
static void dmfe_packet_receive(unsigned long unused)
{
struct net_device *dev = dmfe_dev;
board_info_t *db = (board_info_t *)dev->priv;
struct sk_buff *skb;
u8 rxbyte, *rdptr;
u16 i, RxStatus, RxLen, GoodPacket, tmplen;
//#ifndef EMU32
u32 tmpdata;
//#endif
DMFE_DBUG(0, "dmfe_packet_receive()", 0);
/* Check packet ready or not */
do {
ior(db, 0xf0); /* Dummy read */
rxbyte = inb(db->io_data); /* Got most updated data */
/* packet ready to receive check */
if (rxbyte == DM9000_PKT_RDY)
{
/* A packet ready now & Get status/length */
GoodPacket = TRUE;
outb(0xf2, db->ioaddr);
/* Selecting io mode */
RxStatus = (u16)0;
RxLen = (u16)0;
/* modify Select io mode by jackal 10/28/2003 */
switch (db->io_mode)
{
case DM9000_BYTE_MODE:
RxStatus = inb(db->io_data) +
(inb(db->io_data) << 8);
RxLen = inb(db->io_data) +
(inb(db->io_data) << 8);
break;
case DM9000_WORD_MODE:
RxStatus = inw(db->io_data);
RxLen = inw(db->io_data);
break;
case DM9000_DWORD_MODE:
//#if defined(EMU32)
// // Emulate 32bits mode on ISA of pc
// RxStatus = inw(db->io_data);
// RxLen = inw(0x320);
//#else
tmpdata = inl(db->io_data);
RxStatus = tmpdata;
RxLen = tmpdata >> 16;
//#endif
break;
default:
break;
}
/* Packet Status check */
if (RxLen < 0x40)
{
GoodPacket = FALSE;
db->runt_length_counter++;
} else if (RxLen > DM9000_PKT_MAX)
{
printk("<DM9000> RST: RX Len:%x\n", RxLen);
db->device_wait_reset = TRUE;
db->long_length_counter++;
}
if (RxStatus & 0xbf00)
{
GoodPacket = FALSE;
if (RxStatus & 0x100)
db->stats.rx_fifo_errors++;
if (RxStatus & 0x200)
db->stats.rx_crc_errors++;
if (RxStatus & 0x8000)
db->stats.rx_length_errors++;
}
/* Move data from DM9000 */
if (!db->device_wait_reset) {
if ( GoodPacket && ((skb = dev_alloc_skb(RxLen + 4)) != NULL ) ) {
skb->dev = dev;
skb_reserve(skb, 2);
rdptr = (u8 *) skb_put(skb, RxLen-4);
/* Read received packet from RX SARM */
if (db->io_mode == DM9000_BYTE_MODE) {
/* Byte mode */
for (i=0; i<RxLen; i++)
rdptr[i]=inb(db->io_data);
} else if (db->io_mode == DM9000_WORD_MODE) {
/* Word mode */
tmplen = (RxLen + 1) / 2;
for (i = 0; i < tmplen; i++)
((u16 *)rdptr)[i] = inw(db->io_data);
} else {
/* DWord mode */
//#if defined(EMU32)
// //Emulate 32bits mode on ISA of PC
// tmplen = (RxLen + 3) / 4;
// for (i = 0; i < tmplen; i++)
// {
// ((u16 *)rdptr)[i*2] = inw(db->io_data);
// ((u16 *)rdptr)[i*2+1] = inw(0x320);
// }
//#else
tmplen = (RxLen + 3) / 4;
for (i = 0; i < tmplen; i++)
((u32 *)rdptr)[i] = inl(db->io_data);
//#endif
}
/* Pass to upper layer */
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
db->stats.rx_packets++;
} else {
/* Without buffer or error packet */
if (db->io_mode == DM9000_BYTE_MODE) {
/* Byte mode */
for (i = 0; i < RxLen; i++)
inb(db->io_data);
} else if (db->io_mode == DM9000_WORD_MODE) {
/* Word mode */
tmplen = (RxLen + 1) / 2;
for (i = 0; i < tmplen; i++)
inw(db->io_data);
} else {
/* DWord mode */
//#if defined(EMU32)
// //Emulate 32 bits mode on ISA of PC
// tmplen = (RxLen + 3) / 4;
// for (i = 0; i < tmplen; i++)
// {
// inw(db->io_data);
// inw(0x320);
// }
//#else
tmplen = (RxLen + 3) / 4;
for (i = 0; i < tmplen; i++)
inl(db->io_data);
//#endif
}
}
}
}
/* Status check: this byte must be 0 or 1 */
else if (rxbyte > DM9000_PKT_RDY) {
// printk("RX SRAM 1st byte != 01, must reset.\n");
iow(db, 0x05, 0x00); /* Stop Device */
iow(db, 0xfe, 0x80); /* Stop INT request */
db->device_wait_reset = TRUE;
db->reset_rx_status++;
}
}while(rxbyte == DM9000_PKT_RDY && !db->device_wait_reset);
}
/*
Read a word data from SROM
*/
static u16 read_srom_word(board_info_t *db, int offset)
{
iow(db, 0xc, offset);
iow(db, 0xb, 0x4);
udelay(200);
iow(db, 0xb, 0x0);
return (ior(db, 0xd) + (ior(db, 0xe) << 8) );
}
/*
Set DM9000 multicast address
*/
static void dm9000_hash_table(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
struct dev_mc_list *mcptr = dev->mc_list;
int mc_cnt = dev->mc_count;
u32 hash_val;
u16 i, oft, hash_table[4];
DMFE_DBUG(0, "dm9000_hash_table()", 0);
/* Set Node address */
for (i = 0, oft = 0x10; i < 6; i++, oft++)
iow(db, oft, dev->dev_addr[i]);
/* Clear Hash Table */
for (i = 0; i < 4; i++)
hash_table[i] = 0x0;
/* broadcast address */
hash_table[3] = 0x8000;
/* the multicast address in Hash Table : 64 bits */
for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
hash_val = cal_CRC((char *)mcptr->dmi_addr, 6, 0) & 0x3f;
hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
}
/* Write the hash table to MAC MD table */
for (i = 0, oft = 0x16; i < 4; i++) {
iow(db, oft++, hash_table[i] & 0xff);
iow(db, oft++, (hash_table[i] >> 8) & 0xff);
}
}
/*
Calculate the CRC valude of the Rx packet
flag = 1 : return the reverse CRC (for the received packet CRC)
0 : return the normal CRC (for Hash Table index)
*/
static unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
{
u32 crc = ether_crc_le(Len, Data);
if (flag)
return ~crc;
return crc;
}
/*
Read a byte from I/O port
*/
static u8 ior(board_info_t *db, int reg)
{
outb(reg, db->ioaddr);
return inb(db->io_data);
}
/*
Write a byte to I/O port
*/
static void iow(board_info_t *db, int reg, u8 value)
{
outb(reg, db->ioaddr);
outb(value, db->io_data);
}
/*
Read a word from phyxcer
*/
static u16 phy_read(board_info_t *db, int reg)
{
/* Fill the phyxcer register into REG_0C */
iow(db, 0xc, DM9000_PHY | reg);
iow(db, 0xb, 0xc); /* Issue phyxcer read command */
udelay(100); /* Wait read complete */
iow(db, 0xb, 0x0); /* Clear phyxcer read command */
/* The read data keeps on REG_0D & REG_0E */
return ( ior(db, 0xe) << 8 ) | ior(db, 0xd);
}
/*
Write a word to phyxcer
*/
static void phy_write(board_info_t *db, int reg, u16 value)
{
/* Fill the phyxcer register into REG_0C */
iow(db, 0xc, DM9000_PHY | reg);
/* Fill the written data into REG_0D & REG_0E */
iow(db, 0xd, (value & 0xff));
iow(db, 0xe, ( (value >> 8) & 0xff));
iow(db, 0xb, 0xa); /* Issue phyxcer write command */
udelay(500); /* Wait write complete */
iow(db, 0xb, 0x0); /* Clear phyxcer write command */
}
#ifdef MODULE
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
MODULE_DESCRIPTION("Davicom DM9000 ISA/uP Fast Ethernet Driver");
MODULE_PARM(debug, "i");
MODULE_PARM(mode, "i");
MODULE_PARM(reg5, "i");
MODULE_PARM(reg9, "i");
MODULE_PARM(rega, "i");
MODULE_PARM(nfloor, "i");
//MODULE_PARM(SF_mode, "i");
/* Description:
when user used insmod to add module, system invoked init_module()
to initilize and register.
*/
int init_module(void)
{
DMFE_DBUG(0, "init_module() ", debug);
if (debug)
dmfe_debug = debug; /* set debug flag */
switch(mode) {
case DM9000_10MHD:
case DM9000_100MHD:
case DM9000_10MFD:
case DM9000_100MFD:
case DM9000_1M_HPNA:
media_mode = mode;
break;
default:
media_mode = DM9000_AUTO;
}
#if 0
/* added by jackal for SF_mode */
switch(SF_mode)
{
case VLAN_Enable:
case FlowControl:
case TxPausePacket:
sf_mode = SF_mode;
break;
default:
sf_mode = 0;
break;
}
#endif
nfloor = (nfloor > 15) ? 0:nfloor;
return dmfe_probe(0); /* search board and register */
}
/* Description:
when user used rmmod to delete module, system invoked clean_module()
to un-register DEVICE.
*/
void cleanup_module(void)
{
board_info_t * db;
DMFE_DBUG(0, "clean_module()", 0);
unregister_netdev(dmfe_dev);
db = (board_info_t *)dmfe_dev->priv;
release_region(dmfe_dev->base_addr, 2);
kfree(db); /* free board information */
kfree(dmfe_dev); /* free device structure */
DMFE_DBUG(0, "clean_module() exit", 0);
}
#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -