本文以海思3535的stmmac驱动注册过程为例,介绍网络驱动探测、网络设备探测过程。原文地址 http://blog.youkuaiyun.com/linchuanzhi_886/article/details/44458713
1.由于我们使用的是以太网,直接用alloc_etherdev()函数返回一个struct net_device的地址ndev。
在alloc_ether的过程中,会把ndev->dev->name赋值为“eth%”
2. 第一步成功后,获取STMMAC的资源,包括内存、中断。
3. 初始化mac信息。主要是根据mac控制器的能力,给mac_device_info结果体成员赋值。如全/半双工模式、10/100/1000Mbps,并且读取mac地址,如果mac地址无效,自动分配一个mac地址。里面有DMA操作函数。
4. `static int stmmac_mac_device_setup(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
struct mac_device_info *device;
if (priv->plat->has_gmac)
device = dwmac1000_setup(priv->ioaddr);
else
device = dwmac100_setup(priv->ioaddr);
if (!device)
return -ENOMEM;
if (priv->plat->enh_desc) {
device->desc = &enh_desc_ops;
pr_info("\tEnhanced descriptor structure\n");
} else
device->desc = &ndesc_ops;
****priv->hw = device;****
return 0;
}
`
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
4.ether_setup(dev);设置ndev的头部信息:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
填充ndev的netdev_ops,实现网络设备的open、发生,停止,超时处理函数,ioctl调用。
`static const struct net_device_ops stmmac_netdev_ops = {
.ndo_open = stmmac_open,
.ndo_start_xmit = stmmac_xmit,
.ndo_stop = stmmac_release,
.ndo_change_mtu = stmmac_change_mtu,
.ndo_set_rx_mode = stmmac_multicast_list,
.ndo_tx_timeout = stmmac_tx_timeout,
.ndo_do_ioctl = stmmac_ioctl,
.ndo_set_config = stmmac_config,
ifdef STMMAC_VLAN_TAG_USED
.ndo_vlan_rx_register = stmmac_vlan_rx_register,
endif
ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = stmmac_poll_controller,
endif
.ndo_set_mac_address = stmmac_eth_mac_addr,
};`
- 现在内核基本都支持ETHTOOL,填充ndev的ethtooll_ops。
( (netdev)->ethtool_ops = (ops)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
static struct mii_bus *stmmac_mii_bus;
int stmmac_mdio_register(struct net_device *ndev)
{
…….
stmmac_mii_bus->name = “STMMAC MII Bus”;
stmmac_mii_bus->read = &stmmac_mdio_read;
stmmac_mii_bus->write = &stmmac_mdio_write;
stmmac_mii_bus->reset = &stmmac_mdio_reset;
snprintf(stmmac_mii_bus->id, MII_BUS_ID_SIZE, “%x”,
priv->plat->bus_id);
stmmac_mii_bus->priv = ndev;
stmmac_mii_bus->irq = irqlist;
stmmac_mii_bus->phy_mask = priv->phy_mask;
stmmac_mii_bus->parent = priv->device;
err = mdiobus_register(stmmac_mii_bus);
……
}
int mdiobus_register(struct mii_bus *bus)
{
int i, err;
if (NULL == bus || NULL == bus->name ||
NULL == bus->read ||
NULL == bus->write)
return -EINVAL;
BUG_ON(bus->state != MDIOBUS_ALLOCATED &&
bus->state != MDIOBUS_UNREGISTERED);
bus->dev.parent = bus->parent;
bus->dev.class = &mdio_bus_class;
bus->dev.groups = NULL;
dev_set_name(&bus->dev, "%s", bus->id);
err = device_register(&bus->dev);
if (err) {
printk(KERN_ERR "mii_bus %s failed to register\n", bus->id);
return -EINVAL;
}
mutex_init(&bus->mdio_lock);
if (bus->reset)
bus->reset(bus);
for (i = 0; i < PHY_MAX_ADDR; i++) {
if ((bus->phy_mask & (1 << i)) == 0) {
struct phy_device *phydev;
phydev = mdiobus_scan(bus, i);
if (IS_ERR(phydev)) {
err = PTR_ERR(phydev);
goto error;
}
}
}
bus->state = MDIOBUS_REGISTERED;
pr_info("%s: probed\n", bus->name);
return 0;
error:
while (–i >= 0) {
if (bus->phy_map[i])
device_unregister(&bus->phy_map[i]->dev);
}
device_del(&bus->dev);
return err;
}
- 1
- 1
struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
{
struct phy_device *phydev;
int err;
phydev = get_phy_device(bus, addr);
if (IS_ERR(phydev) || phydev == NULL)
return phydev;
err = phy_device_register(phydev);
if (err) {
phy_device_free(phydev);
return NULL;
}
return phydev;
}
struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
{
struct phy_device *dev = NULL;
u32 phy_id;
int r;
r = get_phy_id(bus, addr, &phy_id);
if (r)
return ERR_PTR(r);
/* If the phy_id is mostly Fs, there is no device there */
if ((phy_id & 0x1fffffff) == 0x1fffffff)
return NULL;
dev = phy_device_create(bus, addr, phy_id);
return dev;
}
int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
{
int phy_reg;
/* Grab the bits from PHYIR1, and put them
* in the upper half */
phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
printk(KERN_INFO "ID1 = 0x%x at %s \n",phy_reg,bus->name);
if (phy_reg < 0)
return -EIO;
*phy_id = (phy_reg & 0xffff) << 16;
/* Grab the bits from PHYIR2, and put them in the lower half */
phy_reg = mdiobus_read(bus, addr, MII_PHYSID2);
printk(KERN_INFO "ID2 = 0x%x at %s \n",phy_reg,bus->name);
if (phy_reg < 0)
return -EIO;
*phy_id |= (phy_reg & 0xffff);
return 0;
}
9.初始化sk_buff队列头,skb_queue_head_init。然后申请中断,开启中断。