关闭

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

标签: 设备驱动linuxDM9000网卡驱动
402人阅读 评论(0) 收藏 举报
分类:

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

4、dm9000_drv_remove 将设备从内核移除,并释放内存区域。

 dm9000_drv_suspend 函数并不真正把设备从内核中移除,而是使用netif_device_detach来标志设备为removed状态。dm9000_drv_resume 函数将挂起的设备复位并初始化,软后用netif_device_attach将设备标志为attached状态,并设置挂起标志位。

5、dm9000_netdev_ops定义了操作net_device的重要函数,我们在驱动程序中根据需要的操作要填充这些函数

static const struct net_device_ops dm9000_netdev_ops = {
	.ndo_open		= dm9000_open,
	.ndo_stop		= dm9000_stop,
	.ndo_start_xmit		= dm9000_start_xmit,
	.ndo_tx_timeout		= dm9000_timeout,
	.ndo_set_rx_mode	= dm9000_hash_table,
	.ndo_do_ioctl		= dm9000_ioctl,
	.ndo_change_mtu		= eth_change_mtu,
	.ndo_set_features	= dm9000_set_features,
	.ndo_validate_addr	= eth_validate_addr,
	.ndo_set_mac_address	= eth_mac_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER
	.ndo_poll_controller	= dm9000_poll_controller,
#endif
};

6、open函数进行的操作有向内核注册中断,复位并初始化dm9000.检查MII接口,使能传输等。在字符设备驱动中是把中断注册放在模块初始化函数中,而网卡驱动则放在open函数中。原因是网卡有禁用操作,当被禁用的时候,要把占用的中断号释放。

1jiffies用来记录自系统启动以来产生的节拍的总数。启动时,内核将该变量初始化为0,此后,每次时钟中断处理程序都会增加该变量的值。一秒内时钟中断的次数等于Hz,所以jiffies一秒内增加的值也就是Hz。将以秒为单位的时间转化为jiffiesseconds * Hz.

jiffies转化为以秒为单位的时间:jiffies / Hz

static int dm9000_open(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;

	if (netif_msg_ifup(db))
		dev_dbg(db->dev, "enabling %s\n", dev->name);

	/* If there is no IRQ type specified, default to something that
	 * may work, and tell the user that this is a problem */

	if (irqflags == IRQF_TRIGGER_NONE)
		dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");

	irqflags |= IRQF_SHARED;

	/* GPR:GPIO寄存器REG_1F bit0 activate phyxcer为了 清除power_down信号且激活PHY,所以要给GPIO0写零*/
	iow(db, DM9000_GPR, 0);	
	mdelay(1); /* delay needs by DM9000B */

	/* Initialize DM9000 board */
	dm9000_reset(db);
	dm9000_init_dm9000(dev);

	if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))    //申请中断
		return -EAGAIN;

	/* Init driver variable */
	db->dbug_cnt = 0;

	mii_check_media(&db->mii, netif_msg_link(db), 1);        //检测检测mii接口状态,双工duplex状态的改变,若改变了返回1
	netif_start_queue(dev);            //启动发送队列,使能传输,调用 hard_start_xmit
	
	dm9000_schedule_poll(db);           //当TYPE为DM9000E时,计数200(2*HZ)吃后将db->phy_poll加入内核工作队列中

	return 0;
}


7、stop 函数,对open的操作进行反操作。

static int dm9000_stop(struct net_device *ndev)
{
	board_info_t *db = netdev_priv(ndev);

	if (netif_msg_ifdown(db))
		dev_dbg(db->dev, "shutting down %s\n", ndev->name);

	cancel_delayed_work_sync(&db->phy_poll);       /* 终止phy_poll队列中被延迟的任务 */

	netif_stop_queue(ndev);
	netif_carrier_off(ndev);

	/* free interrupt */
	free_irq(ndev->irq, ndev);

	dm9000_shutdown(ndev);

	return 0;
}

8、发送操作dm9000_start_xmit,将skb中的data部分写入DM9000TX RAM

(1)netif_stop_queuenetif_wake_queue()函数与netif_stop_queue()是数据发送流程中要调用的两个重要的函数,分别用于唤醒和阻止上层向下层传送数据包。原型定义于include/linux/netdevice.h中。

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);  //获得自旋锁

	/* 下面四个函数将发送的数据包送入 DM9000 的TX RAM */
	writeb(DM9000_MWCMD, db->io_addr);

	(db->outblk)(db->io_data, skb->data, skb->len);           //把skb->data中的数据送入到MWCMD的TX RAM
	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_start_xmit通过调用dm9000_send_packet来发送数据。
		dm9000_send_packet(dev, skb->ip_summed, skb->len);      //skb->ip_summed(控制校验操作)
	} else {
		/* Second packet */
		db->queue_pkt_len = skb->len;
		db->queue_ip_summed = skb->ip_summed;
		netif_stop_queue(dev);   //阻止上层向下层传送数据包
	}
	
 /*如果发送的是第二个数据包(表明队列中此时有包发送),
 则将其加入队列中:将skb->len和skb->ip_summed(控制校验操作)
 赋值给board_info_t中有关队列的相关成员。调用函数netif_stop_queue(dev),
 通知内核现在queue已满,不能再将发送数据传到队列中,
 注:第二个包的发送将在tx_done中实现。*/

 	spin_unlock_irqrestore(&db->lock, flags);         //释放自旋锁

	/* free this SKB */
	dev_kfree_skb(skb);

	return NETDEV_TX_OK;
}

9、在dm9000_start_xmit中调用dm9000_send_packet来发送数据。

static void dm9000_send_packet(struct net_device *dev,
			       int ip_summed,
			       u16 pkt_len)
{
	board_info_t *dm = to_dm9000_board(dev);

	/* The DM9000 is not smart enough to leave fragmented packets alone. */
	if (dm->ip_summed != ip_summed) {
		if (ip_summed == CHECKSUM_NONE)
			iow(dm, DM9000_TCCR, 0);
		else
			iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);
		dm->ip_summed = ip_summed;
	}

	/* Set TX length to DM9000 */
	iow(dm, DM9000_TXPLL, pkt_len);
	iow(dm, DM9000_TXPLH, pkt_len >> 8);

	/* 设置TXCR寄存器的bit[0] TXREQ来自动发送包*/
	iow(dm, DM9000_TCR, TCR_TXREQ);	/* 发送完成后自动清除发送请求 */
}




0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场