5. 驱动开发
文章目录
- 一、驱动开发
- 1.1 前言
- 1.2 何谓驱动框架
- 1.3 内核驱动框架中LED的基本情况
- 1.3.1 相关文件
- 1.3.2 九鼎移植的内核中led驱动
- 1.3.3 案例分析驱动框架的使用
- 1.3.4 典型的驱动开发行业现状
- 1.4 初步分析led驱动框架源码
- 1.4.1 涉及到的文件
- 1.4.2 subsys_initcall
- 1.4.3 led_class_attrs
- 1.4.4 led_classdev_register
- 1.5 在内核中添加或去除某个驱动
- 1.5.1 去除九鼎移植的LED驱动
- 1.5.2 添加led驱动框架支持
- 二、实践---基于驱动框架写led驱动
- 2.1 分析
- 2.2 在驱动中将LED设备分开
- 三、gpiolib引入
一、驱动开发
1.1 前言
驱动一般是驱动开发工程师或内核维护者。驱动编程协作是有一定的要求,接口标准化,从而尽量降低驱动开发者难度。
1.2 何谓驱动框架
(1) 内核中驱动部分维护者针对每个种类的驱动设计一套成熟的、标准的、典型的驱动实现,然后把不同厂家的同类硬件驱动中相同的部分抽出来自己实现好,再把不同部分留出接口给具体的驱动开发工程师来实现,这就叫驱动框架。
(2) 内核维护者在内核中设计了统一管控系统资源的体系,这些体系让内核能够对资源在各个驱动之间的使用统一协调和分配,保证整个内核的稳定运行。譬如系统中所有的GPIO就属于系统资源,每个驱动模块如果要使用某个GPIO就要先调用特殊的接口先申请,申请到后使用,使用完后要释放。又譬如中断号也是一种资源,驱动在使用前也必须去申请。这也是驱动框架的组成部分。
(3) 一些特定的接口函数、一些特定的数据结构,这些是驱动框架的直接表现。
1.3 内核驱动框架中LED的基本情况
1.3.1 相关文件
(1) drivers/leds目录,这个目录就是驱动框架规定的LED这类硬件驱动存放的位置。
(2) led-class.c和led-core.c,这两个文件加起来属于LED驱动框架的第一部分,这两个文件是内核开发者提供的,描述的是内核中所有厂家的不同LED硬件的相同部分的逻辑。
(3) leds-xxxx.c,这个文件是LED驱动框架的第2部分,是由不同厂商的驱动工程师编写添加的,厂商驱动工程师结合自己公司的硬件的不同情况来对LED进行操作,使用第一部分提供的接口来和驱动框架进行交互,最终实现驱动的功能。
1.3.2 九鼎移植的内核中led驱动
(1) 九鼎实际未使用内核推荐的led驱动框架
(2) drivers/char/led/x210-led.c
1.3.3 案例分析驱动框架的使用
(1) 以leds-s3c24xx.c为例。leds-s3c24xx.c中通过调用led_classdev_register来完成LED驱动的注册,而led_classdev_register是在drivers/leds/led-class.c中定义的。所以其实SoC厂商的驱动工程师是调用内核开发者在驱动框架中提供的接口来实现自己的驱动的。
(2) 驱动框架的关键点就是:分清楚内核开发者提供了什么,驱动开发者自己要提供什么
1.3.4 典型的驱动开发行业现状
(1) 内核开发者对驱动框架进行开发和维护、升级,对应led-class.c和led-core.c
(2) SoC厂商的驱动工程师对设备驱动源码进行编写、调试,提供参考版本,对应leds-s3c24xx.c
(3) 做产品的厂商驱动工程师以SoC厂商提供的驱动源码为基础,来做移植和调试
1.4 初步分析led驱动框架源码
1.4.1 涉及到的文件
(1) led-core.c(只简单包含一些头文件)
(2) led-class.c(包含led驱动框架的主要部分)
1.4.2 subsys_initcall
(1) 经过基本分析,发现LED驱动框架中内核开发者实现的部分主要是led-class.c
(2) 对led-class.c分析应该从下往上,遵从对模块的基本分析方法。
(3) 为什么LED驱动框架中内核开发者实现的部分要实现成一个模块?
因为内核开发者希望这个驱动框架是可以被装载/卸载的。这样当内核使用者不需要这个驱动框架时可以完全去掉,需要时可以随时加上。
(4) subsys_initcall是一个宏,定义在linux/init.h中。经过对这个宏进行展开,发现这个宏的功能是:将其声明的函数放到一个特定的段:.initcall4.init。
subsys_initcall
__define_initcall(“4”,fn,4)
(5) 分析module_init宏,可以看出它将函数放到了.initcall6.init段中。
module_init
__initcall
device_initcall
__define_initcall(“6”,fn,6)
(6) 内核在启动过程中需要顺序的做很多事,内核如何实现按照先后顺序去做很多初始化操作。内核的解决方案就是给内核启动时要调用的所有函数归类,然后每个类按照一定的次序去调用执行。这些分类名就叫.initcalln.init。n的值从1到7。内核开发者在编写内核代码时只要将函数设置合适的级别,这些函数就会被链接的时候放入特定的段,内核启动时再按照段顺序去依次执行各个段即可。
比如负责内核链接的文件 vmlinux.lds( 此文件编译内核时会自动生成)。
(7) 经过分析,可以看出,subsys_initcall和module_init的作用是一样的,只不过前者所声明的函数要比后者在内核启动时的执行顺序更早。
1.4.3 led_class_attrs
(1) 什么是attribute,对应将来/sys/class/leds/目录里的内容,一般是文件和文件夹。这些文件其实就是sysfs开放给应用层的一些操作接口(非常类似于/dev/目录下的那些设备文件)
(2) attribute有什么用,作用就是让应用程序可以通过/sys/class/leds/目录下面的属性文件来操作驱动进而操作硬件设备。
(3) attribute其实是另一条驱动实现的路线。有区别于之前讲的file_operations那条线。
1.4.4 led_classdev_register
(1) 分析可知,led_classdev_register这个函数其实就是去创建一个属于leds这个类的一个设备。其实就是去注册一个设备。所以这个函数其实就是led驱动框架中内核开发者提供给SoC厂家驱动开发者的一个注册驱动的接口。
(2) 当使用led驱动框架去编写驱动的时候,这个led_classdev_register函数的作用类似于我们之前使用file_operations方式去注册字符设备驱动时的register_chrdev函数。
1.5 在内核中添加或去除某个驱动
1.5.1 去除九鼎移植的LED驱动
(1) 九鼎移植的驱动在应用层的接口在/sys/devices/platform/x210-led/目录下,有led1、led2、led3、led4四个设备文件,各自管理一个led。
(2) 要去掉九鼎自己移植的led驱动,要在make menucofig中去掉选择项,然后重新make得到zImage,然后重启时启动这个新的zImage即可。
make menuconfig Devices Driverscharcter devicesx210 led driver //按N去掉,保存退出重新make 编译得到新的zImage
(3) 新的内核启动后,如果/sys/devices/platform/目录下已经没有了x210-led这个目录,就说明去掉这个驱动成功了。
1.5.2 添加led驱动框架支持
(1) 当前内核中是没有LED驱动框架的,要去添加它。
make menuconfigDevice Drivers[*]LED support[*]LED class support
然后make编译之后,重新得到zImage,通过tftp启动,进入/sys/class,看见添加的leds就是成功。
二、实践—基于驱动框架写led驱动
2.1 分析
(1) 参考 drivers/leds/leds-s3c24xx.c
(2) 关键点:led_classdev_register
1) 驱动被加载了,/sys/class/leds/目录下确实多出来了一个表示设备的文件夹。文件夹里面有相应的操控led硬件的2个属性brightness和max_brightness
2) led-class.c中brightness方法有一个show方法和store方法,这两个方法对应用户在/sys/class/leds/myled/brightness目录下直接去读写这个文件时, 实际执行的代码。
当show brightness时,实际就会执行led_brightness_show函数
当echo 1 > brightness时,实际就会执行led_brightness_store函数
(3) show方法实际要做的就是读取LED硬件信息,然后把硬件信息返回即可。所以show方法和store方法必要要会去操控硬件。但是led-class.c文件又属于驱动框架中的文件,它本身无法直接读取具体硬件,因此在show和store方法中使用函数指针的方式调用了struct led_classdev结构体中的相应的读取/写入硬件信息的方法。
(4) struct led_classdev结构体中的实际用来读写硬件信息的函数,就是要写的驱动文件leds-s5pv210.c中要提供的。
2.2 在驱动中将LED设备分开
(1) 好处 :驱动层实现对各个LED设备的独立访问,并向应用层展示出4个操作接口led1、led2、led3、led4,这样应用层可以完全按照自己的需要对LED进行控制。
驱动的设计理念:不要对最终需求功能进行假定,而应该只是直接的对硬件的操作。有一个概念就是:机制和策略的问题。在硬件操作上驱动只应该提供机制而不是策略。策略由应用程序来做。
#include <linux/module.h> // module_init module_exit
#include <linux/init.h> // __init __exit
#include <linux/fs.h>
#include <linux/leds.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank.h>
#include <linux/io.h>
#include <linux/ioport.h>#define GPJ0CON S5PV210_GPJ0CON
#define GPJ0DAT S5PV210_GPJ0DATstatic struct led_classdev mydev1; // 定义结构体变量
static struct led_classdev mydev2; // 定义结构体变量
static struct led_classdev mydev3; // 定义结构体变量// 这个函数就是要去完成具体的硬件读写任务的
static void s5pv210_led1_set(struct led_classdev *led_cdev,enum led_brightness value)
{printk(KERN_INFO "s5pv210_led1_set\n");writel(0x11111111, GPJ0CON);// 在这里根据用户设置的值来操作硬件// 用户设置的值就是valueif (value == LED_OFF){// 用户给了个0,希望LED灭//writel(0x11111111, GPJ0CON);// 读改写三部曲writel((readl(GPJ0DAT) | (1<<3)), GPJ0DAT);}else{// 用户给的是非0,希望LED亮//writel(0x11111111, GPJ0CON);writel((readl(GPJ0DAT) & ~(1<<3)), GPJ0DAT);}
}static void s5pv210_led2_set(struct led_classdev *led_cdev,enum led_brightness value)
{printk(KERN_INFO "s5pv2102_led_set\n");writel(0x11111111, GPJ0CON);// 在这里根据用户设置的值来操作硬件// 用户设置的值就是valueif (value == LED_OFF){// 用户给了个0,希望LED灭//writel(0x11111111, GPJ0CON);// 读改写三部曲writel((readl(GPJ0DAT) | (1<<4)), GPJ0DAT);}else{// 用户给的是非0,希望LED亮//writel(0x11111111, GPJ0CON);writel((readl(GPJ0DAT) & ~(1<<4)), GPJ0DAT);}
}static void s5pv210_led3_set(struct led_classdev *led_cdev,enum led_brightness value)
{printk(KERN_INFO "s5pv210_led3_set\n");writel(0x11111111, GPJ0CON);// 在这里根据用户设置的值来操作硬件// 用户设置的值就是valueif (value == LED_OFF){// 用户给了个0,希望LED灭//writel(0x11111111, GPJ0CON);// 读改写三部曲writel((readl(GPJ0DAT) | (1<<5)), GPJ0DAT);}else{// 用户给的是非0,希望LED亮//writel(0x11111111, GPJ0CON);writel((readl(GPJ0DAT) & ~(1<<5)), GPJ0DAT);}
}static int __init s5pv210_led_init(void)
{// 用户insmod安装驱动模块时会调用该函数// 该函数的主要任务就是去使用led驱动框架提供的设备注册函数来注册一个设备int ret = -1;// led1mydev1.name = "led1";mydev1.brightness = 255; mydev1.brightness_set = s5pv210_led1_set;ret = led_classdev_register(NULL, &mydev1);if (ret < 0) {printk(KERN_ERR "led_classdev_register failed\n");return ret;}// led2mydev2.name = "led2";mydev2.brightness = 255; mydev2.brightness_set = s5pv210_led2_set;ret = led_classdev_register(NULL, &mydev2);if (ret < 0) {printk(KERN_ERR "led_classdev_register failed\n");return ret;}// led3mydev3.name = "led3";mydev3.brightness = 255; mydev3.brightness_set = s5pv210_led3_set;ret = led_classdev_register(NULL, &mydev3);if (ret < 0) {printk(KERN_ERR "led_classdev_register failed\n");return ret;}return 0;
}static void __exit s5pv210_led_exit(void)
{led_classdev_unregister(&mydev1);led_classdev_unregister(&mydev2);led_classdev_unregister(&mydev3);
}module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL"); // 描述模块的许可证
MODULE_AUTHOR("aston <1264671872@qq.com>"); // 描述模块的作者
MODULE_DESCRIPTION("s5pv210 led driver"); // 描述模块的介绍信息
MODULE_ALIAS("s5pv210_led"); // 描述模块的别名信息
测试结果:
三、gpiolib引入
(1) 一个事实:很多硬件都要用到GPIO、GPIO会复用
(2) 如果同一个GPIO被2个驱动同时控制了,就会出现bug
(3) 内核提供gpiolib来统一管理系统中所有GPIO
(4) gpiolib本身属于驱动框架的一部分
后续整理总结[6.Linux内核的gpiolib]。
相关文章:

