打印

问一个以太网驱动问题,请高手解答

[复制链接]
2213|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhlyp|  楼主 | 2007-4-12 10:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式


周立功的tcp/ip代码里的hardware.c里rec_packet函数里有这么一段     
   if(bnry!=curr)    //此时表示有新的数据包在缓冲区里
       {            //在任何操作都最好返回page0
        if(REC_BUFF_NUM==MAX_REC_BUFF)//接收缓冲区号清零
        {
            REC_BUFF_NUM=0;
        }
        REC_BUFF_PTR_WORDS=REC_BUFF[REC_BUFF_NUM].words;//设定接收缓冲区的起始地址
        //=======================================
        
        WriteToNet(0x09,bnry);    //RSAR1写入读页地址的高字节
        WriteToNet(0x08,0x00); //RSAR0写入读页地址的低字节
        WriteToNet(0x0b,0x00);    //RSCR1写入读取字节计数高字节
        WriteToNet(0x0a,18);   //RSCR0写入读取字节计数高字节
        WriteToNet(0x00,0x0a); //启动Remote DMA读操作
        //读取一包的前4个字节:4字节的8019头部
        for(i=0;i<2;i++)
        {
            *REC_BUFF_PTR_WORDS=ReadFromNet(0x10);
            tmp=*REC_BUFF_PTR_WORDS;
            REC_BUFF_PTR_WORDS++;
        }
        //0:接收状态;1:下一包的指针;2:本包低位;3:本包高位;
        //=======================================中止DMA操作
        WriteToNet(0x0b,0x00);    //RSCR1写入读取字节计数高字节
        WriteToNet(0x0a,0x00);    //RSCR0写入读取字节计数高字节
        WriteToNet(0x00,0x22);    //结束或放弃DMA操作
        //=======================================
        tmp[1]=tmp[1]-4;//去掉4个字节的CRC
        REC_BUFF[REC_BUFF_NUM].words[1]=tmp[1];    //把真正的接收的帧的长度保存到缓冲区
        //=====================以上各步操作表示读入的数据包有效
        //0:接收状态;1:下一包的指针;2:本包高位;3:本包低位;
        if(((tmp[0]&0x0001)==0)||((tmp[0]&0xff00)>0x7f00)
            ||((tmp[0]&0xff00)<0x4c00)||(tmp[1]>0x0600))
        {//接收状态错误或下一数据包的起始页地址错误或接收的数据包长度>1536字节
            page(1);
            curr=ReadFromNet(0X07);     //page1读取CURR的值
            page(0);        //切换回page0
            bnry = curr -1;    //把bnry恢复为下16K中的空余部分
            if(bnry < 0x4c) 
            {
                bnry =0x7f;
            }
            WriteToNet(0x03,bnry);     //把BNRY恢复到指向下一帧write to bnry        
            WriteToNet(0x07,0xff);        //清除中断标志
            //goto rea1;
            OS_EXIT_CRITICAL();
            return(0);

请问,那个tmp接受到的是什么数据?是以太帧的前两个字节吗?tmp[1]=tmp[1]-4;为什么是去掉4个字节的CRC?难道tmp[0]和tmp[1]包括了整个数据帧的全部? 

相关帖子

沙发
eleven11| | 2007-4-12 10:24 | 只看该作者

1

#ifndef _NE2KIF_H
#define _NE2KIF_H

#define ETH_NETIF_HEAD_LEN     14

#define DMA_TYPE               16
   
#if   DMA_TYPE==16
  #define NE2K_OUT(value,addr) *((volatile UINT16 *)NeBase + addr)=value 
  #define NE2K_IN(addr)        *((volatile UINT16 *)NeBase + addr) 
#elif DMA_TYPE==8
  #define NE2K_OUT(value,addr) *((volatile UINT8 *)NeBase + addr)=value 
  #define NE2K_IN(addr)        *((volatile UINT8 *)NeBase + addr)
#else
  #error "The value of DMAType is wrong"
#endif

//all addr[1,0] must be X0
#define    NE_CR        0x00       //R/W,对不同的页,CR都是同一个
#define    NE_DMA        0x10       //0x10-0x10 是DMA端口,重复,只用0x10.
#define    NE_RESET    0x18       //0x18-0x1f 是网卡复位端口,重复,只用0x1f,读写它将复位网卡

//page0 registers
#define NE_PSTART    0x01       //W,接收缓冲环起始页
#define NE_PSTOP    0x02       //W,接收缓冲环终止页(不包括此页)
#define NE_BNRY        0x03       //R/W,接收缓冲环读指针,指向下一个包到来时的起始页,应初始化成=CURR=PSTART
#define NE_TPSR        0x04       //W,Local DMA发送缓冲起始页寄存器
#define NE_TBCR0    0x05       //W,Local DMA发送长度低位
#define NE_TBCR1    0x06       //W,Local DMA发送长度高位
#define NE_FIFO        0x06
#define NE_ISR        0x07       //R/W,中断状态寄存器
#define NE_RSAR0    0x08       //W,Remote DMA目的起始地址低位
#define NE_CRDA0    0x08       //R,Remote DMA目的起始地址低位
#define NE_RSAR1    0x09       //W,Remote DMA目的起始地址高位
#define NE_CRDA1    0x09       //R,Remote DMA目的起始地址高位
//这两个是CPU向网卡写入或读出数据包的实际长度,执行Remote DMA命令前设置
#define NE_RBCR0    0x0A       //W,Remote DMA数据长度低位
#define NE_8019ID0  0x0A       //R,    
#define NE_RBCR1    0x0B       //W,Remote DMA数据长度高位
#define NE_8019ID1    0x0B       //R,    
#define NE_RCR        0x0C       //W,接收配置寄存器,初始化时写入0x04,表示只接收发给本网卡MAC地址的,大于64字节的以太网包或广播包
#define NE_TCR        0x0D       //发送配置寄存器,初始化开始时写入0x02,置网卡为Loop Back模式,停止发送数据包,初始化结束写入0x00。正常发送数据包并加上CRC
#define NE_DCR        0x0E       //W,数据配置寄存器,初始化时写入0x48,8位模式,FIFO深度8字节,DMA方式
#define NE_IMR        0x0F       //W,中断屏蔽寄存器它的各位和ISR中的各位相对应,向IMR写入值即为打开相应中断

//page1 registers
#define NE_PAR0        0x01       //R/W,网卡MAC地址最高位
#define NE_PAR1        0x02       //R/W,网卡MAC地址
#define NE_PAR2        0x03       //R/W,网卡MAC地址
#define NE_PAR3        0x04       //R/W,网卡MAC地址
#define NE_PAR4        0x05       //R/W,网卡MAC地址
#define NE_PAR5        0x06       //R/W,网卡MAC地址最低位
#define NE_CURR        0x07       //R/W,接收缓冲环写指针
#define NE_MAR0        0x08       //R/W,组播寄存器 
#define NE_MAR1        0x09       //R/W,组播寄存器 
#define NE_MAR2        0x0A       //R/W,组播寄存器 
#define NE_MAR3        0x0B       //R/W,组播寄存器 
#define NE_MAR4        0x0C       //R/W,组播寄存器 
#define NE_MAR5        0x0D       //R/W,组播寄存器 
#define NE_MAR6        0x0E       //R/W,组播寄存器 
#define NE_MAR7        0x0F       //R/W,组播寄存器 

#define    CMD_STOP    0x01       //网卡停止收发数据
#define    CMD_RUN        0x02       //网卡执行命令并开始收发数据包(命令为下面四种)
#define    CMD_XMIT    0x04       //Local DMA SEND(网卡――>以太网 )
#define    CMD_NODMA    0x20       //停止DMA操作
#define    CMD_PAGE0    0x00       //选择第0页(要先选页,再读写该页寄存器)
#define    CMD_PAGE1    0x40       //选择第1页
#define    CMD_PAGE2    0x80       //选择第2页
#define    CMD_PAGE3    0xC0       //选择第3页

//CR命令寄存器的命令 
#define    CMD_STOP    0x01       //网卡停止收发数据
#define    CMD_RUN        0x02       //网卡执行命令并开始收发数据包(命令为下面四种)
#define    CMD_XMIT    0x04       //Local DMA SEND(网卡――>以太网 )
#define    CMD_READ    0x08       //Remote DMA READ,用于手动接收数据(网卡――>CPU)
#define    CMD_WRITE    0x10       //Remote DMA WRITE (网卡<――CPU)
#define    CMD_SEND    0x18       //SEND COMMAND命令,用于自动接收数据包(网卡――>CPU)
#define    CMD_NODMA    0x20       //停止DMA操作
#define    CMD_PAGE0    0x00       //选择第0页(要先选页,再读写该页寄存器)
#define    CMD_PAGE1    0x40       //选择第1页
#define    CMD_PAGE2    0x80       //选择第2页
#define    CMD_PAGE3    0xC0       //选择第3页

//写入TPSR的值 
#define    SEND_PAGE0  0x40       //发送缓冲起始地址 
#define    SEND_PAGE1  0x46       //发送缓冲起始地址 
//写入PSTART的值 
#define    RECV_START    0x4C       //接收缓冲起始地址 
//写入PSTOP的值 
#define    RECV_STOP    0x80       //接收缓冲结束地址 

//中断状态寄存器的值 
#define    ISR_PRX        0x01       //正确接收数据包中断。做接收处理
#define    ISR_PTX        0x02       //正确发送数据包中断。做不做处理要看上层软件了。
#define    ISR_RXE        0x04       //接收数据包出错。做重新设置BNRY=CURR处理。 
#define    ISR_TXE        0x08       //由于冲突次数过多,发送出错。做重发处理
#define    ISR_OVW        0x10       //网卡内存溢出。做软件重启网卡处理。见手册。
#define    ISR_CNT        0x20       //出错计数器中断,屏蔽掉(屏蔽用IMR寄存器)。
#define    ISR_RDC        0x40       //Remote DMA结束 。屏蔽掉。轮询等待DMA结束。
#define    ISR_RST        0x80       //网卡Reset,屏蔽掉。

#define CR_TXP      0x04

//数据控制寄存器
//初始化时写入0x48,8位模式,FIFO深度8字节,DMA方式。
#define    DCR_WTS        (0x80|0x01)
#define    DCR_BOS        (0x80|0x02)
#define    DCR_LAS        (0x80|0x04)
#define    DCR_LS        (0x80|0x08)
#define    DCR_ARM        (0x80|0x10)
#define    DCR_FIFO2    (0x80|0x00)
#define    DCR_FIFO4    (0x80|0x20)
#define    DCR_FIFO8    (0x80|0x40)
#define    DCR_FIFO12    (0x80|0x60)

#if DMA_TYPE==16
   #ifdef LITTLE_ENDIAL
      #define DCR_WTS_BOS  (DCR_WTS | DCR_BOS)
   #else
      #define DCR_WTS_BOS  DCR_WTS
   #endif   
#else
   #define DCR_WTS_BOS  0
#endif

//RCR接收配置寄存器
//初始化时写入0x04。只接收发给本网卡MAC地址大于64字节的以太网包或广播包
#define    RCR_SEP        (0xC0|0x01)
#define    RCR_AR        (0xC0|0x02)
#define    RCR_AB        (0xC0|0x04)
#define    RCR_AM        (0xC0|0x08)
#define    RCR_PRO        (0xC0|0x10)
#define    RCR_MON        (0xC0|0x20)

//TCR发送配置寄存器
//初始化开始时写入0x02,置网卡为Loop Back模式,停止发送数据包,
//初始化结束写入0x00。正常发送数据包并加上CRC。
#define    TCR_CRC            (0xE0|0x01)
#define    TCR_LOOP_NONE    (0xE0|0x00)
#define    TCR_LOOP_INT    (0xE0|0x02)
#define    TCR_LOOP_EXT    (0xE0|0x06)
#define    TCR_ATD            (0xE0|0x08)
#define    TCR_OFST        (0xE0|0x10)

#define RSR_PRX         0x01

#define MIN_PACKET_LEN  64
#define MAX_PACKET_LEN  1514

#define NE2KIF_MAX_PACKET_LEN 1518

#define RTL_DELAY_AFTER_HARDWARE_RESET 0xFFFF

#define NE2KPAGE(Index)  NE2K_OUT((NE2K_IN(NE_CR) & 0x3B)|(UINT8)(Index << 6), NE_CR)

void NE2KIfIsr(PNETIF pNetIf, UINT32 NeBase);
void NE2KIfInit(PNETIF pNetIf, UINT32 NeBase);
void NE2KIfSend(PNETBUF pBuf, UINT32 NeBase);
PNETBUF NE2KIfRecv(UINT32 NeBase);

#endif

使用特权

评论回复
板凳
eleven11| | 2007-4-12 10:24 | 只看该作者

2

#include "netcfg.h"
#include "netdef.h"
#include "netsys.h"
#include "mem.h"
#include "netif.h"
#include "ne2kif.h"

static UINT8 StartPageOfPacket;

static UINT8 LastSendStartPage;

/*==============================================================
Function:
Description: 
Parameters:
Returns:
Notes:
==============================================================*/
void NE2KIfInit(PNETIF pNetIf, UINT32 NeBase)
{
   int i;
   
   for(i=0; i < RTL_DELAY_AFTER_HARDWARE_RESET; i++);
   
   NE2K_OUT(0, NE_RESET);
   i = NE2K_IN(NE_RESET);

   NE2K_OUT(CMD_PAGE1 | CMD_NODMA | CMD_STOP, NE_CR);
   
   NE2K_OUT(RECV_START + 1, NE_CURR);     
   NE2K_OUT(pNetIf->MAC[0], NE_PAR0);
   NE2K_OUT(pNetIf->MAC[1], NE_PAR1);
   NE2K_OUT(pNetIf->MAC[2], NE_PAR2);
   NE2K_OUT(pNetIf->MAC[3], NE_PAR3);
   NE2K_OUT(pNetIf->MAC[4], NE_PAR4);
   NE2K_OUT(pNetIf->MAC[5], NE_PAR5);

   NE2K_OUT(CMD_PAGE0 | CMD_NODMA | CMD_STOP, NE_CR);

   NE2K_OUT(TCR_LOOP_INT, NE_TCR);
   NE2K_OUT(RECV_START,  NE_PSTART);
   NE2K_OUT(RECV_STOP,   NE_PSTOP);
   NE2K_OUT(RECV_START,  NE_BNRY);
   NE2K_OUT(SEND_PAGE0, NE_TPSR);
   NE2K_OUT(RCR_AB,      NE_RCR); 
   NE2K_OUT(0, NE_RBCR0);
   NE2K_OUT(0, NE_RBCR1);   
   NE2K_OUT(DCR_LS | DCR_FIFO8 | DCR_WTS_BOS, NE_DCR);   
   NE2K_OUT(ISR_OVW | ISR_PRX | ISR_RXE, NE_IMR);
   NE2K_OUT(0xff, NE_ISR);                          
   NE2K_OUT(TCR_LOOP_NONE, NE_TCR);
      
   NE2K_OUT(CMD_PAGE0 |CMD_NODMA | CMD_RUN, NE_CR);

   LastSendStartPage = SEND_PAGE0;
   StartPageOfPacket = RECV_START + 1;      
}

/*==============================================================
Function:
Description: 
Parameters:
Returns:
Notes:
==============================================================*/
void NE2KIfIsr(PNETIF pNetIf, UINT32 NeBase)
{
   UINT8 isr,curr;   
   
   isr = NE2K_IN(NE_ISR);
   
   if (isr & ISR_OVW){
    
      NE2K_OUT(ISR_OVW,NE_ISR);
   }

   if (isr & ISR_RXE){
   
      NE2K_OUT(ISR_RXE,NE_ISR);        
      NE2KPAGE(1);
      curr = NE2K_IN(NE_CURR);
      NE2KPAGE(0);
      NE2K_OUT(curr-1, NE_BNRY);
   }   

   if (isr & ISR_PRX){
   
      NE2K_OUT(ISR_PRX, NE_ISR);
      pNetIf->lpInput(pNetIf);
   }

   NE2K_OUT(0xff, NE_ISR);             
}

/*==============================================================
Function:
Description: 
Parameters:
Returns:
Notes:
==============================================================*/
static void NE2KIfDMAWrite(UINT16 Count, PUINT8 pBuf, UINT32 NeBase)
{
   int i;

   #if DMA_TYPE==16
   Count = (Count + 1) >> 1;
   #endif
   
   for (i = 0; i < Count; i ++){
    
      #if DMA_TYPE==16
      NE2K_OUT(*(((PUINT16)pBuf)+i),NE_DMA);
      #else
      NE2K_OUT(pBuf,NE_DMA);
      #endif
   }   
}

/*==============================================================
Function:
Description: 
Parameters:
Returns:
Notes:
==============================================================*/
void NE2KIfSend(PNETBUF pBuf, UINT32 NeBase)
{  
   static BOOL InSend = FALSE;
   PNETBUF pt;
   UINT16 TotLen;
   
   if (InSend){
   
      return;
   
   }else{
   
      InSend = TRUE;
   }
   
   for (pt = pBuf, TotLen = 0; pt != NULL; pt = pt->pSub){
   
      TotLen += pt->TotLen;
   }
   
   if (TotLen < MIN_PACKET_LEN){
   
      TotLen = MIN_PACKET_LEN;
   
   }else if (TotLen > MAX_PACKET_LEN){
   
      TotLen = MAX_PACKET_LEN;
   }
   
   if (LastSendStartPage == SEND_PAGE0){
   
      LastSendStartPage = SEND_PAGE1;
   
   }else{
   
      LastSendStartPage = SEND_PAGE0;   
   }
   
   NE2K_OUT(TotLen & 0xff, NE_RBCR0);
   NE2K_OUT(TotLen >> 8,   NE_RBCR1);
   NE2K_OUT(0,             NE_RSAR0);
   NE2K_OUT(LastSendStartPage, NE_RSAR1);
   NE2K_OUT(CMD_PAGE0 | CMD_WRITE | CMD_RUN, NE_CR);       

   for (pt = pBuf; pt != NULL; pt = pt->pSub){
   
      NE2KIfDMAWrite(pt->TotLen, pt->PayLoad, NeBase);      
   } 

   NE2K_OUT(0, NE_RBCR0);
   NE2K_OUT(0, NE_RBCR1);
   NE2K_OUT(CMD_PAGE0 | CMD_NODMA | CMD_RUN, NE_CR);    
   
   while((NE2K_IN(NE_CR) & CR_TXP) == CR_TXP);
   
   NE2K_OUT(LastSendStartPage, NE_TPSR);
   NE2K_OUT(TotLen & 0xff, NE_TBCR0);
   NE2K_OUT(TotLen >> 8, NE_TBCR1);    
   NE2K_OUT(CMD_PAGE0 | CMD_NODMA | CMD_XMIT | CMD_RUN, NE_CR);  
   
   InSend = FALSE; 
}

/*==============================================================
Function:
Description: 
Parameters:
Returns:
Notes:
==============================================================*/
static void NE2KIfDMARead(UINT16 Count, PUINT8 pBuf, UINT16 Addr, UINT32 NeBase)
{
   int i;
   
   NE2K_OUT((UINT8)(Addr>>8),NE_RSAR1);
   NE2K_OUT((UINT8)Addr,NE_RSAR0);   
   NE2K_OUT((UINT8)(Count>>8),NE_RBCR1);
   NE2K_OUT((UINT8)Count,NE_RBCR0);
   NE2K_OUT(CMD_PAGE0 | CMD_READ | CMD_RUN, NE_CR);
   
   #if DMA_TYPE==16
   Count = (Count + 1) >> 1;
   #endif
   
   for (i = 0; i < Count; i ++){
    
      #if DMA_TYPE==16
      *(((PUINT16)pBuf)+i) = NE2K_IN(NE_DMA);
      #else
      pBuf = NE2K_IN(NE_DMA);
      #endif
   }

   NE2K_OUT(0, NE_RBCR0);
   NE2K_OUT(0, NE_RBCR1);    
   NE2K_OUT(CMD_PAGE0 | CMD_NODMA | CMD_RUN, NE_CR);
}

/*==============================================================
Function:
Description: 
Parameters:
Returns:
Notes:
==============================================================*/
PNETBUF NE2KIfRecv(UINT32 NeBase)
{
   PNETBUF pt;
   UINT16 TotLen;
   UINT8 PDHeader[4];
   UINT8 curr,bnry;

   pt = NULL;

   NE2KPAGE(1);
   curr = NE2K_IN(NE_CURR);
   NE2KPAGE(0);

   if (StartPageOfPacket >= RECV_STOP || StartPageOfPacket < RECV_START){
   
      StartPageOfPacket = curr;
      return NULL;
   }
    
   if (StartPageOfPacket == curr){
   
      return NULL;
   }        
    
   NE2KIfDMARead(4, PDHeader, (StartPageOfPacket << 8), NeBase);        
   
   TotLen = (PDHeader[2] | (PDHeader[3] << 8 ));

   if (PDHeader[0] & RSR_PRX)
   if (TotLen <= NE2KIF_MAX_PACKET_LEN)
   if ((pt = RecvBufAlloc()) != NULL){
         
      pt->PayLoad = pt->Data + (NETIF_HEAD_MAX_LEN - ETH_NETIF_HEAD_LEN);
      pt->TotLen  = TotLen - 4; 
      NE2KIfDMARead(pt->TotLen, pt->PayLoad, (StartPageOfPacket << 8) + 4, NeBase);     
   }
   
   StartPageOfPacket = PDHeader[1];
   
   bnry = StartPageOfPacket-1;
   
   if (bnry < RECV_START){
   
      bnry = RECV_STOP - 1;
   }
   
   NE2K_OUT(bnry, NE_BNRY);
   
   return pt;  
}

使用特权

评论回复
地板
zhlyp|  楼主 | 2007-4-12 12:42 | 只看该作者

疑问

   NE2KIfDMARead(4, PDHeader, (StartPageOfPacket << 8),  NeBase);       
   
   TotLen = (PDHeader[2] | (PDHeader[3] << 8 ));

第一句话应该是读取帧的前四个字节把,每个帧前四个字节不是目标地址吗?
PDHeader[2]和PDHeader[3]存的是长度?

使用特权

评论回复
5
coke| | 2007-4-12 17:08 | 只看该作者

re

每个数据包的前面和后面各有4个字节一般是不被应用程序所用的.用RTL8019举例说明:
第一个字节0x01为接收的状态,也就是RSR(接收状态寄存器的值)
第2个字节0x50 Next Packet Pointer,是一个指针,表示下一个数据包将存储在0x50页开始的地址0x5000.事实上等于此时的CURR=0x50.
第3和第4是接收的长度.表示该数据包的长度.这里是0x4000,要注意的是长度的高位和低位是颠倒的:
最后面的4个字节就是CRC校验码

使用特权

评论回复
6
zhlyp|  楼主 | 2007-4-12 19:32 | 只看该作者

懂了,谢谢楼上

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

29

主题

93

帖子

0

粉丝