这些结构体就是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 的过程中
当内核启动的时候会执行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); }