嵌入式linux设备驱动开发笔记--赖永诚

上传人:j****9 文档编号:47103717 上传时间:2018-06-29 格式:PDF 页数:55 大小:547.68KB
返回 下载 相关 举报
嵌入式linux设备驱动开发笔记--赖永诚_第1页
第1页 / 共55页
嵌入式linux设备驱动开发笔记--赖永诚_第2页
第2页 / 共55页
嵌入式linux设备驱动开发笔记--赖永诚_第3页
第3页 / 共55页
嵌入式linux设备驱动开发笔记--赖永诚_第4页
第4页 / 共55页
嵌入式linux设备驱动开发笔记--赖永诚_第5页
第5页 / 共55页
点击查看更多>>
资源描述

《嵌入式linux设备驱动开发笔记--赖永诚》由会员分享,可在线阅读,更多相关《嵌入式linux设备驱动开发笔记--赖永诚(55页珍藏版)》请在金锄头文库上搜索。

1、嵌入式 Linux 设备驱动开发 赖永诚 第 1 页 共 55 页 嵌入式 Linux 设备驱动开发 嵌入式 Linux 设备驱动开发 驱动程序就是操作系统中用于控制和访问各种输入/输出设备的程序,驱动程序的重要性勿需多言。 而且,在实际的嵌入式系统开发中,操作系统的内核一般不需要做太多的修改,大量的工作往往是针对独 特的硬件平台编写、修改和调试各个外设的驱动程序,因此掌握驱动程序的设计对于嵌入式 Linux 系统开 发特别重要。 1. 设备驱动概述 1. 设备驱动概述 在 Linux 中,几乎所有的内容都是文件,对设备驱动的访问也是以文件操作的方法实现的。无论是字 符设备还是块设备,用户对

2、设备的操作都是通过虚拟文件系统转换为设备驱动与硬件操作例程的交互;即 使是访问网络的 Socket 接口,也是通过虚拟文件系统(VFS)实现的。Linux 通过虚拟文件系统为用户提供 了一个统一的设备访问接口,使用户能够透明地访问设备驱动程序。设备驱动程序是 Linux 内核的重要组 成部分。它向操作系统的其他部分屏蔽了设备硬件的复杂性,实现了硬件设备的透明管理。 1.1 设备类型分类 1.1 设备类型分类 根据物理设备的特点和工作方式,以及驱动程序向内核注册的调用接口的不同,Linux 系统的设备驱 动程序分为字符设备(Char Device)、块设备(Block Device)和网络设备(

3、Network Device)三种。 (1) 字符设备 字符设备是一类像键盘那样以字符(字节)为单位,逐个进行输入/输出的设备,如键盘、打印机等。 字符设备接口支持面向字符的 I/O 操作,不经系统的快速缓存,所以它们负责管理自己的缓冲区结构。字 符设备接口只支持顺序存取的功能,一般不能进行任意长度的 I/O 请求,而是限制 I/O 请求的长度必须是 设备要求的基本块长的倍数。 在系统内部,I/O 操作的存取通过一组固定的入口点来进行,这组入口点是由每个设备的设备驱动程 序提供的。一般来说,字符型设备驱动程序能够提供如下几个入口点: open 入口点:打开设备准备 I/O 操作。对字符特别设备

4、文件进行打开操作,都会调用设备的 open 入口点。open 子程序必须对将要进行的 I/O 操作做好必要的准备工作,如清除缓冲区等。如果设备是独占 的,即同一时刻只能有一个程序访问此设备,则 open 子程序必须设置一些标志以表示设备处于忙碌状态。 close 入口点:关闭一个设备。当最后一次使用设备终结后,调用 close 子程序。独占设备必须标 记设备可再次使用。 read 入口点:从设备上读数据。对于有缓冲区的 I/O 操作,一般是从缓冲区里读数据。对字符特 别设备文件进行读操作将调用 read 子程序。 write 入口点:向设备写数据。对于有缓冲区的 I/O 操作,一般是把数据写入

