网络设备的probe函数跟字符设备的probe函数类似,上面这个probe函数主要完成DM9000的初始化工作,主要是获取并申请硬件资源和中断号、初始化net_device结构体,最后注册网络设备。主要是网络设备成员较多,导致这个probe看起来有些长而已。
在上面的探测函数中,我们注册了网络操作函数集合,跟踪下dm9000_netdev_ops的定义
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_multicast_list = dm9000_hash_table, .ndo_do_ioctl = dm9000_ioctl, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, //设置MAC地址 #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = dm9000_poll_controller, #endif }; |
打开网络设备就是激活网络接口,使得它能够接收网络上的数据并传送到网络的协议栈上去,当然也可以将数据发送到网络上去。下面我们看看这个dm9000_open的实现
static int dm9000_open(struct net_device *dev) { board_info_t *db = netdev_priv(dev); //获得net_device的私有数据 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 (irqflags == IRQF_TRIGGER_NONE) dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n"); irqflags |= IRQF_SHARED; if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev)) //申请中断 return -EAGAIN; dm9000_reset(db); //重置网卡 dm9000_init_dm9000(dev); //初始化网卡,这里主要对DM9000寄存器进行设置 db->dbug_cnt = 0; mii_check_media(&db->mii, netif_msg_link(db), 1); netif_start_queue(dev);//告诉上层网络协议该驱动还有空的缓冲区可用,即可接受数据 dm9000_schedule_poll(db); return 0; } |
在上面这个open函数中,我们注册了一个中断处理函数,这个中断主要完成接收数据的功能。当网络上的数据到来时,将触发硬件中断,根据注册的中断向量表确定处理函数,进入中断向量处理函数,将数据送到上层协议进行处理或者转发出去。需要注意的是中断处理函数会根据中断的原因来调用不同的处理函数。硬件芯片可能因为三种情况而触发中断:硬件将一个外发数据包发送完成;一个新的数据包到达硬件;网络接口也能够产生中断来指示错误。对于以上三种中断对应的处理方式分别是:通知协议栈可以重启发送队列,即调用netif_wake_queue函数;调用接收函数;处理错误。下面我们看看这个中断处理函数dm9000_interrupt
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__); spin_lock_irqsave(&db->lock, flags); //关其他中断 reg_save = readb(db->io_addr); iow(db, DM9000_IMR, IMR_PAR); int_status = ior(db, DM9000_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); if (int_status & ISR_PRS) //接收中断 dm9000_rx(dev); if (int_status & ISR_PTS) //发送完毕产生的中断 dm9000_tx_done(dev, db); if (db->type != TYPE_DM9000E) { if (int_status & ISR_LNKCHNG) { schedule_delayed_work(&db->phy_poll, 1); } } iow(db, DM9000_IMR, db->imr_all); //中断使能 writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock, flags); return IRQ_HANDLED; } |