微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 嵌入式Linux设备驱动开发之:字符设备驱动编程

嵌入式Linux设备驱动开发之:字符设备驱动编程

时间:09-13 来源:互联网 点击:

程想要删除该设备,则必须保证其他设备没有使用该设备。因此使用计数器就可以很好地完成这项功能。

这里,实现计数器操作的是在2.6内核早期版本的linux/module.h>中定义的3个宏,它们在最新版本里早就消失了,在下面列出只是为了帮读者理解老版本中的驱动代码。

n MOD_INC_USE_COUNT:计数器加1。

n MOD_DEC_USE_COUNT:计数器减1。

n MOD_IN_USE:计数器非零时返回真。

另外,当有多个物理设备时,就需要识别次设备号来对各个不同的设备进行不同的操作,在有些驱动程序中并不需要用到。

注意

虽然这是对设备文件执行的第一个操作,但却不是驱动程序一定要声明的操作。若这个函数的入口为NULL,那么设备的打开操作将永远成功,但系统不会通知驱动程序。

(5)释放设备。

释放设备的函数接口是release()。要注意释放设备和关闭设备是完全不同的。当一个进程释放设备时,其他进程还能继续使用该设备,只是该进程暂时停止对该设备的使用;而当一个进程关闭设备时,其他进程必须重新打开此设备才能使用它。

释放设备时要完成的工作如下。

n 递减计数器MOD_DEC_USE_COUNT(最新版本已经不再使用)。

n 释放打开设备时系统所分配的内存空间(包括filp->private_data指向的内存空间)。

n 在最后一次释放设备操作时关闭设备。

(6)读写设备。

读写设备的主要任务就是把内核空间的数据复制到用户空间,或者从用户空间复制到内核空间,也就是将内核空间缓冲区里的数据复制到用户空间的缓冲区中或者相反。这里首先解释一个read()和write()函数的入口函数,如表11.5所示。

表11.5 read、write函数接口语法要点

所需头文件

#includelinux/fs.h>

函数原型

ssize_t(*read)(structfile*filp,char*buff,size_tcount,loff_t*offp)
ssize_t(*write)(structfile*filp,constchar*buff,size_tcount,loff_t*offp)

函数传入值

filp:文件指针

buff:指向用户缓冲区

count:传入的数据长度

offp:用户在文件中的位置

函数返回值

成功:写入的数据长度

虽然这个过程看起来很简单,但是内核空间地址和应用空间地址是有很大区别的,其中一个区别是用户空间的内存是可以被换出的,因此可能会出现页面失效等情况。所以不能使用诸如memcpy()之类的函数来完成这样的操作。在这里要使用copy_to_user()或copy_from_user()等函数,它们是用来实现用户空间和内核空间的数据交换的。

copy_to_user()和copy_from_user()的格式如表11.6所示。

表11.6 copy_to_user()/copy_from_user()函数语法要点

所需头文件

#includeasm/uaccess.h>

函数原型

unsignedlongcopy_to_user(void*to,constvoid*from,unsignedlongcount)
unsignedlongcopy_from_user(void*to,constvoid*from,unsignedlongcount)

函数传入值

to:数据目的缓冲区

from:数据源缓冲区

count:数据长度

函数返回值

成功:写入的数据长度
失败:-EFAULT

要注意,这两个函数不仅实现了用户空间和内核空间的数据转换,而且还会检查用户空间指针的有效性。如果指针无效,那么就不进行复制。

(7)ioctl。

大部分设备除了读写操作,还需要硬件配置和控制(例如,设置串口设备的波特率)等很多其他操作。在字符设备驱动中ioctl函数接口给用户提供对设备的非读写操作机制。

ioctl函数接口的具体格式如表11.7所示。

表11.7 ioctl函数接口语法要点

所需头文件

#includelinux/fs.h>

函数原型

int(*ioctl)(structinode*inode,structfile*filp,unsignedintcmd,unsignedlongarg)

函数传入值

inode:文件的内核内部结构指针

filp:被打开的文件描述符

cmd:命令类型

arg:命令相关参数

下面列出其他在驱动程序中常用的内核函数。

(8)获取内存。

在应用程序中获取内存通常使用函数malloc(),但在设备驱动程序中动态开辟内存可以以字节或页面为单位。其中,以字节为单位分配内存的函数有kmalloc(),注意的是,kmalloc()函数返回的是物理地址,而malloc()等返回的是线性虚拟地址,因此在驱动程序中不能使用malloc()函数。与malloc()不同,kmalloc()申请空间有大小限制。长度是2的整次方,并且不会对所获取的内存空间清零。

以页为单位分配内存的函数如下所示。

n get_zeroed_page():获得一个已清零页面。

n get_free_page():获得一个或几个连续页面。

n get_dma_pages():获得用于DMA传输的页面。

与之相对应的释放内存用也有kfree()或free_page函数族。

表11.8给出了kmalloc()函数的语法格式。

表11.8 kmalloc()函数语法要点

所需头文件

#includelinux/malloc.h>

函数原型

void*kmalloc(unsignedintlen,intflags)

函数传入

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top