5. 驱动开发
文章目录一、驱动开发1.1 前言1.2 何谓驱动框架1.3 内核驱动框架中LED的基本情况1.3.1 相关文件1.3.2 九鼎移植的内核中led驱动1.3.3 案例分析驱动框架的使用1.3.4 典型的驱动开发行业现状1.4 初步分析led驱动框架源码1.4.1 涉及到的文件1.4.2 subsys_initcall1.4.3 led_class_…...
模板方法模式详解
模板方法模式(行为模式) 1. 模板方法模式介绍 父类定义算法骨架,细节的具体实现延迟到子类子类只是定义某些自己的个性化处理,但不改变执行顺序 2. 好处 减少代码冗余,共性抽取后算法流程更加清晰与规范降低流程性…...
关于 Lightweight process container,ChatGPT的答案
晓楚 Can you give me a list of process container? As an AI language model, I can provide you with a list of popular process containers, which are as follows: Docker Kubernetes Apache Mesos LXC OpenVZ systemd-nspawn rkt (Rocket) Linux Containers (LXC) Ga…...

机器学习和深度学习的综述
机器学习和深度学习的综述 1.1.1人工智能、机器学习、深度学习的关系 人工智能(Artificial Intelligence,AI)是最宽泛的概念,是研发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。由于这个定义…...

