Linux系统将每一个驱动都映射成一个文件.这些文件称为设备文件或驱动文件,都保存在/dev目录中。编写linux驱动最重要的一步就是编写回调函数,否则与设备文件交互的数据无法得到处理。
1. 编写linux驱动程序的步骤:
第 1 步:建立 Linu x 驱动骨架 (装载和卸载 Linu x 驱动):
Linux 内核在使用驱动时首先需要装载驱动。当 Linux系统退出时需要卸载 Linux 驱动,在卸载的过程中需要释放由 linux 驱动占用的资源,例如,删除设备文件、释放内存地址空间等。在 Linux 驱动程序中需要提供两个函数来分别处理驱动初始化和退出的工作,这两个函数分别module_init和 module_exit宏指定。
第 2 步:注册和注销设备文件:
建立设备文件的工作一般在第一步编写的处理linux初始化工作的函数中完成------misc_register创建设备文件;
删除设备文件一般在第一步编写的处理linux退出工作的函数中完成-----misc_deregister删除设备文件。
第 3 步:指定与驱动相关的信息:
驱动程序都是自描述的。例如:modififo命令获取驱动的作者、姓名、使用的开源协议、别名、驱动描述等信息。通过
MODULE_AUTHOR\MODULE_LICENSE等完成。
第 4 步:指定回调函数
事件:linux包含的许多动作。例如:想设备文件写入数据名称称为写事件,linux系统会调用对应驱动程序的write回调函数,从设备文件读数据时会触发“读事件”,linux系统会调用对应的read函数。
回调函数通过相关机制进行注册,例如,与设备文件相关的回调函数会通过 misc_register 函数进行注册。
第 5 步:编写业务逻辑:
核心部分,具体的实现根据具体的情况决定。
第 6 步:编写 Makefile文件:
Linu: 内核源代码的编译规则是通过 Makefi le 文件定义的。
第 7 步:编译 Linux 驱动程序
Linux 驱动程序,可以直接编译进内核,也可以作为模块单独编译。
第 8 步:安装和卸载 Linux 驱动:
1.如果将linux驱动编译进内核,只要linux使用内核驱动程序会自动装载。
2.如果linux驱动模块单独存在,需使用insomod或modprobe命令装载linux驱动模块,使用rmmod命令卸载模块。
注意:区分insmod 和 modprobe命令:
modprobe可以检查驱动模块的依赖性。如 A 模块依赖子B 模块(装载A 之前必须先装载 B)。如果使用 insmod 命令装载A 模块,会出现错误。 而使用 modprobe 命令装载 A 模块, B 模块会现在装载。在使用 modprobe 命令装载驱动模块之前,需要先使用 depmod 命令检测 Linux 驱动模块的依赖关系。
2.学习第一个linux驱动:统计单词个数:利用设备文件作为介质与应用程序进行交互。
内容:应用程序通过向设备文件传递一个由空格分隔的字符串(每一个被空格隔开的子字符串称为一个单词),然后从设备文件读出来的是该字符串包含的单词数。
1>准备工作:
代码:1.建立存放linux驱动程序的目录:
Mkdir –p /root/drivers/ch06/word_count
Cd /root/drivers/ch06/word_count
2.建立驱动源代码文件(.c)
Ehco ‘’>word_count.c
3.编写一个Makefile文件
echo ’obj-m :=word_count.o’ > Makefile
其中 obj-m表示将 Linux 驱动作为模块(.ko 文件)编译。
如果使用 obj-y,则将 Linux 驱动编译 进 Linux 内核。
其中 built-in.o 文件是连接向一类程序的.o 文件生成的中间目标文件。该目标文件包含了所有可连接进 Linux 内核的字符驱动(通过 make menuconfig 命令可以配置每一个驱动及其他内核程序是否允许编译进内核)。
如果 Linux 驱动依赖其他程序,如 process.c、 data.c,需要按如下方式编写 Makefile 文件。
obj-m := word_count . 。
word_count_y : = process.o data.o
其中依赖文件要使用 module_y 或 module_objs 指定。 module 表示模块名,如 word_count .
2>编写linux驱动程序的骨架:
Linux系统包括:用户空间【printf】和内核空间【printk】,且用户空间不可以直接访问内核空间。用户空间编写一个可以访问内核的驱动程序,用户空间通过访问设备文件从而访问驱动程序。
那么,如何在linux 驱动程序中动态分配内存空间呢?解决类似的问题也很简单。既然 Linux 驱动无法直接调用运行在用户空间的函数,那么,在Linux 内核 中就必须要提供替代品。
使用下面的命令编译Linux驱动源代码。
make -c /usr/src/linux-headers-3.0.0-15-generic M=/ root/driver/ch06/word_count
安装驱动: insmod xxxx.ko
卸载驱动:rmmod xxxx
查看驱动是否安装成功:lsmod |grep xxx
查看由linux驱动输出的日志信息:
Dmesg | grep xxx|tail-n 2
Cat /usr/log/syslog|grep xxx |tail –n 2
3>指定与驱动相关的信息:
- 一般需要为 Linux 驱动程序,指定如下信息:
模块作者:使用 MODULE AUTHOR 宏指定。
模块描述:使用 MODULE DESCRIPTION 宏指定。
模块别名:使用 MODULE ALIAS 宏指定。
开源协议z 使用 MODULE_LICENSE 宏指定。
2.查看.ko文件信息使用:
modinfo word_count.kc
3.使用之前讲述的命令指定上述4种信息。
例如:MODULE_AUTHOR(“linging”);
5.开源协议:GPL、LGPL、BSD协议、Apache license2.0协议、MIT协议。
这儿着重介绍GPL: 通用性公开许可证(General Public License,简称GPL)。GPL同其它的自由软件许可证一样,许可社会公众享有:运行、复制软件的自由,发行传播软件的自由,获得软件源码的自由,改进软件并将自己作出的改进版本向社会发行传播的自由。与其它不同之处:开源的更彻底、且具有传染性。
4>注册和注销设备文件:
设备文件位于/dev目录下。设备文件与普通文件不同,不能使用 IO 函数建立,需要使用 misc_register 函数建立设备文件, 使用 misc_deregister 函数注销(移除〉设备文件。而且设备文件还需要一个结构体( miscdevice)来描述与其相关的信息。
注意:
1. 设备文件由主设备号和次设备号描述。而使用 misc_register函数只能设置次设备号。 主设备号统一设为10。主设备号为 10的设备是 Linux系统中拥有共同特性的简单字符设备。
2. Fileoperations.owner=module结构:表示fileoperation被应用在这些有module指定的驱动模块
Fileoperations.owner=This.module表示只可以应用于当前模块
3.注册成功返回非0整数,注册失败,返回0
4.static:C 语言中用 static 声明函数、变量等资源,系统会将这些函数和变量单独放在内存的某一个区域,直到程序完全退出,否则这些资源不会被释放。
5.使用ls –l /dev查看主次设备号。
6.使用cat /proc/devices显示当前系统中有哪些主次设备号。
5>指定回调函数
通过 file_operations.read和 file_operations. write 成员变量可以分别指定读写设备文件要调用的回调函数指针。
6>实现统计单词个数的算法:
由空格、制表符、回车符和换行符分隔的字符串算做一个单词。
4.使用多种多种方式测试linux驱动:
1. 使用Ubuntu _linux测试 Linux 驱动:
2. 在 Android 模拟器上通过原生( Native ) C 程序测试 Linux 驱动
第一种方法:
1>查看是否可以将 word count.ko 安装在 Android 模拟器上?
答:执行 bui ldsh 脚本-à选择“Android模拟器”[脚本会自动将 word count.ko 文件上传到 Android模拟器的Ida饱/local 目录,并进行安装]。
2>注意:如果读者选择的是 S3C6410 开发板,在安装 word count.ko 时就会输出如下的错误信息:
insmod: init_module ‘/data/local/word_count. ko’ failed ( Function not implemented )
表示编译 Linux 驱动的 Linux 内核版本与当前 Android 模拟器的版本不相同,无法安装。 所以在编译 Linux 驱动时,必须选择与当前运行的 Linux 内核版本相同的 Linux 内核进行编译, 否则就 无法安装 Linux 驱动。
3>用于 Android 模拟器的 goldfish 内核默认不允许动态装载 Linux 驱动模块,因此需要在编译 Linux 内核之前执行如下命令配置 Linux 内核: cd /kernel/goldfish
make menuconfig
4>现在执行 build.sh脚本文件完成对 word_count驱动的编译、上传和安装的工作,然后进入 Android 模拟器的终端,使用echo和dmesg命令可以测试word_count驱动和查看测试结果。
第二种方法:
1>android模拟器可以直接运行普通的Linux程序需要满足一下几个条件:
android模拟器、开发板或手机需要有root权限。
可执行文件需要使用交叉编译器进行编译、以便支持ARM处理器。
2>现在开始测试:
首先在/root/drivers/ch06/word_count目录中建立一个 Android.mk 文件。并输入如下的内容:
LOCAL PATH:= $ (call my-dir)
include $(CLEAR_ VARS)
#指定要编译的源代码文件
LOCAL _SRC _FILES := test_word _count .c
#指定模块名,也是编译后生成的可执行文件名
LOCAL_MODULE := test_word_count
LOCAL MODULE_TAGS :=optional
include $(BUILD_ EXECUTABLE)
LOCAL. MODULE _TAGS. 表示当前工程(Android.mk文件所在的目录)在什么模式下编译.
其次:1.为了将 test_word_count.c 文件编译成可在 Android 模拟器上运行的可执行程序,可以将 word_count 目录复制到<Android 源代码目录〉的某个子目录,也可以在<Android 源代码目录〉目录中为 word_count目录建立一个符号链接。例如:
ln-s/root/drivers/ch06/word_count /sources/android/android4/ development/word_ count
2.现在进入/sources/android/android4 目录,执行下面的命令初始化编译命令source ./build/envsetup .sh
3.可以使用下面两种方法编译:test_word_count.c.
(1)进入/sources/android/android4/development/word_count 目录,并执行如下的命令:mm
(2)在/sources/android/android自录下执行如下的命令:
mmm development/word_count
4.现在执行下面的命令将 test_word_count 文件上传到 Android 模拟器:
# adb push ./emulator/test_word_count /data/local
5.然后进入 Android 模拟器的终端,并执行下面的命令测试 word_count 驱动(需要先使用 chmod 命令设置 test_word_count 的可执行权限〉:
# chmod 777 /data/1ocal/test _word _count
# /data/local/test_word_count
# /data/1ocal/test _word_ count ’a bb ccc ddd eee ’
执行上面的命令后, 如果输出的单词个数是 5, 表示程序测试成功。
3.使用 Android NDK 测试 Linux 驱动
4.使用 Java 代码直接操作设备文件来测试 Linux 驱动
5.使用 S3C6410 开发板测试 Linux 驱动
6.将驱动编译进 Linux 内核进行测试
使用如下的步骤将 word_count驱动加入 Linux 内核源代码树:
第 1 步:将 word_count.c 文件放入 Linux 内核源代码:将word_count.c 文件放到<Liunx内核目录〉/drvers/cbar目录中。
第 2 步:修改Kconfig 文件:
打开/root/kemel/goldfish/drivers/char/Kconfig文件,找到 endmenu,并在 eodmenu 前面添加如下代码:
config WORD_COUNT
boo1 "word_count driver”
help
This is a word count driver . It can get a word count from /dev/wordcount
第 3 步:修改 Makefile 文件
Obj-$(CONFIG_WORD_COUNT) += word_count.O
第 4 步:设置.config 文件
第 5 步:编译 Linux 内核
进入/root/kernel/goldfish 目录,执行下面的命令编译 Linux 内核: make
5.使用eclipse开发和测试 linux驱动程序
1> 在 Eclipse 中开发 Li nu x 驱动程序
步骤如下:
·第1步:建立C工程---第 2 步:建立C源代码文件链接[单击 word__count_eclipse 工程右键菜单中的“New">"Soruce Folder”菜单项目,打开“New Soruce Folder对话框, 在“Folder name”文本框中输入“src “--à单击 “Finish”按钮建立一个保存 Linux 驱动源代码文件的目录----单击 src 目录---右键菜单中单击 “Import”菜单项--打开 “ Import ” 对话框--选择“File System ”项---单击 "Next”按钮进入下一个设置界面--选择word_count.c--单击“advanced“-----选择“ Create links in workspace”复选框---finish]------ 第 3 步:设置 include 路径:/root/kernel/goldfish/include /root/kernel/goldfish/arc/arm/include------第 4 步:编译 Linux 驱动。
2> 在 Eclipse 中测试 Linux 驱动
第 1 步:导入 test_word_count.c 文件---第 2 步:设置 include 路径------第 3 步:建立 Target[单击 word_count_ eclipse_ test 工程右键菜单的“Make Targets”〉“Create” 菜单项,打开 “Create Make Target”对话框,在“Target name” 文本框中输入“word_count_eclipse_test”,然后单击“OK” 按钮关闭对话框]-----第 4 步: Build 工程[单击 word_count_eclipse_test 工程右键菜单的“Make Targets" > “Build” 菜单项, 打开“Make Targets”对话框,选中在第 3 步建立的“word_count_ eclipse_test”,然后单击“Build” 按钮,会在 word_count_eclipse_test 工程中生成一些配置文件]------第 5 步; 运行测试程序[单击工程右键菜单的“Run As”>”Local C/C++ Application”菜单项]