VxWorks DM9000 驱动移植

更新时间:2024-04-27 08:40:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

111122-1257

Vxworks-dm9000驱动移植

前言

本次移植时基于公司自己的开发板:cpu:ppc8377,cpu自带2个网卡,然后扩展一个dm9000网卡,这次移植就是使用vxwroks6.6来移植dm9000.

Vxworks5.5和vxworks6.6对网络驱动有两种不同的模型,5.5下标准模型是end模型,而6.6下标准的是vxbus模型,但是vxworks6.6下可以兼容5.5的end模型,本次移植已经分别已经实现,故下面先对6.6下的end移植介绍,然后再对vxbus移植作介绍,因为本次移植没有改变太多的东西(因为vxbus下涉及很多东西,而这次成功移植的vxbus只是使用了里面很少的一部分),同时提交2个包,一个是end的target-111117-1738.rar,一个是vxbus的target-111121-1602.rar。

Vxworks-dm9000驱动移植 .............................................................................................. 1 前言 .................................................................................................................................... 1 一.Dm9000-vxwork6.6-end模型移植 ........................................................................... 2

1.概述 ......................................................................................................................... 2

1.1End模型 ....................................................................................................... 2 1.2.驱动层的内存缓冲池 .................................................................................. 2 2.涉及的代码 ............................................................................................................. 3

2-1:添加资源文件,config.h和configNet.h ................................................... 3

2-1-1.config.h ............................................................................................. 3 2-1-2. configNet.h ...................................................................................... 3 2-1-3 ........................................................................................................... 3 2-2.入口函数DM9000EndLoad(char* initString, void *pArg)分析和移植 ............................................................................................................................ 3

2-2-1.初始化网卡名 .................................................................................. 3 2-2-2.网卡资源calloc和资源结构体 ....................................................... 4 2-2-3.基地址,资源部分初始化 .............................................................. 5 2-2-4.map_op-->地址映射 ........................................................................ 5 2-2-5.网卡rest ........................................................................................... 6 2-2-6.注册函数结构体 .............................................................................. 7 2-2-7.网卡内存分配 .................................................................................. 8 2-2-8.网卡资源配置 .................................................................................. 8 2-2-9.最后,使end设备准备好 .............................................................. 9 2-2-10.ior,iow,phy_read,phy_write ............................................................ 9 2-2-11.endload总结 ................................................................................. 10 2-3 dm9000FuncTable ...................................................................................... 11 2-4.dm9000Start ............................................................................................ 11 2-5.dm9000Ioctl ............................................................................................ 12 2.6. dm9000Send .............................................................................................. 12 2-7.dm9000int .................................................................................................. 16

1

111122-1257

2-8. dm9000McastAdd dm9000MCastDel dm9000McastGet dm9000PollSend dm9000PollRcv等解析 ................................................................................... 22

二.Dm9000-vxwork6.6-vxbus模型移植 ..................................................................... 24

1. 前言: ................................................................................................................. 24 2.涉及代码 ............................................................................................................... 25

2-1.usrAppinit.c的void usrAppInit(void)函数 ........................................... 25 2.2. ethRegister ................................................................................................. 25 2.3.ethDevPlbRegistration ............................................................................ 25 2.4. ethInstInit,ethInstInit2, ........................................................................ 26 2.5. ethInstConnect ........................................................................................... 27 2.6. ethMuxConnect ......................................................................................... 27 2.7.vxbus的 end_device ................................................................................. 28 2.8. DM9000EndLoad ...................................................................................... 29 2.9.vxbus操作时使用vxbus独有特性探索之hwconf.c .............................. 29

三.移植过程中配到的困难 .......................................................................................... 30

一.Dm9000-vxwork6.6-end模型移植

1.概述 1.1End模型

End模型是比较成熟的模型,VxWorks网络协议栈增加一层MUX层。MUX层是VxWorks方便在网络接口硬件上实现多种协议而增加的一层。它主要用于管理底层的多种硬件的设备驱动,向上层不同协议提供统一的接口,降低了上层协议与底层物理硬件的藕合,使得网络驱动和上层协议彼此保持独立,既方便在现有硬件基础上实现新的上层协议,也利于用新的硬件支持原有的上层协议。

MUX与END的交互是通过提供一套可供底层调用接口服务来实现的,实现END驱动必须遵循这套接口关系。所以我们只要在驱动中实现对应的接口函数,我们的移植工作就成功了。

1.2.驱动层的内存缓冲池

缓冲池数据结构网络设备驱动与上层协议进行数据交换需要相应的内存缓冲,并且管理这些缓冲也需要相应的函数。VxWorks提供了netBufLib函数库用于创建和管理网络设备用到的内存缓冲池,网络设备驱动可以直接使用也可以在此基础上设计自己特定的内存缓冲池。数据以簇的形式保存,数据结构mBlks(内存块)和clBlks(簇块)形成的数据链结构则用于指定各个簇。

在clBlk之上是mBlk结构。该结构存储一个到clBlk的连接,也可以存储一个到另一个mBlk的连接。通过mBlk的连接,可以引用任意数量的数据。

下面的修改中会介绍对mblk等缓冲池的操作,这个地方是移植的重点,也是难点。对网卡

2

111122-1257

驱动的修改部分,主要为如下几个方面:开始的map_op(对硬件的初始化),endload,start,ioctl(基本不用动),send,dm9000int, reciveint,而send中断时只是在中断函数中对计数器进行减一操作。还有send/recive是对mblk的处理。而对poll等多播还有后面的函数基本上无需修改,直接使用普通的send和Rec即可。

2.涉及的代码

2-1:添加资源文件,config.h和configNet.h

2-1-1.config.h

在config.h中添加加上如下定义: #define INCLUDE_DM9000_END 2-1-2. configNet.h

在configNet.h中对结构体数组endDevTbl[] 仿照原先的定义,添加对dm9000网卡的定义,如下:

#ifdef INCLUDE_DM9000_END

