前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DM9000驱动分析之发送

DM9000驱动分析之发送

作者头像
DragonKingZhu
发布2022-05-08 15:43:24
3410
发布2022-05-08 15:43:24
举报
文章被收录于专栏:Linux内核深入分析
代码语言:javascript
复制
/*分析DM9000发生数据函数**/
/*
 *  Hardware start transmission.
 *  Send a packet to media from the upper layer.
 */
static int
dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	unsigned long flags;
	board_info_t *db = netdev_priv(dev);

	dm9000_dbg(db, 3, "%s:\n", __func__);

	if (db->tx_pkt_cnt > 1)
		return NETDEV_TX_BUSY;

	spin_lock_irqsave(&db->lock, flags);

	/* Move data to DM9000 TX RAM */
	//写数据到DM9000 Tx RAM中, 写地址自动增加
	writeb(DM9000_MWCMD, db->io_addr);

	/*将skb中的数据写入寄存器,然后发送字节改变*/
	(db->outblk)(db->io_data, skb->data, skb->len);
	dev->stats.tx_bytes += skb->len;

	db->tx_pkt_cnt++;
	/*第一个发送包立刻发送, 第二个排列到发送队列中去*/
	/* TX control: First packet immediately send, second packet queue */
	if (db->tx_pkt_cnt == 1) {
		dm9000_send_packet(dev, skb->ip_summed, skb->len);
	} else {
		/* Second packet */
		db->queue_pkt_len = skb->len;
		db->queue_ip_summed = skb->ip_summed;
		
		/*告诉网络协议栈,停止发送数据。*/
		netif_stop_queue(dev);
	}

	spin_unlock_irqrestore(&db->lock, flags);

	/* free this SKB */
	/*释放skb*/
	dev_kfree_skb(skb);
	
	return NETDEV_TX_OK;
}


/*当发送完成后,会触发一次发送完成的中断。 当然要去中断处理函数中*/
static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
{
	struct net_device *dev = dev_id;
	board_info_t *db = netdev_priv(dev);
	int int_status;
	unsigned long flags;
	u8 reg_save;

	dm9000_dbg(db, 3, "entering %s\n", __func__);

	/* A real interrupt coming */

	/* holders of db->lock must always block IRQs */
	spin_lock_irqsave(&db->lock, flags); 

	/* Save previous register address */
	reg_save = readb(db->io_addr);		//存储以前的地址

	/* Disable all interrupts */   //屏蔽所有中断
	iow(db, DM9000_IMR, IMR_PAR);

	/* Got DM9000 interrupt status */
	int_status = ior(db, DM9000_ISR);	/* Got ISR */
	iow(db, DM9000_ISR, int_status);	/* Clear ISR status */

	if (netif_msg_intr(db))
		dev_dbg(db->dev, "interrupt status %02x\n", int_status);

	/* Received the coming packet */   //接受中断发生
	if (int_status & ISR_PRS)
		dm9000_rx(dev);

	/* Trnasmit Interrupt check */
	if (int_status & ISR_PTS)					//检测是否发送完成
		dm9000_tx_done(dev, db);

	if (db->type != TYPE_DM9000E) {
		if (int_status & ISR_LNKCHNG) {
			/* fire a link-change request */
			schedule_delayed_work(&db->phy_poll, 1);
		}
	}

	/* Re-enable interrupt mask */
	iow(db, DM9000_IMR, db->imr_all);		//使能中断

	/* Restore previous register address */
	writeb(reg_save, db->io_addr);		//恢复以前的地址

	spin_unlock_irqrestore(&db->lock, flags);

	return IRQ_HANDLED;
}


/*分析中断发送完成处理函数*/

static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
{
	int tx_status = ior(db, DM9000_NSR);	/* Got TX status */	//得到发送的状态

	if (tx_status & (NSR_TX2END | NSR_TX1END)) {
		/* One packet sent complete */		//是一个包就发送完成
		db->tx_pkt_cnt--;
		dev->stats.tx_packets++;

		if (netif_msg_tx_done(db))
			dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);

		/* Queue packet check & send */		//如果超过2个,进入队列。发送
		if (db->tx_pkt_cnt > 0)
			dm9000_send_packet(dev, db->queue_ip_summed,
					   db->queue_pkt_len);
		netif_wake_queue(dev);   //唤醒发送队列
	}
}


/*
* 总结:
       1. 通知网络协议栈,停止发送队列
       2. 写skb数据到寄存器中去
       3. 释放skb资源
       4. 当发送完成后,唤醒发送队列
*/
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-01-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档