111122-1257
taskDelay(10); pCrr = ( volatile unsigned int *)(IMMR_BASE_ADDR + REG_LCRR); *pCrr = LCRR_DEFAULT; taskDelay(10); }
dm9kUPMAProg(); //这个函数也不列出了
dm9000_addr_base[0] = (unsigned int)(DM9000A_MAC_BASE); //这2句可以去掉 dm9000_data_base[0] = (unsigned int)(DM9000A_MAC_BASE + 0x00 + 0x4); 2-2-5.网卡rest
dm9000Reset(pDrvCtrl); 对网卡的初始化,包括mac,phy,这个地方需要修改,函数内部: UWORD enaddr; UCHAR tmp; int i;
iow(dev,0x00, 0x03); iow(dev,0x00, 0x03); taskDelay(1);
DRV_LOG (DRV_DEBUG_LOAD, \for(i=0;i<6;i++)
dev->enetAddr[i] = DM9KDefaultMacAddr[i]; //这部分填充mac地址,但并没有写进dm9000寄存器中 /* I/O mode */
tmp=ior( dev,0xfe );
dev->io_mode = (tmp & 0xff) >> 7; /*这个地方涉及到了phy的模式 */
DRV_LOG (DRV_DEBUG_LOAD, \
/* Set PHY */
set_PHY_mode( dev );
iow( dev,0xff, DM9000_REGFF_OFF ); /* disable TX/RX interrupt mask */ iow( dev, 0x05, DM9000_REG05_OFF); /* RX disable */
DRV_LOG (DRV_DEBUG_LOAD, \
说明:对于上面的这行set_PHY_mode( dev );比较重要,单独列出 static void set_PHY_mode( END_DEVICE *dev ) {
UWORD phy_reg4 = 0x01e1, phy_reg0=0x1000; iow( dev,0x1e, 0x01 ); /* Let GPIO0 output */
iow(dev, 0x1f, DM9000_PHY_OFF ); /* disable PHY */
DRV_LOG (DRV_DEBUG_LOAD, \ if ( !(dev->op_mode & DM9000_AUTO) ){ switch(dev->op_mode)
6
111122-1257
{
/*case DM9008A cljG*/ case DM9000_10MHD: phy_reg4 = 0x21; phy_reg0 = 0x0000; break;
case DM9000_10MFD: phy_reg4 = 0x41; phy_reg0 = 0x0100; break;
case DM9000_100MHD: phy_reg4 = 0x81; phy_reg0 = 0x2000; break;
case DM9000_100MFD: case DM900xA_PECL: phy_reg4 = 0x101; phy_reg0 = 0x2100; break; }
}//因为开始设置的是8,所以这个地方不会进入, phy_write(dev, 0, 0x8000); /* Tmp */
DRV_LOG (DRV_DEBUG_LOAD, \ if(dev->op_mode == DM900xA_PECL) phy_write(dev, 16, 0x4014);
phy_write(dev, 4, phy_reg4); /* Set PHY media mode */ phy_write(dev, 0, phy_reg0); /* Tmp */
iow( dev,0x1f, DM9000_PHY_ON ); /* Enable PHY */ }
上面这个函数要注意的是对phy操作时的寄存器操作的正确性,
2-2-6.注册函数结构体
if (END_OBJ_INIT (&pDrvCtrl->end, (DEV_OBJ *)pDrvCtrl, DM9000_DEV_NAME, pDrvCtrl->unit, &dm9000FuncTable, \
|| END_MIB_INIT (&pDrvCtrl->end, M2_ifType_ethernet_csmacd, &pDrvCtrl->enetAddr[0], 6, ETHERMTU, END_SPEED) == ERROR) {
DRV_LOG (DRV_DEBUG_LOAD, \3, 4, 5, 6); goto errorExit; }
这个调用比较经典,直接把2步弄到了一步,其中dm9000FuncTable在这里被注册,后面会
7
111122-1257
分析到其中涉及的函数。 2-2-7.网卡内存分配
if (dm9000MemInit (pDrvCtrl) == ERROR) {
DRV_LOG (DRV_DEBUG_LOAD, \goto errorExit; }
内存池初始化,其中涉及到了对mblk等的初始化,可以参看关于5.5中这部分的解释,这部分不用过多修改,不是重点。可以参看源码 2-2-8.网卡资源配置
dm9000Config (pDrvCtrl);这个函数里面调用比较深,主要内容是对dm9000的中断,模式,mac写进dm9000寄存器,列出关键代码,可以参考数据手册理解对寄存器的操作
DRV_LOG (DRV_DEBUG_LOAD, \ /* Program operating register */
iow(dev, 0xff, DM9000_REGFF_OFF ); /* Enable FIFO chain */ iow(dev, 0x00, dev->reg0 );
iow(dev, 0x02, 0x00 ); /* TX Polling clear */ iow(dev, 0x08, DM9000_REG08 ); /* Less 3Kb, 200us */
iow(dev, 0x09, DM9000_REG09 ); /* Flow Control : High/Low Water */ iow(dev, 0x0a, DM9000_REG0A ); /* Flow Control */ iow(dev, 0x2f, 0x00); /* Special Mode */ iow(dev, 0x01, 0x2c); /* clear TX status */ iow(dev, 0xfe, 0x0f); /* Clear interrupt status */ /* iow(dev, 0x2d, 0x80); */ /* LED mode setting */
/* Set address filter table */
/* Set Physical Address Register */ /* Set Multicast Address Register */
dm9000_hash_table( dev ); //这个地方是把mac地址和多播地址给写进dm9000的对应寄存器,不贴代码了。 if( oo == 2 ) {
/* Activate DM9000 */
iow(dev, 0x05, DM9000_REG05 ); /* RX enable */
iow(dev, 0xff, DM9000_REGFF ); /* Enable TX/RX interrupt mask */ }
if( oo == 1 ) {
/* Activate DM9000 */ //会调用这个
iow(dev, 0x05, DM9000_REG05_OFF ); /* RX disable */
iow(dev, 0xff, DM9000_REGFF_OFF ); /* disable TX/RX interrupt mask */ }
8
111122-1257
/* Init Driver variable */ dev->tx_pkt_cnt = 0; dev->device_wait_reset = 0; taskDelay(1);
2-2-9.最后,使end设备准备好
END_OBJ_READY (&pDrvCtrl->end,
IFF_UP | IFF_RUNNING | IFF_NOTRAILERS | IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX); 让设备准备好。
2-2-10.ior,iow,phy_read,phy_write
这几个函数是最底层的涉及对寄存器操作的函数,要认真填充,特别是对phy的操作,使用的是新片内部的phy。
static __inline__ void outb(unsigned int ioaddr, unsigned short reg) { *(volatile unsigned short*)ioaddr = reg; }
static __inline__ unsigned short inb(unsigned int ioaddr) { unsigned short t; t = *(volatile unsigned short*)ioaddr; return t; }
#define dm9k_inb (unsigned char)inb //Read a byte from I/O port
static __inline__ unsigned char ior(END_DEVICE *dev, unsigned short reg) { outb(dev->io_addr, reg); return (unsigned char)inb(dev->io_data); }
//Write a byte to I/O port
static __inline__ void iow(END_DEVICE *dev, int reg, unsigned char value) { outb(dev->io_addr, reg); outb(dev->io_data, value); }
下面是phy的操作:
static UWORD phy_read( END_DEVICE *dev, int reg ) {
9
111122-1257
UCHAR tmp1, tmp2;
/* Fill the phyxcer register into REG_0C */ iow(dev, 0x0c, DM9000_PHY | reg );
iow(dev, 0x0b, 0x0c ); /* Issue phyxcer read command */ do {
taskDelay(1); /* Wait read complete */ tmp1=ior(dev,0x0b); }while( tmp1 & 0x01 );
iow(dev, 0x0b, 0x0 ); /* Clear phyxcer read command */
/* The read data keeps on REG_0D & REG_0E */ tmp1=ior(dev,0x0e); tmp2=ior(dev,0x0d);
return ( (tmp1 << 8 ) | tmp2 ); }
static void phy_write( END_DEVICE *dev, int reg, UWORD value) {
UCHAR tmp1;
/* Fill the phyxcer register into REG_0C */ iow(dev, 0x0c, DM9000_PHY | reg );
/* Fill the written data into REG_0D & REG_0E */ iow( dev,0x0d, (value & 0xff) );
iow( dev,0x0e, ( (value >> 8) & 0xff) );
iow(dev, 0x0b, 0x0a ); /* Issue phyxcer write command */ taskDelay(1);
while( ((tmp1=ior(dev,0x0B))&0x01) !=0){ taskDelay(1); DRV_LOG (DRV_DEBUG_LOAD, \ }
iow( dev,0x0b, 0x00 ); /* Clear phyxcer write command */ }
2-2-11.endload总结
endload的源码介绍就这么多,主要涉及:
对资源进行初始化,就是END_DEVICE结构体内部成员,但是一般的end模型,会把一步的参数通过第一步的configNet.h中通过DM9000_LOAD_STRING来传递,我把这部分给去除了,直接赋值。对phy的初始化,其中调用了2层的函数,主要是使phy设置网络的模式和使能phy,对网络函数结构体的初始化:dm9000FuncTable,使其上层接下来可以调用其中的start函数,下面将会提到
10