Synopsys Sentaurus TCAD系列教程之--Sprocess(SmallMOS_2D3D) 解析
SmallMOS_2D3D解析 #header## STI depth set sti_depth 0.15 ## Half STI width set sti_width sti_width ## Half gate length set gate_len <lg/2> ## SD length (from center) set sd_len [expr $gate_len0.05]#endheader## X lines line x location 0.0 spacing 0.…...

好使!NAS中傻瓜式配置反向代理及SSL证书,提升网络安全性!
对于有NAS或者有个人主机的朋友来说,将机器映射到外网是基本操作。 但是一般来说,能直接从外网访问的往往仅有80和443端口。事实上,运营商一般把家庭宽带的这两个端口都封了,所以如果我们想要从外网访问自己家中机器部署的服务&a…...
数据结构队列-先进先出
一,概述 队列这个概念非常好理解。你可以把它想象成排队买票,先来的先买,后来的人只能站末尾,不允许插队。先进者先出,这就是典型的“队列”。 二,顺序队列和链式队列 队列和栈一样,也是一种…...
CentOS 7使用TiUP部署TiDB
本文主要是根据官方文档指导,结合实际主机情况,在Cent OS7上使用TiUP在线部署TiDB。 环境说明 类型操作系统版本配置中控机Deepin 20.34核CPU6G内存40G硬盘TiDB部署机Cent OS 7.38核CPU48G内存100硬盘网络情况中控机与外网相连,中控机与部署…...

