手把手教你写一个Linux下的mdio调试工具(附完整C代码)
从零构建Linux MDIO调试工具深入PHY寄存器操作实战当你面对一块没有预装mii-tool或ethtool的嵌入式开发板或者需要直接操作PHY芯片寄存器进行底层调试时自己动手编写一个轻量级MDIO工具会成为解决问题的关键。本文将带你深入Linux内核的MII接口机制从Socket通信到ioctl调用完整实现一个可读写PHY寄存器的命令行工具。1. MDIO工具开发基础与环境准备MDIOManagement Data Input/Output是IEEE 802.3定义的双线串行接口用于MAC与PHY之间的管理通信。在Linux系统中内核通过MII ioctl接口向用户空间暴露了这一能力。我们的工具本质上是一个精心设计的ioctl调用封装器。开发环境需要准备运行Linux的开发板或PC内核版本≥2.6GCC工具链基本的C编程知识目标网络设备的PHY芯片手册关键头文件包括#include linux/mii.h // MII相关数据结构 #include sys/ioctl.h // ioctl系统调用 #include net/if.h // 网络接口定义2. 核心架构设计与实现2.1 网络接口初始化工具首先需要绑定到特定网络接口。我们使用socket创建本地数据报套接字作为ioctl的通信通道int sockfd socket(PF_LOCAL, SOCK_DGRAM, 0); if (sockfd 0) { perror(socket creation failed); return -1; } struct ifreq ifr; memset(ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, argv[1], IFNAMSIZ - 1);2.2 PHY地址自动发现通过SIOCGMIIPHYioctl可以获取接口关联的PHY地址这避免了手动配置的麻烦int ret ioctl(sockfd, SIOCGMIIPHY, ifr); if (ret 0) { perror(Failed to get PHY address); close(sockfd); return -1; } struct mii_ioctl_data *mii (struct mii_ioctl_data*)ifr.ifr_data; printf(Discovered PHY ID: 0x%x\n, mii-phy_id);2.3 寄存器读写实现读写操作分别使用SIOCGMIIREG和SIOCSMIIREG命令。我们设计统一的错误处理机制#define CMD_READ 1 #define CMD_WRITE 2 int handle_mdio_op(int sockfd, struct ifreq *ifr, int cmd, uint16_t reg, uint16_t val) { struct mii_ioctl_data *mii (struct mii_ioctl_data*)ifr-ifr_data; mii-reg_num reg; if (cmd CMD_WRITE) { mii-val_in val; return ioctl(sockfd, SIOCSMIIREG, ifr); } else { int ret ioctl(sockfd, SIOCGMIIREG, ifr); if (ret 0) { printf(REG 0x%x: 0x%04x\n, reg, mii-val_out); } return ret; } }3. 命令行接口设计良好的CLI设计能提升工具易用性。我们支持以下命令格式mdio-tool interface read reg mdio-tool interface write reg value实现代码框架int main(int argc, char **argv) { if (argc 4 || strcmp(argv[2], read) 0 argc ! 4 || strcmp(argv[2], write) 0 argc ! 5) { print_usage(argv[0]); return 1; } // 初始化socket和ifreq... if (strcmp(argv[2], read) 0) { uint16_t reg strtoul(argv[3], NULL, 0); handle_mdio_op(sockfd, ifr, CMD_READ, reg, 0); } else if (strcmp(argv[2], write) 0) { uint16_t reg strtoul(argv[3], NULL, 0); uint16_t val strtoul(argv[4], NULL, 0); handle_mdio_op(sockfd, ifr, CMD_WRITE, reg, val); } close(sockfd); return 0; }4. 高级功能扩展4.1 批量寄存器操作添加批量读取功能方便调试时扫描寄存器空间void scan_registers(int sockfd, struct ifreq *ifr, uint16_t start, uint16_t end) { printf(Scanning registers 0x%x-0x%x:\n, start, end); for (uint16_t reg start; reg end; reg) { if (handle_mdio_op(sockfd, ifr, CMD_READ, reg, 0) 0) { // 输出已在handle_mdio_op中处理 } else { fprintf(stderr, Failed to read reg 0x%x\n, reg); } } }4.2 权限处理与错误恢复MDIO操作通常需要root权限。我们添加友好的错误提示if (geteuid() ! 0) { fprintf(stderr, Error: This tool requires root privileges\n); fprintf(stderr, Try running with sudo or as root user\n); return -EPERM; }对于常见的错误代码提供解释性信息错误代码含义建议解决方案EINVAL无效参数检查寄存器地址是否有效ENODEV设备不存在确认接口名称正确EIOPHY通信错误检查MDIO总线连接EPERM权限不足以root用户运行5. 编译与使用指南使用以下命令编译工具gcc mdio-tool.c -o mdio-tool -Wall -Wextra实际应用示例读取PHY ID寄存器通常为寄存器2sudo ./mdio-tool eth0 read 2修改PHY控制寄存器寄存器0的复位位sudo ./mdio-tool eth0 write 0 0x8000扫描前16个寄存器sudo ./mdio-tool eth0 scan 0 15调试技巧结合ethtool -d的输出对比寄存器值修改前务必记录原始值以便恢复某些寄存器位是只读的写入会失败
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2589157.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!