S3C2440驱动简析——DM9000网卡驱动(4)

     本文我们主要来分析.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, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = dm9000_poll_controller, #endif };

这里定义了操作net_device的一些重要操作,分别介绍如下:

 

1.dm9000_open

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; if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev)) return -EAGAIN; //申请中断资源 /* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */ iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ mdelay(1); /* delay needs by DM9000B */ /* Initialize DM9000 board */ dm9000_reset(db); //复位DM9000芯片 dm9000_init_dm9000(dev); //配置DM9000芯片内寄存器,使其能工作 /* Init driver variable */ db->dbug_cnt = 0; mii_check_media(&db->mii, netif_msg_link(db), 1); //检测mii接口的状态 netif_start_queue(dev); //启动设备工作队列 dm9000_schedule_poll(db); //阻塞 return 0; }

 

2.dm9000_stop

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); //取消设备阻塞 netif_stop_queue(ndev); //停止工作队列 netif_carrier_off(ndev); /* free interrupt */ free_irq(ndev->irq, ndev); //释放中断资源 dm9000_shutdown(ndev); return 0; }

其工作与open函数基本是相对应的,主要是资源的释放和停止设备发送队列。

 

3.dm9000_start_xmit

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 */ writeb(DM9000_MWCMD, db->io_addr); //写数据到DM9000的发送缓冲区 (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 */ dev_kfree_skb(skb); //释放skb return NETDEV_TX_OK; }

主要功能是将从上层传入的数据发送到media中。

 

4.dm9000_timeout

static void dm9000_timeout(struct net_device *dev) { board_info_t *db = netdev_priv(dev); u8 reg_save; unsigned long flags; /* Save previous register address */ spin_lock_irqsave(&db->lock, flags); //上锁 reg_save = readb(db->io_addr); //把残留数据保存起来 netif_stop_queue(dev); dm9000_reset(db); dm9000_init_dm9000(dev); /* We can accept TX packets again */ dev->trans_start = jiffies; /* prevent tx timeout */ netif_wake_queue(dev); /* Restore previous register address */ writeb(reg_save, db->io_addr); //复原上次的残留数据 spin_unlock_irqrestore(&db->lock, flags); //解锁 }

看门狗被触发后调用此函数,主要执行设备的重启动作。

 

5.dm9000_hash_table

static void dm9000_hash_table(struct net_device *dev) { board_info_t *db = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&db->lock, flags); dm9000_hash_table_unlocked(dev); spin_unlock_irqrestore(&db->lock, flags); }

核心函数dm9000_hash_table_unlocked(dev)完成设置组播地址的功能。

 

6.dm9000_ioctl

static int dm9000_ioctl(struct net_device *dev, struct ifreq *req, int cmd) { board_info_t *dm = to_dm9000_board(dev); if (!netif_running(dev)) return -EINVAL; return generic_mii_ioctl(&dm->mii, if_mii(req), cmd, NULL); }

核心函数 generic_mii_ioctl(&dm->mii, if_mii(req), cmd, NULL)代码如下

int generic_mii_ioctl(struct mii_if_info *mii_if, struct mii_ioctl_data *mii_data, int cmd, unsigned int *duplex_chg_out) { int rc = 0; unsigned int duplex_changed = 0; if (duplex_chg_out) *duplex_chg_out = 0; mii_data->phy_id &= mii_if->phy_id_mask; mii_data->reg_num &= mii_if->reg_num_mask; switch(cmd) { case SIOCGMIIPHY: mii_data->phy_id = mii_if->phy_id; /* fall through */ case SIOCGMIIREG: mii_data->val_out = mii_if->mdio_read(mii_if->dev, mii_data->phy_id, mii_data->reg_num); break; case SIOCSMIIREG: { u16 val = mii_data->val_in; if (mii_data->phy_id == mii_if->phy_id) { switch(mii_data->reg_num) { case MII_BMCR: { unsigned int new_duplex = 0; if (val & (BMCR_RESET|BMCR_ANENABLE)) mii_if->force_media = 0; else mii_if->force_media = 1; if (mii_if->force_media && (val & BMCR_FULLDPLX)) new_duplex = 1; if (mii_if->full_duplex != new_duplex) { duplex_changed = 1; mii_if->full_duplex = new_duplex; } break; } case MII_ADVERTISE: mii_if->advertising = val; break; default: /* do nothing */ break; } } mii_if->mdio_write(mii_if->dev, mii_data->phy_id, mii_data->reg_num, val); break; } default: rc = -EOPNOTSUPP; break; } if ((rc == 0) && (duplex_chg_out) && (duplex_changed)) *duplex_chg_out = 1; return rc; }

一个非常熟悉的switch case 结构函数,具体完成的动作这里不细讲啦~

 

7.eth_change_mtu

int eth_change_mtu(struct net_device *dev, int new_mtu) { if (new_mtu < 68 || new_mtu > ETH_DATA_LEN) return -EINVAL; dev->mtu = new_mtu; return 0; }

修改MTU值

 

8.eth_validate_addr

int eth_validate_addr(struct net_device *dev) { if (!is_valid_ether_addr(dev->dev_addr)) return -EADDRNOTAVAIL; return 0; }

判断地址是否全0xff或全0,非法

 

9.eth_mac_addr

int eth_mac_addr(struct net_device *dev, void *p) { struct sockaddr *addr = p; if (netif_running(dev)) return -EBUSY; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); return 0; }

把addr的sa_data成员绑定到设备地址

 

10.dm9000_poll_controller

static void dm9000_poll_controller(struct net_device *dev) { disable_irq(dev->irq); dm9000_interrupt(dev->irq, dev); enable_irq(dev->irq); }

函数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__); /* 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); //获取中断状态 iow(db, DM9000_ISR, int_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; }

 

 

到此为止,已经粗略的介绍完dm9000_netdev_ops的各个重要的操作。本博文应该是这个系列的倒数第二篇了,最后一篇用来分析dm9000_ethtod_ops的操作,敬请关注~

 

 

 

本系列课程链接地址

DM9000网卡驱动(1)http://blog.csdn.net/jarvis_xian/archive/2011/06/10/6537446.aspx
DM9000网卡驱动(2)http://blog.csdn.net/jarvis_xian/archive/2011/06/12/6539931.aspx
DM9000网卡驱动(3)http://blog.csdn.net/jarvis_xian/archive/2011/06/13/6542411.aspx
DM9000网卡驱动(4)http://blog.csdn.net/jarvis_xian/archive/2011/06/15/6545109.aspx
DM9000网卡驱动(5)http://blog.csdn.net/jarvis_xian/archive/2011/06/15/6547203.aspx

你可能感兴趣的:(S3C2440驱动简析——DM9000网卡驱动(4))