
驱动开发
文章平均质量分 83
lanhuazui10
这个作者很懒,什么都没留下…
展开
-
Linux设备树语法2
设备树简单理解就是描述设备信息(资源)的一棵树。设备树(Device Tree)用代码体现如下:这些代码被保存在.dts/dtsi后缀文件中,也即设备树源文件 DTS(DeviceTree Source)。这些源文件同我们的C代码一样,并不能直接使用的,而是得经过一个编译过程生成机器可运行的二进制文件,如:dts文件使用dtc工具编译生成dtb文件,这个dtb文件就是内核可以使用的文件。转载 2024-12-01 21:19:36 · 65 阅读 · 0 评论 -
设备树dts语法1
Arm系统启动,硬件设备可以通过DTS(devicetree)或ACPI引导初始化,这里只讲DTS方式,ACPI是由BIOS配置。如上图,一般来说,arm内核通过dts引导启动,需要内核Image、dtb和filesystem,其中dtb是由dts通过dtc工具生成,里面包括初始化设备的硬件信息。内核Image启动过程中会解析dtb中内容,并根据信息初始化设备平台。这里提一句,dts由虽然由用户配置,但是配置必须与硬件信息相匹配,否则会出现初始化失败或设备部分功能不正常的问题。转载 2024-12-01 21:09:59 · 115 阅读 · 0 评论 -
Linux驱动 | 从0写一个设备树节点实例
设备树是每一个Linux驱动工程师都必须掌握的一个知识点,有很多之前做单片机的朋友刚接触Linux驱动时,会一脸懵!其实设备树的使用并没有大家想像的那么复杂,对于大部分工程师来说,只要会修改即可。在学习设备树之前,大家一定要搞清楚什么是platform总线,有了这些基础知识后,我们就可以来编写一个设备树的实例。下面彭老师就给大家讲解如何自己添加一个设备树节点,并如何在驱动中提取出设备树的信息。转载 2024-12-01 19:50:19 · 224 阅读 · 0 评论 -
手把手教linux驱动11-linux设备驱动统一模型
我们使用#把宏参数变为一个字符串。调用:printf("%d",x+3);--> 打印:The value of x+3 is 20这是因为”The value of”#VALUE”is ” FORMAT”\n”实际上是包含了”The value of “,#VALUE,”is “,FORMAT,”\n” 五部分字符串,其中VALUE和FORMAT被宏参数的实际值替换了。用##把两个宏参数贴合在一起调用:ADD_TO_SUM(2,100);--> 打印:sum2+=(100)转载 2024-12-01 16:46:54 · 101 阅读 · 0 评论 -
内核窥探|在kernel中的链表
一个链表要想区分节点的不同类型,那么节点中必须要有信息能够区分该节点类型,为了方便节点扩展,我们参考Linux内核,定义一个统一类型的结构体:int type;其中成员type表示该节点的类型:有了该结构体,我们要定义其他类型的结构体只需要包含该结构体即可,这个思想有点像面向对象语言的基类,后续派生出新的属性叫子类,说到这,一口君又忍不住想挖个坑,写一篇如何用C语言实现面向对象思想的继承、多态、interface。下面我们定义2种类型的结构体:i2c这种类型设备的专用结构体:转载 2024-12-01 16:39:31 · 70 阅读 · 0 评论 -
Linux下SPI驱动详解
SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。转载 2024-11-29 23:47:00 · 254 阅读 · 0 评论 -
Linux input 子系统详解
1.1.相关资料和代码研究Linux输入设备种类繁杂,常见的包括触摸屏、键盘、鼠标、摇杆等;这些输入设备属于字符设备,而linux将这些设备的共同特性抽象出来,Linux input 子系统就产生了。应用有两条路径,如下所示/dev/input查看设备信息U: Uniq=B: PROP=0B: MSC=10event节点里面存放的数据都是没有经过处理的原始数据流。cat 对应的eventX节点就可以查看输入的数据。转载 2024-11-29 22:54:35 · 459 阅读 · 0 评论 -
Linux驱动|cdev_init、cdev_alloc区别
搞懂上面字符设备创建步骤之后,我们就可以来真正分析cdev_init、cdev_alloc这两个函数了。转载 2024-11-29 20:53:54 · 144 阅读 · 0 评论 -
Linux 虚拟文件系统四大对象:超级块、inode、dentry、file之间关系
操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。通常文件系统是用于存储和组织文件的一种机制,便于对文件进行方便的查找与访问。文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等。随着文件种类的增多,扩增了更多的文件系统,为了对各种文件系统进行统一的管理与组织。转载 2024-11-29 20:22:59 · 238 阅读 · 0 评论 -
Linux驱动-进程、文件描述符、file、inode关系详解
Linux 中一切都可以看作文件,包括普通文件、链接文件、Socket 以及设备驱动等,对其进行相关操作时,都可能会创建对应的文件描述符。文件描述符(file descriptor)是内核为了高效管理已被打开的文件所创建的索引,用于指代被打开的文件,对文件所有 I/O 操作相关的系统调用都需要通过文件描述符。Linux启动后,会默认打开3个文件描述符,分别是:0:标准输入 standard input1:正确输出 standard output2:错误输出 error output。转载 2024-11-29 18:08:46 · 257 阅读 · 0 评论 -
Linux内核i2c-tools--读写i2c设备寄存器的在线调试命令
文章来自一口linux博客(),拿来记录学习心得。本文基于RockPi 4A Debian系统介绍i2c设备的调试工具i2c-tools。i2c-tools的相关命令常用于linux系统读写i2c设备寄存器的在线调试。转载 2024-11-29 00:44:47 · 198 阅读 · 0 评论 -
驱动学习(四) 字符设备详解
文章来自一口linux博客(),这里做笔记使用。转载 2024-11-28 23:24:48 · 150 阅读 · 0 评论 -
i2c的设备树和驱动是如何匹配以及何时调用probe的?
文章来自一口linux博客(),大家可以去他博客学习,这里只是拿来记录笔记学习体会的。转载 2024-11-27 20:51:36 · 221 阅读 · 0 评论 -
中断申请函数request_irq详解
根据我们前面中断模型的知识,可以看出发生中断时,内核并不判断究竟是共享中断线上的哪个设备产生了中断,它会循环执行所有该中断线上注册的中断处理函数(即irqaction->handler函数)。因此将设备结构体通过dev_id传递给设备中断处理程序的另一个作用就是使用共享中断时,可以在中断处理函数内通过读取该设备结构 (dev_id) 中提供的中断Flag标志位地址信息进行判断,是否是该设备产生了中断,然后再进一步判断是否继续往下执行还是跳到下一个irqaction->handler函数再判断执行。转载 2024-11-08 20:57:45 · 1096 阅读 · 0 评论 -
ioremap() 函数和iounmap函数
但是CPU通常并没有为这些已知的外设I/O内存资源的物理地址预定义虚拟地址范围,驱动程序并不能直接通过物理地址访问I/O内存资源,而必须将它们映射到核心虚地址空间内(通过页表),然后才能根据映射所得到的核心虚地址范围,通过访内指令访问这些I/O内存资源。典型地,如X86处理器为外设专门实现了一个单独的地址空间,称为"I/O地址空间"或者"I/O端口空间",CPU通过专门的I/O指令(如X86的IN和OUT指令)来访问这一空间中的地址单元。readl() 从内存映射的 I/O 空间上。转载 2024-11-08 20:48:12 · 172 阅读 · 0 评论 -
Linux内核时间子系统--RTC时间架构
同时发现rtc0文件为指向/sys/devices/platform/fe5e0000.i2c/i2c-5/5-0051/rtc/rtc0的符号链接,RTC芯片是I2C接口,所以rtc0挂载在I2C的总线上,总线控制器地址fe5e0000,控制器编号为5,RTC芯片作为slave端地址为0x51。在瑞芯微的系统中,安卓部分程序其实最终也是依赖**/sys/class/rtc/rtc0** 下的文件节点实现时间管理功能的。这是就是为什么,我们的设备关机并重启后,仍然能够显示正确的时间的原因。转载 2024-11-02 15:46:19 · 289 阅读 · 0 评论 -
【转】驱动学习---linux内核定时器使用及操作
其中 del_timer_sync 是用在 SMP 系统上的(在非SMP系统上,它等于del_timer),当要被注销的定时器函数正在另一个 cpu 上运行时,del_timer_sync() 会等待其运行完,所以这个函数会休眠。注销一个定时器,可以通过 del_timer(struct timer_list *timer) 或 del_timer_sync(struct timer_list *timer)。需要注意的是 expires 的值是32位的,因为内核定时器并不适用于长的未来时间点。转载 2024-11-02 15:28:18 · 45 阅读 · 0 评论 -
【转】手把手教Linux驱动10-platform总线详解
这样在 platform_driver_register() 注册时,会将当前注册的 platform_driver 中的 name 变量的值和已注册的所有 platform_device 中的 name 变量的值进行比较,只有找到具有相同名称的 platform_device 才能注册成功。需要注意的是:platform_driver 和 platform_device 中的 name 变量的值必须是相同的【在不考虑设备树情况下,关于设备树,后面会写新的文章详细讲述】。转载 2024-11-01 21:36:25 · 55 阅读 · 0 评论 -
驱动学习-poll机制深入理解
可以看到不按键时poll函数5s超时,按键按下后先执行gpio_key_isr,然后应用层进程变为可运行态会被调度执行,poll函数返回值POLLIN,if语句成立,调用read函数,进而驱动的read函数被调用,同时wait_event_interruptible()函数condition条件满足,将key值返回给应用层,应用层一次调用poll函数,驱动层poll函数可能被调用2次(刚开始执行一次,超时时执行一次)。有人会问如果驱动的poll()函数不调用poll_wait(),即屏蔽掉该行会怎么样?转载 2024-11-01 17:36:17 · 214 阅读 · 0 评论 -
Linux内核:通过wait_event和wake_up内在机制分析等待队列
的几个状态之后,现在我们开始着重讲解其中的一个状态,等待状态,由上面的等待状态的描述,我们可以知道处于等待状态的进程正在等待某一个事件或者某一个资源,它肯定位于系统中的某一个等待队列中。所以在这里我们也可以通过此来判断等待队列是否有等待队列项,如果没有等待队列项,task_list链表的nest指针应该是指向自己的,而不会指向其他等待队列项。作用:其实只要定义一个等待队列头,并且初始化,就相当于在Linux内核中重新开辟了一条等待队列,后面的等待队列项只要往后加等待队列项就可以了。该等待队列是独一无二的。转载 2024-10-31 20:00:05 · 330 阅读 · 0 评论 -
内核驱动中的链表
使用宏 list_for_each_entry(pos, head, member) 或者使用 list_for_each_entry_safe(pos, head, member) 进行链表遍历。void list_add_tail(struct list_head *new, struct list_head *head) 是在链表的尾部插入。void list_add(struct list_head *new, struct list_head *head) 一般是在元素节点的中间插入。转载 2024-10-31 00:53:16 · 92 阅读 · 0 评论 -
自旋锁--死锁
上面这种有一个条件是在单核CPU(可用ps -ef| grep softirq查看是否是单个CPU,因为一个softirq对应一个CPU),因为进程A此时拥有自旋锁了,该CPU被禁止抢占了,此时A内核阻塞了,又放弃了CPU占用,进程B申请自旋锁后一直自旋,一直占用CPU,其他进程,包含进程A又无法获得CPU了,导致了死锁。内核发生访问资源冲突的时候,可以有两种锁的解决方案选择:一个是原地等待,一个是挂起当前进程,调度其他进程执行(休眠)。进程拥有自旋锁的时候,该CPU上是禁止抢占的。原创 2024-10-31 00:32:13 · 482 阅读 · 0 评论 -
驱动学习:进程&文件描述符&file&inode&设备号关系
通过对比驱动的入参和应用程序的入参,我们也不难猜出应用层open一个设备时,其所对应的设备号将会通过inode参数传入到驱动中,而进行读写操作时文件句柄所携带的信息也将会通过file参数输入到驱动中。驱动代码如下,需要注意的是,在驱动模块加载时就要完成所支持的从设备上下文的相关变量的赋值,包括但不局限于devno,class_dev。也可以多个文件对应一个设备。前面我们学习vfs层的时候,实际上就已经列出了inode的结构,其中i_rdev成员中所记录的信息就是当前操作设备的设备号。转载 2024-10-29 22:46:58 · 94 阅读 · 0 评论 -
驱动-读写接口实现(read&write)
如果读取失败,则会返回-1,并设置相应的错误码。用户程序调用write接口时,通过系统调用,驱动模块中会根据文件的fd数据,最后调用到file_operations 中的*write函数指针。正确的做法是在内核空间开辟自己可以操作的内存,将用户空间的数据拷贝到内核空间之后,内核操作自己的这块内存即可,即使进程意外结束,内核也不会崩溃,这种做法的安全性是要比前者的高的。用户程序调用read接口时,通过系统调用,驱动模块中会根据文件的fd数据,最后调用到file_operations 中的*read函数指针。转载 2024-10-29 17:40:51 · 249 阅读 · 0 评论 -
驱动学习(十一)异步IO机制-信号驱动
读进程去设备中读数据,设备没有数据可读,那么当前进程继续执行等待通知,若内核检测到设备有数据可读之后,会给读进程发送通知信号,读进程会执行该信号对应的处理函数去读数据。转载 2024-10-28 17:59:24 · 108 阅读 · 0 评论 -
驱动学习(十)I/O复用模型-poll机制
不如直接阻塞啊,阻塞还能让进程放弃cpu的资源呢,select遍历加轮询不是占用资源嘛,还是有点尬的,这是个测试,只是打开了一个设备文件,调用了多个驱动后就有意义了啊!poll机制测试成功,虽然没有看到read不是无脑阻塞,而是因为select通过驱动的poll收到了POLLIN或者是POLLRDNORM而调用的read。原文链接:https://blog.csdn.net/a834605978/article/details/125791507。在test1中写入数据,可以看到test读到了数据。转载 2024-10-28 17:55:34 · 41 阅读 · 0 评论 -
驱动学习(九)驱动并发处理,互斥锁
一类设备对应一个驱动程序,一类设备可以有多个子设备,当多个子设备同时访问一个驱动程序时,会造成竞态。这样test1拿到驱动资源了,test1读到的数据是test输入的数据。竞态就是两个子设备同时访问了一个驱动程序,就是他俩同时进厕所了,坑位只有一个,这这这,不像话啊。会造成数据错乱,这里我没有还原出来,但是对于内核级别来说是致命的。在test没使用完驱动资源之前,test1是拿不到资源的,光标一直在闪。模拟条件:一个驱动,两个设备文件,一起访问。效果与互斥锁一样,代码太长了要不不放了。转载 2024-10-28 17:50:45 · 102 阅读 · 0 评论 -
驱动学习(八)ioctl设备管理
linux内核给用户提供了两类系统调用函数:一类是数据操作函数,比如read、write…另外一类函数是非数据操作函数,比如ioctl…,用户程序可以用ioctl给底层设备发送指令。可以看到第一次的cmd没有传参,arg为0;第三次未传参arg被第二次的赋值为123456,验证完毕。思路:在test.c中调用ioctl函数发送cmd,在驱动模块中让对应的cmd打印不同的信息。ioctl是一个系统调用函数,应用程序可以用它给内核发送指令。2.2.1 合成标准命令码的宏函数。环境 ubuntu 20.04。转载 2024-10-28 17:43:54 · 137 阅读 · 0 评论 -
驱动学习(七)字符设备的非阻塞I/O操作
是指在不能进行设备操作时,并不挂起或休眠该进程,而是给请求进程一个非正确的返回值,底层设备驱动通过不停的查询操作是否可进行,直到操作可进行后给请求进程返回一个正确的结果。fd=open("/dev/设备文件名",O_RDWR|O_NONBLOCK);此时让test1写入,再次执行test,test读到test1写入的数据返回了。阻塞请求读数据的进程(使请求读的进程休眠)test在没有读到数据的时候返回了,此时test1还未写入。(进程在不能进行设备的操作时,并不休眠,而是立即返回)若有,驱动代码返回;转载 2024-10-28 17:39:19 · 46 阅读 · 0 评论 -
驱动学习(六)字符设备的阻塞I/O操作
原文链接:https://blog.csdn.net/a834605978/article/details/125770688。test先读再写,test1先写再读,此时在test1未写入之前,test处于读堵塞状态。在执行设备操作时,若不能获得资源则挂起进程直到满足可操作的条件后再进行操作。当进程休眠时,进程在休眠等待队列中等待被唤醒运行。只是测试了可以被中断的读阻塞,不可被中断的未测。当进程正常运行时,进程在运行队列中等待被运行。Makefile 可以参考上一节。2. 驱动中如何实现读阻塞?转载 2024-10-28 17:34:57 · 44 阅读 · 0 评论 -
驱动学习(五)自动创建设备文件
思路:在上一节代码的基础上添加:自动创建设备文件类(安装时)、自动创建设备文件(安装时)、自动删除代码(卸载时)。查看内核打印信息是否正确和查看字符设备文件是否创建成功来验证结果。linux内核为我们提供了一组函数,可以用来在模块加载时自动在/dev目录下创建设备对应的设备文件,并在模块卸载时删除该设备文件。所有打印信息,autoCreateNode0读写读、autoCreateNode1读写读。创建设备文件类成功、创建设备文件成功,查看设备文件。完整内核打印信息,打开、读写、关闭,都没有问题。转载 2024-10-28 17:25:16 · 105 阅读 · 0 评论 -
驱动学习(四) 字符设备驱动简单了解
1. 什么是字符设备?是指只能一个字节一个字节的读写的设备,不能随机的读取设备中的某一段数据源,读取数据需要按照先后顺序。字符设备是面向字节流的。2. 常见的字符设备有哪些?鼠标、键盘、串口、控制台tty3. 什么是块设备?可以从设备的任意位置读取一定长度数据的设备4. 常见的块设备有哪些?硬盘、磁盘、光盘、U盘、SD卡5. 字符设备驱动框架5.1 设备号5.1.1 什么是设备号?设备号是设备在内核中的身份和标志,是内核区分不同设备的唯一信息。转载 2024-10-28 17:12:36 · 143 阅读 · 0 评论 -
驱动学习(三)符号导出
内核中每个模块之间是相互独立的,也就是说A模块的全局变量和函数,B模块是无法访问的。若B模块想要使用A模块中的已有符号,那么必须将A模块中的符号做符号导出,导出到模块符号表中,然后B模块可以使用A模块导出的符号。分别创建两个驱动模块文件夹,分别编写符号导出驱动模块(export_symbols.c)和符号使用驱动模块(use_symbols.c)。在export_symbols.c中使用EXPORT_SYMBOL()宏函数和EXPORT_SYMPOL_GPL()宏函数测试导出符号。原创 2024-10-28 15:24:39 · 1095 阅读 · 0 评论 -
驱动学习(二)模块传参
编译出错了,查询后发现是**__ATTR**宏的权限问题,将上述的0666改为0664,问题解决。具体参考了https://blog.csdn.net/Q1302182594/article/details/53558192。在/sys/module/目录下,进入自己安装的驱动模块目录下,例如我此时安装的驱动模块是module_param,进入此目录,再进入parameters目录下,就可以看到定义的全局变量。驱动程序通过shell终端给驱动中的参数赋实参值,驱动程序通过声明后的全局变量接收参数。转载 2024-10-28 15:05:13 · 34 阅读 · 0 评论 -
ubuntu 20.04编译驱动报gcc-12 not found错误
按照如下操作,发现可以解决,记录下,主要是Ubuntu缺少g++-12的包。安装包以后发现可以正常编译。原创 2024-10-27 22:02:42 · 1422 阅读 · 0 评论 -
自旋锁、互斥锁区别
内核锁:基于内核对象构造的锁机制,就是通常说的内核构造模式。:cpu利用最大化。它发现资源被锁住,请求就排队等候。线程切换到别处干活,直到接受到可用信号,线程再切回来继续处理请求。:托管代码->用户模式代码->内核代码损耗、线程上下文切换损耗。在锁的时间比较短时,系统频繁忙于休眠、切换,是个很大的性能损耗。自旋锁+自循环。通常说的用户构造模式。线程不休眠,一直循环尝试对资源访问,直到可用。:完美解决内核锁的缺点。:长时间一直循环会导致cpu的白白浪费,高并发竞争下、CPU的消耗特别严重。转载 2024-09-18 13:12:59 · 168 阅读 · 0 评论 -
linux 内核 – ioctl 函数详解
在新版内核中, 与 取代了。在实际应用中,ioctl 最常见的 errorno 值为 ENOTTY(error not a typewriter),顾名思义,即第一个参数 fd 指向的不是一个字符设备,不支持 ioctl 操作,这时候应该检查前面的 open 函数是否出错或者设备路径是否正确。ioctl 是设备驱动程序中设备控制接口函数,一个字符设备驱动通常会实现设备打开、关闭、读、写等功能,在一些需要细分的情境下,如果需要扩展新的功能,通常以增设 ioctl() 命令的方式实现。转载 2023-10-09 19:43:47 · 2580 阅读 · 0 评论 -
信号基础知识
信号(signal)是一种进程间通信机制,它给应用程序提供一种异步的软件中断,使应用程序有机会接受其他程序活终端发送的命令(即信号)。应用程序收到信号后,有三种处理方式:忽略,默认,或捕捉。进程收到一个信号后,会检查对该信号的处理机制。如果是SIG_IGN,就忽略该信号;如果是SIG_DFT,则会采用系统默认的处理动作,通常是终止进程或忽略该信号;如果给该信号指定了一个处理函数(捕捉),则会中断当前进程正在执行的任务,转而去执行该信号的处理函数,返回后再继续执行被中断的任务。转载 2023-10-07 20:11:06 · 1389 阅读 · 0 评论 -
make -C M= modules编译流程解析
C $(KERNEL_DIR) 代表切换工作目录,因为内核源码顶层的Makefile文件定义了伪目标 modules,所以要先将工作目录切换到内核源码顶层 Makefile 所在位置。这个可以让makefile 回到自己所指定的目录下查找模块源码,将其编译,生成 ko 文件。obj-m 表示把文件 chrdevbase.o 作为"模块"编译,不会编译进内核,但会生成一个独立的 ko 文件。下面是最简易的单文件单模块编译,假设我们要将源文件 chrdevbase.c 编译成 ko 文件。转载 2023-10-05 21:27:06 · 474 阅读 · 0 评论 -
busybox简介
BusyBox 包含了许多常见的 Unix 工具和命令,例如文件操作命令(如 ls、cp、mv)、文本处理工具(如 grep、sed、awk)、系统管理工具(如 ps、top、ifconfig)、网络工具(如 telnet、ftp、ping)等等。它的可执行文件相对较小,占用的内存和存储空间较少,适合于嵌入式设备、虚拟机、容器和其他资源有限的环境。BusyBox 是一个单一可执行文件的软件集合,旨在提供一个轻量级的 Unix 工具箱,包含了许多常用的命令和实用程序。原创 2023-09-23 21:34:33 · 645 阅读 · 0 评论