linux网络设备驱动DM9000驱动分析(4)

来源:互联网 发布:淘宝福利群真的省钱吗 编辑:程序博客网 时间:2024/04/28 20:44

 转载请注明出处:http://blog.csdn.net/gotowu/article/details/46329809

14、接受数据

在中断函数中,我们可以看到调用了dm9000_rx。接收数据并存入skbuff,并提交协议上一层。

1)首先看看下面这个结构体,这个结构体按照DM9000的接收格式封装了dm9000接收的数据包信息 

struct dm9000_rxhdr {      u8RxPktReady;u8RxStatus;__le16RxLen;} __packed;

(2)接收函数dm9000_rx,这段程序当中有一个难点,就是在分配skb的时候有个+4指的是增加FCS位这个字段包括4字节循环冗余校检码(CRC)用于检查错误。

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

skb_reserve可以在缓冲区的头部预留一定的空间,它通常被用来在缓冲区中给协议头预留空间或者在某个边界上对齐。这个函数改变datatail指针,而datatail指针分别指向负载的开头和结尾。这个函数通常在分配缓冲区之后就调用,此时的datatail指针还是指向同一个地方,在分配SKB之后,向数据缓存区填充数据之前,会有这样的一条语句skb_reserve(skb, 2),这是因为以太网头长度为14B,再加上2B就正好16字节边界对齐,所以大多数以太网设备都会在数据包之前保留2Bskb->data的前面保留2字节,为了对齐用。| DA |SA |TYPE 14 bytes   IP packet16 byte对齐的!

rdptr = (u8 *) skb_put(skb, RxLen - 4);  增加的Rxlen-4好像是为了保存数据剩下的FCSEND

static voiddm9000_rx(struct net_device *dev){board_info_t *db = netdev_priv(dev);struct dm9000_rxhdr rxhdr;     /* 该结构体按照DM9000的接收格式封装了dm9000接收的数据包信息 */ struct sk_buff *skb;u8 rxbyte, *rdptr;bool GoodPacket;int RxLen;/* Check packet ready or not 判断包是否已经接收过来了。需要用到MRCMDX寄存器。*/do {ior(db, DM9000_MRCMDX);/* Dummy read. MRCMDX : memory data read command without address increment register*/                                                         //MRCMDX寄存器是存储数据读命令寄存器(地址不增加)/* Get most updated data */rxbyte = readb(db->io_data);/* Status check: this byte must be 0 or 1 */              //0、1为正确,2表示接收出错if (rxbyte & DM9000_PKT_ERR) {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))           //0x01 没有准备好,直接返回*/ return;/* A packet ready now  & Get status/length */GoodPacket = true;writeb(DM9000_MRCMD, db->io_addr);    /* MRCMD是地址增加的数据读取命令 读指针自动增加*/ (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));      //一次性读入四个字节的内容到rxhdr变量                                                                                          //这四个字节是存储在RX_SRAM中的每个包的信息头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 */            //检查包的完整性,需要用到MRCMD寄存器,if (RxLen < 0x40) {                     //因为数据读取到struct dm9000_rxhdr rxhdr;中,RXLEn为其成员GoodPacket = false;if (netif_msg_rx_err(db))dev_dbg(db->dev, "RX: Bad Packet (runt)\n");}if (RxLen > DM9000_PKT_MAX) {               //同上,检查包的大小如果数据长度大于DM9000_PKT_MAX ,即 1536 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寄存器中各位对接收的校验      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_buff的protocol全部搞定*/  if (GoodPacket &&    ((skb = netdev_alloc_skb(dev, RxLen + 4)) != NULL)) {          //分配一个skbuff给网络设备的接收skb_reserve(skb, 2);                                                  rdptr = (u8 *) skb_put(skb, RxLen - 4);          /* Read received packet from RX SRAM */                   //读取数据 从RX SRAM 到sk_buff中(db->inblk)(db->io_data, rdptr, RxLen);dev->stats.rx_bytes += RxLen;/* Pass to upper layer */          //获取上层协议类型skb->protocol = eth_type_trans(skb, dev);        //eth_type_trans判断数据帧的类型,及协议类型if (dev->features & NETIF_F_RXCSUM) {if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)skb->ip_summed = CHECKSUM_UNNECESSARY;elseskb_checksum_none_assert(skb);}netif_rx(skb);                      //将skbuff结构体交给上层dev->stats.rx_packets++;   //计数加1}else { // 坏包,丢弃/* need to dump the packet's data */                      (db->dumpblk)(db->io_data, RxLen);}} while (rxbyte & DM9000_PKT_RDY);}

———————————————END——————————————
0 0
原创粉丝点击