5、缓冲区里。对字符特 别设备文件进行写操作将调用 write 子程序。 ioctl 入口点:执行读、写之外的操作。 (2) 块设备 块设备是一类像磁盘那样以记录块或者“扇区”为单位,成块进行输入/输出的设备,如磁盘、USB 接 口等。块设备接口仅支持面向块的 I/O 操作,所有 I/O 操作都通过在内核地址空间中的 I/O 缓冲区进行, 它可以支持几乎任意长度和任意位置上的 I/O 请求,即提供随机存取的功能。 (3) 网络设备 网卡、Modem 是最常见的网络设备。网络设备与字符设备和块设备最大的不同之处就在与网络设备没 有对应的设备文件。网卡是最典型的一个例子,网卡把向外发送的数据写入通往远

6、程计算机系统的一条通 信线路上,把从远程系统中接受到的报文装入内核内存。在 Linux 系统中,计算机为每一个网卡分配一个 不同的符号名,例如:eth0,eth1 等。然而,这个名字并没有对应的设备文件,也没有对应的索引节点。 由于没有使用文件系统,所以系统管理员必须建立设备名和网络地址之间的联系。因此,应用程序和网络 接口之间的数据通信不是基于标准的有关文件的 read()、 write()等系统调用, 而是基于 BSD socket 机制, 使用 socket()、bind()、listen()、accept()、connect()等系统调用对网络地址进行操作。在系统和驱嵌入式 Linux

7、 设备驱动开发 赖永诚 第 2 页 共 55 页 动程序之间定义有专门的数据结构(sk_buff)进行数据传递。 1.2 设备驱动程序开发的特性与共性 1.2 设备驱动程序开发的特性与共性 Linux 操作系统内核中存在着许多不同的设备驱动,如网卡、打印机、声卡等驱动程序。虽然这些驱 动程序各自负责不同的硬件,并且完成相应的功能,但它们具有如下一些共性。 (1)内核代码 设备驱动程序是内核的一部分,像内核中其他代码一样,出错将导致系统的严重损伤。一个编写较差 的设备驱动程序甚至能使系统崩溃并导致文件系统的破坏和数据丢失。 (2)内核接口 设备驱动程序必须为 Linux 内核或者其从属子系统提

8、供一个标准接口。 (3)接口内核机制与服务 设备驱动程序可以使用标准的内核服务,如内存分配中断、发送和等待队列等。 (4)动态可加载 多数 Linux 设备驱动程序可以在内核模块发出加载请求时加载,同时在不再使用时卸载。 (5)可配置 Linux 设备驱动程序可以链接到内核中。当内核被编译时,哪些内核被链接到内核是可配置的。 1.3 设备驱动程序的组成 1.3 设备驱动程序的组成 设备驱动程序可以分为 3 个主要组成部分: 自动配置和初始化子程序:这部分程序负责检测所要驱动的硬件设备是否存在和是否能正常工作。 如果该设备正常,则对这个设备及其相关的、设备驱动程序需要的软件状态进行初始化。这部分

9、驱动程序 仅在初始化的时候被调用一次。 服务于 I/O 请求的子程序:这部分程序又成为驱动程序的上半部分。由系统调用来进行程序的调 用。这部分程序在执行的时候,系统仍认为是与进行调用的进程属于同一个进程,只是由用户态变成了内 核态,具有进行此系统调用的用户程序的运行环境,因此可以在其中调用 sleep()等与进程运行环境有关 的函数。 中断服务子程序:中断服务子程序又称为驱动程序的下半部分。 2. 内核的数据类型及链表2. 内核的数据类型及链表 现代版本的 Linux 内核的可移植性是非常好的,可以运行在许多不同的体系结构上。由于 Linux 的多 平台特性,任何一个重要的驱动程序都应该都是可

10、移植的。 当 Linux 内核在体系结构差异较大的平台之间移植时,会产生与数据类型相关的问题。坚持使用严格 的数据类型, 并且在编译内核时使用-Wall Wstrict-prototypes 选项, 可以防止大多数的代码缺陷。 内核使用的数据类型主要被分为三大类: 类似 int 这样的标准 C 语言类型; 类似 u32 这样的有确定大小的类型 像 pid_t 这样的用于特定内核对象的类型。 在不同的 CPU 体系结构上,C 语言的数据类型所占空间不一样。我们将讨论应该在什么情况下使用这 三种典型类型,以及如何使用。 如果读者遵循我们提供的指导方针,读者的驱动程序甚至可能在那些未经测试的平台上编

