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


一个 PHY 设备对应一个实例 , 然后需要向 Linux 内核注册这个实例 。使用函数完成 PHY 设备的注册 , 函数原型如下:
int (*phy)
函数参数和返回值含义如下:
phy:需要注册的 PHY 设备 。
返回值:0 成功 , 负值 失败 。
PHY 设备的注册过程一般是先调用函数获取 PHY 设备 , 此函数内容如下:
1 struct phy_device *get_phy_device(struct mii_bus *bus, int addr,bool is_c45)2 {3struct phy_c45_device_ids c45_ids = {0};4u32 phy_id = 0;5int r;6 7r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);8if (r)9return ERR_PTR(r);1011/* If the phy_id is mostly Fs, there is no device there */12if ((phy_id & 0x1fffffff) == 0x1fffffff)13return NULL;1415return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);16 }
第 7 行 , 调用函数获取 PHY ID , 也就是读取 PHY 芯片的那两个 ID 寄存器 ,  得到 PHY 芯片 ID 信息 。
第 15 行 , 调用函数创建  , 此函数先申请内存 , 然 后初始化的各个结构体成员 , 最终返回创建好的。函 数注册的就是这个创建好的。
2、PHY 驱动
PHY 驱动使用结构体表示 , 结构体也定义在 /linux/phy.h 文件中 , 结构体 内容如下(为了缩小篇幅 , 省略了注释部分):
1 struct phy_driver {2u32 phy_id; /* PHY ID */3char *name;4unsigned int phy_id_mask; /* PHY ID 掩码 */5u32 features;6u32 flags;7const void *driver_data;8 9int (*soft_reset)(struct phy_device *phydev);10int (*config_init)(struct phy_device *phydev);11int (*probe)(struct phy_device *phydev);12int (*suspend)(struct phy_device *phydev);13int (*resume)(struct phy_device *phydev);14int (*config_aneg)(struct phy_device *phydev);15int (*aneg_done)(struct phy_device *phydev);16int (*read_status)(struct phy_device *phydev);17int (*ack_interrupt)(struct phy_device *phydev);18int (*config_intr)(struct phy_device *phydev);19int (*did_interrupt)(struct phy_device *phydev);20void (*remove)(struct phy_device *phydev);21int (*match_phy_device)(struct phy_device *phydev);22int (*ts_info)(struct phy_device *phydev,struct ethtool_ts_info *ti);23int (*hwtstamp)(struct phy_device *phydev, struct ifreq *ifr);24bool (*rxtstamp)(struct phy_device *dev, struct sk_buff *skb,int type);25void (*txtstamp)(struct phy_device *dev, struct sk_buff *skb,int type);26int (*set_wol)(struct phy_device *dev,struct ethtool_wolinfo *wol);27void (*get_wol)(struct phy_device *dev,struct ethtool_wolinfo *wol);28void (*link_change_notify)(struct phy_device *dev);29int (*read_mmd_indirect)(struct phy_device *dev, int ptrad,30int devnum, int regnum);31void (*write_mmd_indirect)(struct phy_device *dev, int ptrad,32int devnum, int regnum, u32 val);33int (*module_info)(struct phy_device *dev,34struct ethtool_modinfo *modinfo);35int (*module_eeprom)(struct phy_device *dev,36struct ethtool_eeprom *ee, u8 *data);3738struct device_driver driver;39 };
可以看出 ,  重点是大量的函数 , 编写 PHY 驱动的主要工作就是实现这些函数 ,  但是不一定全部实现 , 稍后我们会简单分析一下 Linux 内核通用 PHY 驱动 。
①、注册 PHY 驱动
结构体初始化完成以后 , 就需要向 Linux 内核注册 , PHY 驱动的注册使用函数 , 注册phy驱动的时候会设置驱动的总线为 , 也就是MDIO 总线 , 关于 MDIO 总线稍后会讲解 , 函数原型如下:
int (*)
函数参数和返回值含义如下:
:需要注册的 PHY 驱动 。
返回值:0 成功 , 负值 失败 。
②、连续注册多个 PHY 驱动
一个厂家会生产多种 PHY 芯片 , 这些 PHY 芯片内部差别一般不大 , 如果一个个的去注册 驱动将会导致一堆重复的驱动文件 , 因此 Linux 内核提供了一个连续注册多个 PHY 驱动的函数。首先准备一个数组 , 一个数组元素就表示一个 PHY 芯片的驱 动 , 然后调用一次性注册整个数组中的所有驱动 , 函数原型如下: