三 Linux 网络驱动-MAC、PHY层驱动框架(11)


int (*, int n)
函数参数和返回值含义如下:
:需要注册的多个 PHY 驱动数组 。
n:要注册的驱动数量 。
返回值:0 成功 , 负值 失败 。
③、卸载 PHY 驱动
卸载 PHY 驱动的话使用 r 函数 , 函数原型如下:
void r(*drv)
函数参数和返回值含义如下:
:需要卸载的 PHY 驱动 。
返回值:无 。
3、MDIO 总线
前面说了 , PHY 子系统也是遵循设备、总线、驱动模型的 , 设备和驱动就是和。总线就是 MDIO 总线 , 因为 PHY 芯片是通过 MIDO 接口来管理的 , MDIO 总线最 主要的工作就是匹配 PHY 设备和 PHY 驱动 。在文件 /net/phy/.c 中有如下定义:
1 struct bus_type mdio_bus_type = {2.name = "mdio_bus",3.match = mdio_bus_match,4.pm = MDIO_BUS_PM_OPS,5.dev_groups = mdio_dev_groups,6 };
示例代码定义了一个名为“”的总线 , 这个就是 MDIO 总线 , 总线 的名字为“” , 重点是总线的匹配函数为。此函数内容如下:
1 static int mdio_bus_match(struct device *dev,struct device_driver *drv)2 {3struct phy_device *phydev = to_phy_device(dev);4struct phy_driver *phydrv = to_phy_driver(drv);5 6if (of_driver_match_device(dev, drv))7return 1;8 9if (phydrv->match_phy_device)10return phydrv->match_phy_device(phydev);1112return (phydrv->phy_id & phydrv->phy_id_mask) ==13(phydev->phy_id & phydrv->phy_id_mask);14 }
第 6 行 , 采用设备树的话先尝试使用 ce 来对设备和驱动进行匹配 , 也 就是检查属性值与匹配表里面的内容是否一致 。但是对于本章教程 而言 , 并不是通过 ce 来完成 PHY 驱动和设备匹配的 。
第 9、10 行 , 检查 PHY 驱动有没有提供匹配函数  , 如果有的话就直接调 用 PHY 驱动提供的匹配函数完成与设备的匹配 。
第 12、13 行 , 如果上面两个匹配方法都无效的话就使用最后一种 ,  里面有两个 成员变量和  , 表示此驱动所匹配的 PHY 芯片 ID 以及 ID 掩码 , PHY 驱动 编写人员需要给这两个成员变量赋值 。也有一个成员变量 , 表示此 PHY 芯 片的 ID ,  里面的是在注册 PHY 设备的时候调用函数直接读取 PHY 芯片内部 ID 寄存器得到的!很明显 PHY 驱动和 PHY 设备中的 ID 要一样 , 这样才能匹配 起来 。所以最后一种方法就是对比 PHY 驱动和 PHY 设备中的是否一致 , 这里需要与 PHY 驱动里面的进行与运算 , 如果结果一致的话就说明驱动和设备匹配 。
如果 PHY 设备和 PHY 驱动匹配 , 那么就使用指定的 PHY 驱动 , 如果不匹配的话就使用 Linux 内核自带的通用 PHY 驱动 。
4、通用 PHY 驱动
前面多次提到Linux内核已经集成了通用PHY驱动 , 通用PHY驱动名字为“ PHY” ,  打开 /net/phy/.c , 找到函数 , 内容如下:
1 static int __init phy_init(void)2 {3int rc;4 5rc = mdio_bus_init();6if (rc)7return rc;8 9rc = phy_drivers_register(genphy_driver,10ARRAY_SIZE(genphy_driver));11if (rc)12mdio_bus_exit();1314return rc;15 }
是整个 PHY 子系统的入口函数 , 第 9 行会调用函数向内核直 接注册一个通用 PHY 驱动: , 也就是通用 PHY 驱动 , 也就是说 Linux 系统启动 以后默认就已经存在了通用 PHY 驱动 。
是一个数组 , 有两个数组元素 , 表示有两个通用的 PHY 驱动 , 一个是针对 10/100/1000M 网络的 , 一个是针对10G 网络的 。定义在 /net/phy/.c 里面 , 内容如下: