注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

TCP/IP驱动七——接收函数  

2013-07-10 21:37:21|  分类: TCPIP驱动 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

TCP/IP驱动七——接收函数

 

上面已经分析了发送数据的函数dm9000_start_xmit()。下面就分析一下接收的函数,不过在看这个函数前,先得弄明白,接收是怎么样的一个过程。

      在地址0C00h~3FFFh范围内的RX SRAM中,存储着接收来的数据。其中的每个包都有4个字节的信息头。可以使用MRCMDXMRCMD寄存器来得到这些信息。第一个字节用来检查数据包是否接收到了RX_SRAM中,如果这个字节是"01",意味着一个包已经接收。如果是"00",则还没有数据包被接收到RX_SRAM中。第二个字节保存接收到的数据包的信息,格式和RSR寄存器一样。根据这个格式,接收到的包能被校验是正确的还是错误的包。第三和第四字节保存了接收的数据包的长度。这四个字节以外的其他字节就是接收包的数据。看下图可以更好的理解这种格式。

 

 TCP/IP驱动七——接收函数 - 还东国 - 还东国的博客

根据包的结构可以知道接收一个包应该按照下面的步骤来进行:

 

第一步:判断包是否已经接收过来了。需要用到MRCMDX寄存器。MRCMDX寄存器是存储数据读命令寄存器(地址不增加)。 这个寄存器只是用来读接收包标志位"01"。下面这段代码是一个例子,用来判断RX ready

 

u8 RX_ready = ior( IOaddr, 0xF0 );         /* dummy read the packet ready flag */ 虚读 

RX_ready = (u8) inp( IOaddr + 4 );         /* got the most updated data */  

