嵌入式Linux应用开发-第十章LED模板总线设备驱动模型

news2024/12/23 0:36:51

嵌入式Linux应用开发-第十章LED模板总线设备驱动模型

  • 第十章 LED模板驱动程序的改造:总线设备驱动模型
    • 10.1 原来的框架
    • 10.2 要实现的框架
    • 10.3 写代码
      • 10.3.1 注意事项
      • 10.3.2 实现 platform_device结构体
      • 10.3.3 实现 platform_driver结构体
    • 10.4 课后作业

第十章 LED模板驱动程序的改造:总线设备驱动模型

在这里插入图片描述

10.1 原来的框架

在这里插入图片描述

10.2 要实现的框架

在这里插入图片描述

10.3 写代码

使用 GIT下载所有源码后,本节源码位于如下目录:

01_all_series_quickstart\ 
05_嵌入式 Linux驱动开发基础知识\source\ 
02_led_drv\04_led_drv_template_bus_dev_drv 

10.3.1 注意事项

① 如果 platform_device中不提供 release函数,如下图所示不提供红框部分的函数:
在这里插入图片描述

则在调用 platform_device_unregister时会出现警告,如下图所示:

rootaroc-rk3399-pc;/mnti# insmod board_A_led.ko
rootaroc-rk3399-pc:/mnt]# rmmod board_A_led.ko
2412528005524125,29502724125.3051301
Device 'xxxxxx led.0' does not have a release() function, it is broken and must be fixed
---- cut here -----------
WARNING: at drivers/base/core.c:251

你可以提供一个 release函数,如果实在无事可做,把这函数写为空。

② EXPORT_SYMBOL a.c编译为 a.ko,里面定义了 func_a;如果它想让 b.ko使用该函数,那么 a.c里需要导出此函数(如果 a.c, b.c都编进内核,则无需导出):

EXPORT_SYMBOL(led_device_create); 

并且,使用时要先加载 a.ko。 如果先加载 b.ko,会有类似如下“Unknown symbol”的提示:

rootaroc-rk3399-pc:/mnt]# insmod chip_demo_gpio.ko
24299,917448] chip_demo_gpio: Unknown symbo register led operations (err 0)
24299.935714] chip_demo_gpio: Unknown symbol led class destroy device (err 0)
24299.9508431 chip_demo_gpio: Unknown symbol led class create device (err 0)
24299,9714821 chip_demo_gpio: Unknown symbol register led operations (err 0)
24299.982958] chip_demo_gpio: Unknown symbol led class destroy device (err 0)
24299,9948341 chip_demo_gpio: Unknown symbol led class create device (err 0)
can't insert 'chip_demo_gpio.ko': unknown symbol in module, or unknown nsmoc: parameter

10.3.2 实现 platform_device结构体

board_A.c作为一个可加载模块,里面也有入口函数、出口函数。在入口函数中注册 platform_device结构体,在 platform_device结构体中指定使用哪个 GPIO引脚。
首先看入口函数,它调用 platform_device_register函数,向内核注册 board_A_led_dev结构体:

50 static int __init led_dev_init(void) 
51 { 
52     int err; 
53 
54     err = platform_device_register(&board_A_led_dev); 
55 
56     return 0; 
57 } 
58 

board_A_led_dev结构体定义如下。 在 resouces数组中指定了 2个引脚(第 27~38行);
我们还提供了一个空函数 led_dev_release(第 23~25行),它被赋给 board_A_led_dev结构体(第 46行),这个函数在卸载 platform_device时会被调用,如果不提供的话内核会打印警告信息。

23 static void led_dev_release(struct device *dev) 
24 { 
25 } 
26 
27 static struct resource resources[] = { 
28         { 
29                 .start = GROUP_PIN(3,1), 
30                 .flags = IORESOURCE_IRQ, 
31                 .name = "xxxxxx_led_pin", 
32         }, 
33         { 
34                 .start = GROUP_PIN(5,8), 
35                 .flags = IORESOURCE_IRQ, 
36                 .name = "xxxxxx_led_pin", 
37         }, 
38 }; 
39 
40 
41 static struct platform_device board_A_led_dev = { 
42         .name = "xxxxxx_led", 
43         .num_resources = ARRAY_SIZE(resources), 
44         .resource = resources, 
45         .dev = { 
46                 .release = led_dev_release, 
47          }, 
48 }; 
49 

10.3.3 实现 platform_driver结构体

chip_demo_gpio.c中注册 platform_driver结构体,它使用 Bus/Dev/Drv模型,当有匹配的platform_device时,它的 probe函数就会被调用。
在 probe函数中所做的事情跟之前的代码没有差别。
先看入口函数。
第 150行向内核注册一个 platform_driver结构体; 这个结构体的核心在于第 140行的 chip_demo_gpio_probe函数。
138 static struct platform_driver chip_demo_gpio_driver = {
139 .probe = chip_demo_gpio_probe,
140 .remove = chip_demo_gpio_remove,
141 .driver = {
142 .name = “xxxxxx_led”,
143 },
144 };
145
146 static int __init chip_demo_gpio_drv_init(void)
147 {
148 int err;
149
150 err = platform_driver_register(&chip_demo_gpio_driver);
151 register_led_operations(&board_demo_led_opr);
152
153 return 0;
154 }
155

