Linux设备驱动工程师之路——高级字符设备驱动程序
K-Style
转载请注明来自于衡阳师范学院08电2 K-Style http://blog.csdn.net/ayangke,QQ:843308498 邮箱:[email protected]
高级字符设备驱动在简单字符驱动的基础上添加ioctl方法、阻塞非阻塞读写、poll方法、和自动创建设备文件的功能。
一、重要知识点
1.ioctl
ioctl命令:使用4个字段定义一个ioctl命令,包括
type: 幻数,一般使用一个字符定义,在内核中唯一。
number: 序数。
direction: 数据传输方向,当不涉及数据传输时,此字段无效。
size: 所涉及用户数据的大小,当不涉及数据传输时,此字段无效。
_IOC_NONE
_IOC_READ
_IOC_WRITE
“方向”字段的可能值。“读”和“写”是不同的位,可以用“OR”在一起指定读写。
_IOC(dir, type, size)
_IO(type,nr)
_IOR(type, nr, size)
_IOW(type, nr, size)
用于生产ioctl命令的宏
_IOC_DIR(cmd)
_IOC_TYPE(cmd)
_IOC_NR(cmd)
_IOC_SIZE(cmd)
用于解码ioctl命令的宏
intaccess_ok(int type, const void *addr, unsigned long size)
这个函数验证指向用户空间的指针是否可用,如果允许访问,access_ok返回非0值。
int put_user(datum, ptr)
int get_user(local, ptr)
int __put_user(datum, ptr)
int __get_user(local, ptr)
用于向(或从)用户空间保存(或获取)单个数据项的宏。传送的字节数目由sizeof(*ptr)决定。前两个要先调用access_ok,后两个(__put_user和__get_user)则假设access_ok已经被调用过了。
2.阻塞型I/O
typedef struct {/*…..*/} wait_queue_head_t
void init_waitqueue_head(wait_queue_head_t*queue)
DECLARE_WAIT_QUEUE_HEAD(queue)
预先定义的Linux内核等待队列类型。wait_queue_head_t类型必须显示地初始化,初始化方法可以在运行时调用init_waitqueue_head,或在编译时DECLARE_WAIT_QUEUE_HEAD。
void wait_event((wait_queue_head_t q, intcondition)
int wait_event_interruptible(wait_queue_head_tq, int condition)
int wait_event_timeout(wait_queue_head_t q,int condition, int time)
int wait_event_interruptible_timeout(wait_queue_head_tq, int condition, int time)
使进程在指定的队列上休眠,直到给定的condition值为真。
void wake_up(struct wait_queue **q)
void wake_up_interruptible(structwait_queue **q)
这些函数唤醒休眠在队列q上的进程。_interruptible形式的函数只能唤醒可中断的进程。在实践中约定做法是在使用wait_event时用wake_up,而在使用wait_event_interruptible时使用wake_up_interruptible。
3.poll方法
poll方法分两步处理,第一步调用poll_wait指定等待队列,第二步返回是否可操作的掩码。
POLLIN表示设备可读的掩码,POLLRDORM表示数据可读的掩码。POLLOUT表示设备可写的掩码,POLLWRNORM表示数据可读的掩码。一般同时返回POLLIN和POLLRDORM或者POLLOUT和POLLWRNORM。
4.select系统调用
原型为intselect(int mafdp1, fd_set *restrict readfds, fd_set *restrict writefds, fd_set*restrict exceptfds, struct timeval *restrict tvptr)
返回值:就绪的描述符数,若超时则返回0,若出错则返回-1
void FD_ISSET(int fd, fd_set *fdset)
void FD_CLR(int fd, fd_set *fdset)
void FD_SET(int fd, fd_set *fdset)
void FD_ZERO(fd_set *fdset)
调用FD_ZERO将一个指定的fd_set变量的所有位设置为0。调用FD_SET设置一个fd_set变量指定位。调用FD_CLR则将一指定位清除。最后,调用FD_ISSET测试一指定位是否设置。
5.自动创建设备文件
struct class *class_create(struct module*owner, const char *name)
struct device *device_create(struct class*class, struct device *parent, dev_t devt, const char *fmt, ...)
通过这两个函数可以专门用来创建一个字符设备文件节点,class_create 第一个参数指定所有者,第二参数指定类得名字。class_device_create第一个参数指定第一个参数指定所要创建的设备所从属的类,第二个参数是这个设备的父设备,如果没有就指定为NULL,第三个参数是设备号,第四个参数是设备名称。
二、驱动代码