PHY设备驱动

news2025/7/15 6:36:18

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. 设备驱动与控制器驱动之间的关系图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/369116.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

零日漏洞发展格局及防御策略

在过去的一年半中&#xff0c; 在野利用的零日漏洞数量持续飙升 &#xff0c;这些软件制造商尚不知晓的漏洞正在被国家行为体黑客组织和勒索软件团伙滥用。 今年上半年&#xff0c;Google Project Zero统计了近20个零日漏洞&#xff0c;其中 大部分针对微软、苹果和谷歌构建的…

【《C Primer Plus》读书笔记】第13章:文件输入/输出

【《C Primer Plus》读书笔记】第13章&#xff1a;文件输入/输出13.1 与文件进行通信13.1.1 文件是什么13.1.2 文本模式和二进制模式13.1.3 I/O的级别13.1.4 标准文件13.2 标准I/O13.3 一个简单的文件压缩程序13.4 文件I/O&#xff1a;fprintf()、fscanf()、fgets()和fputs()13…

【LVGL】学习笔记--(1)Keil中嵌入式系统移植LVGL

一 LVGL简介最近emwin用的比较烦躁&#xff0c;同时被LVGL酷炫的界面吸引到了&#xff0c;所以准备换用LVGL试试水。LVGL(轻量级和通用图形库)是一个免费和开源的图形库&#xff0c;它提供了创建嵌入式GUI所需的一切&#xff0c;具有易于使用的图形元素&#xff0c;美丽的视觉效…

极光笔记 | 埋点体系建设与实施方法论

PART 01 前 言随着网络技术的发展&#xff0c;从粗犷型到精细化运营型&#xff0c;再到现在的数字化运营&#xff0c;数据变得越来越细分和重要&#xff0c;不仅可以进行策略调整&#xff0c;还可以实现自动化的精细化运营。而数据价值的起点就是埋点&#xff0c;只有合理地埋点…

[计算机网络(第八版)]第一章 概述(学习笔记)

1.1 计算机网络在信息时代中的作用 21世纪是以网络为核心的信息时代&#xff0c;21世纪的重要重要特征&#xff1a;数字化、网络化与信息化。 三大类网络 电信网络&#xff1a;向用户提供电话、电报、传真等服务&#xff1b;有线电视网络&#xff1a;向用户传送各种电视节目&am…

zabbix4.0-使用zabbix监控别的主机-使用模板来创建图形

目录 1、 配置zabbix的yum源 2、下载zabbix-agent 3、配置zabbix-agent的配置文件 4、关闭防火墙&#xff0c;selinux 5、重启zabbix-agent 6、连通性测试&#xff0c;在zabbix-server服务器上面使用zabbix_get获取zabbix-agent服务器上的数据 7、在zabbix web端配置zab…

Windows 11 22H2 中文版、英文版 (x64、ARM64) 下载 (updated Feb 2023)

Windows 11, version 22H2&#xff0c;2023 年 2 月 更新 请访问原文链接&#xff1a;https://sysin.org/blog/windows-11/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;www.sysin.org 全新推出 Windows 11 全新 Windows 体验&#x…

考PMP的用处有哪些?备考攻略+资料分享

说到底&#xff0c;考PMP就是为了给工作提供便利&#xff0c;你考了之后会用它&#xff0c;将学习的东西运用到工作中&#xff0c;比如提高项目完成率&#xff0c;能升职加薪啊等等&#xff0c;那自然很是有用的。 不用&#xff0c;那就只是一张当摆设的纸&#xff0c;当然&am…

项目经理如何度量项目?及项目度量指标实例【静说】

度量项目是项目经理的一个重要职责&#xff0c;通过度量项目&#xff0c;项目经理可以了解项目的进展情况&#xff0c;及时发现问题并采取相应的措施&#xff0c;以确保项目能够按时、按质、按预算完成。 分享给大家一些常见的项目度量指标&#xff1a; 1. 项目进度&#xff…

docker-compose 简单配置php和nginx及注意事项

docker-compose.yml内容&#xff1a; /docker/web/config/nginx/conf/default.conf内容&#xff1a; server { listen 80; server_name localhost; root /usr/share/nginx/html; error_log /var/log/nginx/localhost.log; location / { try_files $…