11、译和运行。 2.1 使用标准 C 语言类型 2.1 使用标准 C 语言类型 尽管大多数程序员习惯于自由使用像 int 和 long 这样的标准类型,但编写设备驱动程序时需要小心, 以避免类型冲突和潜在的代码缺陷。 问题是,当我们需要“两个字节的填充符”或者“用四个字节字符串表示的某个东西”时,我么不能 使用标准类型, 因为在不同的体系架构上, 普通 C 语言的数据类型所占空间的大小并不相同。 下面是在 x86 下数据类型所占的字节数: 嵌入式 Linux 设备驱动开发 赖永诚 第 3 页 共 55 页 arch char short int long ptr long-long u8 u16

12、 u32 u64 i686 1 2 4 4 4 8 1 2 4 8 下面是在其他平台上的数据类型所占的字节数: arch char short int long ptr long-long u8 u16 u32 u64 i386 1 2 4 4 4 8 1 2 4 8 alpha 1 2 4 8 8 8 1 2 4 8 armv41 1 2 4 4 4 8 1 2 4 8 ia64 1 2 4 8 8 8 1 2 4 8 m68k 1 2 4 4 4 8 1 2 4 8 mips 1 2 4 4 4 8 1 2 4 8 ppc 1 2 4 4 4 8 1 2 4 8 sparc 1 2 4 4

13、 4 8 1 2 4 8 sparc64 1 2 4 4 4 8 1 2 4 8 其中基于 sparc64 平台的 Linux 用户空间可以运行 32 位代码,用户空间指针是 32 位宽的,但内核空 间是 64 位的。 内核中的地址是 unsigned long 类型,指针大小和 long 类型相同。 尽管在混合使用不同数据类型时我们必须小心谨慎,但有时有理由这样做。这样的一种情况是内存地 址,只要一涉及到内核,内存地址就变得很特殊。虽然从概念上讲地址是指针,但是通过使用无符号整数 类型(unsigned long)可以很好地实现内存管理;内核把物理内存看作是一个巨型数组,一个内存地址就 是该

14、数组的一个索引。此外,我们可以很方便地对指针取值;但在直接处理内存地址时,我们几乎从来不 会以这种方式对它们取值。使用一个整数类型可以防止这种取值,因而可避免代码缺陷。所以,内核中的 普通内存地址通常是 unsigned long,这利用了如下事实:至少在当前 Linux 支持的所有平台上,指针和 long 整型的大小总是相同的。 C99 标准定义了 intptr_t 和 uintptr_t 类型,它们是能够保存指针值的整型变量。这些类型在 Linux 2.6 的内核中几乎没有用到。 2.2 为数据项分配确定的空间大小 2.2 为数据项分配确定的空间大小 有时内核代码需要特定大小的数据项,多半

15、是用来匹配预定义的二进制结构,或者和用户空间进行通 信,或者通过在结构体中插入“填白”字段来对齐数据。 当我们需要知道自己的数据大小时,内核提供了下列数据类型。所有这些类型都在头文件 中申明,这个文件又被头文件包含: 相应的有符号类型也存在, 但是几乎没有。 如果需要它们的话, 只需将名字中的 u 用 s 替换就可以了。 2.3 接口特定的类型 2.3 接口特定的类型 内核中最常用的数据类型由它们自己的 typedef 申明,这样可以防止出现任何移植性问题。例如,一 个进程的标识符(pid)通常使用 pid_t 类型,而不是 int。使用 pid_t 屏蔽了在实际的数据类型中任何可能 的差异。

16、 “接口特定(interface-specific)”是指由某个库定义的一种数据类型,以便为某个特定的数据 结构提供接口。 注意,近来已经很少定义新的接口特定的类型。许多内核开发人员已经不再喜欢使用 typedef 语句, 他们更愿意看到直接用在代码中的真实的类型信息,而不是隐藏在用户定义的类型之后。不过,许多较老 的接口特定类型还是保留在内核中,它们不会很快就消失。 即使没有定义接口特定的类型,也应该始终使用和内核其余部分一致的、适当的数据类型。例如, jiffies 计数总是属于 unsigned long 类型,而不管它的实际大小如何,因此,在使用 jiffies 的时候应typedef unsigned char u8; /* 无符号字节(8 位) */ ty

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 中学教育 > 初中教育

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号