ImageVerifierCode 换一换
格式:DOCX , 页数:13 ,大小:20.80KB ,
资源ID:2436788      下载积分:15 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.docduoduo.com/d-2436788.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录   微博登录 

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(2、在Ubuntu上为Android系统编写Linux内核驱动程序.docx)为本站会员(dreamzhangning)主动上传,道客多多仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知道客多多(发送邮件至docduoduo@163.com或直接QQ联系客服),我们立即给予删除!

2、在Ubuntu上为Android系统编写Linux内核驱动程序.docx

1、-在 Ubuntu 上为 Android 系统编写 Linux 内核驱动程序一、引言在智能手机时代,每个品牌的手机都有自己的个性特点。正是依靠这种与众不同的个性来吸引用户,营造品牌凝聚力和用户忠城度,典型的代表非 iphone 莫属了。据统计,截止 2011 年 5 月,AppStore 的应用软件数量达 381062 个,位居第一,而 Android Market 的应用软件数量达 294738,紧随 AppStore 后面,并有望在 8 月份越过 AppStore。随着Android 系统逐步扩大市场占有率,终端设备的多样性亟需更多的移动开发人员的参与。据业内统计,Android 研发人才

2、缺口至少 30 万。目前,对 Android 人才需求一类是偏向硬件驱动的 Android 人才需求,一类是偏向软件应用的 Android 人才需求。总的来说,对有志于从事 Android 硬件驱动的开发工程师来说,现在是一个大展拳脚的机会。那么,就让我们一起来看看如何为 Android 系统编写内核驱动程序吧。这里,我们不会为真实的硬件设备编写内核驱动程序。为了方便描述为 Android 系统编写内核驱动程序的过程,我们使用一个虚拟的硬件设备,这个设备只有一个 4 字节的寄存器,它可读可写。想起我们第一次学习程序语言时,都喜欢用“Hello, World”作为例子,这里,我们就把这个虚拟的设

3、备命名为“hello” ,而这个内核驱动程序也命名为 hello 驱动程序。其实,Android 内核驱动程序和一般 Linux 内核驱动程序的编写方法是一样的,都是以 Linux 模块的形式实现的,具体可参考前面 Android 学习启动篇一文中提到的 Linux Device Drivers 一书。不过,这里我们还是从 Android 系统的角度来描述 Android 内核驱动程序的编写和编译过程。参照这两篇文章在 Ubuntu 上下载、编译和安装 Android 最新源代码和在 Ubuntu 上下载、编译和安装 Android 最新内核源代码(Linux Kernel)准备好 Andro

4、id 内核驱动程序开发环境。二. 进入到 kernel/common/drivers 目录,新建 hello 目录::/Android$ cd kernel/common/:/Android/kernel/common/drivers$ mkdir hello三. 在 hello 目录中增加 hello.h 文件:#ifndef _HELLO_ANDROID_H_ #define _HELLO_ANDROID_H_ #include #include #define HELLO_DEVICE_NODE_NAME “hello“ #define HELLO_DEVICE_FILE_NAME “h

5、ello“ #define HELLO_DEVICE_PROC_NAME “hello“ #define HELLO_DEVICE_CLASS_NAME “hello“ struct hello_android_dev int val; struct semaphore sem; struct cdev dev; ; #endif 这个头文件定义了一些字符串常量宏,在后面我们要用到。此外,还定义了一个字符设备结构体 hello_Android_dev,这个就是我们虚拟的硬件设备了,val 成员变量就代表设备里面的寄存器,它的类型为 int,sem 成员变量是一个信号量,是用同步访问寄存器 va

6、l 的,dev 成员变量是一个内嵌的字符设备,这个 Linux 驱动程序自定义字符设备结构体的标准方法。四.在 hello 目录中增加 hello.c 文件,这是驱动程序的实现部分。驱动程序的功能主要是向上层提供访问设备的寄存器的值,包括读和写。这里,提供了三种访问设备寄存器的方法,一是通过 proc 文件系统来访问,二是通过传统的设备文件的方法来访问,三是通过 devfs 文件系统来访问。下面分段描述该驱动程序的实现。首先是包含必要的头文件和定义三种访问设备的方法:#include #include #include #include #include #include #include #

7、include “hello.h“ /*主设备和从设备号变量*/ static int hello_major = 0; static int hello_minor = 0; /*设备类别和设备变量*/ static struct class* hello_class = NULL; static struct hello_android_dev* hello_dev = NULL; /*传统的设备文件操作方法*/ static int hello_open(struct inode* inode, struct file* filp); static int hello_release(s

8、truct inode* inode, struct file* filp); static ssize_t hello_read(struct file* filp, char _user *buf, size_t count, loff_t* f_pos); static ssize_t hello_write(struct file* filp, const char _user *buf, size_t count, loff_t* f_pos); /*设备文件操作方法表*/ static struct file_operations hello_fops = .owner = THI

