PHY设备驱动
1. 概述
MAC控制器的驱动使用的是platform总线的连接方式,PHY设备驱动是基于device、driver、bus的连接方式。
其驱动涉及如下几个重要部分:
总线 - sturct mii_bus (mii stand for media independent interface)
设备 - struct phy_device
驱动 - struct phy_driver
phy设备不像i2c/spi有一个board_info函数进行设备的添加,而是直接读取phy中的寄存器<根据IEEE的规定,PHY芯片的前16个寄存器的内容必须是固定的>。
2. mdio_bus总线
2.1 总线注册的入口函数
# linux-4.9.225\drivers\net\phy\phy_device.c
static int __init phy_init(void)
{int rc;rc = mdio_bus_init(); //mdio_bus总线的注册if (rc)return rc;rc = phy_drivers_register(genphy_driver,ARRAY_SIZE(genphy_driver), THIS_MODULE); //通用PHY驱动if (rc)mdio_bus_exit();return rc;
}subsys_initcall(phy_init);
subsys_initcall(phy_init) 这行的作用非常重要,这一行就决定了内核在启动的时候会调用该函数,注册完了之后紧接着又注册一个通用的PHY驱动。
2.2 总线注册函数— mdio_bus_init解析
# linux-4.9.225\drivers\net\phy\mdio_bus.c
static struct class mdio_bus_class = {.name = "mdio_bus",.dev_release = mdiobus_release,
};static int mdio_bus_match(struct device *dev, struct device_driver *drv)
{struct mdio_device *mdio = to_mdio_device(dev);if (of_driver_match_device(dev, drv))return 1;if (mdio->bus_match)return mdio->bus_match(dev, drv);return 0;
}struct bus_type mdio_bus_type = {.name = "mdio_bus", //总线名称.match = mdio_bus_match, //用来匹配总线上设备和驱动的函数.pm = MDIO_BUS_PM_OPS,
};
EXPORT_SYMBOL(mdio_bus_type);int __init mdio_bus_init(void)
{int ret;ret = class_register(&mdio_bus_class); //注册设备类 (在linux设备模型中,我再仔细讲这个类的概念)if (!ret) {ret = bus_register(&mdio_bus_type);//总线注册if (ret)class_unregister(&mdio_bus_class);}return ret;
}
其中
(1) class_register(&mdio_bus_class)执行后会有以下设备类:
/sys/class/mdio_bus
(2)bus_register(&mdio_bus_type)执行后会有以下总线类型:
/sys/bus/mdio_bus
2.3 总线中的match函数解析
/*** mdio_bus_match - determine if given MDIO driver supports the given* MDIO device* @dev: target MDIO device* @drv: given MDIO driver** Description: Given a MDIO device, and a MDIO driver, return 1 if* the driver supports the device. Otherwise, return 0. This may* require calling the devices own match function, since different classes* of MDIO devices have different match criteria.*/
static int mdio_bus_match(struct device *dev, struct device_driver *drv)
{struct mdio_device *mdio = to_mdio_device(dev);if (of_driver_match_device(dev, drv))return 1;if (mdio->bus_match) //实现匹配的函数return mdio->bus_match(dev, drv);return 0;
}
3. 设备驱动的注册
在phy_init函数中不仅注册了mdio_bus总线,还注册了一个通用的PHY驱动作为缺省的内核PHY驱动,但是如果PHY芯片的内部寄存器和802.3定义的并不一样或者需要特殊的功能配置以实现更强的功能,这就需要专有的驱动。
对于市场上存在的主流PHY品牌,一般在内核源码 drivers\net\phy目录下都有对应的驱动。本节主要以realtek RTL8211F为例,讲述PHY的驱动,代码如下:
# linux-4.9.225\drivers\net\phy\realtek.c
static struct phy_driver realtek_drvs[] = {......, {.phy_id = 0x001cc916,.name = "RTL8211F Gigabit Ethernet",.phy_id_mask = 0x001fffff,.features = PHY_GBIT_FEATURES,.flags = PHY_HAS_INTERRUPT,.config_aneg = &genphy_config_aneg,.config_init = &rtl8211f_config_init,.read_status = &genphy_read_status,.ack_interrupt = &rtl8211f_ack_interrupt,.config_intr = &rtl8211f_config_intr,.suspend = genphy_suspend,.resume = genphy_resume,},
};module_phy_driver(realtek_drvs); //注册PHY驱动static struct mdio_device_id __maybe_unused realtek_tbl[] = {{ 0x001cc912, 0x001fffff },{ 0x001cc914, 0x001fffff },{ 0x001cc915, 0x001fffff },{ 0x001cc916, 0x001fffff },{ }
};MODULE_DEVICE_TABLE(mdio, realtek_tbl);
3.1 phy驱动的注册
同一品牌的PHY设备有多种不同的型号,内核为了支持一次可以注册多个型号的PHY的驱动,在include\linux\phy.h中提供了用于注册PHY驱动的宏module_phy_driver。该宏的定义如下:
# linux-4.9.225\include\linux\phy.h#define phy_module_driver(__phy_drivers, __count) \
static int __init phy_module_init(void) \
{ \return phy_drivers_register(__phy_drivers, __count, THIS_MODULE); \
} #define module_phy_driver(__phy_drivers) \phy_module_driver(__phy_drivers, ARRAY_SIZE(__phy_drivers))
phy_driver_register定义如下(注意这里与老版本内核有一定的改动)
/*** phy_driver_register - register a phy_driver with the PHY layer* @new_driver: new phy_driver to register* @owner: module owning this PHY*/
int phy_driver_register(struct phy_driver *new_driver, struct module *owner)
{int retval;new_driver->mdiodrv.flags |= MDIO_DEVICE_IS_PHY;new_driver->mdiodrv.driver.name = new_driver->name;//驱动名称new_driver->mdiodrv.driver.bus = &mdio_bus_type; //驱动挂载的总线new_driver->mdiodrv.driver.probe = phy_probe; //PHY设备和驱动匹配后调用的probe函数 new_driver->mdiodrv.driver.remove = phy_remove;new_driver->mdiodrv.driver.owner = owner;retval = driver_register(&new_driver->mdiodrv.driver); //向linux设备模型框架中注册device_driver驱动if (retval) {pr_err("%s: Error %d in registering driver\n",new_driver->name, retval);return retval;}pr_debug("%s: Registered new driver\n", new_driver->name);return 0;
}int phy_drivers_register(struct phy_driver *new_driver, int n,struct module *owner)
{int i, ret = 0;for (i = 0; i < n; i++) {ret = phy_driver_register(new_driver + i, owner);//注册数组中所有的phy驱动if (ret) {while (i-- > 0)phy_driver_unregister(new_driver + i);break;}}return ret;
}
3.2 MODULE_DEVICE_TABLE(mdio, realtek_tbl)解析
宏定义展开后如下:
#define MODULE_DEVICE_TABLE(mdio, realtek_tbl) \
extern const struct mdio_device_id __mod_mdio__realtek_tbl_device_table \__attribute__ ((unused, "realtek_tbl")))
4. 设备驱动与控制器驱动之间的关系图
相关文章:

