在系统内部,I/O设备等等存取通过一组固定的入口点来进行,这组入口点由每个
设备的设备驱动程序提供。在Linux系统里,设备驱动程序提供的入口点由一个结构来向系统进行说明,此结构体定义为:
Structfile_operations{
int (*lseek)(struct innode *innode, structfile *file,off_t off, int pos);
/*移动文件指针的位置*/
int (*read)(struct innode *innode, structfile *file, char *buf, int count);
/*读操作,buf为存放读取结果的缓冲区,count为要读取的数据长度*/
int (*write)(struct innode *innode, structfile *file, char *buf, int count);
/*写操作,与read类似*/
int (*readdir)(struct innode *innode, structfile *file, struct dirent *dirent, int count);
/*取得下一个目录入口点*/
int (*select)(struct innode *innode, structfile *file, int sel_type, select_table *wait);
/*检查设备,看数据是否可读或设备是否可用于写数据*/
int (*ioctl)(struct innode *innode, structfile *file, unsigned int cmd, unsigned int arg);
/*进行读写以外的其他特殊操作,参数cmd为自定义的命令*/
int (*mmap)(void)
/*把设备的内容映射到地址空间*/
int (*open)(struct innode *innode, structfile *file);
/*打开设备进行I/O操作*/
int (*release)(struct innode *innode, structfile *file);
/*关闭设备*/
}
操作步骤
①编写设备驱动程序zhangjiajie.c;
#include
#include
#include
#include
#include
#include
unsigned int zjj_major = 0;
/*buf涓哄瓨鏀捐鍙栫粨鏋滅殑缂撳啿鍖猴紝length涓鸿璇诲彇鏁版嵁鐨勯暱搴?/
static ssize_t zjj_read(struct file *file, char *buf, size_t length, loff_t *offset)
{
int n = 0;
n = min( strlen("zhangjiajie's driver!"), length );
if( copy_to_user(buf,"zhangjiajie's driver!", n) )
{
return -EFAULT;
}
return n;
}
static ssize_t zjj_write( struct file *file, const char *buf, size_t length,loff_t *offset)
{
return length;
}
static int zjj_open(struct inode *inode, struct file *file)
{
printk("open file succeed\n");
return 0;
}
static int zjj_release(struct inode *inode, struct file *file)
{
printk("close file succeed\n");
return 0;
}
static const struct file_operations zjj_fops = {
.open = zjj_open,
.read = zjj_read,
.write = zjj_write,
.release = zjj_release,
};
static int __init zjj_init(void)
{
zjj_major = register_chrdev(0,"ZJJ_DRIVER",&zjj_fops);
if( zjj_major < 0 )
{
printk("register dirver error\n");
return -1;
}
else{
printk("register driver %d succeed\n",zjj_major);
}
return 0;
}
static void __exit zjj_exit(void)
{
unregister_chrdev(zjj_major,"ZJJ_DRIVER");
printk("unistall driver succeed\n");
}
module_init(zjj_init);
module_exit(zjj_exit);
②在zhangjiajie.c同一目录下编写Makefile文件;
obj-m:=zhangjiajie.o
KERNELBUILD:=/lib/modules/3.2.13/build
default:
③ $make:编译Makefile文件,生成zhangjiajie.ko文件;
④ $insmod./zhangjiajie.ko:挂载驱动;
⑤ $cat/proc/devices:查看添加的设备的主驱动号,我的驱动号为250,如下图3所示;
⑥ $mknod/dev/zhangjiajie c 250 0:挂载设备驱动。
⑦编译测试程序,测试驱动。
#include
#include
#include
#include
int main(void)
{
int fd, n;
char string[32];
for(n = 0; n < 32; n++){
string[n] = ' ';
}
printf("Input string: ");
scanf("%s",string);
fd = open("/dev/ZJJ_DRIVER",O_RDWR);
write(fd,string,32);
read(fd,string,32);
printf("from ZJJ_DRIVER: %s\n",string);
return 1;
}
(一)intregister_chrdev(unsigned int major, const char *name, struct
file_operations*fops);
major为设备驱动程序向系统申请的主设备号,如果为0则系统为此驱动程序动态分配一个主设备号。Name是设备名。Fops为对各个调用的入口点的说明。
返回0便是返回成功,返回-EINVAL表示申请的主设备号非法,返回-EBUSY表示说申请的主设备号正被其他设备驱动程序使用。如果动态分配主设备号成功,会返回说分配的主设备号。
如果register_chrdev成功,设备名就会出现在/proc/devices文件里。
(二) obj-m:=zhangjiajie.o
Makefile中的该语句表示最终生成模块文件,生成的模块文件名为zhangjiajie.o。
(三) Make –Cxxx M=$(shell pwd) modules
表示首先改变目录到-C指定的位置,M=选项是makefile在构造modukes目标前,返
回到模块源码目录。然后modules目标指向obj-m变量中设定的模块。
操作过程中要注意到的
① .c驱动程序文件和 .o文件名要一致;
② Makefile文件名的M要大写;
③ make时需要切换到root权限。