自学记录—精通Linux 设备驱动程序开发

参考书:《精通Linux 设备驱动程序开发》
缘由:借了前辈的这本书研究一下,自学并记录
开始时间:2023.3.22 弄毕设有点闷,看这本书放松一下
说明:每个人的理解都可以不同,笔者也不一定对的,同时笔者在用国内chatgpt3.5镜像问相关问题时,发现条件不同、问法不同,答案有些也会不同,设备驱动程序开发这块也的确可以根据具体需求而设计出不同的

3/22

第1章引言,跳过
第2、3章关于内核,昨天浅看了一下,里面细节没懂,跳过了
第4章驱动程序的基本概念,这里记一下。

1、中断处理

IRQ:中断请求(Interrupt Request),硬件信号,异步
ISR:中断服务例程,代码段,立即执行,负载小

ps:自己理解下的图,自学,可能会理解有失偏颇

中断上下文特点:
(1)不能停
(2)为保护临界区,用自旋锁,互斥体不得不用时才采用

临界区是指在多线程或并发编程中,访问共享资源的代码段,该代码段需要被互斥地访问以避免竞态条件(race condition)的发生。在任何时刻,只能有一个线程进入临界区执行代码,其他线程必须等待当前线程退出临界区后才能进入。

自旋锁和互斥体都是用于保护共享资源的同步机制,但它们有一些区别:
(1)等待方式不同:当一个线程尝试获取一个已经被占用的互斥体时,它会被阻塞并进入睡眠状态,直到互斥体被释放。而当一个线程尝试获取一个已经被占用的自旋锁时,它会一直循环等待,直到自旋锁被释放。
(2)实现机制不同:互斥体通常使用操作系统提供的原语来实现,因此需要从用户态切换到内核态,这种切换代价比较高。而自旋锁则是通过在用户态下不断地检查锁的状态来实现的,因此不需要切换到内核态,这使得自旋锁的效率比较高。
(3)适用场景不同:由于自旋锁需要不断地检查锁的状态,因此只适用于保护临界区比较短小的情况,否则会浪费大量的 CPU 时间。而互斥体则适用于保护临界区比较长或者需要等待时间比较长的情况。

(3)中断处理函数不能与用户空间直接交互数据

原因有2:
1、访问用户空间的数据需要通过复杂的机制进行特权级切换和内存映射等操作——>增加系统的开销和安全风险
2、调度器工作于进程之间,若中断处理函数睡眠并调度出去,无法返回运行队列

(4)中断处理函数将工作分为2部分(之后拓展)

(5)中断处理函数不必是可重用的

不必是可重用的有2方面:
1、中断函数运行时,在其返回之前,相应的IRQ都被禁止——>同一中断处理函数的不同实例不可能同时运行在同一处理器上。
2、专门为特定的硬件中断或软件中断而设计的,只有在相应的中断发生时才会被调用。由于每个中断都具有其独特的上下文和要求,因此中断处理函数通常不适合在其他中断或程序中重用。因此,编写可重用的中断处理函数可能会增加代码复杂性并降低系统性能。

(6)中断处理函数可被更高优先级IRQ的中断处理函数打断

2、IRQ号

在Linux系统中,IRQ号可以通过/proc/interrupts文件查看。该文件列出了系统中每个IRQ的统计信息和使用情况。可以使用命令行工具如cat、less或者grep来查看/proc/interrupts文件。

3、一个设备实例

不方便全打出来,而且里面有些知识参考后面章节,记录一些我个人我觉得有意思的

1、Linux中断——request_irq()(2.6.19内核开始,中断处理接口有点变化)
2、其他 free_irq() /enable_irq()…不一一列举了

3/23

4、softirq和tasklet

之前提到中断处理函数将工作分为2部分,这里细讲其中底(下)半部机制:
有篇博客关于这中断上下半部分区别总结不错: 关于Linux中断一些思考
上半部分:硬件,快,异步
下半部分
Linux2.5移除了BH(bottom half),目前使用方式是三种,softirq软中断、tasklet协程任务、工作队列

书中有个这三者详细比较的表格,挺清晰的(拍照上传侵权,个人懒得再画个表格),感觉从“使用场景”反推其它特点比较好理解,其中还有个讨论:LKML正在进行去除tasklet的讨论,比如将现存的tasklet基于其场景随机应变地转换为softirq或工作队列,具体取决于系统的需求和设计

软中断适用于需要快速响应的中断处理,延后的工作不会睡眠
tasklet适用于需要延迟处理的中断,延后的工作不会睡眠
工作队列适用于需要异步处理的任务。延后的工作会睡眠

回头又看了第2章2.7内存分配的内容。

