Verilog数字系统设计教程(第2版).pdf
https://github.com/shigh1005/pdf_book
《Linux设备驱动开发详解:基于最新的Linux 4.0内核.pdf》
《Linux设备驱动开发详解(基于最新4.0内核)》前言
2015-04-28
阅读数:1056
Linux从未停歇脚步。Linus Torvalds,世界上最伟大的程序员之一,Linux内核的创始人,Git的缔造者,仍然在没日没夜的合并补丁,升级内核。做技术,从来没有终南捷径,拼的就是坐冷板凳的傻劲。
这是一个连阅读都被碎片化的时代,在这样一个时代,人们趋向于激进、浮躁。内心的不安宁使我们极难静下心来研究什么。我见过许许多多的Linux工程师,他们的简历书写着“精通”Linux内核,有多年的工作经验,而他们的“精通”却只是把某个寄存器从0改成1,从1改成0的不断重复;我见过许许多多的Linux工程师,他们终日埋头苦干,敲打着自己的机器和电路板,却从未冷静下来思考,并不断重构和升华自己的知识体系。
这是要把牢底坐穿的程序员。这样“忙忙碌碌”的程序员,从来都不是什么好程序员。
优秀的程序员,最优秀的品质是能够内心宁静地学习与思考问题,透析代码背后的架构、原理和设计思想。没有思想的代码是垃圾代码,没有思想的程序员,只是在完成低水平重复建设的体力活。很多程序员,连自己写的代码最后在机器里面怎么跑都从不过问,很多事情莫名其妙地发生了,很多bug莫名其妙地消失了……永远都是得过且过。
由此,衍生出《Linux设备驱动开发详解》新版的第一个出发点,那就是带给读者更多关于Linux开发背后思想的讲解,奠定根基。《Linux设备驱动开发详解(基于4.0内核)》呈现给读者的,更多的是一种思考,而不是知识点的简单罗列。
这次更新更进一步加强了对驱动编程所涉及Linux内核最底层机理的讲解,并对前2版的基础理论部分进行了大篇幅地重写,实例代码也被大面积重构。大幅度修改的内容包括中断、定时器、进程生命周期、uevent、并发、编译乱序、执行乱序、等待队列、I/O模型、内存管理等。这些知识点是如此重要,是真正证明程序员对Linux理解的部分,只有打好根基,才能游刃有余。
新版删除了《Linux设备驱动开发详解》第一版、第二版大量描述各种具体具体驱动类型的章节比如Sound、PCI、MTD、TTY等,而将更多焦点转移到了驱动编程背后的内核原理, 并试图从Linux内核上百个驱动子系统中寻找出内部的规律,以培养读者举一反三的能力。
Linux内核有上百个驱动子系统,这一点从内核的drivers子目录就可以看出来:
好吧,傻子才会一个目录一个目录地去看,一个目录一个目录地从头学起。我们势必要寻找各种驱动子系统的共性,摸索规律。本次更新,我们将更多看到各驱动子系统的类比,以及驱动子系统的层次化设计。
技术工作,从来都不是一劳永逸。这世界变化太快,当前技术革新的速度数倍于我们父辈祖辈祖祖辈经过的任何时代。证明你是真球迷还是伪球迷的时候到了。这是伪程序员的地狱,也是真程序员痛苦中的狂欢。
从浩如烟海的知识体系中、不断更新的软件版本中终生学习,不断攻克一个个挑战,获取新的养分,寻找新的灵感,这实在是黑暗码农生涯中不断闪现的璀璨光芒。
自本书第一版、第二版发布后,内核版本不断刷新,3.0、3.1、3.2…3.19、4.0、4.1,变化的是软件的架构,不变的是Linus的热情。
这无疑是本次升级的第二个出发点,更新Linux驱动编程的知识体系以符合最新的时代。所以,本次更新大量新增了关于Device Tree、ARM Linux移植、Linux电源管理、GPIO、clock、timer、pinmux、DMA等的内容。我们的操作平台,也转移到了QEMU模拟的4核Cortex-A9电路板,书中的实例,基本都转移到了市面流行的新芯片。
最近两三年,老是听到许多程序员抱怨,缺乏讲新内核的资料、缺乏从头到尾讲Device Tree的资料,但是我想说,这实在不是什么难点。难点仍然是本书第一个出发点要解决的问题,如果有好的基础,以优秀程序员极强的学习能力,应该很快就可以掌握这些新知识。机制没有变,变化的是只是策略。
所以学习能力,也是优秀程序员的又一品质。没有人生下来就是天才,良好学习能力的培训,本身也是通过不断学习来获取的。可以说,学的越多的人,学新东西一定越快,学习能力也变得越强。因为,知识的共通性实在太多。
读者阅读本书的思路,不应该是企图把它当成一本工具书、查API的书,而是一本梳理完整理论体系、开发思想、软件架构的书。唯如此,我们才能适应未来新的变化。
不知不觉中,离本书的第一次出版已经过去了七个年头。而自本次更新开始实施至今,也经过了一轮寒暑更替。岁月如歌,七载而下,我已非当年的意气青年。本书一版,二版,再版,这实非当初的预料。回首过去,我们惊奇地发现,这七年,正好是Linux由弱而盛,节节胜利的七年。也是许多如我一般的码农成家立业、结婚生子的七年。未来七年的Linux会是什么样子,我们无从预料。本书是否会有更进一步的新版,我们也无法预知,一如Linux没有路线图。社区和生态就是最好的Roadmap,万事随缘,而唯一不变的只是激情。
时代的滚滚车轮,推动着Linux内核的版本不断向前,也推动着每个人的人生。红尘滚滚,
我不去想是否能够成功,
既然选择了远方,
便只顾风雨兼程。
最后,本书能得以出版,要感谢带领我向前的人生导师和我的众多小伙伴,他们或者在我人生的关键时刻改变了我,或者带给了我黑暗程序生涯中无尽的快乐和动力。我的小伙伴,他们力挺我,鼓励我,也辱骂我,奚落我,这些,就是真挚的友情。
谨以此书,致以对杨平先生、何昭然、方毅伟、李华毅、宋志吾、杜向龙、叶祥振、刘昊、王榕、何晔、王立赛、曾过、刘永生、段炳华、章君义、王文琪、卢鹏、刘涛、徐西宁、吴赫、任桥伟、秦龙廷、胡良兵、张家旺、王雷、Bryan Wu、Eric Miao、Qipan Li、Guoying Zhang、陈健松、应荣军、Haoyu Zhong、刘洪涛、季久峰、邴杰、孙志忠、吴国举、Bob Liu、赵小吾、贺亚锋、刘仕杰、Hao Yin等老师和小伙伴的深深感激;谨以此书,致以对我的父母大人、老婆大人、兄长和姐姐、伟大丈母娘的深深感激,本书新版的写作时间超过一年,其过程是一种巨大的肉体和精神折磨,没有他们的默默支持和不断鞭策,是不可能完成的;谨以此书,致以对为本书做出巨大贡献的编辑、策划老师们,尤其是张国强老师深深的感激!
由于篇幅的关系,我没有办法一一列举所有我要感激的人入感谢名单。但是,我这些年从你们那里获得的,远远大于我付出的。所以,内心深处,唯有怀着对小伙伴深深的感恩,不断前行。岁月如歌,吾歌狂行。
宋宝华
2015年4月于上海浦东
1.4 Linux 设备驱动
1.4.1 设备的分类及特点
计算机系统的硬件主要由 CPU、存储器和外设组成。随着 IC 制作工艺的发展,目前, 芯片的集成度越来越高,往往在 CPU 内部就集成了存储器和外设适配器。譬如,相当多的 ARM、PowerPC、MIPS 等处理器都集成了 UART、I2C 控制器、SPI 控制器、USB 控制器、 SDRAM 控制器等,有的处理器还集成了 GPU(图形处理器)、视频编解码器等。
驱动针对的对象是存储器和外设(包括 CPU 内部集成的存储器和外设),而不是针对 CPU 内核。Linux 将存储器和外设分为 3 个基础大类。
● 字符设备。
● 块设备。
● 网络设备。
字符设备指那些必须以串行顺序依次进行访问的设备,如触摸屏、磁带驱动器、鼠标 等。块设备可以按任意顺序进行访问,以块为单位进行操作,如硬盘、eMMC 等。字符设备 和块设备的驱动设计有出很大的差异,但是对于用户而言,它们都要使用文件系统的操作接 口 open()、close()、read()、write() 等进行访问。
在 Linux 系统中,网络设备面向数据包的接收和发送而设计,它并不倾向于对应于文件 系统的节点。内核与网络设备的通信与内核和字符设备、网络设备的通信方式完全不同,前 者主要还是使用套接字接口。
SRAM、Flash、SDRAM、
磁盘的读写方式,UART、I2C、USB 等设备的接口以及轮询、中断、DMA 的原理,
PCI 总线的工作方式以及 CPU 的内存管理单元(MMU)
虚拟机环境:
http://pan.baidu.com/s/1c08gzi4(密码为 puki)
1.5.2 QEMU 实验平台
QEMU 模拟了 vexpress Cortex-A9 SMP 四核处理器开发板,板上集成了 Flash、SD、 I2C、LCD 等。ARM 公司的 Versatile Express 系列开发平台提供了超快的环境,用于为下一 代片上系统设计方案建立原型,比如 Cortex-A9 Quad Core。
在 http://www.arm.com/zh/products/tools/development-boards/versatile-express/index.php 上 可以发现更多关于 Versatile Express 系列开发平台的细节。
本书配套虚拟机映像中已经安装好了工具链,包含 arm-linux-gnueabihf-gcc 和 arm-linux- gnueabi-gcc 两个版本。
Linux 内核在 /home/baohua/develop/linux 目录中,在该目录下面,包含内核编译脚本:
第1章 Linux设备驱动概述及开发环境构建 11
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
make LDDD3_vexpress_defconfig
make zImage -j8
make modules -j8
make dtbs
cp arch/arm/boot/zImage extra/
cp arch/arm/boot/dts/*ca9.dtb
cp .config extra/
由此可见,我们用的默认内核配置文件是 LDDD3_vexpress_defconfig。上述脚本也会自
动将编译好的 zImage 和 dtbs 复制到 extra 目录中。
extra 目录下的 vexpress.img 是一张虚拟的 SD 卡,将作为根文件系统的存放介质。它能
以 loop 的形式被挂载(mount),譬如在 /home/baohua/develop/linux 目录下运行。
sudo mount -o loop,offset=$((2048*512)) extra/vexpress.img extra/img
可以把 vexpress.img 的根文件系统分区挂载到 extra/img,这样我们可以在目标板的根文
件系统中放置我们喜欢的内容。
/home/baohua/develop/linux 目录下面有个编译模块的脚本 module.sh,它会自动编译内核
模块并安装到 vexpress.img 中,其内容如下:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- modules
extra/
12 Linux设备驱动开发详解:基于最新的Linux 4.0内核
sudo mount -o loop,offset=$((2048*512)) extra/vexpress.img extra/img
sudo make ARCH=arm modules_install INSTALL_MOD_PATH=extra/img
sudo umount extra/img
运行 extra 下面的 run-nolcd.sh 可以启动一个不含 LCD 的 ARM Linux。run-nolcd.sh 的内
容为 qemu-system-arm -nographic -sd vexpress.img -M vexpress-a9 -m 512M -kernel zImage -dtb
vexpress-v2p-ca9.dtb -smp 4 -append “init=/linuxrc root=/dev/mmcblk0p1 rw rootwait earlyprintk
console=ttyAMA0” 2>/dev/null,运行结果为:
baohua@baohua-VirtualBox:~/develop/linux/extra$ ./run-nolcd.sh
Uncompressing Linux… done, booting the kernel.
Booting Linux on physical CPU 0x0
Initializing cgroup subsys cpuset
Linux version 3.16.0+ (baohua@baohua-VirtualBox) (gcc version 4.7.3 (Ubuntu/
Linaro 4.7.3-12ubuntu1) ) #3 SMP Mon Dec 1 16:53:04 CST 2014
CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c53c7d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine model: V2P-CA9
bootconsole [earlycon0] enabled
Memory policy: Data cache writealloc
PERCPU: Embedded 7 pages/cpu @9fbcd000 s7232 r8192 d13248 u32768
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 130048
Kernel command line: init=/linuxrc root=/dev/mmcblk0p1 rw rootwait earlyprintk
console=ttyAMA0
PID hash table entries: 2048 (order: 1, 8192 bytes)
Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
Memory: 513088K/524288K available (4583K kernel code, 188K rwdata, 1292K rodata,
247K init, 149K bss, 11200K reserved)
Virtual kernel memory layout:
vector : 0xffff0000 – 0xffff1000
fixmap : 0xffc00000 – 0xffe00000
vmalloc : 0xa0800000 – 0xff000000
lowmem : 0x80000000 – 0xa0000000
modules : 0x7f000000 – 0x80000000
.text : 0x80008000 – 0x805c502c
.init : 0x805c6000 – 0x80603c40
.data : 0x80604000 – 0x80633100
( 4 kB)
(2048 kB)
(1512 MB)
( 512 MB)
( 16 MB)
(5877 kB)
( 248 kB)
( 189 kB)
( 150 kB)
.bss : 0x80633108 – 0x806588a8
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
Hierarchical RCU implementation.
RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4.
RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
NR_IRQS:16 nr_irqs:16 16
L2C: platform modifies aux control register: 0x02020000 -> 0x02420000
L2C: device tree omits to specify unified cache
L2C: DT/platform modifies aux control register: 0x02020000 -> 0x02420000
L2C-310 enabling early BRESP for Cortex-A9
L2C-310 full line of zeros enabled for Cortex-A9
L2C-310 dynamic clock gating disabled, standby mode disabled
L2C-310 cache controller enabled, 8 ways, 128 kB
L2C-310: CACHE_ID 0x410000c8, AUX_CTRL 0x46420001
smp_twd: clock not found -2
sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 178956969942ns
Console: colour dummy device 80×30
…
运行 extra 下面的 run-lcd.sh 可以启动一个含 LCD 的 ARM Linux,运行结果如图 1.11
所示。
图 1.11 含 LCD 的 ARM Linux
除了 QEMU 模拟的 ARM 电路板以外,本书配套的 Ubuntu 中还包含一些直接可以
在 Ubuntu 上 运 行 的 案 例, 譬 如 /home/baohua/develop/training/kernel 中 就 包 含 了 globalfifo、
globalmem 等,这些目录的源代码都包含了 Makefile,在其中直接 make,生成的 .ko 可以直
接在 Ubuntu 上运行。
1.5.3 源代码阅读和编辑
源代码是学习 Linux 的权威资料,在 Windows 上阅读 Linux 源代码的最佳工具是 Source Insight,在其中建立一个工程,并将 Linux 的所有源代码加入该工程,同步这个工程之后, 我们将能非常便捷地在代码之间进行关联阅读,如图 1.12 所示。
类似 http://lxr.free-electrons.com/、http://lxr.oss.org.cn/ 这样的网站提供了 Linux 内核源代 码的交叉索引,在其中输入 Linux 内核中的函数、数据结构或变量的名称就可以直接得到以 超链接形式给出的定义和引用它的所有位置。还有一些网站也提供了 Linux 内核中函数、变 量和数据结构的搜索功能,在 google 中搜索“linux identifier search”可得。
在 Linux 主机上阅读和编辑 Linux 源码的常用方式是 vim + cscope 或者 vim + ctags,vim 是一个文本编辑器,而 cscope 和 ctags 则可建立代码索引,建议读者尽快使用基于文本界面 全键盘操作的 vim 编辑器,如图 1.13 所示。
此时,我们只需要有一个感性认识,那就是,上述暂时陌生的元素都是 Linux 内核为字 符设备定义的,以实现驱动与内核接口而定义的。Linux 对各类设备的驱动都定义了类似的 数据结构和函数。
第2章
驱动设计的硬件基础
本章导读
本章讲述底层驱动工程师必备的硬件基础,给出了嵌入式系统硬件原理及分析方法的一 个完整而简洁的全景视图。
2.1 节描述了微控制器、微处理器、数字信号处理器以及应用于特定领域的处理器各自 的特点,分析了处理器的体系结构和指令集。
2.2 节对嵌入式系统中所使用的各类存储器与 CPU 的接口、应用领域及特点进行了归纳 整理。
2.3 节分析了常见的外设接口与总线的工作方式,包括串口、I2C、SPI、USB、以太网接口、 PCI 和 PCI-E、SD 和 SDIO 等。
嵌入式系统硬件电路中经常会使用 CPLD 和 FPGA,作为驱动工程师,我们不需要掌握 CPLD 和 FPGA 的开发方法,但是需要知道它们在电路中能完成什么工作,2.4 节讲解了这项 内容。
2.5 ~ 2.7 节给出了在实际项目开发过程中硬件分析的方法,包括如何进行原理图分析、 时序分析及如何快速地从芯片数据手册中获取有效信息。
2.8 节讲解了调试过程中常用仪器仪表的使用方法,涉及万用表、示波器和逻辑分析仪。 2.1 处理器
2.1.1 通用处理器
目前主流的通用处理器(GPP)多采用 SoC(片上系统)的芯片设计方法,集成了各种功 能模块,每一种功能都是由硬件描述语言设计程序,然后在 SoC 内由电路实现的。在 SoC 中,每一个模块不是一个已经设计成熟的 ASIC 器件,而是利用芯片的一部分资源去实现某 种传统的功能,将各种组件采用类似搭积木的方法组合在一起。
ARM 内核的设计技术被授权给数百家半导体厂商,做成不同的 SoC 芯片。ARM 的功耗 很低,在当今最活跃的无线局域网、3G、手机终端、手持设备、有线网络通信设备等中应用 非常广泛。至本书编写时,市面上绝大多数智能手机、平板电脑都使用 ARM SoC 作为主控