Android深度探索(卷1)HAL与驱动开发学习笔记

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android深度探索(卷1)HAL与驱动开发学习笔记相关的知识,希望对你有一定的参考价值。

android深度探索(1)HAL与驱动开发学习笔记(6

第六章 第一个Linux驱动程序 统计单词个数

 

Linux系统将每一个驱动都映射成一个文件.这些文件称为设备文件或驱动文件,都保存在/dev目录中。这种设计理念使得与Linux驱动进行交互就像与普通文件进行交互一样容易。虽然C语言里没有事件的概念,但却有与事件类似的概念,这就是回调(c a l l b a c k)函数。因此,编写Lin u x驱动最重要的一步就是编写阴调函数,否则与设备文件交互的数据将无法得到处理。

6.1编写Linux驱动的步骤

  1. 建立Linux驱动骨架
  2. 注册和注销设备文件
  3. 指定与驱动相关的信息
  4. 指定回调函数
  5. 编写业务逻辑
  6. 编写makefile 文件
  7. 编译Linux驱动程序
  8. 安装和卸载Linux驱动

* 上面8步中的前5步是关于如何编写Lin u x驱动程J字的,通过后3步可以使L i n u x驱动正常工作。

 

6.2 编写L i n u驱动程序前的准备工作

本例的L i n u x驱动源代码并未与li n u x内核源代码放在一起,而是单独放在一个目录。* 首先使用下面的命令建立存放Li n u x驱动程序的目录。

# mkdir  -p/root/drivers/ch06/word_count

# cd  /root/drivers/ch0 6/word_count

* 然后,使用下面的命令建立驱动源代码文件(word count.c)

# echo ’’>word_count.c

最后编写一个M a k e f i l e文件,

# echo ‘obj-m := word_count.o >  Makefile

 

6.3 编写L i n u x驱动程序的骨架(初始化和退出驱动)

代码中使用了p r i n t k函数。该函数用于输出日志信息printk函数与p r i n t f函数的用法类似。linux系统将内存分为了用户空间和内核空间,这两个空间的程序不能直接访问。p r i n t f函数运行在用户空间,p r i n t k函数运行在核空间。因此,属于内核程序的L i n u x驱动是不能直接访问p r i n t f函数的。运行在这两块内存中的程序之间交互的-方法很多。其中,设备文件就是一种主要的交互方式,如果用户空间的程序要访问内核空间,只要做一个可以访问内核空间的驱动程序,然后用户空间的程序通过设备文件与驱动程序进行交互即可.那么,如何在linux驱动程序中动态分配内存空间呢?解决类似的问题也很简单。既然L i n u x驱动无法直接调用运行在用户空间的函数,那么,在L i n u x内核中就必须要提供替代品。可以进入<Li n u x内核源代码>/i n c l u d e目录,该目录的各个子目录中…包含了大量的C语言头文件,这些头文件中定义资源就是运行在用户空间的程序的替代品。

6.4. 安装查看和卸载Linux驱动

* 安装Linux驱动

# ismod word_count.ko

* 查看word_count 是否安装成功

# lsmod  I  grep  word_count

* 卸载Linux驱动

# remmod word_count

* 查看Linux驱动的输出信息

# dmesg | grep word_cound | tail -n 2

 

6.5 指定与驱动相关的信息

一般需要为L i n u x驱动程序,指定如下信息。

模块作者:使用MODULE_AUTHOR宏指定。

模块描述:使用MODULE_DESCRIPTION宏指定。

模块别名:使用MODULE_ALIAS宏指定。

开源协议:使用MODULE_LICENSE宏指定。

 

代码如下(一般放在word_count.c最后):

    MODULE_AUTHOR(“lining”);

MODULE_DESCRIPTION(“statistics of word count .”);

MODULE_ALIAS(“word count module .”);

MODULE_LICENSE(“GPL”);

 

6.6 注册和注销设备文件

w o r d_c o u n t驱动建立一个设备文件,该设备文件的名称是w o r d c o unt,位于/d e v目录中。设备文件与普通文件不同,不能使用I O函数建立,需要使用m i s c_r egister函数建立设备文件,使用m i s c_d e r e g i s t e r函数注销(移除〉设备文件。

* 编写中的注意事项

1.备文件由主设备号和次设备号描述。而使用m i s c _ r e g i s t e r函数只能设置次设备号。主设备号统一设为10。主设备号为1 0的设备是L i n µ x系统中拥有共同特性的简单字符设备。这类设备称为m i s c设备。

   2. miscdevice.name变量的值就是设备文件的名称。在本例中设备文件名称为w o r d c o u n t .

   3. 果成功注册了设备文件,m i s c _ _ r e g i s t e r函数返回非0的整数,如果注册设备文件失败返回0

    4. w o r d_c o u n t . c中的所有函数、变量都声明成了s t a t i cC语言中用s t a t i c声明函数、变量等资源,系统会将这些函数和变量单独放在内存的某一个区域,直到程序完全退出,否则这些资源不会被释放, L i n u x驱动一旦装载,除非手动卸载或关机,驱动会一直驻留内存,因此这些函数和变量资源会一直在内存中。也就是说多次调用这些资源不用再进行压栈,出栈操作了,有利于提高驱动的运行效率。

 

6.7 指定回调函数

  1. w o r d _ c o u n t_r e a dword_c o u n t_w r i t e函数的参数基本相同,只有第2个参数b u f稍微有差异。word _count _r e a d.函数的b u f参数类型是c h a r*,而w o r d _count _w r i t e函数的b u f参数类型是co n s t  char*;这就意味着w o r d _count _w r i t e函数中的b u f参数值无法修改。Word_count_read函数中的b u f参数表示从设备文件读出的数据,也就是说b u f中的数据都可能自设备文件读出,至于可以读出多少数据,取决于w o r d _count _r e a d.函数的返回值。
  2. 由于内核空间的程序不能直接访问用户空间中的数据,因此需要在.w o r d_c o u n t -r e a dword _c o unt_w r i t e函数中分别使用copy_to_user和c o p y _ from_user函数将数据从内核空间复制到用户空间戒从用户空间复制到内核空间。

 

6.8测试Linux驱动的多种方法

 

1.使用Ubuntu Linux测试Linux驱动

2.A n d r o i d模拟器上通过原生(Native  )C程序测试L i n u x驱动

* 用于Andr o i d模拟的g o l d f i s h内核默认不允许动态装载L i n u x驱动模块,因此需要在编译L i n u x内核之前执行如下命令配置L i n u x内核。

# cd kernel goldfish

    # make menuconfig

* 行上面的命令后,按空格键将第二顶“Enable loadable  module  s u p p ort”选中前面是(*),然后按回车键选入子菜单,选中前3项,否则L i n u x驱动模快仍然无法安装和卸载。当退出设置菜单时保持设置。最后重新编译Linux内核,成功编译内核后,  A n d r o i d模拟器可以使用新生成的zImage内核文件动态装载L i n u x驱动模块。

*在执行build.h脚本文件完成对w o r ld_c o u n t驱动的编译、上传和安装的工作,然后进入A n d r o i d模拟器的终端,使用e c h od mesg命令可以演出w o r d _ c o u n t驱动和查看测试时结果。

* 了使编译步骤尽可能简单使用Android设 置 编 译 参 数 , 并 使 用 make命令进行编译。首先在root/driver/ch06/word_count目录中建立一个A n d r o i d . m k文件,并输入如下的内容。

LOCAL  PATH:=  $  (call  my -dir)

include  $(CLEAR  VARS)

#指定要编译的源代码文件

LOCAL _SRC _FILES := test _word_count .c

#指定模块名,也是编译后生成的可执行文件名

LOCAL_MODULE= test_word_cunt

LOCAL _MODU LE _T AGS= optional

include  $(BUILD_EXECUTABLE)

A r i dro i d . m k文件中有如下两个地方需要说明一下.

 LO C AL _MODULE_TAGS.

表示当前工程(A n d roi d .mk文件所在的目录)在什么模式下编译。如果设为optional,表示不考虑模式,也就是说,在任何膜式下都会编译。该变量可以设置的值有us eruse r d e b u g、e ng、  o p t i o n a l其中eng是默认值。

include  $(BUILD_EXEC UT ABLE) .

BUILD _EXECUTABLE表示建立可执行的文件。可执行文件路径是<A n d r o i d源代码目录〉

3.使用Android ADK设置Linux驱动

4.使用JAVA代码直接操作设备文件来测试Linux驱动

5.使用S3C6410开发板测试Linux驱动

6.将驱动编译进Linux内核进行测试

 

以上是关于Android深度探索(卷1)HAL与驱动开发学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

Android深度探索(卷1)HAL与驱动开发学习笔记

Android深度探索(卷1)HAL与驱动开发第十章总结

Android深度探索(卷1)HAL与驱动开发第六章总结

《Android深度探索》(卷1)HAL与驱动开发 第五章心得体会

Android深度探索(卷1)HAL与驱动开发5-7章

《Android深度探索》(卷1)HAL与驱动开发 第九章心得体会