java单元测试批处理数据模板【亿点点日志配合分页以及多线程处理】
文章目录引入相关资料环境准备分页查询处理,减少单次批量处理的数据量级补充亿点点日志,更易观察多线程优化查询_切数据版多线程_每个线程都分页处理引入 都说后端开发能顶半个运维,我们经常需要对大量输出进行需求调整,很多时候…...

【数据结构】模拟实现 堆
堆数据结构是一种数组对象,它可以被看作一颗完全二叉树的结构(数组是完全二叉树),堆是一种静态结构。堆分为最大堆和最小堆。最大堆:每个父结点都大于孩子结点。最小堆:每个父结点都小于孩子结点。堆的优势…...

Go语言学习的第三天--上部分(基础用法)
前两天经过不断度娘,与对up主的跟踪学习了解了go的历史,今天开始了go的基础!!本章主要是go 的注释、变量及常量的梳理一、注释不管什么语言都有自己的注释,go也不例外 !!单行注释 // 多行注释 …...

linux面试基础篇
题目目录1.简述DNS分离解析的工作原理,关键配置2.apache有几种工作模式,分别简述两种工作模式及其优缺点?3.写出172.0.0.38/27 的网络id与广播地址4.写出下列服务使用的传输层协议(TCP/UDP)及默认端口5.在局域网想获得…...