ESP32-FPV-Camera介绍和使用

ESP32-FPV-Camera介绍和使用1. 编译目标2. 编译步骤Step 1 软件配置环境准备Step 2 获取开源代码Step 3 2.4G WiFi频段选择Step 4 要确保2.4G WiFi网卡处于Monitor状态Step 5 修改频点相关代码Step 6 修改WiFi网卡相关代码Step 7 OpenGL 版本问题Step 8 构建天空端Step 9 构建地…

从0开始写Vue项目-Vue实现用户数据批量上传和数据导出

从0开始写Vue项目-环境和项目搭建_慕言要努力的博客-CSDN博客从0开始写Vue项目-Vue2集成Element-ui和后台主体框架搭建_慕言要努力的博客-CSDN博客从0开始写Vue项目-Vue页面主体布局和登录、注册页面_慕言要努力的博客-CSDN博客从0开始写Vue项目-SpringBoot整合Mybatis-plus实现…

04--WXML

1、什么是WXML什么是Wxml呢&#xff1f;我们首先要介绍一下Html&#xff0c;Html的全称为HyperTextMarkup Language&#xff0c;翻译过来就是超文本标记语言&#xff0c;这种语言目前已经普遍用于前端开发&#xff0c;而wxml正是从html演变而来&#xff0c;它基于微信这个平台&…

4EVERLAND:ERC-721 Token的存储选择

4EVERLAND&#xff1a;一个 Web3 基础设施&#xff0c;可促进项目更轻松、更快速地托管前端、存储数据/NFT/文件&#xff0c;并在 IPFS、Arweave 和 Dfinity 之上访问它们。 NFT , 数字所有权 使用以太坊标准的 NFT 创新ERC-721解决了互联网内容的主要问题之一&#xff1a;所…

计算机网络(2)从十六进制的ip数据报中得到详细字段信息

本博文介绍如何将十六进制的ip报文拆分出具体的字段信息。社会计算机网络和网络协议分析的初学者参考&#xff08;今天看了网络协议分析期末复习重点的最后一个大题&#xff0c;竟然一头雾水&#xff0c;然后快马加鞭翻阅各种资料&#xff0c;然后差不多学会 了&#xff09;wir…

RK3568平台开发系列讲解(驱动基础篇)中断子系统框架

🚀返回专栏总目录 文章目录 一、中断硬件的组成二、软件框架三、中断常见概念沉淀、分享、成长,让自己和他人都能有所收获!😄 📢中断是指 CPU 正常运行期间,由于内外部事件或程序预先安排的事件,引起的 CPU 暂时停止正在运行的程序, 转而为该内部或外部预先安排的事…

零基础入门反序列化及常用trick

前言 反序列化是一个尤为重要的知识点&#xff0c;最近对反序列化进行了简单学习&#xff0c;并总结如下&#xff0c;希望能对正在学习的师傅有所帮助。 前提 了解序列化和反序列化 学习反序列化之前&#xff0c;首先要知道序列化&#xff0c;简单的举个栗子来说 <?ph…

C语言学习及复习笔记-【10】数组

10. 字符串 定义&#xff1a;在 C 语言中&#xff0c;字符串实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。因此&#xff0c;一个以 null 结尾的字符串&#xff0c;包含了组成字符串的字符。 以下是 C/C 中定义的字符串的内存表示&#xff1a; 10.1 C 中有大量操作字符串…

Linux 脚本(sh)之 定时清理悬空、指定镜像,自动增长版本号

定时任务(images_clean)&#xff1a; 位置&#xff1a;/mydata/hostmachine_jenkins/images_clean.sh 作用&#xff1a;Jenkins发布之后&#xff0c;遗留下来的老版镜像以及悬空镜像进行定时清理 注意&#xff1a;如果你需要发布新的服务&#xff0c;那么你需要进入当前目录…

Git导出增量包的操作步骤

前言在项目开发部署中&#xff0c;通常是将一个Git项目全量打包发布&#xff0c;但有的场景只需要导出有变更的那部分文件&#xff0c;增量发布&#xff0c;此时就需要使用Git导出增量包了。一、查看提交记录拿到提交ID码①例如使用的gitlab使用方法参考下图(一目了然) 【推荐】…