9、S_MODULE, .open = hello_open, .release = hello_release, .read = hello_read, .write = hello_write, ; /*定义设备属性*/ static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store); /*访问设置属性方法*/ static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf); static

10、 ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count); 定义传统的设备文件访问方法,主要是定义 hello_open、hello_release、hello_read 和hello_write 这四个打开、释放、读和写设备文件的方法:/*打开设备方法*/ static int hello_open(struct inode* inode, struct file* filp) struct hello_android_dev* dev;

11、 /*将自定义设备结构体保存在文件指针的私有数据域中,以便访问设备时拿来用*/ dev = container_of(inode-i_cdev, struct hello_android_dev, dev); filp-private_data = dev; return 0; /*设备文件释放时调用,空实现*/ static int hello_release(struct inode* inode, struct file* filp) return 0; /*读取设备的寄存器 val 的值 */ static ssize_t hello_read(struct file* filp, c

12、har _user *buf, size_t count, loff_t* f_pos) ssize_t err = 0; struct hello_android_dev* dev = filp-private_data; /*同步访问*/ if(down_interruptible( if(count val) goto out; /*将寄存器 val 的值拷贝到用户提供的缓冲区 */ if(copy_to_user(buf, goto out; err = sizeof(dev-val); out: up( return err; /*写设备的寄存器值 val*/ static ssiz

13、e_t hello_write(struct file* filp, const char _user *buf, size_t count, loff_t* f_pos) struct hello_android_dev* dev = filp-private_data; ssize_t err = 0; /*同步访问*/ if(down_interruptible( if(count != sizeof(dev-val) goto out; /*将用户提供的缓冲区的值写到设备寄存器去*/ if(copy_from_user( goto out; err = sizeof(dev-val);

14、 out: up( return err; 定义通过 devfs 文件系统访问方法,这里把设备的寄存器 val 看成是设备的一个属性,通过读写这个属性来对设备进行访问,主要是实现 hello_val_show 和 hello_val_store 两个方法,同时定义了两个内部使用的访问 val 值的方法_hello_get_val 和_hello_set_val :/*读取寄存器 val 的值到缓冲区 buf 中,内部使用*/ static ssize_t _hello_get_val(struct hello_Android_dev* dev, char* buf) int val = 0;

15、/*同步访问*/ if(down_interruptible( val = dev-val; up( return snprintf(buf, PAGE_SIZE, “%d/n“, val); /*把缓冲区 buf 的值写到设备寄存器 val 中去,内部使用 */ static ssize_t _hello_set_val(struct hello_android_dev* dev, const char* buf, size_t count) int val = 0; /*将字符串转换成数字*/ val = simple_strtol(buf, NULL, 10); /*同步访问*/ if(

16、down_interruptible( dev-val = val; up( return count; /*读取设备属性 val*/ static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev); return _hello_get_val(hdev, buf); /*写设备属性 val*/ static ssi

17、ze_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev); return _hello_set_val(hdev, buf, count); 定义通过 proc 文件系统访问方法 ,主要实现了 hello_proc_read 和 hello_proc_write 两个方法,同时定义了在 p

18、roc 文件系统创建和删除文件的方法 hello_create_proc 和hello_remove_proc:/*读取设备寄存器 val 的值,保存在 page 缓冲区中*/ static ssize_t hello_proc_read(char* page, char* start, off_t off, int count, int* eof, void* data) if(off 0) *eof = 1; return 0; return _hello_get_val(hello_dev, page); /*把缓冲区的值 buff 保存到设备寄存器 val 中去*/ static ss

19、ize_t hello_proc_write(struct file* filp, const char _user *buff, unsigned long len, void* data) int err = 0; char* page = NULL; if(len PAGE_SIZE) printk(KERN_ALERT“The buff is too large: %lu./n“, len); return -EFAULT; page = (char*)_get_free_page(GFP_KERNEL); if(!page) printk(KERN_ALERT“Failed to a

20、lloc page./n“); return -ENOMEM; /*先把用户提供的缓冲区值拷贝到内核缓冲区中去*/ if(copy_from_user(page, buff, len) printk(KERN_ALERT“Failed to copy buff from user./n“); err = -EFAULT; goto out; err = _hello_set_val(hello_dev, page, len); out: free_page(unsigned long)page); return err; /*创建/proc/hello 文件*/ static void hel

21、lo_create_proc(void) struct proc_dir_entry* entry; entry = create_proc_entry(HELLO_DEVICE_PROC_NAME, 0, NULL); if(entry) entry-owner = THIS_MODULE; entry-read_proc = hello_proc_read; entry-write_proc = hello_proc_write; /*删除/proc/hello 文件*/ static void hello_remove_proc(void) remove_proc_entry(HELLO

22、_DEVICE_PROC_NAME, NULL); 最后,定义模块加载和卸载方法,这里只要是执行设备注册和初始化操作:/*初始化设备*/ static int _hello_setup_dev(struct hello_Android_dev* dev) int err; dev_t devno = MKDEV(hello_major, hello_minor); memset(dev, 0, sizeof(struct hello_android_dev); cdev_init( dev-dev.owner = THIS_MODULE; dev-dev.ops = /*注册字符设备*/ er

23、r = cdev_add( if(err) return err; /*初始化信号量和寄存器 val 的值*/ init_MUTEX( dev-val = 0; return 0; /*模块加载方法*/ static int _init hello_init(void) int err = -1; dev_t dev = 0; struct device* temp = NULL; printk(KERN_ALERT“Initializing hello device./n“); /*动态分配主设备和从设备号*/ err = alloc_chrdev_region( if(err dev);

24、cleanup: kfree(hello_dev); unregister: unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1); fail: return err; /*模块卸载方法*/ static void _exit hello_exit(void) dev_t devno = MKDEV(hello_major, hello_minor); printk(KERN_ALERT“Destroy hello device./n“); /*删除/proc/hello 文件*/ hello_remove_proc(); /

25、*销毁设备类别和设备*/ if(hello_class) device_destroy(hello_class, MKDEV(hello_major, hello_minor); class_destroy(hello_class); /*删除字符设备和释放设备内存*/ if(hello_dev) cdev_del( kfree(hello_dev); /*释放设备号*/ unregister_chrdev_region(devno, 1); MODULE_LICENSE(“GPL“); MODULE_DESCRIPTION(“First Android Driver“); module_in

26、it(hello_init); module_exit(hello_exit); 五.在 hello 目录中新增 Kconfig 和 Makefile 两个文件其中 Kconfig 是在编译前执行配置命令 make menuconfig 时用到的,而 Makefile 是执行编译命令 make 是用到的:Kconfig 文件的内容config HELLOtristate “First Android Driver“default nhelpThis is the first android driver.Makefile 文件的内容obj-$(CONFIG_HELLO) += hello.o在

27、 Kconfig 文件中,tristate 表示编译选项 HELLO 支持在编译内核时,hello 模块支持以模块、内建和不编译三种编译方法,默认是不编译,因此,在编译内核前,我们还需要执行 make menuconfig 命令来配置编译选项,使得 hello 可以以模块或者内建的方法进行编译。在 Makefile 文件中,根据选项 HELLO 的值,执行不同的编译方法。六. Make menuconfig修改 arch/arm/Kconfig 和 drivers/kconfig 两个文件,在 menu “Device Drivers“和 endmenu 之间添加一行:source “driv

28、ers/hello/Kconfig“这样,执行 make menuconfig 时,就可以配置 hello 模块的编译选项了。. 七. 修改 drivers/Makefile 文件,添加一行:obj-$(CONFIG_HELLO) += hello/八. 配置编译选项::/Android/kernel/common$ make menuconfig找到“Device Drivers“ = “First Android Drivers“选项,设置为 y。注意,如果内核不支持动态加载模块,这里不能选择 m,虽然我们在 Kconfig 文件中配置了 HELLO 选项为 tristate。要支持动态加

29、载模块选项,必须要在配置菜单中选择 Enable loadable module support 选项;在支持动态卸载模块选项,必须要在 Enable loadable module support 菜单项中,选择 Module unloading 选项。九. 编译::/Android/kernel/common$ make编译成功后,就可以在 hello 目录下看到 hello.o 文件了,这时候编译出来的 zImage已经包含了 hello 驱动。十. 验证 hello 驱动参照在 Ubuntu 上下载、编译和安装 Android 最新内核源代码( Linux Kernel)一文所示,运行

30、新编译的内核文件,验证 hello 驱动程序是否已经正常安装::/Android$ emulator -kernel ./kernel/common/arch/arm/boot/zImage &:/Android$ adb shell进入到 dev 目录,可以看到 hello 设备文件:rootandroid:/ # cd devrootandroid:/dev # ls进入到 proc 目录,可以看到 hello 文件:rootandroid:/ # cd procrootandroid:/proc # ls访问 hello 文件的值:rootandroid:/proc # cat hell

31、o0rootandroid:/proc # echo 5 hellorootandroid:/proc # cat hello5进入到 sys/class 目录,可以看到 hello 目录:rootandroid:/ # cd sys/classrootandroid:/sys/class # ls进入到 hello 目录,可以看到 hello 目录:rootandroid:/sys/class # cd hellorootandroid:/sys/class/hello # ls进入到下一层 hello 目录,可以看到 val 文件:rootandroid:/sys/class/hello

32、# cd hellorootandroid:/sys/class/hello/hello # ls访问属性文件 val 的值:rootandroid:/sys/class/hello/hello # cat val5rootandroid:/sys/class/hello/hello # echo 0 valrootandroid:/sys/class/hello/hello # cat val0至此,我们的 hello 内核驱动程序就完成了,并且验证一切正常。这里我们采用的是系统提供的方法和驱动程序进行交互,也就是通过 proc 文件系统和 devfs 文件系统的方法,下一篇文章中,我们将通过自己编译的 C 语言程序来访问/dev/hello 文件来和 hello 驱动程序交互,敬请期待。

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报