linux網絡設備驅動DM9000驅動分析(4)

 轉載請註明出處:http://blog.csdn.net/gotowu/article/details/46329809

14、接受數據

在中斷函數中,我們可以看到調用了dm9000_rx。接收數據並存入skbuff,並提交協議上一層。

1)首先看看下面這個結構體,這個結構體按照DM9000的接收格式封裝了dm9000接收的數據包信息 

struct dm9000_rxhdr {      
	u8	RxPktReady;
	u8	RxStatus;
	__le16	RxLen;
} __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 void
dm9000_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;
				else
					skb_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——————————————
發佈了33 篇原創文章 · 獲贊 16 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章