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

📄 dmfe.c

📁 A Davicom DM9102A NIC fast ethernet driver for Linux.
💻 C
📖 第 1 页 / 共 5 页
字号:

/*
  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 */

 /* Transciver Selection */
 if (db->op_mode & 0x10)		/* 1M HomePNA */
    db->cr6_data|=0x40000;		/* External MII select */
 else
    db->cr6_data&=~0x40000;		/* Internal 10/100 transciver */
 
 update_cr6(db->cr6_data, db->ioaddr);

 /* 10/100M phyxcer force mode need */
 if ( !(db->media_mode & 0x18))       /* Skip for AUTO mode or HomePNA */
   { /* Forece Mode */
    phy_reg=phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);
    if ( !(phy_reg & 0x1) )
      {
       /* parter without N-Way capability */
       phy_reg=0x0;
       switch(db->op_mode)
        {
         case DMFE_10MHF: phy_reg=0x0; break;
         case DMFE_10MFD: phy_reg=0x100; break;
         case DMFE_100MHF: phy_reg=0x2000; break;
         case DMFE_100MFD: phy_reg=0x2100; break;
        }
       phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
       if ( db->chip_type && (db->chip_id==PCI_DM9102_ID) )
	  mdelay(20);
       phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
      }
   }
}

/*
  Write a word to Phy register
*/
static void phy_write(u32 iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id)
{
 u16 i;
 u32 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(u32 iobase, u8 phy_addr, u8 offset, u32 chip_id)
{
 int i;
 u16 phy_data;
 u32 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(u32 ioaddr, u32 phy_data)
{
 outl(phy_data, ioaddr);                        /* MII Clock Low */
 DELAY_1US;
 outl(phy_data|MDCLKH, ioaddr);                 /* MII Clock High */
 DELAY_1US;
 outl(phy_data, ioaddr);                        /* MII Clock Low */
 DELAY_1US;
}

/*
  Read one bit phy data from PHY controller
*/
static u16 phy_read_1bit(u32 ioaddr)
{
 u16 phy_data;

 outl(0x50000, ioaddr);
 DELAY_1US;
 phy_data=(inl(ioaddr)>>19) & 0x1;
 outl(0x40000, ioaddr);
 DELAY_1US;

 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;
}

/*
  Parser SROM and media mode
*/
static void dmfe_parse_srom(struct dmfe_board_info * db)
{
 char * srom=db->srom;
 int dmfe_mode, tmp_reg;

 DMFE_DBUG(0, "dmfe_parse_srom() ", 0);
 
 /* Init CR15 */
 db->cr15_data=CR15_DEFAULT;

 /* Check SROM Version */
 if ( ((int)srom[18] & 0xff) == SROM_V41_CODE)
   { /* SROM V4.01 */

    /* Get NIC support media mode */
    db->NIC_capability=*(u16 *)(&srom[34]);
    db->PHY_reg4=0;
    for (tmp_reg=1; tmp_reg<0x10; tmp_reg<<=1)
       {
        switch( db->NIC_capability & tmp_reg )
         {
          case 0x1: db->PHY_reg4|=0x0020; break;
          case 0x2: db->PHY_reg4|=0x0040; break;
          case 0x4: db->PHY_reg4|=0x0080; break;
          case 0x8: db->PHY_reg4|=0x0100; break;
         }
       }

    /* Media Mode Force or not check */
    dmfe_mode=*((int *)&srom[34]) & *((int *)&srom[36]);
    switch(dmfe_mode)
     {
      case 0x1: dmfe_media_mode=DMFE_10MHF; break;	/* Select 10MHF */
      case 0x4: dmfe_media_mode=DMFE_100MHF; break;	/* Select 100MHF */
      case 0x2: dmfe_media_mode=DMFE_10MFD; break;	/* Select 10MFD */
      case 0x8: dmfe_media_mode=DMFE_100MFD; break;	/* Select 100MFD */
      case 0x100: 
      case 0x200: dmfe_media_mode=DMFE_1M_HPNA; break;	/* Select HomePNA */
     }

    /* Special Function setting */
    /* VLAN function */
    if ( (SF_mode & 0x1) || (srom[43] & 0x80) ) db->cr15_data|=0x40;
   
    /* Flow Control */
    if ( (SF_mode & 0x2) || (srom[40] & 0x1) ) db->cr15_data|=0x400;

    /* TX pause packet */
    if ( (SF_mode & 0x4) || (srom[40] & 0xe) ) db->cr15_data|=0x9800;
   }

 /* Parse HPNA parameter */
 db->HPNA_command=1;

 /* Accept remote command or not */
 if (HPNA_rx_cmd==0)
    db->HPNA_command |= 0x8000;

 /* Issue remote command & operation mode */
 if (HPNA_tx_cmd==1)
    switch(HPNA_mode)	/* Issue Remote Command */
     {
      case 0: db->HPNA_command |= 0x0904; break;
      case 1: db->HPNA_command |= 0x0a00; break;
      case 2: db->HPNA_command |= 0x0506; break;
      case 3: db->HPNA_command |= 0x0602; break;
     }
 else
    switch(HPNA_mode)	/* Don't Issue */
     {
      case 0: db->HPNA_command |= 0x0004; break;
      case 1: db->HPNA_command |= 0x0000; break;
      case 2: db->HPNA_command |= 0x0006; break;
      case 3: db->HPNA_command |= 0x0002; break;
     }

 /* Check DM9801 or DM9802 present or not */
 db->HPNA_present=0;
 update_cr6(db->cr6_data|0x40000, db->ioaddr);
 tmp_reg=phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
 if ( (tmp_reg&0xfff0) == 0xb900 )
   {
    /* DM9801 or DM9802 present */
    db->HPNA_timer=8;	/* Check remote device status after 8 second */
    if (phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id)==0x4404)
      {/* DM9801 HomeRun */
       db->HPNA_present=1;
       dmfe_program_DM9801(db, tmp_reg);
      }
    else
      {/* DM9802 LongRun */
       db->HPNA_present=2;
       dmfe_program_DM9802(db);
      }
   }

}

/* Description: 
   Init HomeRun DM9801
*/
static void dmfe_program_DM9801(struct dmfe_board_info * db, int HPNA_rev)
{
	uint reg17, reg25;

	if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9801_NOISE_FLOOR;
	switch(HPNA_rev) {
	case 0xb900: /* DM9801 E3 */
		db->HPNA_command |= 0x1000;
		reg25 = phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id);
		reg25 = ( (reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000;
		reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
		break;
	case 0xb901: /* DM9801 E4 */
		reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor;
		reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3;
		break;
	case 0xb902: /* DM9801 E5 */
	case 0xb903: /* DM9801 E6 */
	default:
		db->HPNA_command |= 0x1000;
		reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5;
		reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor;
		break;
	}
	phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
	phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id);
	phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id);
}