if ( RX_ready == 1 ) {                     /* ready check: this byte must be 0 or 1 */  

       /* check the RX status and to get RX length (see datasheet ch.5.6.3) */  

       /* income RX a packet (see datasheet ch.5.6.4) */  

} else if ( RX_ready != 0 ) {              /* stop device and wait to reset device */  

       iow( IOaddr, 0xFF, 0x80 );          /* stop INT request */  

       iow( IOaddr, 0xFE, 0x0F );          /* clear ISR status */  

       iow( IOaddr, 0x05, 0x00 );          /* stop RX function */  

       u8 device_wait_reset = TRUE;        /* raise the reset flag */  

 

 第二步:检查包的状态和长度。需要用到MRCMD寄存器(存储数据读命令,读指针自动增加)。下面这段例子代码用来读RX状态和长度。

 

u8 io_mode = ior( IOaddr, 0xFE ) >> 6; /* ISR bit[7:6] keep I/O mode */  

outp( IOaddr, 0xF2 );                /* trigger MRCMD reg_F2h with read_ptr++ */  

/* int RX_status : the RX packet status, int RX_length : the RX packet length */  

if ( io_mode == 2 ) {                /* I/O byte mode */  

RX_status = inp( IOaddr + 4 ) + ( inp( IOaddr + 4 ) << 8 );   

RX_length = inp( IOaddr + 4 ) + ( inp( IOaddr + 4 ) << 8 );        }   

else if ( io_mode == 0 ) {           /* I/O word mode */  

RX_status = inpw( IOaddr + 4 );   

RX_length = inpw( IOaddr + 4 );             }   

else if ( io_mode == 1 ) {           /* I/O dword mode */  

(u32) status_tmp = inpl( IOaddr + 4 );           /* got the RX 32-bit dword data */  

RX_status = (u16)( status_tmp & 0xFFFF );   

RX_length = (u16)( ( status_tmp >> 16 ) & 0xFFFF );          } 

 

第三步:读包的数据。也需要MRCMD寄存器。例子代码如下:

 

/* u8 RX_data[] : the data of the received packet */  

if ( io_mode == 2 ) {                 /* I/O byte mode */  

for ( i = 0 ; i < RX_length ; i++ ) /* loop to read a byte data from RX SRAM */  

  RX_data[ i ] = (u8) inp( IOaddr + 4 );          }   

else if ( io_mode == 0 ) {            /* I/O word mode */  

int length_tmp = ( RX_length + 1 ) / 2;   

for ( i = 0 ; i < length_tmp ; i++ ) /* loop to read a word data from RX SRAM */  

 ( (u16 *)RX_data)[ i ] = inpw( IOaddr + 4 );           }   

else if ( io_mode == 1 ) {            /* I/O dword mode */  

int length_tmp = ( RX_length + 3 ) / 4;   

for ( i = 0 ; i < length_tmp ; i++ ) /* loop to read a dword data from RX SRAM */  

 ( (u32 *)RX_data)[ i ] = inpl( IOaddr + 4 ); }         /* inpl() is inport 32-bit I/O */ 

 

下面的dm9000_rx()函数实际上是按照上面这三个步骤来实现的,具体实现并不一定是要参照例子代码。 注意这里按照DM9000接收包的格式定义了一个结构体dm9000_rxhdr用来表示头部的四个字节。代码清单如下:

 

struct dm9000_rxhdr {   

    u8  RxPktReady;   

    u8  RxStatus;   

    __le16  RxLen;   

} __attribute__((__packed__)); 

 

接收函数代码如下:

 

/*  

 *  Received a packet and pass to upper layer  

 */  

static void  

dm9000_rx(struct net_device *dev)   

{   

    // netdev_priv的作用是得到网卡私有数据的起始地址,在alloc_netdev函数中,//net_device这个是和网卡的私有数据是一起分配的,大家可以去看这个函数,那么要想//得到网卡的私有数据的地址,就可以通过这个函数来取得。

    board_info_t *db = netdev_priv(dev);   

    struct dm9000_rxhdr rxhdr;   

    struct sk_buff *skb;   

    u8 rxbyte, *rdptr;   

    bool GoodPacket;   

    int RxLen;   

  

    /* Check packet ready or not */  

    do {   

        ior(db, DM9000_MRCMDX); /* Dummy read */  

  

        /* Get most updated data */  

                /*读一下最新数据的第一个字节*/  

        rxbyte = readb(db->io_data);   

  

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

                /*DM9000_PKT_RDY定义是0x01,如果第一个字节大于0x01,则不是正确的状态。因为第一个字节只能是01h00h*/  

        if (rxbyte > DM9000_PKT_RDY) {   

            dev_warn(db->dev, "status check fail: %d\n", rxbyte);   

            iow(db, DM9000_RCR, 0x00);  /* Stop Device */  

            iow(db, DM9000_ISR, IMR_PAR);   /* Stop INT request */  

            return;   

        }   

  

        if (rxbyte != DM9000_PKT_RDY)   

            return;   

  

        /* A packet ready now  & Get status/length */  

        GoodPacket = true;   

        writeb(DM9000_MRCMD, db->io_addr);   

  

        (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));/*一次性读入四个字节的内容到rxhdr变量*/  

  

        RxLen = le16_to_cpu(rxhdr.RxLen);   

  

        if (netif_msg_rx_status(db))   

            dev_dbg(db->dev, "RX: status %02x, length %04x\n",   

                rxhdr.RxStatus, RxLen);   

  

        /* Packet Status check */  

        if (RxLen < 0x40) {   

            GoodPacket = false;   

            if (netif_msg_rx_err(db))   

                dev_dbg(db->dev, "RX: Bad Packet (runt)\n");   

        }   

  

        if (RxLen > DM9000_PKT_MAX) {   

            dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);   

        }   

  

        /* rxhdr.RxStatus is identical to RSR register. */  

        if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |   

                      RSR_PLE | RSR_RWTO |   

                      RSR_LCS | RSR_RF)) {   

            GoodPacket = false;   

            if (rxhdr.RxStatus & RSR_FOE) {   

                if (netif_msg_rx_err(db))   

                    dev_dbg(db->dev, "fifo error\n");   

                dev->stats.rx_fifo_errors++;   

            }   

            if (rxhdr.RxStatus & RSR_CE) {   

                if (netif_msg_rx_err(db))   

                    dev_dbg(db->dev, "crc error\n");   

                dev->stats.rx_crc_errors++;   

            }   

            if (rxhdr.RxStatus & RSR_RF) {   

                if (netif_msg_rx_err(db))   

                    dev_dbg(db->dev, "length error\n");   

                dev->stats.rx_length_errors++;   

            }   

        }   

  

        /* Move data from DM9000 */  

                /*关键的代码在这里。使用到了上面提到的sk_buff。将RX SRAM中的data段数据放入sk_buff,然后发送给上层。sk_buffprotocol负责完成*/  

        if (GoodPacket   

            && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {   

            skb_reserve(skb, 2);   

            rdptr = (u8 *) skb_put(skb, RxLen - 4);   

  

            /* Read received packet from RX SRAM */  

  

            (db->inblk)(db->io_data, rdptr, RxLen);   

            dev->stats.rx_bytes += RxLen;   

  

            /* Pass to upper layer */  

            skb->protocol = eth_type_trans(skb, dev);   

            netif_rx(skb);   

            dev->stats.rx_packets++;   

  

        } else {   

            /* need to dump the packet's data */  

  

            (db->dumpblk)(db->io_data, RxLen);   

        }   

    } while (rxbyte == DM9000_PKT_RDY);   

这样一来,收和发就都有了。总算有时间看一看TCP的事儿了。不容易。还得好好努力啊。

  评论这张
 
阅读(1412)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017