【梦想终会实现】Linux驱动学习5

news/2025/2/8 15:50:55/

加油加油坚持住!

1、

Linux驱动模型:驱动模型即将各模型中共有的部分抽象成C结构体。Linux2.4版本前无驱动模型的概念,每个驱动写的代码因人而异,随后为规范书写方式,发明了驱动模型,即提取公共信息组成一个个类,为添加设备和驱动提供统一的接口,使得开发变得简单化、规范化,但驱动本身仍然存在开发难度,设备(触摸屏、蓝牙等)的最底层代码不需要驱动工程师搞,Linux设备模型也不需要驱动工程师搞,驱动工程师需要做的是把二者结合。早期的驱动是需要手动inmod的,有驱动模型后直接注册即可。

驱动模型分为四类:类、总线、设备、驱动、Kobject、sysfs、udev。

深入理解Linux设备模型与驱动开发-CSDN博客 (五星推荐)

比如led,rtc,beep,key这类结构简单的设备,它们的控制不需要时序,它们没有相应的物理总线。所以linux内核不会为它们创建驱动总线。为了是这部分设备的驱动开发也能够遵循设备驱动模型,linux内核引入了一种虚拟的总线——平台总线(platform bus)。

2、Linux的底层模型(主要是写内核的人写的,搞驱动的一般不用)

基本结构体Kobject:各类对象的最小单元,对象引用计数(kref)、维护对象链表(entry、parent)、对象上锁(kset)、对用户空间的描述(ktype)。

kobj_type:提供在sysfs下的操作。attribute:sysfs下的属性;sysfs_ops:对象在sysfs下的操作方法。

kset:描述sysfs下的目录关系。

驱动开发注意包含和引用的关系,包含是结构体成员,绑定是指针。如

struct kobject {const char		*name;struct list_head	entry;   // 上下节点    包含关系struct kobject		*parent; // 上下层之间   绑定关系struct kset		*kset;       // 上锁        绑定关系struct kobj_type	*ktype;struct sysfs_dirent	*sd;struct kref		kref;        // 对象引用计数unsigned int state_initialized:1;unsigned int state_in_sysfs:1;unsigned int state_add_uevent_sent:1;unsigned int state_remove_uevent_sent:1;unsigned int uevent_suppress:1;
};

3、Linux的上层模型

设备

struct device是硬件设备在内核驱动框架中的抽象。

device_register用于向内核驱动框架注册一个设备。

通常device不会单独使用,而是被包含在一个具体设备结构体中,如struct usb_device。

驱动

device_driver是驱动程序在内核驱动框架中的抽象。

name:驱动程序的名字,用于驱动与对应设备的匹配。

probe:用于检测此设备是否可以用本驱动,毕竟不同厂家的设备对应的驱动是不同的。

类:

相关结构体:struct class 和 struct class_device。

class的真正意义在于作为同属于一个class的多个设备的容器

内核中驱动会被类和总线双重管理。

模型思想即面向对象的思想,结构体包一层结构体即类继承类,有一个基类(device_driver),然后创建子类(usb_device)。驱动开发要有思想复杂度!一层套一层。

4、Linux设备总线开发目的是方便管理。

CPU与外部通信的方式:

32位地址总线寻址:片上外设可以通过SOC的内存寻址,因为设备是硬编码进SOC的,硬编码一般是数字前端工程师设计的,使用Verilog HDL语言。(在Linux中设计为平台总线形式,大部分设备均为平台总线)

通过IIC、SPI、USB总线与外部通信。

EXPORT_SYMBOL_GPL的应用:

// 如下代码表示函数允许被其他仅支持GPL的内核模块使用,而不是使用.h声明的方式
void platform_driver_unregister(struct platform_driver *drv)
{driver_unregister(&drv->driver);
}
EXPORT_SYMBOL_GPL(platform_driver_unregister);

platfrom设备驱动分析: 

// device驱动源码分析static struct platform_driver pm860x_backlight_driver = {  // .driver		= {.name	= "88pm860x-backlight",  // name为驱动唯一标识符.owner	= THIS_MODULE,},.probe		= pm860x_backlight_probe, // 驱动的侦测函数.remove		= pm860x_backlight_remove,// 驱动的卸载函数
};static int __init pm860x_backlight_init(void)
{return platform_driver_register(&pm860x_backlight_driver);
}
module_init(pm860x_backlight_init);  // 模块注册static void __exit pm860x_backlight_exit(void)
{platform_driver_unregister(&pm860x_backlight_driver);
}
module_exit(pm860x_backlight_exit);  // 模块卸载
static struct platform_device this_device = {.name   = "tv_ntsc",   // 设备名,用于内核设备树和其他机制中标识这个设备.id	= 0,.dev	= {.platform_data = &ntsc_panel_data,}
};static int __init ntsc_init(void)                  // __init阶段执行,执行完毕后释放该数据段
{int ret;ret = platform_driver_register(&this_driver);    // 注册驱动if (!ret) {ret = platform_device_register(&this_device);// 注册成功则注册该设备if (ret)platform_driver_unregister(&this_driver);// 否则,卸载设备,以保持内核稳定性。}return ret;
}module_init(ntsc_init);  // 模块注册

