本书是一本介绍linux设备驱动开发理论、框架与实例的书,本书基于ldd6410开发板,以 linux 2.6版本内核为蓝本,详细介绍自旋锁、信号量、完成量、中断顶/底半部、定时器、内存和i/o映射以及异步通知、阻塞i/o、非阻塞i/o等linux 设备驱动理论;字符设备、块设备、tty设备、i2c设备、lcd设备、音频设备、usb设备、网络设备、pci设备等linux设备驱动的架构和框架中 各个复杂数据架构和函数的关系,并讲解了linux驱动开发的大量实例,使读者能够独立开发各类linux设备驱动。
封面图
目录
- 赞誉
- 推荐序一
- 推荐序二
- 前言
- 第1章Linux设备驱动概述及开发环境构建1
- 1.1设备驱动的作用1
- 1.2无操作系统时的设备驱动2
- 1.3有操作系统时的设备驱动4
- 1.4Linux设备驱动5
- 1.4.1设备的分类及特点 5
- 1.4.2Linux设备驱动与整个软硬件系统的关系6
- 1.4.3Linux设备驱动的重点、难点 7
- 1.5Linux设备驱动的开发环境构建8
- 1.5.1PC上的Linux环境8
- 1.5.2QEMU实验平台11
- 1.5.3源代码阅读和编辑 13
- 1.6设备驱动Hello World:LED驱动15
- 1.6.1无操作系统时的LED驱动15
- 1.6.2Linux下的LED驱动15
- 第2章驱动设计的硬件基础20
- 2.1处理器20
- 2.1.1通用处理器 20
- 2.1.2数字信号处理器 22
- 2.2存储器24
- 2.3接口与总线28
- 2.3.1串口 28
- 2.3.2I2C29
- 2.3.3SPI30
- 2.3.4USB 31
- 2.3.5以太网接口 33
- 2.3.6PCI和PCI-E 34
- 2.3.7SD和SDIO36
- 2.4CPLD和FPGA37
- 2.5原理图分析40
- 2.6硬件时序分析42
- 2.6.1时序分析的概念 42
- 2.6.2典型的硬件时序 43
- 2.7芯片数据手册阅读方法44
- 2.8仪器仪表使用47
- 2.8.1万用表 47
- 2.8.2示波器 47
- 2.8.3逻辑分析仪 49
- 2.9总结51
- 第3章Linux内核及内核编程52
- 3.1Linux内核的发展与演变52
- 3.2Linux 2.6后的内核特点56
- 3.3Linux内核的组成59
- 3.3.1Linux内核源代码的目录结构 59
- 3.3.2Linux内核的组成部分 60
- 3.3.3Linux内核空间与用户空间 64
- 3.4Linux内核的编译及加载64
- 3.4.1Linux内核的编译 64
- 3.4.2Kconfig和Makefile 66
- 3.4.3Linux内核的引导 74
- 3.5Linux下的C编程特点75
- 3.5.1Linux编码风格75
- 3.5.2GNU C与ANSI C78
- 3.5.3do { } while(0) 语句83
- 3.5.4goto语句85
- 3.6工具链85
- 3.7实验室建设88
- 3.8串口工具89
- 3.9总结91
- 第4章Linux内核模块92
- 4.1Linux内核模块简介92
- 4.2Linux内核模块程序结构95
- 4.3模块加载函数95
- 4.4模块卸载函数97
- 4.5模块参数97
- 4.6导出符号99
- 4.7模块声明与描述100
- 4.8模块的使用计数100
- 4.9模块的编译101
- 4.10使用模块“绕开”GPL102
- 4.11总结103
- 第5章Linux文件系统与设备文件104
- 5.1Linux文件操作104
- 5.1.1文件操作系统调用104
- 5.1.2C库文件操作108
- 5.2Linux文件系统109
- 5.2.1Linux文件系统目录结构 109
- 5.2.2Linux文件系统与设备驱动 110
- 5.3devfs114
- 5.4udev用户空间设备管理116
- 5.4.1udev与devfs的区别116
- 5.4.2sysfs文件系统与Linux设备模型 119
- 5.4.3udev的组成 128
- 5.4.4udev规则文件 129
- 5.5总结133
- 第6章字符设备驱动134
- 6.1Linux字符设备驱动结构134
- 6.1.1cdev结构体134
- 6.1.2分配和释放设备号136
- 6.1.3f ile_operations结构体136
- 6.1.4Linux字符设备驱动的组成138
- 6.2globalmem虚拟设备实例描述142
- 6.3globalmem设备驱动142
- 6.3.1头文件、宏及设备结构体142
- 6.3.2加载与卸载设备驱动143
- 6.3.3读写函数144
- 6.3.4seek函数146
- 6.3.5ioctl函数146
- 6.3.6使用文件私有数据148
- 6.4globalmem驱动在用户空间中的验证156
- 6.5总结157
- 第7章Linux设备驱动中的并发控制158
- 7.1并发与竞态158
- 7.2编译乱序和执行乱序160
- 7.3中断屏蔽165
- 7.4原子操作166
- 7.4.1整型原子操作167
- 7.4.2位原子操作168
- 7.5自旋锁169
- 7.5.1自旋锁的使用169
- 7.5.2读写自旋锁173
- 7.5.3顺序锁174
- 7.5.4读-复制-更新176
- 7.6信号量181
- 7.7互斥体183
- 7.8完成量184
- 7.9增加并发控制后的globalmem的设备驱动185
- 7.10总结188
- 第8章Linux设备驱动中的阻塞与非阻塞I/O189
- 8.1阻塞与非阻塞I/O189
- 8.1.1等待队列191
- 8.1.2支持阻塞操作的globalf ifo设备驱动194
- 8.1.3在用户空间验证globalf ifo的读写198
- 8.2轮询操作198
- 8.2.1轮询的概念与作用198
- 8.2.2应用程序中的轮询编程199
- 8.2.3设备驱动中的轮询编程201
- 8.3支持轮询操作的globalf ifo驱动202
- 8.3.1在globalf ifo驱动中增加轮询操作202
- 8.3.2在用户空间中验证globalf ifo设备的轮询203
- 8.4总结205
- 第9章Linux设备驱动中的异步通知与异步I/O206
- 9.1异步通知的概念与作用206
- 9.2Linux异步通知编程207
- 9.2.1Linux信号207
- 9.2.2信号的接收208
- 9.2.3信号的释放210
- 9.3支持异步通知的globalf ifo驱动212
- 9.3.1在globalf ifo驱动中增加异步通知212
- 9.3.2在用户空间中验证globalf ifo的异步通知214
- 9.4Linux异步I/O215
- 9.4.1AIO概念与GNU C库AIO215
- 9.4.2Linux内核AIO与libaio219
- 9.4.3AIO与设备驱动222
- 9.5总结223
- 第10章中断与时钟224
- 10.1中断与定时器224
- 10.2Linux中断处理程序架构227
- 10.3Linux中断编程228
- 10.3.1申请和释放中断228
- 10.3.2使能和屏蔽中断230
- 10.3.3底半部机制230
- 10.3.4实例:GPIO按键的中断235
- 10.4中断共享237
- 10.5内核定时器238
- 10.5.1内核定时器编程238
- 10.5.2内核中延迟的工作delayed_work242
- 10.5.3实例:秒字符设备243
- 10.6内核延时247
- 10.6.1短延迟247
- 10.6.2长延迟248
- 10.6.3睡着延迟248
- 10.7总结250
- 第11章内存与I/O访问251
- 11.1CPU与内存、I/O 251
- 11.1.1内存空间与I/O空间251
- 11.1.2内存管理单元252
- 11.2Linux内存管理256
- 11.3内存存取261
- 11.3.1用户空间内存动态申请261
- 11.3.2内核空间内存动态申请262
- 11.4设备I/O端口和I/O内存的访问267
- 11.4.1Linux I/O端口和I/O内存访问接口267
- 11.4.2申请与释放设备的I/O端口和I/O内存268
- 11.4.3设备I/O端口和I/O内存访问流程269
- 11.4.4将设备地址映射到用户空间270
- 11.5I/O内存静态映射276
- 11.6DMA 277
- 11.6.1DMA与Cache一致性278
- 11.6.2Linux下的DMA编程279
- 11.7总结285
- 第12章Linux设备驱动的软件架构思想286
- 12.1Linux驱动的软件架构286
- 12.2platform设备驱动290
- 12.2.1platform总线、设备与驱动290
- 12.2.2将globalf ifo作为platform设备293
- 12.2.3platform设备资源和数据295
- 12.3设备驱动的分层思想299
- 12.3.1设备驱动核心层和例化299
- 12.3.2输入设备驱动301
- 12.3.3RTC设备驱动306
- 12.3.4Framebuffer设备驱动309
- 12.3.5终端设备驱动311
- 12.3.6misc设备驱动316
- 12.3.7驱动核心层321
- 12.4主机驱动与外设驱动分离的设计思想321
- 12.4.1主机驱动与外设驱动分离321
- 12.4.2Linux SPI主机和设备驱动322
- 12.5总结330
- 第13章Linux块设备驱动331
- 13.1块设备的I/O操作特点331
- 13.2Linux块设备驱动结构332
- 13.2.1block_device_operations结构体332
- 13.2.2gendisk结构体334
- 13.2.3bio、request和request_queue335
- 13.2.4I/O调度器339
- 13.3Linux块设备驱动的初始化340
- 13.4块设备的打开与释放342
- 13.5块设备驱动的ioctl函数342
- 13.6块设备驱动的I/O请求处理343
- 13.6.1使用请求队列343
- 13.6.2不使用请求队列347
- 13.7实例:vmem_disk驱动349
- 13.7.1vmem_disk的硬件原理349
- 13.7.2vmem_disk驱动模块的加载与卸载349
- 13.7.3vmem_disk设备驱动的block_device_operations351
- 13.7.4vmem_disk的I/O请求处理352
- 13.8Linux MMC子系统354
- 13.9总结357
- 第14章Linux网络设备驱动358
- 14.1Linux网络设备驱动的结构358
- 14.1.1网络协议接口层359
- 14.1.2网络设备接口层363
- 14.1.3设备驱动功能层 367
- 14.2网络设备驱动的注册与注销367
- 14.3网络设备的初始化369
- 14.4网络设备的打开与释放370
- 14.5数据发送流程371
- 14.6数据接收流程372
- 14.7网络连接状态375
- 14.8参数设置和统计数据377
- 14.9DM9000网卡设备驱动实例380
- 14.9.1DM9000网卡硬件描述 380
- 14.9.2DM9000网卡驱动设计分析380
- 14.10总结386
- 第15章Linux I2C核心、总线与设备驱动387
- 15.1Linux I2C体系结构387
- 15.2Linux I2C核心394
- 15.3Linux I2C适配器驱动396
- 15.3.1I2C适配器驱动的注册与注销396
- 15.3.2I2C总线的通信方法397
- 15.4Linux I2C设备驱动399
- 15.4.1Linux I2C设备驱动的模块加载与卸载400
- 15.4.2Linux I2C设备驱动的数据传输400
- 15.4.3Linux的i2c-dev.c文件分析400
- 15.5Tegra I2C总线驱动实例405
- 15.6AT24xx EEPROM的I2C设备驱动实例410
- 15.7总结413
- 第16章USB主机、设备与Gadget驱动414
- 16.1Linux USB驱动层次414
- 16.1.1主机侧与设备侧USB驱动414
- 16.1.2设备、配置、接口、端点415
- 16.2USB主机控制器驱动420
- 16.2.1USB主机控制器驱动的整体结构420
- 16.2.2实例:Chipidea USB主机驱动425
- 16.3USB设备驱动425
- 16.3.1USB设备驱动的整体结构425
- 16.3.2USB请求块430
- 16.3.3探测和断开函数435
- 16.3.4USB骨架程序436
- 16.3.5实例:USB键盘驱动443
- 16.4USB UDC与Gadget驱动446
- 16.4.1UDC和Gadget驱动的关键数据结构与API446
- 16.4.2实例:Chipidea USB UDC驱动451
- 16.4.3实例:Loopback Function驱动453
- 16.5USB OTG驱动456
- 16.6总结458
- 第17章I2C、SPI、USB驱动架构类比459
- 17.1I2C、SPI、USB驱动架构459
- 17.2I2C主机和外设眼里的Linux世界460
- 第18章ARM Linux设备树461
- 18.1ARM设备树起源461
- 18.2设备树的组成和结构462
- 18.2.1DTS、DTC和DTB等462
- 18.2.2根节点兼容性468
- 18.2.3设备节点兼容性470
- 18.2.4设备节点及label的命名475
- 18.2.5地址编码477
- 18.2.6中断连接479
- 18.2.7GPIO、时钟、pinmux连接480
- 18.3由设备树引发的BSP和驱动变更484
- 18.4常用的OF API490
- 18.5总结493
- 第19章Linux电源管理的系统架构和驱动494
- 19.1Linux电源管理的全局架构494
- 19.2CPUFreq驱动495
- 19.2.1SoC的CPUFreq驱动实现495
- 19.2.2CPUFreq的策略501
- 19.2.3CPUFreq的性能测试和调优501
- 19.2.4CPUFreq通知502
- 19.3CPUIdle驱动504
- 19.4PowerTop508
- 19.5Regulator驱动508
- 19.6OPP511
- 19.7PM QoS515
- 19.8CPU热插拔518
- 19.9挂起到RAM522
- 19.10运行时的PM528
- 19.11总结534
- 第20章Linux芯片级移植及底层驱动535
- 20.1ARM Linux底层驱动的组成和现状535
- 20.2内核节拍驱动536
- 20.3中断控制器驱动541
- 20.4SMP多核启动以及CPU热插拔驱动549
- 20.5DEBUG_LL和EARLY_PRINTK的设置556
- 20.6GPIO驱动557
- 20.7pinctrl驱动560
- 20.8时钟驱动572
- 20.9dmaengine驱动578
- 20.10总结580
- 第21章Linux设备驱动的调试581
- 21.1GDB调试器的用法581
- 21.1.1GDB的基本用法581
- 21.1.2DDD图形界面调试工具591
- 21.2Linux内核调试594
- 21.3内核打印信息——printk()596
- 21.4DEBUG_LL和EARLY_PRINTK599
- 21.5使用“/proc”600
- 21.6Oops606
- 21.7BUG_ON()和WARN_ON()608
- 21.8strace609
- 21.9KGDB610
- 21.10使用仿真器调试内核612
- 21.11应用程序调试613
- 21.12Linux性能监控与调优工具616
- 21.13总结618