黑马程序员提高变成
这里写目录标题函数模板1.2.2 函数模板注意事项1.2.3 函数模板案例调用规则类模板与函数模板区别类模板与继承类模板成员函数类外实现#pragma once类模板与友元案例重新定义【】stl2.2 STL基本概念STL六大组件容器算法迭代器初识vectorvector容器嵌套容器string容器string赋值操…...
MySQL5种索引类型
MySQL的类型主要有五种:主键索引、唯一索引、普通索引、空间索引、全文索引 有表: CREATE TABLE t1 ( id bigint unsigned NOT NULL AUTO_INCREMENT, u1 int unsigned NOT NULL DEFAULT 0, u2 int unsigned NOT NULL DEFAULT 0, u3 varchar(20) NOT NU…...
uniapp封装缓存方法,支持类似cookie具有过期时间
1、定义CacheManage类,有set和get方法 class CacheManage {set() {},get() {} }set用来设置缓存,get用来获取缓存 2、完善set业务逻辑 大概逻辑如下: 1、将接收params参数,包含key、data、unit、time key 缓存字段,…...

Jfrog 搭建本地maven仓库以及上传Android库
Jfrog 下载 安装包下载地址:Download Artifactory OSS | JFrog 如果是想下载之前的版本,可以点击上面的Get code source ,如果是最新版本,直接点下面的下载就好。下面以Linux安装为例。 Jfrog安装 对于Linux而言,其实…...

日报周报月报工作总结生成器【智能文案生成器】
日报周报月报工作总结生成器【智能文案生成器】 天天写日报,我真的快奔溃了! 摸了一天鱼,下班还要写日报; 划了一周的水,周末还要写周报; 啊啊啊啊… 在职场上,尤其是互联网公司里,…...
linux日志管理工具logrotate配置
linux日志管理工具logrotate配置logrotate介绍logrotate配置讲解主配置文件解释(/etc/logrotate.conf)logrotete 命令参数添加配置以添加一个nginx配置为例强制启动配置logrotate介绍 logrotate是centos自带工具,其他操作系统可能需要自行安装。logrotate用来进行日…...
[ C++ ] 设计模式——单例模式
目录 1.设计模式: 2.单例模式 饿汉模式 懒汉模式 饿汉模式和懒汉模式的优缺点 1.设计模式: 设计模式(Design Pattern)是一套被反复使用,多数人只晓得,经过分类的,代码设计经验的总结。为什么会产生设计模式这样的…...

HACKTHEBOX——Help
nmap可以看到对外开放了22,80,3000端口可以看到80端口和3000端口都运行着http服务,先从web着手切入TCP/80访问web提示无法连接help.htb,在/etc/hosts中写入IP与域名的映射打开只是一个apache default页面,没什么好看的使用gobuster扫描网站目…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...