5、

一个驱动可以对应多个设备。当设备加载进来时,会通过platform_match函数匹配对应的驱动(根据驱动名)。若存在,则调用driver的probe函数完成驱动的安装。

内核提供platform_device,写驱动的人提供platform_driver,可以全局检索name的形式检索驱动对应的设备。

设备于内核中的执行顺序:

s3c24xx_led -->mini2440_led1 -->mini2440_devices-->platform_add_devices-->platform_device_register 完成设备添加,可从/sys目录找到。

然后内核根据设备名s3c24xx_led查找对应的驱动,若存在,则执行。以此实现platform框架下的设备和驱动匹配。

static struct platform_device mini2440_led1 = {.name		= "s3c24xx_led",.id		= 1,.dev		= {.platform_data	= &mini2440_led1_pdata,    // 这段绑定关系交由各驱动模块自己执行},
};struct device {struct device		*parent;
.......
.......void		*platform_data;	/* Platform specific data, devicecore doesn't touch it */  // 此段指针交由各驱动自行绑定。.......
.......}// driver部分,将
static int s3c24xx_led_probe(struct platform_device *dev)
{struct s3c24xx_led_platdata *pdata = dev->dev.platform_data;  // 此处实现自定义数据的赋值操作struct s3c24xx_gpio_led *led;int ret;led = kzalloc(sizeof(struct s3c24xx_gpio_led), GFP_KERNEL);if (led == NULL) {dev_err(&dev->dev, "No memory for device\n");return -ENOMEM;}platform_set_drvdata(dev, led);............
}

6、

驱动的核心思考点:

能想清楚数据谁写的?给谁了?从哪里传递到哪里?谁接受到数据干啥了?

想想这么设计的优势、必要性是什么?

自己写一个出来。

以上三条就是驱动开发核心部分,区别是不同驱动对应的不同。


http://www.ppmy.cn/news/1570356.html

相关文章

在 Elastic 中实施聚类工作流以提升搜索相关性

作者:来自 Elastic Gus Carlock 及 Kirti Sodhi 我们演示了如何利用 OpenAI text-ada-002 向量将自定义聚类模型集成到 Elastic Stack 中,从而简化 Elastic 生态系统内的工作流程。 在本文中,我们将演示如何通过利用示例文本数据集将自定义聚…

【Linux开发工具】包管理器yum和文本编辑器vim

目录 一、前言 二、Linux中的软件商店yum 1.三种安装软件的方式 2.yum的使用方法 三、Linux中的编辑器vim 1.vim的三种模式及切换 2.命令模式详解 3.底行模式详解 4.替换模式 5.视图模式 6.vim下的多线程操作 7.vim的配置 四、总结 一、前言 在初步认识了Linux的基…

windows11上,使用pipx安装Poetry,Poetry的安装路径是什么?

当使用 pipx 安装 Poetry 时,pipx 会将 Poetry 安装到一个独立的虚拟环境中,并将其可执行文件链接到一个集中的目录中。以下是 pipx 安装 Poetry 时的路径信息: 1. Poetry 的安装路径 pipx 会为每个工具(如 Poetry)创…

k8sollama部署deepseek-R1模型,内网无坑

这是目录 linux下载ollama模型文件下载到本地,打包迁移到k8s等无网络环境使用下载打包ollama镜像非k8s环境使用k8s部署访问方式非ollama运行deepseek模型linux下载ollama 下载后可存放其他服务器 curl -L https://ollama.com/download/ollama-linux-amd64.tgz -o ollama-linu…

开源CodeGPT + DeepSeek-R1 是否可以替代商业付费代码辅助工具

开源CodeGPT + DeepSeek-R1 是否可以替代商业付费代码辅助工具 背景与研究目的 在快速发展的软件开发领域,代码辅助工具已成为提高开发效率和质量的关键。然而,商业付费工具如通义灵码和腾讯AI代码助手,尽管功能强大,但其高昂的成本和许可证限制,使得许多企业寻求更具吸…

K8S组件架构

master节点上 kube-apiserver:服务端,提供k8s api接口服务,接受外部请求管理和控制整个集群。 kube-secheduler:调度计算,负责根据资源需求和约束条件,将pod调度到合适的主机上。 kube-controller-manag…

TCN时间卷积神经网络多变量多步光伏功率预测(Matlab)

代码下载:TCN时间卷积神经网络多变量多步光伏功率预测(Matlab) TCN时间卷积神经网络多变量多步光伏功率预测 一、引言 1.1、研究背景和意义 随着全球能源危机的加剧和环保意识的提升,可再生能源,尤其是太阳能&…

每日Attention学习22——Inverted Residual RWKV

模块出处 [arXiv 25] [link] [code] RWKV-UNet: Improving UNet with Long-Range Cooperation for Effective Medical Image Segmentation 模块名称 Inverted Residual RWKV (IR-RWKV) 模块作用 用于vision的RWKV结构 模块结构 模块代码 注:cpp扩展请参考作者原…