在32位x86系统上,Linux 2.6.23环境下,物理地址空间通常被分配为以下几个部分:
1、内核空间(Kernel Space):占据高端的1GB或3GB空间,用于存储内核代码、数据和堆栈等。
2、用户空间(User Space):占据低端的2GB或1GB空间,用于存储用户进程的代码、数据和堆栈等。
3、DMA空间(Direct Memory Access Space):用于直接内存访问,可用于高速I/O设备的数据传输。
其中,内核空间和用户空间是虚拟地址空间,通过MMU映射到物理地址空间。DMA空间是物理地址空间,可以直接访问

在64位x86系统上,Linux2.6.23环境下,物理地址空间通常被分配为:
(1)用户空间:占据47位(从0到约128TB)的地址空间,用于用户进程的代码、数据和堆栈等。
(2)内核空间:占据17位(从约128TB到约256TB)的地址空间,用于内核代码、数据和堆栈等。
其中,最高的1个GB(从约255TB到约256TB)是预留给内核直接映射的设备的,称为“高端内存”(High Memory)。
------这种地址空间的划分方式被称为“经典模式”(Classic Mode),也可以使用“内核同步模式”(Kernel Same-page Merging,KSM)或“透明大页模式”(Transparent Huge Pages,THP)等技术来优化内存使用效率。

5、udev