/* Description: 
   Init HomeRun DM9802
*/
static void dmfe_program_DM9802(struct dmfe_board_info * db)
{
 uint phy_reg;

 if (!HPNA_NoiseFloor) HPNA_NoiseFloor=DM9802_NOISE_FLOOR;
 phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
 phy_reg=phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
 phy_reg= ( phy_reg & 0xff00) + HPNA_NoiseFloor;
 phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id);
}

/* Description: 
   Check remote HPNA power and speed status. If not correct, 
   issue command again.
*/
static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
{
 uint phy_reg;
 
 /* Got remote device status */
 phy_reg=phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60;
 switch(phy_reg)
  {
   case 0x00: phy_reg=0x0a00;break; /* LP/LS */
   case 0x20: phy_reg=0x0900;break; /* LP/HS */
   case 0x40: phy_reg=0x0600;break; /* HP/LS */
   case 0x60: phy_reg=0x0500;break; /* HP/HS */
  }

 /* Check remote device status match our setting ot not */
 if ( phy_reg != (db->HPNA_command & 0x0f00) )
   {
    phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
    db->HPNA_timer=8;
   }
else
   db->HPNA_timer=600;	/* Match, every 10 minutes, check */
}

#ifdef MODULE

#if LINUX_VERSION_CODE > 0x20118
    MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
    MODULE_DESCRIPTION("Davicom DM910X fast ethernet driver");
    MODULE_LICENSE("GPL");
    MODULE_PARM(debug, "i");
    MODULE_PARM(mode, "i");
    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");
#endif

/* 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 */
 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;
  }

 if (HPNA_mode>4) HPNA_mode=0;	   /* Default: LP/HS */
 if (HPNA_rx_cmd>1) HPNA_rx_cmd=0; /* Default: Ignored remote command */
 if (HPNA_tx_cmd>1) HPNA_tx_cmd=0; /* Default: Don't issue remote command */
 if (HPNA_NoiseFloor > 15)
	HPNA_NoiseFloor = 0;

 return dmfe_probe(0);              /* search board and register */
}

/* Description: 
   when user used rmmod to delete mod

⌨️ 快捷键说明

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