文档详情

嵌入式LINUX按键驱动程序开发

鲁**
实名认证
店铺
DOC
119.50KB
约5页
文档ID:404115019
嵌入式LINUX按键驱动程序开发_第1页
1/5

嵌入式 Linux 按键驱动程序开发摘要: 文章主要阐述了 Linux 驱动程序的基本概念以及字符设备、 块设备和网络设备的特点, 通过键盘驱动实例论述了如何设计和编写模块化的驱动程序, 并解释键盘驱动程序的关键代 码,最后归纳了开发嵌入式 Linux 设备驱动程序的核心思想关键词:设备驱动; Linux ;内核;模块;键盘中图分类号: TP311.1 文献标识码: A引言嵌入式 Linux 以其可应用于多种硬件平台、内核高效稳定、源码开放、软件丰富、网络 通信和文件管理机制完善等优良特性,成为嵌入式系统领域中的一个研究热点在嵌入式 Linux 系统中,内核提供保护机制,用户空间的进程一般不能直接访问硬件,进行嵌入式系 统的开发, 很大的工作量是为各种设备编写驱动程序 键盘设备在嵌入式系统中应用的非常 广泛,分析驱动程序的原理和编写相应的键盘驱动程序在嵌入式开发中显的尤其重要1 设备驱动程序概述1.1 设备驱动程序的概念Linux 设备驱动程序是为特定的硬件提供给用户程序的一组标准化接口,它隐藏了设备 工作的细节 [1] 在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文 件一样对硬件设备进行操作。

1.2 设备驱动程序的类型Linux 系统的设备分为字符设备 (char device) 、块设备 (lock device) 和网络设备 (network device) 三种字符设备是指存取时没有缓存的设备,因此在对字符设备发出读 / 写请求时,实际的硬件I/O —般就紧接着发生了字符设备是 Linux设备中最简单的一种,应用程序可以用与存 取文件相同的系统调换用来打开、 读写及关闭它 典型的字符设备包括鼠标、 键盘、 串行口 等块设备的读写都有缓存来支持,并且块设备必须能够随机存取 (random access) ,是指那些在输入输出时数据处理以块为单位的设备, 采用了缓冲技术, 支持数据的随机读写, 系 统可以通过它们的设备做特殊文件访问, 但是更常见的是通过文件系统访问 典型的块设备 包括硬盘和光盘等网络设备在Linux里做了专门的处理,Linux的网络系统主要是基于 BSD UNIX勺socket 机制 在系统和驱动程序之间定义有专门的数据结构进行数据的传递, 系统支持对发送数据和接收数据的缓存,提供流量控制机制和多协议的支持 [2] 典型的网络设备是网卡2 模块化驱动程序设计及流程2.1 模块化设计思想模块是指整个系统中一些相对独立的程序单元, 每个程序单元完成和实现一个相对独立 的软件功能。

Linux 的内核是一个整体式内核, 如果新添加一个硬件, 就需要重新编译内核; 如果去掉一个硬件,那么这个硬件已经编译进内核的驱动程序就是浪费Linux 内核用模块来解决这个问题,模块是内核的一部分,而且都是设备驱动程序,但 它们并没有被编译到内核中,而是被分别编译并链接成一组目标文件这些文件能被载入正在运行的内核, 或从正在运行的内核中卸载, 必要时内核能请求内核守护进程kerneld对模块进行加载或卸载 同根据需要动态载入模块可以保证内核达到最 小,并且具有很大的灵活性内核模块一部分保存在 Kernel中,另一部分在Modules包中22 几个关键的模块函数(1) i nit_module()函数init_module() 在模块调入内核时被调用,它在内核中用 insmod命令注册一定的功能函数(如图1中的功能1、功能2、功能3 )在注册之后,如果有程序访问内核模块的某个功能, 如功能1,内核将查表获得功能1在module中的位置,然后调用功能1的函数 ,同样功能2和功能3也是这样调用的结(2)clea nup_module()函数cleanup_module()在模块从内核中卸载时被调用,用 rmmod命令把以前注册的功能函数卸载⑷。