PHY设备驱动
1. 概述 MAC控制器的驱动使用的是platform总线的连接方式,PHY设备驱动是基于device、driver、bus的连接方式。 其驱动涉及如下几个重要部分: 总线 - sturct mii_bus (mii stand for media independent interface) 设备 - struct phy_device 驱动 - struc…...

Linux——UDP协议与相关套接字编程
一.概念在网络通信中,传输层中最常用的通信协议有两个:TCP协议与UDP协议。这两种协议虽然都可以用于网络通信,但是通信方式不同决定了应用场景的不同。与TCP协议相比,UDP协议最具特色的不同点有两个:无连接与面向数据报…...
EM算法 简明理解
E:Expection,期望步,利用估计的参数,来确定未知因变量的概率,并利用其来计算期望值。 M:Maximization,最大化,使用最大似然法更新参数值,使E步中期望值出现的概率最大。…...

论坛项目小程序和h5登录
项目中安装uview出现npm安装uview 直接报错:创建一个package.json配置文件在进行安装。cmd到项目。初始化一个package.json文件(vue项目的配置文件) npm init --yes 安装uview项目点击关注进入管页面,需要验证用户是否登录查用户是…...

kubernetes集群pod中的pause容器作用
kubernetes集群pod中的pause容器作用 我们搭建完集群了以后,可以使用最简单的方式创建一个pod,随意你建立什么pod,去访问相应node上执行docker ps 就会看到有一种pause容器,但是你可能从来没有启用 etrics-scraper_dashboard-me…...
【2.24】malloc()分配内存、MySQL事务、项目、动态规划
malloc是如何分配内存的? 在 Linux 操作系统中,虚拟地址空间的内部又被分为内核空间和用户空间两部分,不同位数的系统,地址空间的范围也不同。比如最常见的 32 位和 64 位系统,如下所示: 内核空间与用户空…...

Unity——使用铰链关节制作悬挂物体效果
目的在场景中创建一个悬挂的物体,是把多个模型悬挂在一起可以自由摇摆,类似链条的效果效果图前言什么是铰链关节?铰链关节 将两个刚体(Rigid body)组会在一起,从而将其约束为如同通过铰链连接一样进行移动。…...

