下面就开始写子程序.
#include <linux/types.h> #include <linux/fs.h> #include <linux/mm.h> #include <linux/errno.h> #include <asm/segment.h>
unsigned int test_major = 0;
static int read_test(struct inode *node, struct file *file, char *buf, int count) { int left;
if (verify_area(VERIFY_WRITE, buf, count) == -EFAULT ) return -EFAULT;
for(left = count ; left > 0 ; left--) { __put_user(1, buf, 1); buf++; }
return count; }
|
这个函数是为read调用准备的.当调用read时,read_test()被调用,它把用户的缓冲区全部写1.buf 是read调用的一个参数.它是用户进程空间的一个地址.但是在read_test被调用时,系统进入核心态.所以不能使用buf这个地址,必须用__put_user(),这是kernel提供的一个函数,用于向用户传送数据.另外还有很多类似功能的函数.请参考.在向用户空间拷贝数据之前,必须验证buf是否可用。 这就用到函数verify_area.
static int write_tibet(struct inode *inode, struct file *file, const char *buf, int count) { return count; }
static int open_tibet(struct inode *inode, struct file *file ) { MOD_INC_USE_COUNT; return 0; }
static void release_tibet(struct inode *inode, struct file *file ) { MOD_DEC_USE_COUNT; }
|
这几个函数都是空操作.实际调用发生时什么也不做,他们仅仅为下面的结构提供函数指针。
struct file_operations test_fops = { NULL, read_test, write_test, NULL, /* test_readdir */ NULL, NULL, /* test_ioctl */ NULL, /* test_mmap */ open_test, release_test, NULL, /* test_fsync */ NULL, /* test_fasync */ /* nothing more, fill with NULLs */ }; |
设备驱动程序的主体可以说是写好了。现在要把驱动程序嵌入内核。驱动程序可以按照两种方式编译。一种是编译进kernel,另一种是编译成模块(modules),如果编译进内核的话,会增加内核的大小,还要改动内核的源文件,而且不能动态的卸载,不利于调试,所以推荐使用模块方式。
int init_module(void) { int result;
result = register_chrdev(0, "test", &test_fops);
if (result < 0) { printk(KERN_INFO "test: can't get major number\n"); return result; }
if (test_major == 0) test_major = result; /* dynamic */ return 0; }
|
|