📄 ethernet driver for linux.txt
字号:
static void allocate_rx_buffer(struct dmfe_board_info *db)
{
struct rx_desc *rxptr;
struct sk_buff *skb;
rxptr = db->rx_insert_ptr;
while(db->rx_avail_cnt < RX_DESC_CNT) {
if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL )
break;
rxptr->rx_skb_ptr = skb; /* FIXME (?) */
rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
wmb();
rxptr->rdes0 = cpu_to_le32(0x80000000);
rxptr = rxptr->next_rx_desc;
db->rx_avail_cnt++;
}
db->rx_insert_ptr = rxptr;
}
/*
* Read one word data from the serial ROM
*/
static u16 read_srom_word(long ioaddr, int offset)
{
int i;
u16 srom_data = 0;
long cr9_ioaddr = ioaddr + DCR9;
outl(CR9_SROM_READ, cr9_ioaddr);
outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
/* Send the Read Command 110b */
SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
SROM_CLK_WRITE(SROM_DATA_0, cr9_ioaddr);
/* Send the offset */
for (i = 5; i >= 0; i--) {
srom_data = (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0;
SROM_CLK_WRITE(srom_data, cr9_ioaddr);
}
outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
for (i = 16; i > 0; i--) {
outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr);
udelay(5);
srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0);
outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
udelay(5);
}
outl(CR9_SROM_READ, cr9_ioaddr);
return srom_data;
}
/*
* Auto sense the media mode
*/
static u8 dmfe_sense_speed(struct dmfe_board_info * db)
{
u8 ErrFlag = 0;
u16 phy_mode0,phy_mode1,phy_mode25;
phy_mode0 = phy_read(db->ioaddr, db->phy_addr, 0, db->chip_id);
phy_mode1 = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
phy_mode25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
if ( (phy_mode0 & 0x1000)&& (phy_mode1&0x0020)) {
switch ((phy_mode25&3)|(phy_mode0&0x100)) {
case 0x002: db->op_mode = DMFE_10MHF; break;
case 0x102: db->op_mode = DMFE_10MFD; break;
case 0x001: db->op_mode = DMFE_100MHF; break;
case 0x101: db->op_mode = DMFE_100MFD; break;
default: db->op_mode = DMFE_100MHF;
ErrFlag = 1;
break;
}
} else {
db->op_mode = DMFE_100MHF;
ErrFlag = 1;
}
return ErrFlag;
}
/*
* Set 10/100 phyxcer capability
* AUTO mode : phyxcer register4 is NIC capability
* Force mode: phyxcer register4 is the force media
*/
static void dmfe_set_phyxcer(struct dmfe_board_info *db)
{
u16 phy_reg;
// printk("retart auto negotiation, tester is ljq\n");//add by ljq
/* restart auto negotion */
phy_reg = phy_read(db->ioaddr, db->phy_addr, 0, db->chip_id);
// printk("the phy_reg is %x\n",phy_reg);//add by ljq
// udelay(10000);//add by ljq
phy_write(db->ioaddr, db->phy_addr, 0, 0x200|phy_reg, db->chip_id);
/* Phyxcer capability setting */
do {
phy_reg = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
} while (phy_reg & 0x20 == 0);
// printk("the tester is ljq, display the value of phy_reg\n");//add by ljq
printk("auto negation status %x\n", phy_reg);
// printk("the tester is ljq, display the value of phy_reg\n");//add by ljq
// phy_reg = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);//add by ljq
// printk("the 1 register status is %x\n", phy_reg);//add by ljq
phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id);
printk("auto negation offset 4=%x\n", phy_reg);
// phy_write(db->ioaddr, db->phy_addr, 4 , 0x0000, db->chip_id);//add by ljq
// printk("the tester is ljq, display the value of phy_reg\n");//add by ljq
// phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id);//add by ljq
// printk("the register 4 after chang the value is %x\n",phy_reg);//add by ljq
phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
if (db->media_mode & DMFE_AUTO) {
/* AUTO Mode */
phy_reg |= db->PHY_reg4;
} else {
/* Force Mode */
switch(db->media_mode) {
case DMFE_10MHF: phy_reg |= 0x20; break;
case DMFE_10MFD: phy_reg |= 0x40; break;
case DMFE_100MHF: phy_reg |= 0x80; break;
case DMFE_100MFD: phy_reg |= 0x100; break;
}
}
/* Write new capability to Phyxcer Reg4 */
if ( !(phy_reg & 0x01e0)) {
phy_reg|=db->PHY_reg4;
db->media_mode|=DMFE_AUTO;
}
phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
/* Restart Auto-Negotiation */
if ( !db->chip_type )
phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
}
/*
* Process op-mode
* AUTO mode : PHY controller in Auto-negotiation Mode
* Force mode: PHY controller in force mode with HUB
* N-way force capability with SWITCH
*/
static void dmfe_process_mode(struct dmfe_board_info *db)
{
u16 phy_reg;
/* Full Duplex Mode Check */
if (db->op_mode & 0x4)
db->cr6_data |= CR6_FDM; /* Set Full Duplex Bit */
else
db->cr6_data &= ~CR6_FDM; /* Clear Full Duplex Bit */
update_cr6(db->cr6_data, db->ioaddr);
}
/*
* Write a word to Phy register
*/
static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id)
{
u16 i;
unsigned long ioaddr;
if (chip_id == PCI_DM9132_ID) {
ioaddr = iobase + 0x80 + offset * 4;
outw(phy_data, ioaddr);
} else {
/* DM9102/DM9102A Chip */
ioaddr = iobase + DCR9;
/* Send 33 synchronization clock to Phy controller */
for (i = 0; i < 35; i++)
phy_write_1bit(ioaddr, PHY_DATA_1);
/* Send start command(01) to Phy */
phy_write_1bit(ioaddr, PHY_DATA_0);
phy_write_1bit(ioaddr, PHY_DATA_1);
/* Send write command(01) to Phy */
phy_write_1bit(ioaddr, PHY_DATA_0);
phy_write_1bit(ioaddr, PHY_DATA_1);
/* Send Phy addres */
for (i = 0x10; i > 0; i = i >> 1)
phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
/* Send register addres */
for (i = 0x10; i > 0; i = i >> 1)
phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
/* written trasnition */
phy_write_1bit(ioaddr, PHY_DATA_1);
phy_write_1bit(ioaddr, PHY_DATA_0);
/* Write a word data to PHY controller */
for ( i = 0x8000; i > 0; i >>= 1)
phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
}
}
/*
* Read a word data from phy register
*/
static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id)
{
int i;
u16 phy_data;
unsigned long ioaddr;
if (chip_id == PCI_DM9132_ID) {
/* DM9132 Chip */
ioaddr = iobase + 0x80 + offset * 4;
phy_data = inw(ioaddr);
} else {
/* DM9102/DM9102A Chip */
ioaddr = iobase + DCR9;
/* Send 33 synchronization clock to Phy controller */
for (i = 0; i < 35; i++)
phy_write_1bit(ioaddr, PHY_DATA_1);
/* Send start command(01) to Phy */
phy_write_1bit(ioaddr, PHY_DATA_0);
phy_write_1bit(ioaddr, PHY_DATA_1);
/* Send read command(10) to Phy */
phy_write_1bit(ioaddr, PHY_DATA_1);
phy_write_1bit(ioaddr, PHY_DATA_0);
/* Send Phy addres */
for (i = 0x10; i > 0; i = i >> 1)
phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
/* Send register addres */
for (i = 0x10; i > 0; i = i >> 1)
phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
/* Skip transition state */
phy_read_1bit(ioaddr);
/* read 16bit data */
for (phy_data = 0, i = 0; i < 16; i++) {
phy_data <<= 1;
phy_data |= phy_read_1bit(ioaddr);
}
}
return phy_data;
}
/*
* Write one bit data to Phy Controller
*/
static void phy_write_1bit(unsigned long ioaddr, u32 phy_data)
{
// int i;//add by ljq
phy_data |=1<<18;
outl(phy_data, ioaddr); /* MII Clock Low */
inl(ioaddr);
udelay(1);
// for (i=1; i>0; i--);//add by ljq
outl(phy_data | MDCLKH, ioaddr); /* MII Clock High */
inl(ioaddr);
udelay(1);
// for (i=1; i>0; i--);//add by ljq
outl(phy_data, ioaddr); /* MII Clock Low */
inl(ioaddr);
udelay(1);
// for (i=1; i>0; i--); //add by ljq
}
/*
* Read one bit phy data from PHY controller
*/
static u16 phy_read_1bit(unsigned long ioaddr)
{
u16 phy_data;
//outl(0x50000, ioaddr);
outl(0x10000, ioaddr);
inl(ioaddr);
udelay(1);
phy_data = ( inl(ioaddr) >> 19 ) & 0x1;
//outl(0x40000, ioaddr);
outl(0x00000, ioaddr);
inl(ioaddr);
udelay(1);
return phy_data;
}
/*
* 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)
*/
unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
{
unsigned long Crc = 0xffffffff;
while (Len--) {
Crc = CrcTable[(Crc ^ *Data++) & 0xFF] ^ (Crc >> 8);
}
if (flag)
return ~Crc;
else
return Crc;
}
static int gc_dmfe_info_read (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len =0;
struct dmfe_board_info *db = (struct dmfe_board_info *)data;
struct tx_desc *tmp_tx;
struct rx_desc *tmp_rx;
unsigned long ioaddr = db->ioaddr;
int i;
len +=sprintf(page+len, "CSR0: %x\n", inl(ioaddr+DCR0));
len +=sprintf(page+len, "CSR1: %x\n", inl(ioaddr+DCR1));
len +=sprintf(page+len, "CSR2: %x\n", inl(ioaddr+DCR2));
len +=sprintf(page+len, "CSR3: %x\n", inl(ioaddr+DCR3));
len +=sprintf(page+len, "CSR4: %x\n", inl(ioaddr+DCR4));
len +=sprintf(page+len, "CSR5: %x\n", inl(ioaddr+DCR5));
len +=sprintf(page+len, "CSR6: %x\n", inl(ioaddr+DCR6));
len +=sprintf(page+len, "CSR7: %x\n", inl(ioaddr+DCR7));
len += sprintf(page+len, "Tx descriptores:\n");
for (tmp_tx = db->first_tx_desc, i = 0; i < TX_DESC_CNT; i++, tmp_tx++) {
len += sprintf(page+len, "Tx %d:\n", i);
len += sprintf(page+len, "\ttdes0 %08x\n",tmp_tx->tdes0);
len += sprintf(page+len, "\ttdes1 %08x\n",tmp_tx->tdes1);
len += sprintf(page+len, "\ttdes2 %08x\n",tmp_tx->tdes2);
len += sprintf(page+len, "\ttdes3 %08x\n",tmp_tx->tdes3);
}
len += sprintf(page+len, "Rx descriptores\n");
for(tmp_rx =db->first_rx_desc, i=0; i<RX_DESC_CNT; i++, tmp_rx++){
len += sprintf(page+len, "Rx %d:\n", i);
len += sprintf(page+len, "\trdes0 %08x\n", tmp_rx->rdes0);
len += sprintf(page+len, "\trdes1 %08x\n", tmp_rx->rdes1);
len += sprintf(page+len, "\trdes2 %08x\n", tmp_rx->rdes2);
len += sprintf(page+len, "\trdes3 %08x\n", tmp_rx->rdes3);
}
len += sprintf(page+len, "phy addr:\n");
for(i=0;i<32;i++)
{
u16 data;
data=phy_read(db->ioaddr, db->phy_addr, i, db->chip_id);
len += sprintf(page+len, "%d:%04x\n",i, data);
}
*eof = 1;
return len;
}
MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
MODULE_DESCRIPTION("Davicom DM910X fast ethernet driver");
MODULE_LICENSE("GPL");
//MODULE_PARM(debug,int,S_IRUGO);
//MODULE_PARM(mode, char,S_IRUGO);
//MODULE_PARM(cr6set, "i");
//MODULE_PARM(chkmode, "i");
//MODULE_PARM(HPNA_mode, "i");
//MODULE_PARM(HPNA_rx_cmd, "i");
//MODULE_PARM(HPNA_tx_cmd, "i");
//MODULE_PARM(HPNA_NoiseFloor, "i");
//MODULE_PARM(SF_mode, "i");
//MODULE_PARM_DESC(debug, "Davicom DM9xxx enable debugging (0-1)");
//MODULE_PARM_DESC(mode, "Davicom DM9xxx: Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA");
//MODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function (bit 0: VLAN, bit 1 Flow Control, bit 2: TX pause packet)");
/* Description:
* when user used insmod to add module, system invoked init_module()
* to initilize and register.
*/
static int __init dmfe_init_module(void)
{
int rc;
// printk(version);
// printed_version = 1;
// DMFE_DBUG(0, "init_module() ", debug);
printk("ITC MAC 10/100M Fast Ethernet Adapter driver 1.0 init\n");
if (debug)
dmfe_debug = debug; /* set debug flag */
if (cr6set)
dmfe_cr6_user_set = cr6set;
switch(mode) {
case DMFE_10MHF:
case DMFE_100MHF:
case DMFE_10MFD:
case DMFE_100MFD:
case DMFE_1M_HPNA:
dmfe_media_mode = mode;
break;
default:dmfe_media_mode = DMFE_AUTO;
break;
}
#ifdef NO_PHY_PROBE
// mode=dmfe_media_mode=DMFE_100MHF;
mode=dmfe_media_mode=DMFE_100MFD;
#endif
if (HPNA_mode > 4)
HPNA_mode = 0; /* Default: LP/HS */
if (HPNA_rx_cmd > 1)
HPNA_rx_cmd = 0; /* Default: Ignored remote cmd */
if (HPNA_tx_cmd > 1)
HPNA_tx_cmd = 0; /* Default: Don't issue remote cmd */
if (HPNA_NoiseFloor > 15)
HPNA_NoiseFloor = 0;
rc = dmfe_init_one(SOC_SOC_DMFE1_BASE,SOC_SOC_DMFE1_IRQ);
if (rc < 0)
return rc;
hwaddr[5]++;
rc = dmfe_init_one(SOC_SOC_DMFE2_BASE,SOC_SOC_DMFE2_IRQ);
return 0;
}
/*
* Description:
* when user used rmmod to delete module, system invoked clean_module()
* to un-register all registered services.
*/
static void __exit dmfe_cleanup_module(void)
{
// DMFE_DBUG(0, "dmfe_clean_module() ", debug);
dmfe_remove_one(SOC_SOC_DMFE1_BASE);
dmfe_remove_one(SOC_SOC_DMFE2_BASE);
printk("ITC MAC 10/100M Fast Ethernet Adapter driver 1.0 init cleanup\n");
}
module_init(dmfe_init_module);
module_exit(dmfe_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -