涉及到的主要结构体,整体框架
这些结构体就是linux内核提供的接口,实现这些结构体的成员变量的过程就是驱动开发
struct device_node //路径 include/linux/of.h
struct platform_driver //路径 include/linux/platform_device.h
struct net_device //路径 include/linux/netdevice.h
struct mii_bus //路径 include/linux/phy.h
struct phy_device //路径 include/linux/phy.h
驱动开发的整体框架简单的来说如下四个表格
table 1
**实现 fec_device
和注册 fec_device
由设备树完成
实现 struct platform_device fec_device | 向内核platform总线注册 fec_device |
实现 struct platform_device fec_device | 向内核platform总线注册 fec_device |
table 2.
申请 net_device | 初始化 net_devie | 向内核注册 net_device |
table 3.
申请 mii_bus | 初始化 mii_bus | 向内核注册 mii_bus |
table 4.
申请 phy_device | 初始化 phy_device | 向内核注册 phy_device |
table3、table4 的过程嵌套在 table2 的过程中
fec_probe函数主要执行步奏
当内核启动的时候会执行module_platform_driver(fec_driver);
向 platform
总线注册 mac
驱动,当设备树的compatible
和驱动的compatible
匹配成功之后,会调用fec_probe
函数,此为mac驱动的真正入口。
主要代码解析如下
static int fec_probe(struct platform_device *pdev)
{
//1、获取设备树节点的句柄, 2、创建一个phy的设备树节点句柄
struct device_node *np = pdev->dev.of_node, *phy_node;
//从设备树中获取 fsl,num-tx-queues fsl,num-rx-queues 属性值
fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
//申请 net_device
nde = alloc_etherdev_mqs(sizeof(struct fec_enet_private) + FEC_STATS_SIZE, num_tx_qs, num_rx_qs);
//获取私有数据空间首地址
netdev_priv(ndev);
//从mac的设备树节点中获取phy子节点
of_parse_phandle(np, "phy-handle", 0);
//从设备树节点中获取phy模式,phy-mode = "rgmii-id";
of_get_phy_mode(pdev->dev.of_node);
//复位phy
fec_reset_phy(pdev);
//申请队列和DMA,设置MAC地址
fec_enet_init(struct net_device *ndev)
//唤醒中断
of_property_read_u32(np, "fsl,wakeup_irq", &irq);
//注册MDIO总线、注册phy_device,详解见下文
fec_enet_mii_init(pdev);
->mdiobus_alloc();
->of_get_child_by_name(pdev->dev.of_node, "mdio");
->of_mdiobus_register(fep->mii_bus, node);
//向内核注册net_device
register_netdev(ndev);
}
//注册MDIO总线、注册phy_device,主要代码解析如下
static int fec_enet_mii_init(struct platform_device *pdev)
{
//申请MDIO总线
fep->mii_bus = mdiobus_alloc();
//获取phy节点句柄
node = of_get_child_by_name(pdev->dev.of_node, "mdio");
//向内核注册MDIO总线,获取phy芯片id,向内核注册phy_device
of_mdiobus_register(fep->mii_bus, node);
->mdiobus_register(mdio);
-> get_phy_device(mdio, addr, xxx);
-> phy_device_register(phy);
}