Linux 设备驱动模型

Linux网络设备驱动——驱动模型 Linux素来以其强大的网络功能著名,同时, 设备'>网络设备也作为三大设备之一, 成为Linux驱动学习中必不可少的设备类型, 此外, 由于历史原因, Linux并没有强制对设备'>网络设备贯彻其”一切皆文件”的思想, 设备'>网络设备不以/dev下的设备文件为接口,用户程序通过socket作为访问硬件的接口。sk_buff部分定义如下。是设备'>网络设备媒介层相设备驱动功能层发送数据的接口, 网卡接收到数据是通过中断的方式上报的, 所以网络驱动中的中断处理函数就是第一时间队接收到的数据进行处理的地方, 阅读详情

做Linux做么多年,虽然说看了很多,还没有写过这边方便的博客,今天接学习的机会,来记录下同时复习下

1. 引入设备驱动模型的目的

关于linux设备驱动模型应该有很多文章和博客已经记录和阐述了,至于为什么linux要设计这么一个设备驱动的软件架构,可以看看宋宝华老师的《Linux驱动设备开发详解》第十二章

设备驱动模型有三个重要组件,分别是总线(bus type)、设备(device)和驱动(driver)

  • 总线,主要起连接设备和驱动的作用
  • 设备,顾名思义对应硬件上的设备
  • 驱动,一套操作硬件的方法

在不使用设备驱动模型是,一个外设的驱动在特定的CPU上运行需要一套特定的驱动,那么在多个不同的CPU上就需要多个驱动,按照这种逻辑,N个同类型的外设在M个不同的CPU上就需要N*M份驱动,这种是典型的强耦合,不符合软件工程的基本原则,引用宋宝华老师书上的图片如下
在这里插入图片描述在这里插入图片描述
使用了设备驱动模型后只需要N+M个驱动

2. 设备驱动模型分析

典型的设备驱动模型有platform设备驱动、i2c/spi驱动、块设备、input设备、tty、usb等诸多设备驱动,下面我们具体分析从platform驱动设备来理清bus、driver、device之前的关系

2.1 bus注册

汇编代码.S文件调用
kernel-5.10/init/main.c start_kernel ---->arch_call_rest_init----->rest_init---->kernel_init ---->kernel_init_freeable ---->do_basic_setup ---->driver_init ---->platform_bus_init---->bus_register


struct bus_type platform_bus_type = {
	.name		= "platform",
	.dev_groups	= platform_dev_groups,
	.match		= platform_match,
	.uevent		= platform_uevent,
	.dma_configure	= platform_dma_configure,
	.pm		= &platform_dev_pm_ops,
};


struct bus_type {
	const char		*name;
	const char		*dev_name;
	struct device		*dev_root;
	const struct attribute_group **bus_groups;
	const struct attribute_group **dev_groups;
	const struct attribute_group **drv_groups;

	int (*match)(struct device *dev, struct device_driver *drv);
	int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
	int (*probe)(struct device *dev);
	void (*sync_state)(struct device *dev);
	int (*remove)(struct device *dev);
	void (*shutdown)(struct device *dev);

	int (*online)(struct device *dev);
	int (*offline)(struct device *dev);

	int (*suspend)(struct device *dev, pm_message_t state);
	int (*resume)(struct device *dev);

	int (*num_vf)(struct device *dev);

	int (*dma_configure)(struct device *dev);

	const struct dev_pm_ops *pm;

	const struct iommu_ops *iommu_ops;

	struct subsys_private *p;
	struct lock_class_key lock_key;

	bool need_parent_lock;

	ANDROID_KABI_RESERVE(1);
	ANDROID_KABI_RESERVE(2);
	ANDROID_KABI_RESERVE(3);
	ANDROID_KABI_RESERVE(4);
};

static int platform_match(struct device *dev, struct device_driver *drv)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct platform_driver *pdrv = to_platform_driver(drv);

	/* When driver_override is set, only bind to the matching driver */
	if (pdev->driver_override)
		return !strcmp(pdev->driver_override, drv->name);

	/* Attempt an OF style match first */
	if (of_driver_match_device(dev, drv))
		return 1;

	/* Then try ACPI style match */
	if (acpi_driver_match_device(dev, drv))
		return 1;

	/* Then try to match against the id table */
	if (pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev) != NULL;

	/* fall-back to driver name match */
	return (strcmp(pdev->name, drv->name) == 0);
}

 

