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

原创 2015年07月06日 19:58:35

 转载请注明出处: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——————————————
版权声明:本文为博主原创文章,转载请注明出处!

Linux DM9000网卡驱动程序完全分析

版权声明: 可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息。 说明1:本文分析基于内核源码版本为linux-2.6.31  说明2:本文在理解了linux中总线、设备和驱动模...
  • mrwangwang
  • mrwangwang
  • 2014年07月05日 15:39
  • 958

Linux下的网络设备驱动(一)

版权所有,转载必须说明转自 http://my.csdn.net/weiqing1981127  原创作者:南京邮电大学  通信与信息系统专业 研二 魏清   一.网络设备驱动基础 1.   ...
  • weiqing1981127
  • weiqing1981127
  • 2013年01月20日 10:05
  • 5442

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

转载请注明出处:http://blog.csdn.net/gotowu/article/details/46329809 10、DM9000驱动中有两个中断函数,dm9000_interrupt和d...
  • gotowu
  • gotowu
  • 2015年07月06日 19:32
  • 593

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

转载请注明出处:http://blog.csdn.net/gotowu/article/details/46329809 4、dm9000_drv_remove 将设备从内核移除,并释放内存区域...
  • gotowu
  • gotowu
  • 2015年07月06日 19:03
  • 465

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

本文所分析的DM9000驱动,是基于platform设备模型的。 网络驱动程序不再是对文件进行操作,而是由专门的网络接口struct net_device来实现。应用程序不能直接访问网络驱动程序,只能...
  • gotowu
  • gotowu
  • 2015年07月04日 10:09
  • 582

Linux网络设备驱动(一) _驱动模型

http://www.cnblogs.com/xiaojiang1025/p/6486267.html Linux素来以其强大的网络功能著名,同时, 网络设备也作为三大设备之一, 成为Lin...
  • zdy0_2004
  • zdy0_2004
  • 2017年03月28日 09:51
  • 1040

mini2440 dm9000网卡驱动移植

内核版本:linux-2.6.32.2        实验平台:mini2440
  • mcgrady_tracy
  • mcgrady_tracy
  • 2014年07月07日 19:32
  • 1166

一个十分经典的Linux DM9000网卡驱动程序完全分析(转载)

2012-04-07 00:19:35|  分类: 跟着国嵌学arm|举报|字号 订阅 原文:http://blog.chinaunix.net/link.php?u...
  • RopenYuan
  • RopenYuan
  • 2014年05月05日 20:02
  • 1426

MINI2440+DM9000网络驱动分析之六

在内核网络子系统里面,我们看不到其通过某节点与实际的PHY关联,不像字符设备和块设备,通过某设备节点和具体的物理设备关联起来.虽然像字符设备和块设备中间有可能通过层层子系统到达物理设备的操作层,如输入...
  • tang_jin_chan
  • tang_jin_chan
  • 2013年11月18日 11:59
  • 1223

LINUX移植——DM9000网卡移植

今天跟大家交流一下移植DM9000驱动的,希望对大家有个借鉴,这样本人也是很自豪的嘛,不扯了,开始吧。这篇文章主要讲一下DM9000移植时地址的计算,以及相对应的内核的配置。依然列出主要内容: 1.内...
  • xie0812
  • xie0812
  • 2013年09月03日 21:01
  • 2516
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux网络设备驱动DM9000驱动分析(4)
举报原因:
原因补充:

(最多只允许输入30个字)