设备驱动程序设计
Linux设备分为字符设备、块设备和网络设备。字符设备是不需要缓冲而直接
读写的设备,如串口、键盘、鼠标等,本例就是字符设备驱动程序;块设备的访问
通常需要缓冲来支持,以数据块为单位来读写,如磁盘设备等;网络设备是通过套
接字来访问的特殊设备。
1) 设备驱动程序和内核与应用程序的接口
无论哪种类型的设备,Linux都是通过在内核中维护特殊的设备控制块来与设
备驱动程序接口的。在字符设备和块设备的控制块中,有一个重要的数据结构
file_operations,该结构中包含了驱动程序提供给应用程序访问硬件设备的各种
方法,其定义如下(参见fs.h):
struct file_operations {
loff_t (*llseek) (struct file *, loff_t, int); //响应应用程序中lseek调
用的函数指针
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
//响应应用程序中read调用的函数指针
ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
//响应应用程序中write调用的函数指针
int (*readdir) (struct file *, void *, filldir_t); //响应应用程序中
readdir调用的函数指针
unsigned int (*poll) (struct file *, struct poll_table_struct *);
//响应应用程序中select调用的函数指针
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned
long);
//响应应用程序中ioctl调用的函数指针
int (*mmap) (struct file *, struct vm_area_struct *);
//响应应用程序中mmap调用的函数指针
int (*open) (struct inode *, struct file *); //响应应用程序中open调
用的函数指针
int (*flush) (struct file *);
int (*release) (struct inode *, struct file *); //响应应用程序中close
调用的函数指针
int (*fsync) (struct file *, struct dentry *);
int (*fasync) (int, struct file *, int);
int (*check_media_change) (kdev_t dev);
int (*revalidate) (kdev_t dev);
int (*lock) (struct file *, int, struct file_lock *);
};
多数情况下,只需为上面结构中的少数方法编写服务函数,其他均设为NULL即可。
每一个可装配的设备驱动程序都必须有init_module和cleanup_module两个函数,
装载和卸载设备时内核自动调用这两个函数。在init_module中,除了可以对硬件
设备进行检查和初始化外,还必须调用register_* 函数将设备登记到系统中。本
例中是通过register_chrdev来登记的,如果是块设备或网络设备则应该用
register_blkdev和register_netdev来登记。Register_chrdev 的主要功能是将设
备名和结构file_operations登记到系统的设备控制块中。
2) 与应用程序的数据交换
由于设备驱动程序工作在内核存储空间,不能简单地用"="、"memcpy"等方法与应
用程序交换数据。在头文件uaccess.h中定义了方法put_user(x, ptr)和
get_user(x, ptr),用于内核空间与用户空间的数据交换。值x的类型根据指针
ptr的类型确定,请参见源代码中的my_read与my_write函数。
3) 与硬件设备的接口
Linux中为设备驱动程序访问I/O端口、硬件中断和DMA提供了简便方法,相应的头
文件分别为io.h、irq.h、dma.h。由于篇辐限制,本例中只涉及到I/O端口访问。
Linux提供的I/O端口访问方法主要有:inb()、inw()、outb()、outw()、inb_p()
、inw_p()、outb_p()、outw_p()等。要注意的是,设备驱动程序在使用端口前,
应该先用check_region()检查该端口的占用情况,如果指定的端口可用,则再用
request_region()向系统登记。说明check_region()、request_region()的头文件
是ioport.h。
4) 内存分配
设备驱动程序作为内核的一部分,不能使用虚拟内存,必须利用内核提供的
kmalloc()与kfree()来申请和释放内核存储空间。Kmalloc()带两个参数,第一个
要申请的是内存数量,在早期的版本中,这个数量必须是2的整数幂,如128、256
。关于kmalloc()与kfree()的用法,可参考内核源程序中的malloc.h与slab.c程序。
useful link
阅读(1800) | 评论(0) | 转发(0) |