本来以为LINUX下的驱动设计很难,这几天看了一些资料才发现,虽然驱动设计精通要花很多时间,但是入门还是很容易的。 下面和大家共同分享一些资料,希望有用。
在本章开始, 我们提供例子模块来演示编程概念. ( 所有的例子都可从 O' Reilly' s 的 FTP 网站上得到, 如第 1 章解释的那样 )建立, 加载, 和修改这些例子, 是提高你对驱动如何工作以及如何与内核交互的理解的好方法. 例子模块应该可以在大部分的 2.6.x 内核上运行, 包括那些由发布供应商提供的. 但是, 我们建议你获得一个主流内核, 直接从 kernel.org 的镜像网络, 并把它安装到你的系统中. 供应商的内核可能是主流内核被重重地打了补丁并且和主流内核有分歧; 偶尔, 供应商的补丁可能改变了设备驱动可见的内核 API. 如果你在编写一个必须在特别的发布上运行的驱动, 你当然要在相应的内核上建立和测试. 但是, 处于学习驱动编写的目的, 一个标准内核是最好的. 不管你的内核来源, 建立 2.6.x 的模块需要你有一个配置好并建立好的内核树在你的系统中. 这个要求是从之前内核版本的改变, 之前只要有一套当前版本的头文件就足够了. 2.6 模块针对内核源码树里找到的目标文件连接; 结果是一个更加健壮的模块加载器, 还要求那些目标文件也是可用的. 因此你的第一个商业订单是具备一个内核源码树( 或者从 krenel.org 网络或者你的发布者的内核源码包), 建立一个新内核, 并且安装到你的系统. 因为我们稍后会见到的原因, 生活通常是最容易的如果当你建立模块时真正运行目标内核, 尽管这不是需要的. | 注意 | 你应当也考虑一下在哪里进行你的模块试验, 开发和测试. 我们已经尽力使我们的例子模块安全和正确, 但是 bug 的可能性是经常会有的. 内核代码中的错误可能会引起一个用户进程的死亡, 或者偶尔, 瘫痪整个系统. 它们正常地不会导致更严重地后果, 例如磁盘损伤. 然而, 还是建议你进行你的内核试验在一个没有包含你负担不起丢失的数据的系统, 并且没有进行重要的服务. 内核开发者典型地会保留一台"牺牲"系统来测试新的代码. | 因此, 如果你还没有一个合适的系统, 带有一个配置好并建立好的源码树在磁盘上, 现在是时候建立了. 我们将等待. 一旦这个任务完成, 你就准备好开始摆布内核模块了
许多编程书籍从一个 "hello world" 例子开始, 作为一个展示可能的最简单的程序的方法. 本书涉及的是内核模块而不是程序; 因此, 对无耐心的读者, 下面的代码是一个完整的 "hello world"模块: #include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("Dual BSD/GPL"); static int hello_init(void) { printk(KERN_ALERT "Hello, world\n"); return 0; } static void hello_exit(void) { printk(KERN_ALERT "Goodbye, cruel world\n"); } module_init(hello_init); module_exit(hello_exit); 这个模块定义了两个函数, 一个在模块加载到内核时被调用( hello_init )以及一个在模块被去除时被调用( hello_exit ). moudle_init 和 module_exit 这几行使用了特别的内核宏来指出这两个函数的角色. 另一个特别的宏 (MODULE_LICENSE) 是用来告知内核, 该模块带有一个自由的许可证; 没有这样的说明, 在模块加载时内核会抱怨. printk 函数在 Linux 内核中定义并且对模块可用; 它与标准 C 库函数 printf 的行为相似. 内核需要它自己的打印函数, 因为它靠自己运行, 没有 C 库的帮助. 模块能够调用 printk 是因为, 在 insmod 加载了它之后, 模块被连接到内核并且可存取内核的公用符号 (函数和变量, 下一节详述). 字串 KERN_ALERT 是消息的优先级. [3] 我们在此模块中指定了一个高优先级, 因为使用缺省优先级的消息可能不会在任何有用的地方显示, 这依赖于你运行的内核版本, klogd 守护进程的版本, 以及你的配置. 现在你可以忽略这个因素; 我们在第 4 章讲解它. 你可以用 insmod 和 rmmod 工具来测试这个模块. 注意只有超级用户可以加载和卸载模块. % make make[1]: Entering directory `/usr/src/linux-2.6.10' CC [M] /home/ldd3/src/misc-modules/hello.o Building modules, stage 2. MODPOST CC /home/ldd3/src/misc-modules/hello.mod.o LD [M] /home/ldd3/src/misc-modules/hello.ko make[1]: Leaving directory `/usr/src/linux-2.6.10' % su root# insmod ./hello.ko Hello, world root# rmmod hello Goodbye cruel world root# 请再一次注意, 为使上面的操作命令顺序工作, 你必须在某个地方有正确配置和建立的内核树, 在那里可以找到 makefile (/usr/src/linux-2.6.10, 在展示的例子里面 ). 我们在 "编译和加载" 这一节深入模块建立的细节. 依据你的系统用来递交消息行的机制, 你的输出可能不同. 特别地, 前面的屏幕输出是来自一个字符控制台; 如果你从一个终端模拟器或者在窗口系统中运行 insmod 和 rmmod, 你不会在你的屏幕上看到任何东西. 消息进入了其中一个系统日志文件中, 例如 /var/log/messages (实际文件名子随 Linux 发布而变化). 内核递交消息的机制在第 4 章描述. 如你能见到的, 编写一个模块不是如你想象的困难 -- 至少, 在模块没有要求做任何有用的事情时. 困难的部分是理解你的设备, 以及如何获得最高性能. 通过本章我们深入模块化内部并且将设备相关的问题留到后续章节.
|