plsql过程语言之uxdb与oracle语法差异
序号场景uxdboracle1在存储过程中使用goto子句create or replace procedure uxdbc_oracle_extension_plsql_goto_0001_procedure01(t1 int) language plsql as $$ begin if t1%20 then goto even_number; else goto odd_number; end if; <<even_number>> raise…...

file_get_contents 打开本地文件报错: failed to open stream: No such file or directory
php 使用file_get_contents时报错 failed to open stream: No such file or directory (打开流失败,没有这样的文件或目录) 1. 首先确保文件路径没问题 最好是直接复制一下文件的路径 2. windows电脑可以右键该文件 → 属性→安全 →对象名称 选中后复制一下 3. 然后…...

Candence allegro 创建等长的方法
随着源同步时序电路的发展,越来越多的并行总线开始采用这种时序控制电路,最典型的代表当属目前炙手可热的DDRx系列。下图这种点到点结构的同步信号,对于攻城狮来说,设置等长约束就非常easy了图片。 But,对于有4、6、8、、、等多颗DDR芯片的ACC同步信号来说,要设置等长约束…...
使用Python批量修改文件名称
下载了一些图片,想要更改其文件的名称。 试了许多方法,都不太理想。 于是想到了使用Python来实现。 需要用到的模块及函数: import osrename() 函数用于改变文件或文件夹的名称。它接受两个参数:原文件名和新文件名。 os.rena…...
【跟我一起读《视觉惯性SLAM理论与源码解析》】第八章 ORB-SLAM2中的特征匹配
特征匹配在ORB-SLAM2中是很重要的内容,函数有多次重载,一般而言分为以下 单目初始化下的特征匹配通过词袋进行特征匹配通过地图点投影进行特征匹配通过Sim(3)变化进行特征匹配 在单目初始化下的特征匹配是参考帧和当前帧之间的特…...

【Leedcode】数据结构中链表必备的面试题(第四期)
【Leedcode】数据结构中链表必备的面试题(第四期) 文章目录【Leedcode】数据结构中链表必备的面试题(第四期)1.题目2.思路图解(1)思路一(2)思路二3.源代码总结1.题目 相交链表: 如下(示例)&…...

【2023】助力Android金三银四面试
前言 新气象,新生机。在2023年的Android开发行业中,又有那些新的面试题出现呢?对于Android面试官的拷问,我们又如何正确去解答?万变不离其宗,其实只要Android的技术层面没变化,面试题也就是差不…...

Leetcode.1801 积压订单中的订单总数
题目链接 Leetcode.1801 积压订单中的订单总数 Rating : 1711 题目描述 给你一个二维整数数组 orders,其中每个 orders[i] [pricei, amounti, orderTypei]表示有 amounti笔类型为 orderTypei、价格为 pricei的订单。 订单类型 orderTypei 可以分为两种…...

红帽Linux技术-cp命令
cp是一个复制文件或者目录的命令,其作用是将一个或多个文件或目录从源位置复制到目标位置。 格式:cp [选项] 源文件或目录 目标文件或目录 常用选项: -r:复制目录及其子目录下的所有文件和目录; -p:保留…...

代码随想录算法训练营day41 | 动态规划 01背包问题基础 01背包问题之滚动数组
01背包问题基础 问题描述 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。 举个栗子 背包最大重量为4。 物品为: 重量价值…...

MyBatis学习笔记(三) —— MyBatis核心配置文件详解
3、核心配置文件详解 id是唯一标识,不能重复,但是在真正开发过程中,不可能一个项目中同时使用两个环境,肯定会使用其中的某一个,这时候它的default就比较重要了。 default是设置我们当前使用的默认环境的id <?x…...

使用GDAL进行坐标转换
1、地理坐标系与投影坐标系空间参考中主要包含大地水准面、地球椭球体、投影坐标系等几部分内容。地图投影就是把地球表面的任意点,利用一定数学法则,转换到地图平面上的理论和方法,一般有两种坐标系来进行表示,分别是地理坐标系和…...

日常编程中和日期相关的代码和bug
本文主要是Java中和日期时间相隔的几个常用代码函数代码,做了总结,希望在日常编码中,可以帮到大家。 1.计算闰年 记住一个短语,“四年一润,百年不闰,四百再润”,不管换啥语言,相信…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...

nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...

PH热榜 | 2025-06-08
1. Thiings 标语:一套超过1900个免费AI生成的3D图标集合 介绍:Thiings是一个不断扩展的免费AI生成3D图标库,目前已有超过1900个图标。你可以按照主题浏览,生成自己的图标,或者下载整个图标集。所有图标都可以在个人或…...
node.js的初步学习
那什么是node.js呢? 和JavaScript又是什么关系呢? node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说, 需要在node.js的环境上进行当JavaScript作为前端开发语言来说,需要在浏览器的环境上进行 Node.js 可…...