{ 0, DM9000_LOAD_FUNC,DM9000_LOAD_STRING,1,NULL,FALSE}, #endif 2-1-3

在本文件的前面添加对应的宏定义 #ifdef INCLUDE_DM9000_END

#define DM9000_LOAD_FUNC DM9000EndLoad //定义装载函数

#define DM9000_LOAD_STRING \ //定义装载函数的参数,这个任意,因为后面没有用到

#define DM9000_BUFF_LOAD 1 //这个固定,不需要改动

IMPORT END_OBJ *DM9000_LOAD_FUNC (char *,void *); //把转载函数给声明出去 #endif

注意事项:这个地方定义一定要留意,如果没有写好的话,程序是进不去驱动的。

2-2.入口函数DM9000EndLoad(char* initString, void *pArg)分析和移植

2-2-1.初始化网卡名

if (initString == NULL){

DRV_LOG (DRV_DEBUG_LOAD, \ return (NULL); }

if (initString[0] == '\\0'){

DRV_LOG (DRV_DEBUG_LOAD, \

bcopy((char *)DM9000_DEV_NAME, initString, DM9000_DEV_NAME_LEN);

3

111122-1257

return (NULL); }

这段代码主要为设置网卡名字,上层会调用2次,程序开头把DM9000_DEV_NAME定义为: #define DM9000_DEV_NAME \ 2-2-2.网卡资源calloc和资源结构体

pDrvCtrl = (END_DEVICE *)calloc(sizeof (END_DEVICE), 1); DrvCtrl = pDrvCtrl; if (pDrvCtrl == NULL) {

DRV_LOG (DRV_DEBUG_LOAD, \printf(\goto errorExit; }

memset( (void*)pDrvCtrl, 0, sizeof( END_DEVICE ) );

上面这段代码主要是进行dm9000设备的资源申请处理,本次移植使用的资源结构体如下: typedef struct end_device {

END_OBJ end; /* The class we inherit from. */ END_ERR err; UINT IOBase;

int unit; /* unit number */ int ivec; /* interrupt vector */ int ilevel; /* interrupt level */ long flags; /* Our local flags. */ UCHAR enetAddr[6]; /* ethernet address */

CACHE_FUNCS cacheFuncs; /* cache function pointers */ CL_POOL_ID pClPoolId; /* cluster pool */

BOOL rxHandling; /* rcv task is scheduled */

UCHAR io_mode; /* 0:word, 2:byte */ char tx_pkt_cnt;

char device_wait_reset; UWORD queue_pkt_len;

UCHAR reg0; /* registers saved */ UCHAR nic_type; /* NIC type */

UCHAR op_mode; /* PHY operation mode */

UCHAR mcastFilter[8]; /* multicast filter */ UCHAR dummyBytes[3]; /* dummyBytes, for 32-bit align */ UCHAR txBuf[ETHERMTU + EH_SIZE + 6 + 64 ]; unsigned int io_addr; /这下面的2个参数是我加上去的,为了后面对寄存器操作方便 unsigned int io_data; } END_DEVICE;

这个资源结构体比较简单不过多介绍,下面在函数中会提到

4

111122-1257

2-2-3.基地址,资源部分初始化

(pDrvCtrl->flags) = 0;

(pDrvCtrl->op_mode) = DM9000_MEDIA_MODE; //设置phy的模式,为8,下面会涉及对phy的初始化

pDrvCtrl->ivec=17;

pDrvCtrl->ilevel=17; //这两个是中断号,设为一致,有一个没有用到 pDrvCtrl->unit=0; //这个为eth0后面的0 //下面的是网卡寄存器的基地址和数据地址

pDrvCtrl->io_addr=(unsigned int)(DM9000A_MAC_BASE);

pDrvCtrl->io_data=(unsigned int)(DM9000A_MAC_BASE + 0x00 + 0x4);

2-2-4.map_op-->地址映射

dm9000ConfigInit(pDrvCtrl);这个函数调用其实是map_op,其中涉及对io的映射等,特别是对mpc8377的pOr,pbr的初始化,还有mpc8377自己的UPMA,最后会把源码放在文档目录下,可以参看,初始化代码列为如下,不过多解释: static void ethAddrMap( ) { volatile unsigned int *pOr, *pBr; volatile unsigned int *pWbar3, *pWar3; volatile unsigned int *pBcr, *pCrr; /* map br3 register, and set the value */ pBr = ( volatile unsigned int *)(SYSTEM_CONFIG_BASE_ADDR + REG_BR3); *pBr = DM9000A_MAC_BASE | BR_DEFAULT; taskDelay(10); /* map or3 register, and set the value */ pOr = ( volatile unsigned int *)(SYSTEM_CONFIG_BASE_ADDR + REG_OR3); *pOr = OR_DEFAULT; //*pOr = 0xf0000106; taskDelay(10);

pWbar3=(volatile unsigned int *)(IMMR_BASE_ADDR + LBLAWBAR3_OFFSET_ADDR); *pWbar3 = DM9000A_MAC_BASE; /* 0xd3000000 */ taskDelay(10); pWar3=( volatile unsigned int *)(IMMR_BASE_ADDR + LBLAWAR3_OFFSET_ADDR); *pWar3 = 0x8000001b; /* enable, 256MB */ taskDelay(10); pBcr = ( volatile unsigned int *)(IMMR_BASE_ADDR + REG_LBCR); *pBcr = LBCR_DEFAULT;

5

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

111122-1257

2-3 dm9000FuncTable

这个结构体如下:

static NET_FUNCS dm9000FuncTable = {

(FUNCPTR) dm9000Start, /* Function to start the device. */ (FUNCPTR) dm9000Stop, /* Function to stop the device. */

(FUNCPTR) dm9000Unload, /* Unloading function for the driver. */ (FUNCPTR) dm9000Ioctl, /* Ioctl function for the driver. */ (FUNCPTR) dm9000Send, /* Send function for the driver. */ (FUNCPTR) dm9000MCastAdd, /* Multicast add function for the */ /* driver. */

(FUNCPTR) dm9000MCastDel, /* Multicast delete function for */ /* the driver. */

(FUNCPTR) dm9000MCastGet, /* Multicast retrieve function for */ /* the driver. */

(FUNCPTR) dm9000PollSend, /* Polling send function */ (FUNCPTR) dm9000PollRcv, /* Polling receive function */

endEtherAddressForm, /* put address info into a NET_BUFFER */ endEtherPacketDataGet, /* get pointer to data in NET_BUFFER */ endEtherPacketAddrGet /* Get packet addresses. */ };

上面说过,这个结构体主要涉及dm9000Start,dm9000Ioctl,dm9000Send,其他的都好操作,而dm9000Ioctl关键,但是涉及的源码无需改动就可,通用的。

2-4.dm9000Start

源码如下:

static STATUS dm9000Start( END_DEVICE * pDrvCtrl ) /* device ID */ {

STATUS result;

unsigned char REG05; /*sailot test*/ cpuForDM9000Init(); /*sailor*/

DRV_LOG (DRV_DEBUG_LOAD, \ intConnect(INUM_TO_IVEC(pDrvCtrl->ivec),(VOIDFUNCPTR)dm9000Int,(int)(pDrvCtrl)) if (result == ERROR){ printf(\ return ERROR; } printf(\

11

111122-1257

result = intEnable((int)pDrvCtrl->ivec); if (result == ERROR){ printf(\ return ERROR; }

DRV_LOG (DRV_DEBUG_LOAD, \ /* Activate DM9000 */

iow(pDrvCtrl, 0x05, DM9000_REG05 ); /* RX enable */

iow(pDrvCtrl, 0xff, DM9000_REGFF ); /* Enable TX/RX interrupt mask */ DRV_LOG (DRV_DEBUG_LOAD, \ return (OK); }

其中cpuForDM9000Init(); /*sailor*/涉及对cpu中断寄存器的初始化,要根据硬件寄存器来设置

void cpuForDM9000Init(void){ immap = 0xe0000000; /*config the io pin to the interrupt*/ ic_sicrh = ( volatile unsigned int *)(immap + 0x118); *ic_sicrh &= ~0x4000; /*high-to-low gernerate the interrupt*/ ic_secnr = ( volatile unsigned int *)(immap + 0x73c); *ic_secnr |= 0x4000; /*unmask the interrupts*/ ic_semsr = ( volatile unsigned int *)(immap + 0x738); *ic_semsr |= 0x40000000; }

这个代码操作寄存器并把中断硬件层打卡,而在start函数中intEnable((int)pDrvCtrl->ivec)来打开操作系统软件层。

在start函数中把dm9000Int注册到系统中。这就是中断函数

2-5.dm9000Ioctl

这个函数无需修改,直接移植系统原来的就行

这个函数主要就是返回一些信息,包括网卡的mac地址,mblk信息等,无需修改就可移植到上面。

2.6. dm9000Send

static STATUS dm9000Send( END_DEVICE * pDrvCtrl, M_BLK_ID pMblk ) { int oldLevel = 0;

BOOL freeNow = TRUE; PKT skb; int len;

12

111122-1257

int i;

DRV_LOG (DRV_DEBUG_LOAD, \4, 5, 6);

END_TX_SEM_TAKE (&pDrvCtrl->end, WAIT_FOREVER); oldLevel = intLock (); /* protect dm9000Int */ /* TODO - initiate device transmit */

len = netMblkToBufCopy (pMblk, (char*)(pDrvCtrl->txBuf), NULL); DRV_LOG (DRV_DEBUG_LOAD, \ SEND_DEBUG(\ for (i=0;i

SEND_DEBUG(\

len = max (len, ETHERSMALL);

skb.len = len; //后面数据部分的长度 skb.pData = (char*)pDrvCtrl->txBuf;

if( dmfe_start_xmit( &skb, pDrvCtrl ) ) {

DRV_LOG (DRV_DEBUG_STATUS, \ freeNow = FALSE; intUnlock (oldLevel); netMblkClChainFree (pMblk);

if (!((pDrvCtrl->flags) & DM9000_POLLING)) END_TX_SEM_GIVE (&pDrvCtrl->end); return(END_ERR_BLOCK); }

intUnlock (oldLevel);

END_TX_SEM_GIVE (&pDrvCtrl->end);

END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1);

netMblkClChainFree (pMblk);

DRV_LOG (DRV_DEBUG_LOAD, \ return (OK); }

函数中len = netMblkToBufCopy (pMblk, (char*)(pDrvCtrl->txBuf), NULL);把发送的信息从pMblk中给拷贝到pDrvCtrl->txBuf,而返回拷贝的大小len,后把这些信息付给skb,而skb是封装的临时结构体,如下: typedef struct {

int len;

char * pData;

13

111122-1257

} PKT; /* A dummy DMA data packet */

在调试的时候可以把打印信息放在这里,打印出发送的数据包,即上面代码的 for (i=0;i

如果程序没有错误,这个地方会出来打印信息,并且在用抓包工具可以抓到和打印信息相同的包信息,就说明发送成功了。

后面调用dmfe_start_xmit( &skb, pDrvCtrl ),把数据发送出去,这其中是最关键的代码,如下:

static int dmfe_start_xmit( PKT *skb, END_DEVICE *dev) {

char *data_ptr; int i, oldv;

unsigned char imr=0; int tmplen;

UWORD tmpdata; UCHAR regsave;

DRV_LOG (DRV_DEBUG_TX, \ DRV_LOG (DRV_DEBUG_TX, \ if( (skb->len == 0) || (skb->pData == NULL) ){

DRV_LOG (DRV_DEBUG_STATUS,\ return 2; }

/* Resource flag check *///这个部分是用来确定发送中断是否相应,如果连续2次没响应的话,发送就是错误,直接返回 if( dev->tx_pkt_cnt >= 2){

DRV_LOG (DRV_DEBUG_STATUS,\ regsave= ior( dev,2); return 1; }

/* Move data to DM9000 TX RAM */ data_ptr = (char *)skb->pData;

#if 0 //这个部分为调试信息,就是打印发送包的内容信息 SEND_DEBUG(\ for (i=0;ilen;i++){ SEND_DEBUG(\ if(((i+1) % 20)==0) SEND_DEBUG(\ } SEND_DEBUG(\#endif

outb( dev->io_addr,0xf8 );

14

111122-1257

if( dev->io_mode == 1 ) {

/* Byte mode */

for( i = 0; i < skb->len; i++ )

outb( dev->io_data,(data_ptr[i] & 0xff) ); }

Else //进入2,因为初始化时就设置为了0,为字传送,也就是2,依次接收2个字节 { SEND_DEBUG(\ /* Word mode */

tmplen = (skb->len + 1) / 2; for( i = 0; i < tmplen; i++ ){ outb( dev->io_data, SWAP16(((unsigned short *)data_ptr)[i])); if(((i+1) % 10)==0) SEND_DEBUG(\ } }

SEND_DEBUG(\

/* TX control: First packet immediately send, second packet queue */ if (dev->tx_pkt_cnt == 0) { /* First Packet */ dev->tx_pkt_cnt ++;//在这里应该把发送计数器++,在中断中来--,测试中断响应 /* Set TX length to DM9000 */ iow(dev, 0xfc, skb->len & 0xff );//把发送的数据长度写进dm9000对应的reg,这个地方,我感觉应该是在上面依次发送len长度,这时数据并没有发送出去,只是暂存在内部的缓冲区中,而这个地方是把长度放到寄存器中,然后dm9000来把缓冲区中的数据发送出去。 iow(dev, 0xfd, (skb->len >> 8) & 0xff ); /* Issue TX polling command */ iow(dev, 0x2, 0x01 ); /* Cleared after TX complete */ }

else /* Second packet */ //这是2个包处理的情况(一般不会发生) {

dev->queue_pkt_len = skb->len; dev->tx_pkt_cnt ++; } return 0; }

上面代码outb( dev->io_data, SWAP16(((unsigned short *)data_ptr)[i]));这部分很重要,主要是用来对发送的数据进行16位高低转换,也就是反序,代码如下: static __inline__ unsigned short SWAP16(unsigned short x) { unsigned short y; //SEND_DEBUG(\ y=(((x)&0xff)<<8)|(((x)&0xff00)>>8); //这个算法比较经典 SEND_DEBUG(\

15

111122-1257

return (y); }

2-7.dm9000int

dm9000int是在dm9000Start函数中被注册,里面主要处理recive中断和sent中断(这个主要是对计数器进行--,没别的涉及数据的操作)。

static void dm9000Int( END_DEVICE *pDrvCtrl ) /* interrupting device */ {

UCHAR stat, reg_save, isr_status, nsr_status; /* tx_status, */ UCHAR TX_comple_status;

/* Save previous register address */ DM9000_IN_ADDR( reg_save );

iow(pDrvCtrl, 0xff, DM9000_REGFF_OFF ); /*temp*/ stat = dm9000StatusRead (pDrvCtrl);

//INT_RECIVE_DEBUG(\ /* Clear ISR status */

isr_status=ior(pDrvCtrl,0xfe);

//INT_RECIVE_DEBUG(\ iow(pDrvCtrl, 0xfe, isr_status );

DRV_LOG (DRV_DEBUG_INT, \ /*

* enable interrupts, clear receive and/or transmit interrupts, and clear * any errors that may be set. */

/* Have netTask handle any input packets */

if( (isr_status & 1 )&&(stat & DM9000_RXON) ) {

DRV_LOG (DRV_DEBUG_INT, \ if ( pDrvCtrl->rxHandling != TRUE ){ pDrvCtrl->rxHandling = TRUE; /*dm9000HandleRcvInt(pDrvCtrl);*/ #ifdef DRV_DEBUG g_IntrNum++;

#endif //添加接收中断处理函数

netJobAdd ((FUNCPTR)dm9000HandleRcvInt, (int)pDrvCtrl,0,0,0,0); } }

/* TODO - handle transmit interrupts */ if( isr_status & 2 ) { //发送中断处理

DRV_LOG (DRV_DEBUG_INT, \

16

111122-1257

4, 5, 6);

TX_comple_status=ior(pDrvCtrl,0x1); if (TX_comple_status & 0xc){ /* One packet sent complete */ pDrvCtrl->tx_pkt_cnt--; //处理一个发送中断 INT_DEBUG(\ /* Queue packet check & send */

if (pDrvCtrl->tx_pkt_cnt > 0){ //处理第二个中断 iow(pDrvCtrl, 0xfc, pDrvCtrl->queue_pkt_len & 0xff ); iow(pDrvCtrl, 0xfd, (pDrvCtrl->queue_pkt_len >> 8) & 0xff ); iow(pDrvCtrl, 0x2, 0x01 ); } } } intRet:

/* Re-enable interrupt mask */

iow(pDrvCtrl, 0xff, DM9000_REGFF ); /* Restore previous register address */ DM9000_OUT_ADDR( reg_save ); }

注意事项,其中对发送中断时的2步处理是考虑到中断可能有时候没有来得及相应(情况很多),这时已经发送了2个包了,而此时就要对2次包进行处理了,也就是说发送了2个包,但是只响应了一次中断。

接收中断处理函数netJobAdd ((FUNCPTR)dm9000HandleRcvInt, (int)pDrvCtrl,0,0,0,0);分析: static void dm9000HandleRcvInt( END_DEVICE *pDrvCtrl ) /* interrupting device */ {

char* pData; int i;

unsigned short tmp3;

pDrvCtrl->rxHandling = TRUE;

DRV_LOG (DRV_DEBUG_INT, \ while (OK==dm9000PacketGet (pDrvCtrl)) { if(dm9000Recv (pDrvCtrl, (char*)NULL ) == ERROR) break; }

pDrvCtrl->rxHandling = FALSE; }

pDrvCtrl->rxHandling就是用来标记接收中断是否处理完成的,就是一个接收中断标志函数中涉及dm9000PacketGet()和dm9000Recv(),先看dm9000PacketGet() STATUS dm9000PacketGet( END_DEVICE *pDrvCtrl ) {

UCHAR rxbyte;

rxbyte=ior(pDrvCtrl,0xf0); rxbyte=ior(pDrvCtrl,0xf0);

/* packet ready to receive check */ if( rxbyte == DM9000_PKT_RDY )

17

111122-1257

{

DRV_LOG (DRV_DEBUG_LOAD, \ return OK; }

DRV_LOG (DRV_DEBUG_LOAD, \ return ERROR; }

此函数主要检测dm9000接收寄存器是否准备好 下面分析dm9000PacketGet()函数

static STATUS dm9000Recv( END_DEVICE *pDrvCtrl, /* device structure */ char* pData ) /* packet to process */ {

char* pClusterData; M_BLK_ID pMblk; char* pNewCluster; CL_BLK_ID pClBlk; PKT skb; int i;

DRV_LOG (DRV_DEBUG_LOAD, \#ifdef DRV_DEBUG g_RecvNumError++; #endif

pNewCluster = netClusterGet (pDrvCtrl->end.pNetPool, pDrvCtrl->pClPoolId); if (pNewCluster == NULL) {

DRV_LOG (DRV_DEBUG_RX, \ END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); goto cleanRXD; }

/* Grab a cluster block to marry to the cluster we received. */

if ((pClBlk = netClBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT)) == NULL) {

netClFree (pDrvCtrl->end.pNetPool, pNewCluster);

DRV_LOG (DRV_DEBUG_RX, \ END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); goto cleanRXD; }

/** OK we've got a spare, let's get an M_BLK_ID and marry it to the * one in the ring.*/

if ((pMblk = mBlkGet(pDrvCtrl->end.pNetPool, M_DONTWAIT, MT_DATA)) == NULL) {

netClBlkFree (pDrvCtrl->end.pNetPool, pClBlk); netClFree (pDrvCtrl->end.pNetPool, pNewCluster);

DRV_LOG (DRV_DEBUG_RX, \ END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1);

18

111122-1257

goto cleanRXD; }

END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1); /* align IP header at 32-bit boundary, this is reqired by VxWorks ** TCP/IP stack*/

pClusterData = (char*)((((unsigned long)pNewCluster + 1) & (~1)) | 2 ); /* move packet from Ethernet on-board SRAM to the mbuf pre-allocated ** in system memory */

skb.pData = pClusterData;

skb.len = 0;

//下面的这个函数是重点

if( dmfe_packet_receive( (PKT*)(&skb), pDrvCtrl ) ) {

mBlkFree (pDrvCtrl->end.pNetPool, pMblk); netClBlkFree (pDrvCtrl->end.pNetPool, pClBlk); netClFree (pDrvCtrl->end.pNetPool, pNewCluster);

DRV_LOG (DRV_DEBUG_RX, \ END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); goto cleanRXD; }

/* Join the cluster to the MBlock */

netClBlkJoin (pClBlk, pNewCluster, skb.len, NULL, 0, 0, 0); netMblkClJoin (pMblk, pClBlk);

pMblk->mBlkHdr.mData = pClusterData; pMblk->mBlkHdr.mLen = skb.len;

pMblk->mBlkHdr.mFlags |= M_PKTHDR; pMblk->mBlkPktHdr.len = skb.len;

#if 0 //用来验证数据是否接收出来,用来和抓包工具的数据进行比照 for(i=0;i<(skb.len +1 )/2;i++){ INT_RECIVE_DEBUG(\ if(((i+1) % 20)==0) INT_RECIVE_DEBUG(\}

INT_RECIVE_DEBUG(\#endif

/* make the packet data coherent */

END_CACHE_INVALIDATE (pMblk->mBlkHdr.mData, skb.len); /* Call the upper layer's receive routine. */

END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1); END_RCV_RTN_CALL(&pDrvCtrl->end, pMblk);

DRV_LOG (DRV_DEBUG_INT, \#ifdef DRV_DEBUG g_RecvNum++;

19

111122-1257

g_RecvNumError--; #endif

return (OK); cleanRXD:

return (ERROR); }

对于上面这个函数中的一些步骤,无需多管,这个函数是vxworks封装好的一个标准接收处理函数,思路是依次创建Cluster,clblk,mblk,然后把这3者给联系起来,而把接收得数据使用这个函数dmfe_packet_receive(),把dm9000缓冲池中的数据取出来,放到Cluster里面,然后把mblk的指针返回给上层mux层,接收驱动就算完成了。下面分析dmfe_packet_receive()函数:

static int dmfe_packet_receive( PKT *skb, END_DEVICE *dev ) {

UCHAR tmp1,tmp2; UWORD tmp3; UCHAR rxbyte; UCHAR *rdptr;

UWORD i, RxStatus, RxLen, GoodPacket, tmplen; int oldv;

UWORD RxStatus_tmp,data_tmp;

DRV_LOG (DRV_DEBUG_NO, \ rxbyte=ior(dev,0xf0); rxbyte=ior(dev,0xf0);

/* Status check: this byte must be 0 or 1 */

if( rxbyte > DM9000_PKT_RDY )//仍然是检测是否准备好,这个地方可以去掉 {

iow(dev, 0x05, DM9000_REG05_OFF); /* Stop Device */ iow(dev, 0xff, DM9000_REGFF_OFF); /* Stop Device */ DRV_LOG (DRV_DEBUG_RX,\ dm9000Reset( dev ); dm9000Config( dev ); return 2; }

/* packet ready to receive check */ if( rxbyte == DM9000_PKT_RDY ) {

/* A packet ready now & Get status/length */ GoodPacket = 1;

if( dev->io_mode == 1 ) //字节处理模式,和下面单字节接收对应 { tmp1=ior(dev,0xf2); tmp2=ior(dev,0xf2);

RxStatus = tmp1 + (tmp2 << 8); //读取状态 tmp1=ior(dev,0xf2); tmp2=ior(dev,0xf2);

20

111122-1257

RxLen = tmp1 + (tmp2<<8); //读取数据长度 }

Else //world模式,是这个程序的默认模式,为2字节,程序进入这里 { outb(dev->io_addr, 0xf2); RxStatus = SWAP16(inb(dev->io_data)); //这个16为2交换很重要 RxLen = inb(dev->io_data); }

if( RxLen < 0x40) //下面3个if都是错误检测 {

DRV_LOG (DRV_DEBUG_RX, \ GoodPacket = 0; }

if( RxLen > DM9000_PKT_MAX ) {

DRV_LOG (DRV_DEBUG_RX, \ dm9000Reset( dev ); dm9000Config( dev ); return 2; }

if( RxStatus & 0xbf) {

GoodPacket = 0;

/*if( RxStatus & 0x100 ) fifo error */ /*if( RxStatus & 0x200 ) crc error */ /*if( RxStatus & 0x8000 ) length error */

DRV_LOG (DRV_DEBUG_RX, \ }

/* Move data from DM9000 */ skb->len = 0;

if( GoodPacket && (skb != NULL) ) { /* good packet*/ skb->len = RxLen; rdptr = skb->pData;

/* Read received packet from RX SARM */ if (dev->io_mode == 1) { /* Byte mode */

for( i=0; i

rdptr[i]=dm9k_inb(dev->io_data); }

else

{/* Word mode */ //程序会进入这个地方 tmplen = (RxLen + 1) / 2; for( i = 0; i < tmplen; i++ ) {

21

111122-1257

data_tmp=inb(dev->io_data); ((unsigned short *)rdptr)[i] = SWAP16(data_tmp); } }

return 0; }

else //这就是坏包,处理方式是只是用临时变量来接收,但不提交。 { /* bad packet*/

/* Without buffer or error packet */ if( dev->io_mode == 1 ) {

/* Byte mode */

for( i = 0; i < RxLen; i++ ) tmp1=dm9k_inb(dev->io_data); } else {

/* Word mode */

tmplen = (RxLen + 1) / 2; for( i = 0; i < tmplen; i++ ) (unsigned short )tmp3 = SWAP16(inb(dev->io_data)); }

return 1; } }

DRV_LOG (DRV_DEBUG_RX, \ return 1; }

上面这个函数解析很清楚,在调试的时候可以在里面添加打印信息,打印接收包的数据,看是否和抓包工具抓到的相同,由于是在中断中处理的,打印信息时要用log_msg()函数。

2-8. dm9000McastAdd dm9000MCastDel dm9000McastGet dm9000PollSend dm9000PollRcv等解析

这几个函数比较简单,并且在数据传输上一般不过多处理,可以不写(函数内部写空)或者使用原先的,而对于endEtherAddressForm,endEtherPacketDataGet,endEtherPacketAddrGet这3个函数完全不用动,内部调用的是系统函数。不过dm9000PollSend dm9000PollRcv函数需要在进行处理一下,还得和sent,Rcv差不多,我把代码贴在下面

static STATUS dm9000PollSend( END_DEVICE *pDrvCtrl,M_BLK_ID pMblk) {

int len; u_short stat; PKT skb; int oldv;

22

111122-1257

DRV_LOG (DRV_DEBUG_POLL_TX, \ /* TODO - test to see if tx is busy */

stat = dm9000StatusRead (pDrvCtrl); /* dummy code */ if ((stat & (DM9000_TINT|DM9000_TFULL)) == 0) return ((STATUS) EAGAIN); /* TODO - transmit packet */

len = netMblkToBufCopy (pMblk, (char*)(pDrvCtrl->txBuf), NULL); len = max (len, ETHERSMALL); skb.len = len;

skb.pData = (char*)pDrvCtrl->txBuf;

oldv = intLock();

dmfe_start_xmit( &skb, pDrvCtrl );//可以看到,内部仍然调用了dmfe_start_xmit() intUnlock( oldv );

/* Bump the statistic counter. */

END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1); /* Free the data if it was accepted by device */ netMblkClFree (pMblk);

DRV_LOG (DRV_DEBUG_POLL_TX, \ return (OK); }

//可以看出,poolsend和send没有区别,我有点怀疑我基于原先的包是不是有问题 static STATUS dm9000PollRcv( END_DEVICE *pDrvCtrl, /* device to be polled */ M_BLK_ID pMblk ) /* ptr to buffer */ {

u_short stat; char* pPacket; int len;

PKT skb;

DRV_LOG (DRV_DEBUG_POLL_RX, \ stat = dm9000StatusRead (pDrvCtrl);

/* TODO - If no packet is available return immediately */ if( !(stat&DM9000_RXRDY) ) {

DRV_LOG (DRV_DEBUG_POLL_RX, \ return (EAGAIN); }

pPacket = NULL; /* DUMMY CODE */ len = 64; /* DUMMY CODE */

/* Upper layer must provide a valid buffer. */

if ((pMblk->mBlkHdr.mLen < len) || (!(pMblk->mBlkHdr.mFlags & M_EXT))) {

DRV_LOG (DRV_DEBUG_POLL_RX, \ return (EAGAIN);

23

111122-1257

}

/* TODO - Check packet and device for errors */

END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1);

/* TODO - Process device packet into net buffer */ skb.len = 0;

skb.pData = pMblk->m_data;

if( dmfe_packet_receive( &skb, pDrvCtrl ) ) //调用了dmfe_packet_receive() {

DRV_LOG (DRV_DEBUG_POLL_RX, \ return (EAGAIN); }

/* bcopy (pPacket, pMblk->m_data, len); */

pMblk->mBlkHdr.mFlags |= M_PKTHDR; /* set the packet header */ pMblk->mBlkHdr.mLen = len; /* set the data len */ pMblk->mBlkPktHdr.len = len; /* set the total len */ /* TODO - Done with packet, clean up and give it to the device. */

DRV_LOG (DRV_DEBUG_POLL_RX, \ DRV_LOG (DRV_DEBUG_POLL_RX, \ return (OK); }

可以看出,poollRcv和普通的Rcv也没太大的区别,只是普通的是要自己申请Cluster和Mblk等,而pooll是上层直接传递下来了。

二.Dm9000-vxwork6.6-vxbus模型移植

1. 前言:

Dm9000-vxwork6.6-vxbus模型移植在我的移植方法里面基本上没有太多的设计vxbus的操作,也是我对vxbus不太了解,在这次的移植过程中,基本上只是用了vxbus的外壳,没做其他事情。Vxbus和end的注册方法不一样,end是在configNet.h中添加资源和入口函数,而vxbus是在usrAppinit.c中添加自己的入口函数(我的方法是这样的),而注册方法也不是很一样,依次设计:ethRegister()?vxbDevRegister ((struct vxbDevRegInfo *)ðDevPlbRegistration)? drvBusFuncs ethFuncs?ethInstInit?ethInstInit2?ethInstConnect?

ethMuxConnect?muxDevLoad?muxDevStart.最后2个函数应该是大家比较熟悉的,在end模型中也是这样调用的。而设计的资源文件为:hwconf.c,可以使用,也可以不使用,后续将会设计到,下面涉及源码

24

111122-1257

2.涉及代码

2-1.usrAppinit.c的void usrAppInit(void)函数

void usrAppInit(void) {

#ifdef USER_APPL_INIT USER_APPL_INIT; /* for backwards compatibility */ #endif flashStart(); ethRegister(); //这就是入口函数 #if 1 taskDelay(5); //下面这几个是网卡初始化,驱动写好后添加的网卡设置 ipAttach(0,\ taskDelay(3); ifconfig(\ taskDelay(3); ifconfig(\ taskDelay(3); ifconfig(\#endif }

2.2. ethRegister

void ethRegister(void) { map_op(); //这个函数对应于end中的dm9000ConfigInit(),不多介绍 vxbDevRegister ((struct vxbDevRegInfo *)ðDevPlbRegistration); DRV_LOG (DRV_DEBUG_LOAD,\ taskDelay(3); return; }

vxbDevRegister ((struct vxbDevRegInfo *)ðDevPlbRegistration) 会把 ethDevPlbRegistration给注册进去

2.3.ethDevPlbRegistration

LOCAL struct vxbPlbRegister ethDevPlbRegistration = {

{

25

111122-1257

NULL, /* pNext */

VXB_DEVID_DEVICE, /* devID */ VXB_BUSID_PLB, /* busID = PCI */ VXBUS_VERSION_3, /* vxbVersion */ ETH_NAME, /* drvName */ ðFuncs, /* pDrvBusFuncs */ //这个是最重要的 ethMethods, /* pMethods */ ethProbe, /* devProbe */

//ethParamDefaults /* pParamDefaults */ }, };

其中,前4个不用动,系统分配 #define ETH_NAME \

而ethMethods,涉及的是方法,我把其中只保留了一项,其实也可以全部屏了。 LOCAL struct vxbDeviceMethod ethMethods[] = {

//DEVMETHOD(miiRead, ethPhyRead), //DEVMETHOD(miiWrite, ethPhyWrite), //DEVMETHOD(miiMediaUpdate,ethLinkUpdate), DEVMETHOD(muxDevConnect, ethMuxConnect), //DEVMETHOD(vxbDrvUnlink, ethInstUnlink), { 0, 0 } };

LOCAL struct drvBusFuncs ethFuncs = {

ethInstInit, /* devInstanceInit */ ethInstInit2, /* devInstanceInit2 */ ethInstConnect /* devConnect */ };

这个结构体就是上面提到的调用关系

2.4. ethInstInit,ethInstInit2,

这2个函数,可以参照其他的驱动,在ethInstInit中 LOCAL void ethInstInit(VXB_DEVICE_ID pDev) {

struct hcfDevice *pHcf;

/* Always use the unit number allocated to us in the hwconf file. */ pHcf = (struct hcfDevice *)pDev->pBusSpecificDevInfo; if(OK != vxbInstUnitSet (pDev, pHcf->devUnit)) DRV_LOG (DRV_DEBUG_LOAD,\ else DRV_LOG (DRV_DEBUG_LOAD,\ return;

}可以完全不动,

26

111122-1257

而ethInstInit2

LOCAL void ethInstInit2(VXB_DEVICE_ID pDev) {

END_DEVICE * pDrvCtrl; #if 1

pDrvCtrl = malloc (sizeof(END_DEVICE));

bzero ((char *)pDrvCtrl, sizeof(END_DEVICE)); pDev->pDrvCtrl = pDrvCtrl; pDrvCtrl->ethDev = pDev; #endif return;

}里面可以任何事情都不做,不过你也可以把这里面的初始化放在后面endload里,有人说6.6的ethInstInit2+endload=5.5的endload。

2.5. ethInstConnect

LOCAL void ethInstConnect( VXB_DEVICE_ID pDev){ DRV_LOG (DRV_DEBUG_LOAD,\ taskDelay(3); ethMuxConnect(pDev,NULL); return; }

可以看出,只是调用了ethMuxConnect。

2.6. ethMuxConnect

LOCAL void ethMuxConnect(VXB_DEVICE_ID pDev,void * unused) {

END_DEVICE *pDrvCtrl; VXB_DEVICE_ID miiDev; char *miiIfName; int miiIfUnit;

DRV_LOG (DRV_DEBUG_LOAD,\ /* Save the cookie. */

pDrvCtrl->ethMuxDevCookie = muxDevLoad (pDev->unitNumber, DM9000EndLoad, \

if (pDrvCtrl->ethMuxDevCookie != NULL)

muxDevStart (pDrvCtrl->ethMuxDevCookie);

if (_func_m2PollStatsIfPoll != NULL)

endPollStatsInit (pDrvCtrl->ethMuxDevCookie,_func_m2PollStatsIfPoll);

27

111122-1257

DRV_LOG (DRV_DEBUG_LOAD,\ taskDelay(3); return; }

调用了2个经典的函数

之后就可以进入DM9000EndLoad了在这里面我们看到了,传输的参数是VXB_DEVICE_ID pDev,这是vxbus新的类型,我的做法是,在设备资源结构体中添加了这几个成员:

2.7.vxbus的 end_device

typedef struct end_device {

END_OBJ end; /* The class we inherit from. */ //add the vxbus's code VXB_DEVICE_ID ethDev; UINT32 ethMask; //这个也可以不用要,但另外2个必须要得 void *ethMuxDevCookie; //end

END_ERR err; UINT IOBase;

int unit; /* unit number */ int ivec; /* interrupt vector */ int ilevel; /* interrupt level */ long flags; /* Our local flags. */ UCHAR enetAddr[6]; /* ethernet address */

CACHE_FUNCS cacheFuncs; /* cache function pointers */ CL_POOL_ID pClPoolId; /* cluster pool */

BOOL rxHandling; /* rcv task is scheduled */

UCHAR io_mode; /* 0:word, 2:byte */ char tx_pkt_cnt;

char device_wait_reset; UWORD queue_pkt_len;

UCHAR reg0; /* registers saved */ UCHAR nic_type; /* NIC type */

UCHAR op_mode; /* PHY operation mode */

UCHAR mcastFilter[8]; /* multicast filter */ UCHAR dummyBytes[3]; /* dummyBytes, for 32-bit align */ UCHAR txBuf[ETHERMTU + EH_SIZE + 6 + 64 ]; unsigned int io_addr; /**/ unsigned int io_data; } END_DEVICE;

28

111122-1257

2.8. DM9000EndLoad

因为在init2中添加了初始化分配代码,所以,这个函数中可以省去这些 END_OBJ* DM9000EndLoad( char* initString, void *pArg ){ END_DEVICE *pDrvCtrl;

VXB_DEVICE_ID pDev; //主要增加了这1句, UINT32 dataVal; char tmp; int i;

VXB_INST_PARAM_VALUE val; STATUS r; int cnt; pDev = pArg; pDrvCtrl = pDev->pDrvCtrl; //还有这一句,就把VXB_DEVICE_ID和END_DEVICE绑在一起了 …….. }

上面个的这个参数pArg指向的是VXB_DEVICE_ID,而end里是END_DEVICE。 在后续的程序中都可以在开头加上和上面思想类似的两个操作,因为传输的参数类型变了由END_DEVICE到END_OB,如:

static STATUS dm9000Start(END_DEVICE * pEnd ) /* device ID */?end static STATUS dm9000Start( END_OBJ * pEnd ) /* device ID */-?vxbus 而对于这种,可以这样 END_DEVICE * pDrvCtrl; VXB_DEVICE_ID pDev;

pDrvCtrl = (END_DEVICE *)pEnd; pDev = pDrvCtrl->ethDev;

下面的操作就和end的一样了。

2.9.vxbus操作时使用vxbus独有特性探索之hwconf.c

从上面的移植中可以看到,虽然我们用了vxbus,但是我们只是用到了外壳,并没有用到里面一些实际的东西,经过分析,找到了一个可以用到的地方,就是注册中断的时候 原来的注册方法:

intConnect(INUM_TO_IVEC(pDrvCtrl->ivec), (VOIDFUNCPTR)dm9000Int, (int) (pDrvCtrl)); if (result == ERROR){ printf(\ return ERROR; }

printf(\result = intEnable((int)pDrvCtrl->ivec); if (result == ERROR){ printf(\

29

111122-1257

return ERROR; }

新的注册方法:

vxbIntConnect (pDev, 0, dm9000Int, pDrvCtrl); vxbIntEnable (pDev, 0, dm9000Int, pDrvCtrl);

但是要在一个文件中添加资源信息?hwconf.c,找到hcfDeviceList[]数组,在其中添加 #ifdef INCLUDE_DM9000A_VXB_END /* added, 20110820_0926 */ { \#endif

在文件的上面添加

#define INCLUDE_DM9000A_VXB_END #ifdef INCLUDE_DM9000A_VXB_END

#define DM9000A_MAC_BASE 0xd3000000 //资源的基地址 #define INUM_DM9000END0 17 //本次使用的中断号

const struct hcfResource ethDm9000aEnd0Resources[] = { { \ { \ { \ { \ //无需改动 { \ HCF_RES_STRING, { (void *)\ { \ HCF_RES_INT, { (void *)0 } }};

#define ethDm9000aEnd0Num NELEMENTS(ethDm9000aEnd0Resources) #endif

上面的{ \就照应这0?17,你能明白的。

三.移植过程中配到的困难

1.程序的流程,end和vxbus有很大不同,刚开始直接用vxbus,但是不了解,可以的去研究vxbus,导致浪费了时间,最后拐头使用end,成功后,移植到vxbus上。

2.主要是那个swap地方没有弄好,开始没有注意打印信息,后来发现接收和发送的数据全是空的,后来添加上打印信息,找到了错误的地方,但是已经浪费了很多时间 3.对mac和phy的不理解,并且对dm9000的数据手册不熟悉,没有过多的去参看数据手册。 4.对应在这次开发中涉及的重点和疑惑,最终我感觉上面列出的那几个接口函数都相当重要。如果让列出最终要的部分,是最底层的那几个:ior,iow,phy_read,phy_wirte这四个函数,特别是phy的操作,网上也少有涉及的,最后只能手写对它的操作。

30

本文来源:https://www.bwwdw.com/article/8tyg.html

Top