您的位置:首页 > 其它

DM9000驱动之接受

2015-01-21 18:30 295 查看
/*分析DM9000收到一个数据包后,应该做何处理?*/

/*当收到一个数据包后,DM9000就会触发一次发送中断,跳到中断处理函数处理*/
static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
{
/* Received the coming packet */  //当接受到一个数据包后
if (int_status & ISR_PRS)
dm9000_rx(dev);
}

/*处理发送函数*/
/*
*  Received a packet and pass to upper layer
*/
static void dm9000_rx(struct net_device *dev)
{
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 */
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))	//是否接受完全
return;

/* A packet ready now  & Get status/length */
GoodPacket = true;
writeb(DM9000_MRCMD, db->io_addr);

(db->inblk)(db->io_data, &rxhdr, sizeof(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 */
/*分配skb结构*/
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 */
//从RX中读取数据
(db->inblk)(db->io_data, rdptr, RxLen);
dev->stats.rx_bytes += RxLen;

/* Pass to upper layer */
skb->protocol = eth_type_trans(skb, dev); //获取网络协议
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);										//发送数据到上层去
dev->stats.rx_packets++;

} else {
/* need to dump the packet's data */

(db->dumpblk)(db->io_data, RxLen);
}
} while (rxbyte & DM9000_PKT_RDY);
}

/*这里需要详细说明分配skb这块的细节问题*/

/*第一个问题: 为什么分配的RxLen+4?   dev_alloc_skb(RxLen + 4)*/

/*答: 因为skb结构前面要带有MAC头, IP头, 网络包的头共4个字节。 所以要多分配4个字节*/

/*第二个问题: 为什么skb->data 和 tail指针要加2 ? skb_reserve(skb, 2); */

/*答:因为IP包要求4字节对齐的缘故 */

/*第三个问题: 为什么Rxelen-4 ?  skb_put(skb, RxLen - 4);*/
/*答: 设置tail指针的位置,去掉后面4字节的校验*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  DM9000