chip_demo_gpio_probe函数代码如下。
第 107行:从匹配的 platform_device中获取资源,确定 GPIO引脚。
第 111行:把引脚记录下来,在操作硬件时要用。
第 112行:新发现了一个 GPIO引脚,就调用上层驱动的代码创建设备节点。

100 static int chip_demo_gpio_probe(struct platform_device *pdev) 
101 { 
102     struct resource *res; 
103     int i = 0; 
104 
105     while (1) 
106     { 
107         res = platform_get_resource(pdev, IORESOURCE_IRQ, i++); 
108         if (!res) 
109             break; 
110 
111         g_ledpins[g_ledcnt] = res->start; 
112         led_class_create_device(g_ledcnt); 
113         g_ledcnt++; 
114     } 
115     return 0; 
116 
117 } 
118 

操作硬件的代码如下,第 31、63行的代码里用到了数组 g_ledpins,里面的值来自 platform_device,在 probe函数中根据 platform_device的资源确定了引脚:

23 static int g_ledpins[100]; 
24 static int g_ledcnt = 0; 
25 
26 static int board_demo_led_init (int which) /* 初始化 LED, which-哪个 LED */ 
27 { 
28     //printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which); 
29 
30   printk("init gpio: group %d, pin %d\n", GROUP(g_ledpins[which]), PIN(g_ledpins[which])); 
31     switch(GROUP(g_ledpins[which])) 
32     { 
33         case 0: 
34         { 
35             printk("init pin of group 0 ...\n"); 
36             break; 
37         } 
38         case 1: 
39         { 
40             printk("init pin of group 1 ...\n"); 
41             break; 
42         } 
43         case 2: 
44         { 
45             printk("init pin of group 2 ...\n"); 
46             break; 
47         } 
48         case 3: 
49         { 
50             printk("init pin of group 3 ...\n"); 
51             break; 
52         } 
53     } 
54 
55     return 0; 
56 } 
57 
58 static int board_demo_led_ctl (int which, char status) /* 控制 LED, which-哪个 LED, status:1-亮,0-灭 */ 
59 { 
60     //printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off"); 
61    printk("set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(g_ledpins[which]), PIN(g_ledpins[which])); 
62 
63     switch(GROUP(g_ledpins[which])) 
64     { 
65         case 0: 
66         { 
67             printk("set pin of group 0 ...\n"); 
68             break; 
69         } 
70         case 1: 
71         { 
72             printk("set pin of group 1 ...\n"); 
73             break; 
74         } 
75         case 2: 
76         { 
77             printk("set pin of group 2 ...\n"); 
78             break; 
79         } 
80         case 3: 
81         { 
82             printk("set pin of group 3 ...\n"); 
83             break; 
84         } 
85     } 
86 
87     return 0; 88 } 
89 
90 static struct led_operations board_demo_led_opr = { 
91     .init = board_demo_led_init, 
92     .ctl  = board_demo_led_ctl, 
93 }; 
94 
95 struct led_operations *get_board_led_opr(void) 
96 { 
97     return &board_demo_led_opr; 
98 } 
99 

10.4 课后作业

完善半成品程序:04_led_drv_template_bus_dev_drv_unfinished。
请仿照本节提供的程序(位于 04_led_drv_template_bus_dev_drv目录),改造你所用的单板的 LED驱动程序。

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

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

相关文章

CCF CSP认证 历年题目自练Day13

CCF CSP认证 历年题目自练Day13 题目一 试题编号: 201612-1 试题名称: 中间数 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述   在一个整数序列a1, a2, …, an中,如果存在某个数,大…

web:[极客大挑战 2019]BabySQL

题目 点进页面显示如下 查看源代码 先尝试一下万能密码 没用,or被过滤了 试着双写看看 回显一串,也不是flag 先查询列数尝试一下,把union select过滤了,使用双写 构造payload /check.php?usernameadmin&password1 %27 ununi…

基于Java的医院住院管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统功能具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域…

ShowDoc部署与应用:文档管理的最佳实践

在项目开发和协作中,文档管理扮演着至关重要的角色。ShowDoc作为一款卓越的开源文档管理工具,不仅提供强大的文档管理功能,还具备简单易用的协作和部署特性。我们的项目团队最初选择了ShowDoc作为文档管理工具,用以促进前后端协作…

【超分:光谱响应函数】

Spectral Response Function-Guided Deep Optimization-Driven Network for Spectral Super-Resolution (光谱响应函数引导的深度优化驱动网络光谱超分辨) 高光谱图像(HSI)是许多研究工作的关键。光谱超分辨率(SSR&a…

mysql面试题5:索引、主键、唯一索引、联合索引的区别?什么情况下设置了索引但无法使用?并且举例说明

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:说一说索引、主键、唯一索引、联合索引的区别? 索引、主键、唯一索引和联合索引是数据库中常用的索引类型,它们有以下区别: 索引:索引是一种数…

时序分解 | Matlab实现SSA-VMD麻雀算法优化变分模态分解时间序列信号分解

时序分解 | Matlab实现SSA-VMD麻雀算法优化变分模态分解时间序列信号分解 目录 时序分解 | Matlab实现SSA-VMD麻雀算法优化变分模态分解时间序列信号分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 SSA-VMD麻雀搜索算法SSA优化VMD变分模态分解 可直接运行 分解效果好…

JavaScript Web APIs第二天笔记

Web APIs - 第2天 学会通过为DOM注册事件来实现可交互的网页特效。 能够判断函数运行的环境并确字 this 所指代的对象理解事件的作用,知道应用事件的 3 个步骤 学习会为 DOM 注册事件,实现简单可交互的网页特交。 事件 事件是编程语言中的术语&#xff…

笔试强训Day7

T1&#xff1a;合法括号序列判断 链接&#xff1a;合法括号序列判断__牛客网 给定一个字符串A和其长度n&#xff0c;请返回一个bool值代表它是否为一个合法的括号串&#xff08;只能由括号组成&#xff09;。 经典括号匹配问题&#xff0c;考察栈的使用 #include<iostre…

freertos中函数调用和启动第一个任务(栈相关!!!!!!)

本内容仅就一些较难理解的点讲解&#xff0c;请结合其它文章实用 在函数调用时&#xff0c;m3的处理器使用r0-r3共四个寄存器传参&#xff0c;其余的使用栈传参。 但是&#xff0c;如果传入的参数是全局变量&#xff0c;则不需传参&#xff0c;因为全局变量在函数内部是可见的…

YOLO训练心得

文件框架 通过简单的模型训练&#xff0c;对于YOLO的理解更加透彻了。 detect.py文件 如上图所示&#xff0c;weights表示权重。source表示识别图像的位置。 train.py文件 如上图所示&#xff0c;weights是权重&#xff0c;我们通常使用YOLO提供的训练权重进行训练。data是训…

ADworld reverse wp easyre-153

逆向分析 做逆向题先查壳, 就像做pwn先checksec一样 用PEid查不出来, 用Exeinfo PE可以查出ELF文件的壳 用工具直接脱upx壳, kali自带的工具或者手动安装一个windows的upx工具 脱壳之后拖入IDA32 int __cdecl main(int argc, const char **argv, const char **envp) {int …

SLAM从入门到精通(amcl定位使用)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 学习slam&#xff0c;一般就是所谓的边定位、边制图的知识。然而在实际生产过程中&#xff0c;比如扫地机器人、agv、巡检机器人、农业机器人&…

Sentinel学习——sentinel的使用,引入依赖和配置 对消费者进行流控 对生产者进行熔断降级

前言 Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 本篇博客介绍sentinel的使用&#x…

Bug:elementUI样式不起作用

前端问题合集&#xff1a;VueElementUI 1. Vue引用Element-UI时&#xff0c;组件无效果解决方案 前提&#xff1a; 已经安装好elementUI依赖 //安装依赖 npm install element-ui //main.js中导入依赖并在全局中使用 import ElementUI from element-ui Vue.use(ElementUI)如果此…

电压提前/滞后电路 —— 电赛综测备赛

电容可以让交流波形提前或滞后&#xff0c;不过很多人不知道用法 电压滞后电路 我们从中间输出给示波器 波形&#xff08;红色&#xff09; 电容越大电阻越大&#xff0c;波形越滞后 电压提前电路 波形&#xff08;红色&#xff09;提前 电容越小电阻越小&#xff0c;波形…

【python】numpy库

文章目录 简单介绍功能示例代码 简单介绍 NumPy&#xff08;Numerical Python的简称&#xff09;是Python数值计算最重要的基础包。大多数提供科学计算的包都是用NumPy的数组作为构建基础。 NumPy是在一个连续的内存块中存储数据&#xff0c;独立于其他Python内置对象。NumPy…

uniapp iOS离线打包——如何创建App并提交版本审核?

uniapp 如何创建App&#xff0c;并提交版本审核&#xff1f; 文章目录 uniapp 如何创建App&#xff0c;并提交版本审核&#xff1f;登录 appstoreconnect创建AppiOS 预览和截屏应用功能描述技术支持App 审核信息 App 信息内容版权年龄分级 价格与销售范围App 隐私提交审核 登录…

VS Code使用clang-format自定义C++代码默认格式化样式

解决的问题 让 VS Code 在不使用.clang-format或_clang-format文件时&#xff0c;默认使用自定义的 C 代码格式化样式。以下假定规则文件为D:\ClangFormat\rules.txt。 格式规则 具体设置参照 Clang-Format官方文档&#xff0c;也可以使用 Clang-Format交互式构建器。 贴上…

Spring Boot 中使用 Micrometer 进行度量和监控

Spring Boot 中使用 Micrometer 进行度量和监控 Micrometer 是一个开源的度量库&#xff0c;用于在应用程序中收集、存储和展示度量数据。它提供了一种统一的方式来度量应用程序的各种指标&#xff0c;如响应时间、请求次数、内存使用等。在Spring Boot中&#xff0c;Micromet…