cleanup_module()函数必须把init_module() 函数在内核中注册的功能函数完全卸载,否则,在此模块下次调入时,将会因为有重名的函数而导致调入失败其中 init_module() 函数在运行insmod命令后由系统调用,完成驱动模块的初始化工作cleanup_module ()函数在运行rmmoc命令后由系统调用,完成驱动模块卸载时的清除工作 在2.3版本以后的Linux内核中,提供了一种新的方法来命名这两个函数例如,可以定义 my_init() 函数来代替 init_module() 函数,定义 my_cleanup()函数来代替 cleanup_module()函数,然后在源代码文件末尾使用下面的语句:module_i nit(my_i nit);module_exit(my_clea nup);注意:此时在源代码文件中必须包含" #i nclude

  • ”语句这样做的好处是每个模块都可以有自己的初始化和卸载函数的函数名,多个模块在调试时不会有函数 重名问题2.3 设备驱动程序开发的步骤(1) 定义主、次设备号,也可以动态获取;(2) 实现驱动初始化和清除函数,如果驱动程序采用模块方式,则要实现模块初始化和 清除函数;(3) 设计所要实现的文件操作,定义 file_operations 结构;⑷ 实现所需的文件操作调用,如 read,write 等;(5) 实现中断服务函数,并用 request_irq向内核注册;(6) 将驱动编译到内核或编译成模块,用 insmod命令加载;(7) 生成设备节点文件。

    与普通文件相比,设备文件的操作要复杂得多, 不可能简单地通过read、write 和llseek等命令来实现所有其它类型的操作都可以通过 VFS的ioctl命令调用来执行,为此只需要在驱动程序中实现ioctl ,并在其中添加相应的 case选项即可同3 HD7279键盘驱动的编写3.1 HD7279A键盘简介HD7279是一片具有串行接口, 可连接多达64键的键盘矩阵的字符驱动芯片, 单片即可完 成键盘接口的全部功能, 并且有片选信号, 可方便地实现多于 64键的键盘接口, 广泛的应用 于仪表仪器,工业控制器,控制面板等许多场合3.2 HD7279A键盘驱动程序键盘设备驱动程序的 struct file_operation 结构声明如下所示,在此根据实际需要, 做了适当的精简, 只定义了与用户的键盘应用程序里对设备文件操作的函数相对应的驱动函 数用户可根据自己的需要作相应的定义,使用该方法来提高驱动程序的可移植性static struct file_operations kbd7279_fops =打开设备文件 设备文件其他操作 关闭设备文件 读取设备文件{ open: kbd7279_open, //ioctl: kbd7279_ioctl, //release: kbd7279_close, // read: kbd7279_read, //在嵌入式 Linux 系统中,设备驱动程序就是一个函数和数据结构的集合,所提供的功能是由一个文件操作结构来向系统说明,即 file_operations 结构。

    每个进程对设备的操作, 都会根据MAJOR MINO设备号,转换成对file_operations 结构的访问,当操作系统对设备进行操作时,会调用驱动程序注册的 file_operations 构中的成员,这个结构中的成员几乎 全部是函数指针,所以实质上就是函数跳转表,根据所接收的请求,进行对应的操作static int kbd7279_open (struct inode *inode,struct file *file){ kdb7279_event (kdb7279_stop); // 关闭内核对键盘的操作 MOD_INC_USE_COUNT; 使// 模块的使用次数加 1 return 0;}在用户程序打开设备时,键盘字符设备驱动程序实现的函数 kbd7279_open把键盘控制单元赋值给文件描述符的私有数据 MOD_INC_USE_COU是内核提供的一个宏,它使模块的使用次数加1, 目的是防止当模块被使用的同时又被卸载,只有当模块使用计数为0时,才能 被卸载static int kbd7279_relaese (struct inode *inode, struct file *file){ MOD_DEC_USE_COUNT使模块的使用次数减 1 kdb7279_event (kdb7279_start); // 恢复内核对键盘的操作 return 0;} 当用户关闭设备时,先使模块的使用计数减 1,再还原内核对键盘的控制。

    static int kbd7279_read(struct file *fp, char *buf, size_t count){KEY_LOCK(unit); // 上锁put_user(kbd_buf, buf); // 把处于内核空间记录按键值的数据复制到用户空间buf 中kbd_buf = 0xFF; // 把记录按键值的暂存单元清空 KEY_UNLOCK(unit); // 开锁return 0;}读取键盘状态时, 先锁定键盘控制单元, 防止另一进程同一时刻改变键盘状态 然后从 控制单元获得状态值,并拷贝到用户缓冲区操作完成后解锁,并返回读取字节数其中 copy_to_user 函数实现将内核空间的数据 copy 到用户空间里static int kbd7279_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){switch(cmd){case kbd7279_GETKEY: return kbd7279_getkey(); // 获取按键值break ;default: printk("Unkown Keyboard Command ID.\n"); break ;} return 0;} 函数主要实现把用户空间所保存的按键值送到数码管上显示。

    注册函数 _init kbd7279_Init(void) 中,驱动程序通过调用 register_chrdev( KEYBOARD_MAJOR, "kbd7279", &kbd7279_fops) 注册设备,调用 request_irq(33, kbd7279_ISR,0,"kbd7279","88") 申请中断号void _exit kbd7279_exit(void)// 关闭键盘设备{ unregister_chrdev(KEYBOARD_MAJOR, "kbd7279"); // 注销设备 free_irq(33,"88"); // 释放中断号send_byte(cmd_reset); // 关闭键盘} 在这个函数中,释放了设备所占用的中断号并通过设备注册号关闭了键盘设备4 结束语对 Linux 的驱动原理和键盘驱动的具体实现方法进行了详细的介绍,并加以实现,该驱 动采用了高度的结构化、模块化、层次化的接口方法,可以方便的移植到 Linux 下其它系列 的键盘驱动,也对在嵌入式 Linux 下开发其它的驱动具 有指导意义参考文献:[1] Rubini . A. Linux 设备驱动程序 [M] .北京 : 中国电力出版社 ,2002 .[2] 周立功 . ARM 微控制器基础与实战 [ M]. 北京 :北京航空航人大学出版社 ,2003 。

  • 下载提示
    相似文档
    正为您匹配相似的精品文档