上面是bus_register时注册的platform_bus_type,其中需要注意的是.match函数,当挂在platform总线上的driver和device匹配时会调用,会根据of_match_table、acpi、id_table、drv_name来匹配,至于bus_register函数中的其他调用有兴趣的可以自行去了解kobject/kset,这里不再赘述
相关也可以看看博客linux驱动 平台设备驱动模型,我看看写的比较详细,注意这篇博客的kernel版本和我的不一样,我这是kernel5.10

2.2 driver注册

这里已display中的panel注册为例


static struct mipi_dsi_driver panel_simple_dsi_driver = {
	.driver = {
		.name = "panel-simple-dsi",
		.of_match_table = dsi_of_match,
	},
	.probe = panel_simple_dsi_probe,
	.remove = panel_simple_dsi_remove,
	.shutdown = panel_simple_dsi_shutdown,
};

static int __init panel_simple_init(void)
{
	int err;
//注册platform设备	
	err = platform_driver_register(&panel_simple_platform_driver);
	if (err < 0)
		return err;

	if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
		err = mipi_dsi_driver_register(&panel_simple_dsi_driver);
		if (err < 0)
			return err;
	}

	return 0;
}
module_init(panel_simple_init);


在kernel开始运行时会调用运行.init.text代码段的函数,而运行module_init宏定义的内容,关于module_init、late_initcall、subsys_init等可以查看kernel-5.10/include/linux/module.h、init.h

platform_driver_register


#define platform_driver_register(drv) \
	__platform_driver_register(drv, THIS_MODULE)

int __platform_driver_register(struct platform_driver *drv,
				struct module *owner)
{
	drv->driver.owner = owner;
	drv->driver.bus = &platform_bus_type;
	drv->driver.probe = platform_drv_probe;
	drv->driver.remove = platform_drv_remove;
	drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);
}

int driver_register(struct device_driver *drv)
{
	int ret;
	struct device_driver *other;

	if (!drv->bus->p) {
		pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n",
			   drv->name, drv->bus->name);
		return -EINVAL;
	}

	if ((drv->bus->probe && drv->probe) ||
	    (drv->bus->remove && drv->remove) ||
	    (drv->bus->shutdown && drv->shutdown))
		pr_warn("Driver '%s' needs updating - please use "
			"bus_type methods\n", drv->name);
//检查driver是否已经注册在bus上
	other = driver_find(drv->name, drv->bus);
	if (other) {
		pr_err("Error: Driver '%s' is already registered, "
			"aborting...\n", drv->name);
		return -EBUSY;
	}
//这个函数下面分析
	ret = bus_add_driver(drv);
	if (ret)
		return ret;
	ret = driver_add_groups(drv, drv->groups);
	if (ret) {
		bus_remove_driver(drv);
		return ret;
	}
	kobject_uevent(&drv->p->kobj, KOBJ_ADD);

	return ret;
}
EXPORT_SYMBOL_GPL(driver_register);


int bus_add_driver(struct device_driver *drv)
{
	struct bus_type *bus;
	struct driver_private *priv;
	int error = 0;

	bus = bus_get(drv->bus);
	if (!bus)
		return -EINVAL;

	pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		error = -ENOMEM;
		goto out_put_bus;
	}
	klist_init(&priv->klist_devices, NULL, NULL);
	priv->driver = drv;
	drv->p = priv;
	priv->kobj.kset = bus->p->drivers_kset;
	error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
				     "%s", drv->name);
	if (error)
		goto out_unregister;
//将knode_bus加入到bus的klist_drivers链表中
	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
	if (drv->bus->p->drivers_autoprobe) {
//调用bus中的match函数
		error = driver_attach(drv);
		if (error)
			goto out_unregister;
	}
	module_add_driver(drv->owner, drv);

	error = driver_create_file(drv, &driver_attr_uevent);
	if (error) {
		printk(KERN_ERR "%s: uevent attr (%s) failed\n",
			__func__, drv->name);
	}
	error = driver_add_groups(drv, bus->drv_groups);
	if (error) {
		/* How the hell do we get out of this pickle? Give up */
		printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
			__func__, drv->name);
	}

	if (!drv->suppress_bind_attrs) {
		error = add_bind_files(drv);
		if (error) {
			/* Ditto */
			printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
				__func__, drv->name);
		}
	}

	return 0;

