- 博客(58)
- 收藏
- 关注
原创 56.平台总线模型
平台总线是Linux虚拟出来的总线,与实际I2C,SPI不同,作用是将分离的device.c和driver.c合并,分离的好处是对于不同的开发版只需要更改device.c。ls /sys/bus/platform/devices/ 可以查看注册的device。ls /sys/bus/platform/drivers/ 可以查看注册的driver。
2025-12-25 17:28:25
51
原创 54.并发管理工作队列
在旧版机制中,每个 CPU 只有一个内核线程处理工作。如果某个任务因为等待硬件响应而进入休眠,那么排在它后面的所有任务(即便不耗时)都必须等它醒来。:当 CMWQ 监测到一个正在运行的任务进入休眠(阻塞)时,它会。:保证了 CPU 的流水线不会因为某个任务的“偷懒”而停滞。点击屏幕触发中断,执行中断函数。
2025-12-25 15:16:06
115
原创 53.自定义工作队列传参
这里用到了container_of,可以利用某个成员的地址,顺藤摸瓜拿到拿到整个结构体的地址。每当中断触发,它都会在系统后台异步打印出。编译及在开发板上测试。
2025-12-17 22:53:46
205
原创 52.延迟工作队列
延迟工作队列可以对原有的共享工作队列和自定义工作队列,加上定时器进一步封装,再进入中断程序的下半部分进行延迟进入。delayed_work:「先等延迟,再占队列执行」→ 仅占用执行逻辑的必要时间,不浪费公共资源。由此可以看到延迟了4秒钟,包括进入下半段和下半段延迟。直接延迟:「先占队列,再等延迟」→ 霸占公共资源;这是比在直接在中断下半段延迟的好处。编译及开发板验证测试。
2025-12-13 21:36:38
196
原创 49.为什么说tasklet是一种特殊软中断
tasklet是一种特殊的软中断的原因是:当内核需要做些延迟任务场景(字符设备拷贝数据),会执行tasklet_schedule(),将tasklet加入每个cpu的对应链表中,并触发软中断,对应中断处理函数就会遍历链表去执行相应回调函数。这样做的好处是不需要向内申请额外中断号,所以说tasklet是一种特殊软中断。当调用tasklet时会将tasklet加入链表,并触发软中断。对tasklet_action_common的封装。这里会遍历tasklet,执行对应中断处理函数。
2025-12-10 14:19:17
121
原创 48.自定义软中断
linux/interrupt.h,自定义中断号。编译源码,将镜像符号表覆盖原有的模块符号表。删除相关中间文件及原有的符号表。需要将导出相关函数到符号表。
2025-12-10 13:27:59
154
原创 47.tasklet中断下文
上一节request_irq的中断处理函数是上半文,这里tasklet_init绑定的是下半文函数,用于处理耗时操作,且在函数中不能阻塞休眠,否则系统会异常。点击屏幕会触发中断处理函数(前提需要卸载触摸驱动)编译并在开发版上的测试。
2025-12-08 17:02:03
110
原创 46.request_irq是如何向内核申请中断
每一个具体的外设中断对应一个中断描述描述符struct irq_desc *desc,该描述符中有action字段中会有中断处理函数,在request_threaded_irq中会完成action的初始化,以及desc和action的绑定,如此就申请了中断。共享中断是指多个外设共享一个中断,这是也是desc的action为指针的原因,可以链接多个,通过dev_id去区分中断处理函数。
2025-12-07 13:35:10
185
原创 45.申请一个GPIO中断
中断:cpu停下手中的事情,转去处理中断处理程序,处理完之后,再继续执行之前停下的事情,中断处理程序分为上半段(执行耗时短,任务紧急的事情),下半段(执行耗时任务)。在内核中去掉这个模块,不让后续插入这个ko会有冲突。GIC:接管cpu的外部中断,处理之后交给cpu。将编译的ko拷入开发板上并插入。测试点击屏幕会触发中断函数。
2025-12-06 23:42:59
176
原创 44.驱动的调试方法
3.WARN_ON(condition)和WARN(condition,fmt...) 打印调用关系,会调用dump_stack()4.BUG()和BUG_ON(condition) 触发内核oops,并打印。5.panic(fmt...) 引起系统死机并打印。2.dump_stack() 打印调用关系。1.printk 打印自定义信息。
2025-12-06 12:34:06
62
原创 44.优化驱动的稳定性和效率
2.在整个执行过程是,是流水线机制,存在预读取,可以使用likely和unlikely进行优化。1.可以在相关函数后面增加if判断,如果出错就直接返回。
2025-12-06 12:07:02
225
原创 43.封装驱动提供的api函数
应用工程师是不希望看到驱动的相关定义,比如#define TIMER_OPEN _IO('L',0),因此需要封装,提供相关的api函数。驱动ioctl_timer.c。
2025-12-05 23:22:56
163
原创 38.linux内核打印等级
数字越小,等级越高,insmod的ko之所以不能直接打印printk的信息,是因为默认打印消息没能小于控制台打印消息,所以要改变printk的打印等级。在这个路径下include/linux/kern_levels.h对应着打印等级对应的宏定义。1 代表最小控制台打印等级。7 代表默认控制台打印等级。4 代表默认消息打印等级。方法一:调用printk时设置打印等级。4 代表控制台打印等级。方法二:使用echo直接修改打印等级。qemu测试,符合预期。
2025-11-18 19:24:06
292
原创 35.linux的定时器使用
linux的定时器是一种基于未来时间点的定时器。定时器以现在的时间为起始点,以未来的某一时间为定时器的终点。类似于手机的闹钟,定于7点,响铃之后还想再睡会,可以延期5分钟,到了7点5分就响。可以看出五秒产生一次打印。Makefile编写。
2025-11-09 22:27:01
206
原创 34.信号驱动IO
信号驱动IO不需要应用程序去检查设备的状态。一旦设备准备就绪,就触发SIGIO信号,该信号会通知应用程序数据已经到来。1.sigal.c驱动代码编写。2.Makefile编写。
2025-11-04 22:43:58
104
原创 32.实现非阻塞访问方式
通过file->f_flags 组合位掩码中是否有包含O_NONBLOCK位掩码,并使用flag标志位判断是否有准备好数据。3.应用测试程序read.c write.c编写。read.c通过检查返回值来判断是否有读到数据。write.c写数据,并触发flag为1。直到写才会有数据读出来,读是采用轮询方式。1.驱动nonblock.c代码编写。2.Makefile编写。
2025-11-02 18:51:36
198
原创 30.IO模型
从键盘上输入数据时,会触发内核的中断机制,将数据输入到内核缓冲区,数据输入完时,会触发scanf底层的系统调用read来获取内核缓冲的数据。IO模型:阻塞IO,非阻塞IO,多路复用IO,信号驱动IO,异步IO。他这里会建立一个用户空间和内核空间的信号函数,一旦数据准备好,内核会主动发送准备好的信号,后将数据拷贝用户空间。从图中可以可以看出,他是一个不断轮询的过程,比较吃cpu,不过进程此时可以去干其他的事情。可以理解升级版的阻塞IO,他这个会有多个系统调用去检查内核有没有准备号好数据。
2025-11-02 11:28:08
171
原创 28.互斥锁
同一资源同一时间只能有一个访问者在进行访问,实现这种功能的锁就是互斥锁。类似信号量值为1的情况,也会引起休眠。1.metuxlock.c编写。2.Makefile编写。4.编译及arm环境测试。
2025-11-01 13:32:04
201
原创 27.信号量
从实验结果可以看出a.out执行完close之后,b.out才能open,可以很好的说明信号量会引起调用者b.out的休眠。信号量的本质是一个全局变量,值可以自行设置,当到达0时就不能访问了,会引起休眠。适用场景:持有锁时间比较长用信号量,也可以理解为持有临界资源比较长的场景。特点:信号量会引起调用者的休眠。1.semaphore.c编写。2.Makefile编写。4.编译及arm环境测试。3.应用测试用例编写。
2025-10-31 20:59:13
112
原创 26.自旋锁的死锁
首先,自旋锁是禁止抢占的,在单核cpu中A进程对用共享资源以自旋锁的方式去进行访问,在自旋锁的过程中进入休眠,此时B进程想访问这个共享资源就拿不到,陷入死锁。多核cpu虽然不会出现这种情况,但是消耗多余的时间,等待其它cpu的调度。但多核cpu会有中断死锁。比如A进程以自旋锁的方式访问共享资源是,出现中断,在中断中又出现了该自旋锁,此时会出现死锁,可以调用禁用中断自旋锁spin_lock_irqsave。避免在一个函数里多次使用自旋锁。1.deadclock.c编写。2.Makefile编写。
2025-10-31 19:08:09
215
原创 25.自旋锁
自旋锁是以原地等待的方式获取资源,即当A线程获取自旋锁之后,B会不断尝试获取自旋锁,此时是占CPU的。当然这个例子不能很好的说明自旋功能,后续补充。spinlock.c编写。3.test.c编写。
2025-10-30 19:43:23
206
原创 24.原子操作
所谓的原子操作是指在该操作执行完之前不能被打断。1.atomic.c驱动代码编写。3.应用程序编写test.c。2.Makefile编写。
2025-10-30 17:22:32
96
原创 23.并发与竞争
解决方法:无非就是对共享资源的保护,有以下几种方法,原子操作,自旋锁,信号量,互斥体。执行流 2(如中断处理函数)在执行流 1 的 “读” 和 “写” 之间被触发,也执行。的最终结果错误(比如预期 + 2,实际只 + 1),这就是典型的并发竞争问题。高优先级任务抢占当前低优先级任务,访问共享资源。停下当前任务,去执行中断任务,访问共享资源。多核处理器并发访问。核间并发访问共享资源。竞争:并发任务对共享资源的访问。执行流 1(如进程 A)执行。假设内核中有一个全局变量。并发:多个任务交替执行。
2025-10-30 15:21:27
178
原创 22.点亮一颗led灯
通过全局搜索PMU_GRF_GPIO0B_IOMUX,发现是由PMU_GRF_GPIO0B_IOMUX_H控制gpio0b7,并且是有[14:12]位控制,其中0值代表复用GPIO_B7,可以从图中看出PMU_GRF_GPIO0B_IOMUX_H的地址是由base + offfset构成,base之前的PWU_GRF,为0xFDC20000,所以PMU_GRF_GPIO0B_IOMUX_H=0xFDC2000C。开发板上测试,发现[15]默认是1,是输出,这和实际led灯亮是一致的。
2025-10-30 13:10:57
1016
原创 21.linux驱动错误处理
在内核中0xfffffffffffff000~0xffffffffffffffff(64位系统)用于记录错误码,这和include/linux/error_base.h定义的宏是一一对应的。在内核错误处理中,要遵循一个先进后出的原则,有点类似module_exit取消注册的顺序。IS_ERR 判断是否是落在错误码地址范围内。PTR_ERR 获取对应的错误码。
2025-10-29 17:36:55
218
原创 20.杂项设备驱动
杂项设备的主设备号是10,会自动使用class_create,device_create,相比之前,节约了设备号,并降低了开发难度。位于include/linux/miscdevice.h。1.驱动模块miscdevice.c编写。3.编译并放到qemu下测试。2.Makefile编写。
2025-10-29 11:17:46
190
原创 19.文件私有数据
通过上面的例子可能不能很好理解private_data的作用,假设有这么一个场景,需要注册一类设备,也就是主设备号相同次设备号不同的设备,我们可以封装设备结构体,通过container_of来识别是打开哪个设备,private_data来指向。linux没有明确规定必须使用文件私有数据,但文件私有数据在linux驱动中有着广泛的运用,这是linux驱动的潜规则。文件私有数据就是将私有数据private_data指向设备结构体。1.privat_data_test.c编写。3.用例程序test.c编写。
2025-10-29 09:00:00
153
原创 18.用户空间和内核空间
用户空间执行应用程序,内核空间管理硬件资源,用户空间想访问硬件资源需要通过系统调用,软中断,硬中断进入内核空间。下面通过一个例子来理解。1.usr_kernel.c模块编写 使用到了copy_to/from_user实现内核空间和用户空间的数据交换。3.编译及在qemu测试。
2025-10-28 09:59:53
163
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