自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(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

原创 55.中断线程化

所谓中断线程化,就是为每一个工作,创建一个线程去处理,也就是中断下半部分创建一个线程去处理。

2025-12-25 15:40:18 45

原创 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

原创 51.自定义工作队列

相比于传统工作队列可控性强。

2025-12-12 17:05:07 180

原创 50.共享工作队列

相比于软中断和tasklet,能在中断函数中休眠。

2025-12-10 17:01:03 145

原创 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

原创 42.ioctl控制定时器

【代码】42.ioctl控制定时器。

2025-12-05 16:46:13 143

原创 41.ioctl设备驱动地址传参

【代码】41.ioctl设备驱动地址传参。

2025-12-05 11:36:26 203

原创 40.ioctl设备驱动操作

【代码】40.ioctl设备驱动操作。

2025-12-05 11:01:03 133

原创 39.llseek定位设备驱动

1.llseek.c驱动编写。test.c应用程序编写。makefile编写。

2025-11-23 20:02:33 153

原创 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

原创 37.使用定时器实现秒字符设备

second_driver.c编写。Makefile编写。

2025-11-12 22:39:48 207

原创 36.循环定时器实现

使用mod_timer实现1秒触发一次超时函数。loop_timer.c编写。Makefile编写。

2025-11-11 20:32:06 136

原创 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

原创 33.IO多路复用

3.测试程序read.c write.c编写。直到写入数据才能去读数据。2.Makefile编写。1.poll.c编写。

2025-11-03 19:03:05 129

原创 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

原创 31.使用等待队列实现阻塞访问

2.Makefile编写。1.驱动wq.c编写。

2025-11-02 17:50:45 142

原创 30.IO模型

从键盘上输入数据时,会触发内核的中断机制,将数据输入到内核缓冲区,数据输入完时,会触发scanf底层的系统调用read来获取内核缓冲的数据。IO模型:阻塞IO,非阻塞IO,多路复用IO,信号驱动IO,异步IO。他这里会建立一个用户空间和内核空间的信号函数,一旦数据准备好,内核会主动发送准备好的信号,后将数据拷贝用户空间。从图中可以可以看出,他是一个不断轮询的过程,比较吃cpu,不过进程此时可以去干其他的事情。可以理解升级版的阻塞IO,他这个会有多个系统调用去检查内核有没有准备号好数据。

2025-11-02 11:28:08 171

原创 29.并发与竞争总结

2025-11-01 14:36:12 66

原创 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关注的人

提示
确定要删除当前文章?
取消 删除