2026/5/21 11:27:44
网站建设
项目流程
必要 网站,苏州电商网站开发,wordpress的阅读量,设计营销型网站接前一篇文章#xff1a;Linux MDIO子系统深度剖析#xff1a;从原理到实践#xff08;4#xff09; 五、用户空间访问实例
1. 使用ioctl访问PHY寄存器
虽然大多数情况下PHY的管理由内核驱动自动处理#xff0c;但在调试或特殊应用场景中#xff0c;用户空间程序可能需…接前一篇文章Linux MDIO子系统深度剖析从原理到实践4五、用户空间访问实例1. 使用ioctl访问PHY寄存器虽然大多数情况下PHY的管理由内核驱动自动处理但在调试或特殊应用场景中用户空间程序可能需要直接访问PHY寄存器。Linux提供了通过socket ioctl接口访问PHY寄存器的能力这为用户空间工具提供了底层的PHY管理功能。主要的ioctl命令包括SIOCGMIIPHY获取MDIO总线上的当前PHY地址。SIOCGMIIREG读取指定PHY寄存器的值。SIOCSMIIREG设置指定PHY寄存器的值。这些ioctl命令使用struct mii_ioctl_data作为数据传输结构其定义如下struct mii_ioctl_data { __u16 phy_id; // PHY 设备地址 __u16 reg_num; // 寄存器地址 __u16 val_in; // 写入的值用于写操作 __u16 val_out; // 读取的值用于读操作 };这种用户空间的访问机制类似于提供了一个硬件调试终端让开发者和系统管理员能够直接与PHY芯片对话检查状态、修改配置或进行故障诊断。2. 完整代码示例以下是一个完整的用户空间MDIO工具实现支持读取和写入PHY寄存器。这个工具可以编译为命令行程序用于调试和配置PHY设备。#include stdio.h #include stdlib.h #include string.h #include linux/mii.h #include sys/types.h #include sys/socket.h #include sys/ioctl.h #include net/if.h #include linux/sockios.h #include linux/types.h #include netinet/in.h #define reteck(ret) \ if(ret 0){ \ printf(%m! \%s\ : line: %d\n, __func__, __LINE__); \ goto lab; \ } #define help() \ printf(mdio: 一个用户空间 MDIO 调试工具\n); \ printf(读取操作: mdio 接口名 寄存器地址\n); \ printf(写入操作: mdio 接口名 寄存器地址 数值\n); \ printf(示例:\n); \ printf(mdio eth0 1\t# 读取 eth0 的 PHY 寄存器 1\n); \ printf(mdio eth0 0 0x1120\t# 向 eth0 的 PHY 寄存器 0 写入 0x1120\n\n); \ int sockfd; int main(int argc, char *argv[]){ if(argc 1 || !strcmp(argv[1], -h)){ help(); return 0; } struct mii_ioctl_data *mii NULL; struct ifreq ifr; int ret; memset(ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, argv[1], IFNAMSIZ - 1); sockfd socket(PF_LOCAL, SOCK_DGRAM, 0); reteck(sockfd); // 获取 PHY 地址 ret ioctl(sockfd, SIOCGMIIPHY, ifr); reteck(ret); mii (struct mii_ioctl_data*)ifr.ifr_data; if(argc 3){ // 读取操作 mii-reg_num (uint16_t)strtoul(argv[2], NULL, 0); ret ioctl(sockfd, SIOCGMIIREG, ifr); reteck(ret); printf(读取 PHY 地址: 0x%x 寄存器: 0x%x 值: 0x%x\n, mii-phy_id, mii-reg_num, mii-val_out); // 检查链路状态寄存器 1 的第 2 位 if (mii-reg_num 1) { if (mii-val_out 0x0004) { printf(链路状态: UP\n); } else { printf(链路状态: DOWN\n); } } } else if(argc 4){ // 写入操作 mii-reg_num (uint16_t)strtoul(argv[2], NULL, 0); mii-val_in (uint16_t)strtoul(argv[3], NULL, 0); ret ioctl(sockwd, SIOCSMIIREG, ifr); reteck(ret); printf(写入 PHY 地址: 0x%x 寄存器: 0x%x 值: 0x%x\n, mii-phy_id, mii-reg_num, mii-val_in); } else { help(); } lab: if (sockfd 0) close(sockfd); return 0; }3. 编译与运行这个MDIO工具可以很容易地编译和使用1编译gcc -o mdio mdio_tool.c2安装可选sudo cp mdio /usr/local/bin/3使用示例读取PHY状态寄存器寄存器 1./mdio eth0 1输出结果读取 PHY 地址: 0x1 寄存器: 0x1 值: 0x796d 链路状态: UP写入PHY控制寄存器寄存器0./mdio eth0 0 0x1140输出结果写入 PHY 地址: 0x1 寄存器: 0x0 值: 0x1140检查链路状态./mdio eth0 1然后检查输出中的值寄存器1的第2位从0开始计数表示链路状态1表示链路UP0表示链路DOWN。这个工具提供了对PHY寄存器的底层访问能力对于调试网络连接问题、验证PHY配置或学习 MDIO总线工作原理都非常有用。但需要注意的是不当的寄存器修改可能会导致网络连接中断因此在生产环境中使用需要格外小心。更多内容请看下回。