out_unregister:
	kobject_put(&priv->kobj);
	/* drv->p is freed in driver_release()  */
	drv->p = NULL;
out_put_bus:
	bus_put(bus);
	return error;
}

int driver_attach(struct device_driver *drv)
{
	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
EXPORT_SYMBOL_GPL(driver_attach);

static int __driver_attach(struct device *dev, void *data)
{
	struct device_driver *drv = data;
	int ret;

	/*
	 * Lock device and try to bind to it. We drop the error
	 * here and always return 0, because we need to keep trying
	 * to bind to devices and some drivers will return an error
	 * simply if it didn't support the device.
	 *
	 * driver_probe_device() will spit a warning if there
	 * is an error.
	 */

//调用bus_type中的match函数
	ret = driver_match_device(drv, dev);
	if (ret == 0) {
		/* no match */
		return 0;
	} else if (ret == -EPROBE_DEFER) {
		dev_dbg(dev, "Device match requests probe deferral\n");
		driver_deferred_probe_add(dev);
	} else if (ret < 0) {
		dev_dbg(dev, "Bus failed to match device: %d\n", ret);
		return ret;
	} /* ret > 0 means positive match */

	if (driver_allows_async_probing(drv)) {
		/*
		 * Instead of probing the device synchronously we will
		 * probe it asynchronously to allow for more parallelism.
		 *
		 * We only take the device lock here in order to guarantee
		 * that the dev->driver and async_driver fields are protected
		 */
		dev_dbg(dev, "probing driver %s asynchronously\n", drv->name);
		device_lock(dev);
		if (!dev->driver) {
			get_device(dev);
			dev->p->async_driver = drv;
			async_schedule_dev(__driver_attach_async_helper, dev);
		}
		device_unlock(dev);
		return 0;
	}
//driver和device匹配完成,调用driver中的probe函数完成注册
	device_driver_attach(drv, dev);

	return 0;
}

static inline int driver_match_device(struct device_driver *drv,
				      struct device *dev)
{
	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

2.3 device注册

在kernel未引入dts之前和引入dts之后的device注册时不同的

具体可参考platform_device的生成过程

总之引入设备驱动模型后,隔离了bsp和驱动,使得驱动有更好的可扩展性和跨平台性,另外一个驱动可以支持多个设备

设备驱动模型 - kobject 目录 一. 设备驱动模型简介 二. kobject简介 2.1 kobject内核数据结构 2.2 kobject操作内核接口 三. kobject实例 3.1 Makefile 3.2 实例1 3.3 实例2 3.4 实例3 一. 设备驱动模型简介 Linux设备模型的核心是使用Bus、Class、Device、Driver四个核心数据结构,将大量的、不同功能的硬... 阅读详情

相关推荐

NVME源码流程解析(二)

本文来接着上一章来讲nvme的注册流程,接下来从driver_attach(drv)函数来看起! 1、driver_attach(drv) —— \drivers\base\dd.c /** * driver_attach - try to bind driver to devices. * @drv: driver. * * Walk the list of devices that the bus has on it and try to * match the d...

weixin_38428439的博客 1103

探究Linux的总线、设备、驱动模型

理解Linux的总线、设备、驱动模型是理解Linux驱动框架的关键,也是破解Linux为什么极易移植到不同的平台,以及被如此多广泛领域使用根源的关键。我的优快云直播将以浅显易懂地语言,深入地把这一模型剖析清楚,道出这样的设计的好处。

五.linux设备驱动模型

站在设备驱动这个角度分析,设备驱动模型是如何构建出来,起到什么作用,认识它并在写驱动的时候去利用设备驱动模型 目录 一.linux 设备驱动模型简介 1.1、 什么是设备驱动模型 1.2、 为什么需要设备驱动模型 1.3、 驱动开发的2个点 二.设备驱动模型的底层架构 2.1、kobject结构体 2.2、kobj_type结构体 2.3、kset结构体 三.总线式设备驱...

Mr.Wang的博客 1972

linux驱动模型概述

linux驱动模型概述

时光总不留人,难得过去幸运 1385

linux设备驱动的模型详解

一、什么是设备驱动模型 (1)类class、总线bus、设备device、驱动driver 四个结构体 (2)kobject和对象生命周期 (3)sysfs cat 查看属性信息 、 echo 往里面写东西 (4)udev 同步信息2、设备模型解决了一些什么问题? (1)设备驱动模型负责统一实现和维护一些特性,诸如:电源管理、热插拔、对象生命周期、用

huangliangben的博客 1695

淘宝x-mini-wua生成机制与硬件信息关联性深度解析

本文深度解析了淘宝x-mini-wua的生成机制与硬件信息的关联性,详细介绍了其作为设备指纹令牌的核心作用及技术实现细节。通过分析基础硬件层、环境特征层和行为特征层的数据采集,揭示了淘宝如何利用AES加密和分级加密策略防止破解,并探讨了其安全防护与对抗策略。

weixin_29243279的博客 228

Linux设备驱动模型

文章目录前言1.linux设备驱动模型简介2.设备驱动模型的底层架构3.总线式设备驱动组织方式4.platform平台总线工作原理4.平台总线实践环节 前言 1.linux设备驱动模型简介 1、什么是设备驱动模型 (1)类class、总线bus、设备device、驱动driver(内核代码中有4个结构体) (2)kobject和对象生命周期(自动管理生命周期) (3)sysfs(虚拟文件系统,在内核空间和用户空间间建立关系,把内核的结构体变量的一些值以文件的形式展现出来,通过echo、cat操作属性节点

weixin_44705391的博客 4318

Foxglove 介绍以及入门使用教程

Foxglove 是由Foxglove 工作室开发的一套工具集,包括和等组件。跨平台支持:可以在 Windows、macOS 和 Linux 上运行。多协议兼容:支持 ROS、ROS 2、CAN 数据以及其他自定义协议。丰富的可视化功能:可以绘制点云、轨迹、激光雷达数据、IMU 数据等。实时与离线模式:既可以实时监控机器人状态,也可以加载和回放记录的数据文件。Foxglove 的 3D 视图允许你以三维方式查看机器人的运动轨迹、传感器数据和其他几何信息。你可以旋转、缩放和平移视图以获得更好的观察角度。

zolty 1万+

LINUX设备驱动模型简介

××××××××××××××LINUX设备驱动模型简介×××××××××××××××××第一部分————————————————————————————————————- 1.linux设备驱动模型简介 2.设备驱动模型的底层架构:类,总线,设备,驱动,platform3.实践:使用设备驱动模型来加载上一个led驱动1.linux设备驱动模型简介 《1》什么是设备驱动模型将一个概念时怎样讲明白

love23_linuxer的博客 665

【高清照片】深圳光博会看PCIe Over Fibre 实现方案

本文分析了PCIe over Fibre技术及其在数据中心的应用前景。该技术通过光纤延伸PCIe总线,解决了传统铜缆距离限制问题,支持跨机架资源池化。目前主要有两种实现方式:CDFP混合光缆方案和Retimer转接卡方案,各有优缺点。文章还探讨了CDFP接口的现状、低速信号传输解决方案,以及PCIe速率与光通信发展的对应关系。最后对比了PCIe光缆与以太网光缆的关键差异,指出PCIe光互连在协议透明度和边带信号处理上的特殊要求。随着标准推进,PCIe over Fibre将成为数据中心扩展高带宽、低时延互连

Saniffer的博客 1383

手把手教你用TI MOSFET搭建0-100mA恒流源电路(附避坑指南)

本文详细介绍了如何使用TI MOSFET SI1204D搭建0-100mA恒流源电路,包括基础原理、电路设计、PCB布局和热管理技巧。通过分步指导和避坑指南,帮助工程师实现高精度、低成本的电流控制方案,适用于LED驱动、传感器激励等多种应用场景。

weixin_29310631的博客 482

LINUX设备驱动模型之class

1、LINUX设备驱动模型中的bus、device、driver,。其中bus:实际的总线,device:实际的设备和接口,而driver:对应存在的驱动。 2、但本节要介绍的class,是设备类,完全是抽象出来的概念,没有对应的实体。所谓设备类,是指提供的用户接口相似的一类设备的集合,常见的设备类的有block、tty、input、usb等等。 3、class对应的代码在drivers/ba

当我荒废时间的时候,会有多少人在拼命 3288

第二十一篇: `man`, `tldr`, `explain` - 授人以渔的“终极指令”

我们已经一起学习了19个(组)关键命令,从nvidia-smi到kubectl。但这只是GPU运维武器库中的一小部分。技术日新月异,新的工具、新的参数会不断涌现。这个系列的真正目的,不仅是教会你使用这19件“兵器”,更是希望你掌握学习任何一件新兵器的方法论。这套方法论就是你的“终极指令”。授人以鱼不如授人以渔。至此,《GPU运维指令集:20个关键命令的战地手册》系列已全部完结。我们从nvidia-smi出发,一路探索了监控、诊断、容器、集群、网络、性能等各个维度的命令,最后用自动化脚本将它们串联,又用。

weixin_42587823的博客 1350

(五)Linux设备驱动模型介绍

本系列导航 (一)初识Linux驱动 (二)Linux设备驱动的模块化编程 (三)写一个完整的Linux驱动程序访问硬件并写应用程序进行测试 (四)Linux设备驱动之多个同类设备共用一套驱动 (五)Linux设备驱动模型介绍 (六)Linux驱动子系统-I2C子系统 (七)Linux驱动子系统-SPI子系统 (八)Linux驱动子系统-PWM子系统 (九)Linux驱动子系统-Light子系统 ...

韩朋的博客 3882

lammps教程:in文件结构详解以及一个比较实用的in文件模板

lammps软件只是一个求解器,没有可视化的前处理和后处理软件,所有的命令只能通过代码的方式输入到求解器进行求解计算。 所有的命令都被写到一个称为“in”的文件里,对于初学者来说,熟悉in文件的编写是一个难点。 in文件其实就是一个文本文档,也没有要求文件名或者后缀名中必须带有“in”字样,用任何文件名均可运行。 in文件里的代码是按照编写的顺序进行解释执行,对于大部分命令行来说,前后顺序影响并不是很大,但是,对于一些命令,在执行过程中需要某个参数,则这个参数的定义和计算必须写在命令执行之前。 例如,对晶体

lammps_jiayou的博客 2万+

AES-128-CMAC:背景、汽车应用、CAPL 实现与开源工具验证

本文详解车载诊断中AES-128-CMAC算法的原理与应用,涵盖其在UDS安全访问、刷写鉴权、SecOC认证及密钥派生中的核心作用。结合真实汽车电子场景,提供纯CAPL实现代码与测试脚本,并通过pycryptodome进行逐字节验证,确保算法正确性。全程基于CANoe实测数据,可直接用于HIL环境复现,助力开发者高效落地汽车网络安全方案。

蚂蚁小兵 111

LINUX设备驱动模型分析之一 总体概念说明

这段时间阅读了LINUX SYSFS模块的代码,并完成了相应的学习笔记,阅读这些代码,为我们分析LINUX设备驱动模型提供了基础。下面这一段时间我将分析LINUX设备驱动模型。 本次分析的LINUX设备驱动模型,主要涉及如下几个部分: 一、LINUX设备驱动模型总体概述 二、LINUX总线(BUS)接口分析 三、LINUX设备(DEVICE)接口...

lickylin的专栏 2582

【PyTorch深度学习项目实战100例目录】项目详解 + 数据集 + 完整源码

大家好,我是阿光。本专栏整理了《深度学习100例》,内包含了各种不同的深度学习项目,包含项目原理以及源码,每一个项目实例都附带有完整的代码+数据集。正在更新中~ ✨。

优快云 精品推荐 10万+

linux设备驱动模型

linux设备驱动模型分析

风雨无阻 2338

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

linux设备驱动模型及其他,Linux设备驱动模型

Linux设备驱动模型,主要函数分析整个驱动模型中,最核心的三个函数分别是__bus_register、driver_register、device_registerint __bus_register(struct bus_type *bus, struct lock_class_key *key)retval = kobject_set_name(&priv->subsys.ko...

weixin_30895873的博客 123

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

上一篇: rk3588 linux上camera效果问题
下一篇: Linux kernel下的debug方法
autho
博客等级 码龄14年 52粉丝 27原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

autho

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值