设备管理工具

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基本信息 原书名: Essential Linux Device Drivers 原出版社: Prentice Hall 作者: (印)Sreekrishnan Venkateswaran 译者: 宋宝华 何昭然 史海滨 吴国成 丛书名: 图灵程序设计丛书 操作系统 出版社:人民邮电出版社 ISBN:9787115221674 出版日期:2010 年6月 页码:468 内容简介   本书是linux设备驱动程序开发领域的权威著作。全书基于2.6内核,不仅透彻讲解了基本概念和技术,更深入探讨了其他书没有涵盖或浅尝辄止的许多重要主题和关键难点,如pcmcia、i2c和usb等外部总线以及视频、音频、无线连网和闪存等驱动程序开发,并讲解了相关的内核源码文件,给出了完整的开发实例。   本书适合中高级linux开发人员阅读。 目录 第1章 引言1 1.1 演进1 1.2 gnu copyleft2 1.3 kernel.org2 1.4 邮件列表和论坛3 1.5 linux发行版3 1.6 查看源代码4 1.7 编译内核7 1.8 可加载的模块8 1.9 整装待发9 第2章 内核11 2.1 启动过程11 2.1.1 bios-provided physical ram map12 2.1.2 758mb lowmem available14 2.1.3 kernel command line: ro root=/dev/hda114 2.1.4 calibrating delay...1197.46 .bogomips (lpj=2394935)15 2.1.5 checking hlt instruction16 2.1.6 net: registered protocol family 217 2.1.7 freeing initrd memory: 387k freed17 2.1.8 io scheduler anticipatory registered (default)18 2.1.9 setting up standard pci resources18 2.1.10 ext3-fs: mounted filesystem19 2.1.11 init: version 2.85 booting19 2.2 内核模式和用户模式20 2.3 进程上下文和中断上下文20 2.4 内核定时器21 2.4.1 hz和jiffies21 2.4.2 长延时22 2.4.3 短延时24 2.4.4 pentium时间戳计数器24 2.4.5 实时钟25 2.5 内核中的并发26 2.5.1 自旋锁和互斥体26 2.5.2 原子操作30 2.5.3 读—写锁31 2.5.4 调试32 2.6 proc文件系统32 2.7 内存分配33 2.8 查看源代码34 第3章 内核组件37 3.1 内核线程37 3.1.1 创建内核线程37 3.1.2 进程状态和等待队列41 3.1.3 用户模式辅助程序42 3.2 辅助接口43 3.2.1 链表44 3.2.2 散列链表49 3.2.3 工作队列49 3.2.4 通知链51 3.2.5 完成接口54 3.2.6 kthread辅助接口56 3.2.7 错误处理助手57 3.3 查看源代码58 第4章 基本概念61 4.1 设备驱动程序介绍61 4.2 中断处理63 4.2.1 中断上下文63 4.2.2 分配irq号64 4.2.3 设备实例:导航杆65 4.2.4 softirq和tasklet68 4.3 linux设备模型71 4.3.1 udev71 4.3.2 sysfs、kobject和设备类73 4.3.3 热插拔和冷插拔76 4.3.4 微码下载76 4.3.5 模块自动加载77 4.4 内存屏障78 4.5 电源管理79 4.6 查看源代码79 第5章 字符设备驱动程序81 5.1 字符设备驱动程序基础81 5.2 设备实例:系统cmos82 5.2.1 驱动程序初始化83 5.2.2 打开与释放86 5.2.3 数据交换88 5.2.4 查找92 5.2.5 控制94 5.3 检测数据可用性95 5.3.1 轮询95 5.3.2 fasync98 5.4 和并行端口交互99 5.5 rtc子系统108 5.6 伪字符驱动程序109 5.7 混杂驱动程序110 5.8 字符设备驱动程序注意事项115 5.9 查看源代码115 第6章 串行设备驱动程序118 6.1 层次架构119 6.2 uart驱动程序121 6.2.1 设备实例:手机122 6.2.2 rs-485132 6.3 tty驱动程序132 6.4 线路规程134 6.5 查看源代码141 第7章 输入设备驱动程序143 7.1 输入事件驱动程序144 7.2 输入设备驱动程序150 7.2.1 serio150 7.2.2 键盘150 7.2.3 鼠标152 7.2.4 触摸控制器157 7.2.5 加速度传感器158 7.2.6 输出事件158 7.3 调试159 7.4 查看源代码160 第8章 i2c协议161 8.1 i2c/smbus是什么161 8.2 i2c核心162 8.3 总线事务164 8.4 设备实例:eeprom164 8.4.1 初始化165 8.4.2 探测设备167 8.4.3 检查适配器的功能169 8.4.4 访问设备169 8.4.5 其他函数170 8.5 设备实例:实时时钟171 8.6 i2c-dev174 8.7 使用lm-sensors监控硬件174 8.8 spi总线174 8.9 1-wire总线176 8.10 调试176 8.11 查看源代码176 第9章 pcmcia和cf179 9.1 pcmcia/cf是什么179 9.2 linux-pcmcia子系统181 9.3 主机控制器驱动程序183 9.4 pcmcia核心183 9.5 驱动程序服务183 9.6 客户驱动程序183 9.6.1 数据结构184 9.6.2 设备实例:pcmcia卡185 9.7 将零件组装在一起188 9.8 pcmcia存储189 9.9 串行pcmcia189 9.10 调试191 9.11 查看源代码191 第10章 pci193 10.1 pci系列193 10.2 寻址和识别195 10.3 访问pci198 10.3.1 配置区198 10.3.2 i/o和内存199 10.4 dma200 10.5 设备实例:以太网—调制解调器卡203 10.5.1 初始化和探测203 10.5.2 数据传输209 10.6 调试214 10.7 查看源代码214 第11章 usb216 11.1 usb体系架构216 11.1.1 总线速度218 11.1.2 主机控制器218 11.1.3 传输模式219 11.1.4 寻址219 11.2 linux-usb子系统220 11.3 驱动程序的数据结构221 11.3.1 usb_device结构体221 11.3.2 urb222 11.3.3 管道223 11.3.4 描述符结构223 11.4 枚举225 11.5 设备实例:遥测卡225 11.5.1 初始化和探测过程226 11.5.2 卡寄存器的访问230 11.5.3 数据传输233 11.6 类驱动程序236 11.6.1 大容量存储设备236 11.6.2 usb-串行端口转换器241 11.6.3 人机接口设备243 11.6.4 蓝牙243 11.7 gadget驱动程序243 11.8 调试244 11.9 查看源代码245 第12章 视频驱动程序247 12.1 显示架构247 12.2 linux视频子系统249 12.3 显示参数251 12.4 帧缓冲api252 12.5 帧缓冲驱动程序254 12.6 控制台驱动程序265 12.6.1 设备实例:手机266 12.6.2 启动logo270 12.7 调试270 12.8 查看源代码271 第13章 音频驱动程序273 13.1 音频架构273 13.2 linux声音子系统275 13.3 设备实例:mp3播放器277 13.3.1 驱动程序函数和结构体278 13.3.2 alsa编程287 13.4 调试288 13.5 查看源代码289 第14章 块设备驱动程序291 14.1 存储技术291 14.2 linux块i/o层295 14.3 i/o调度器295 14.4 块驱动程序数据结构和方法296 14.5 设备实例:简单存储控制器298 14.5.1 初始化299 14.5.2 块设备操作301 14.5.3 磁盘访问302 14.6 高级主题304 14.7 调试306 14.8 查看源代码306 第15章 网络接口卡308 15.1 驱动程序数据结构308 15.1.1 套接字缓冲区309 15.1.2 网络设备接口310 15.1.3 激活311 15.1.4 数据传输311 15.1.5 看门狗311 15.1.6 统计312 15.1.7 配置313 15.1.8 总线相关内容314 15.2 与协议层会话314 15.2.1 接收路径314 15.2.2 发送路径315 15.2.3 流量控制315 15.3 缓冲区管理和并发控制315 15.4 设备实例:以太网nic316 15.5 isa网络驱动程序321 15.6 atm321 15.7 网络吞吐量322 15.7.1 驱动程序性能322 15.7.2 协议性能323 15.8 查看源代码324 第16章 linux无线设备驱动326 16.1 蓝牙327 16.1.1 bluez328 16.1.2 设备实例:cf卡329 16.1.3 设备实例:usb适配器330 16.1.4 rfcomm331 16.1.5 网络332 16.1.6 hid334 16.1.7 音频334 16.1.8 调试334 16.1.9 关于源代码334 16.2 红外335 16.2.1 linux-irda335 16.2.2 设备实例:超级i/o芯片337 16.2.3 设备实例:ir dongle338 16.2.4 ircomm340 16.2.5 联网340 16.2.6 irda套接字341 16.2.7 lirc341 16.2.8 查看源代码342 16.3 wifi343 16.3.1 配置343 16.3.2 设备驱动程序346 16.3.3 查看源代码347 16.4 蜂窝网络347 16.4.1 gprs347 16.4.2 cdma349 16.5 当前趋势350 第17章 存储技术设备352 17.1 什么是闪存352 17.2 linux-mtd子系统353 17.3 映射驱动程序353 17.4 nor芯片驱动程序358 17.5 nand芯片驱动程序359 17.6 用户模块361 17.6.1 块设备模拟361 17.6.2 字符设备模拟361 17.6.3 jffs2362 17.6.4 yaffs2363 17.7 mtd工具363 17.8 配置mtd363 17.9 xip364 17.10 fwh364 17.11 调试367 17.12 查看源代码367 第18章 嵌入式linux369 18.1 挑战369 18.2 元器件选择370 18.3 工具链371 18.4 bootloader372 18.5 内存布局374 18.6 内核移植375 18.7 嵌入式驱动程序376 18.7.1 闪存377 18.7.2 uart377 18.7.3 按钮和滚轮378 18.7.4 pcmcia/cf378 18.7.5 sd/mmc378 18.7.6 usb378 18.7.7 rtc378 18.7.8 音频378 18.7.9 触摸屏379 18.7.10 视频379 18.7.11 cpld/fpga379 18.7.12 连接性379 18.7.13 专用领域电子器件380 18.7.14 更多驱动程序380 18.8 根文件系统380 18.8.1 nfs挂载的根文件系统381 18.8.2 紧凑型中间件382 18.9 测试基础设施383 18.10 调试383 18.10.1 电路板返工384 18.10.2 调试器385 第19章 用户空间的驱动程序386 19.1 进程调度和响应时间387 19.1.1 原先的调度器387 19.1.2 o(1)调度器387 19.1.3 cfs388 19.1.4 响应时间388 19.2 访问i/o区域390 19.3 访问内存区域393 19.4 用户模式scsi395 19.5 用户模式usb397 19.6 用户模式i2c400 19.7 uio401 19.8 查看源代码402 第20章 其他设备驱动程序403 20.1 ecc报告403 20.2 频率调整407 20.3 嵌入式控制器408 20.4 acpi408 20.5 isa与mca410 20.6 火线410 20.7 智能输入/输出411 20.8 业余无线电411 20.9 voip411 20.10 高速互联412 20.10.1 infiniband413 20.10.2 rapidio413 20.10.3 光纤通道413 20.10.4 iscsi413 第21章 调试设备驱动程序414 21.1 kdb414 21.1.1 进入调试器415 21.1.2 kdb415 21.1.3 kgdb417 21.1.4 gdb420 21.1.5 jtag调试器421 21.1.6 下载423 21.2 内核探测器423 21.2.1 kprobe423 21.2.2 jprobe427 21.2.3 返回探针429 21.2.4 局限性431 21.2.5 查看源代码431 21.3 kexec与kdump431 21.3.1 kexec432 21.3.2 kdump与kexec协同工作432 21.3.3 kdump433 21.3.4 查看源代码437 21.4 性能剖析437 21.4.1 利用oprofile剖析内核性能438 21.4.2 利用gprof剖析应用程序性能440 21.5 跟踪441 21.6 ltp444 21.7 uml444 21.8 诊断工具444 21.9 内核修改配置选项444 21.10 测试设备445 第22章 维护与发布446 22.1 代码风格446 22.2 修改标记446 22.3 版本控制447 22.4 一致性检查447 22.5 构建脚本448 22.6 可移植代码450 第23章 结束语451 23.1 流程一览表451 23.2 下一步该做什么452 附录a linux汇编453 附录b linux与bios457 附录c seq文件461

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值