Hello驱动(不涉及硬件操作)
APP打开的文件在内核中如何表示
APP打开文件时,可以得到一个整数,这个整数被称为文件句柄。对于APP的每一个文件句柄,在内核里面都有一个“struct file”与之对应。

可以猜测,我们使用open打开文件时,传入的flags、mode等参数会被记录在内核中对应的struct file结构体里(f_flags、f_mode):
int open(const char *pathname, int flags, mode_t mode);
去读写文件时,文件的当前偏移地址也会保存在struct file结构体的f_pos成员里。

打开字符设备节点时,内核中也有对应的struct file
注意这个结构体中的结构体:struct file_operations *f_op,这是由驱动程序提供的。


结构体struct file_operations的定义如下:

编写驱动程序的步骤:
① 确定主设备号,也可以让内核分配
② 定义自己的file_operations结构体
③ 实现对应的drv_open/drv_read/drv_write等函数,填入file_operations结构体
④ 把file_operations结构体告诉内核:register_chrdev
⑤ 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数
⑥ 有入口函数就应该有出口函数:卸载驱动程序时,出口函数调用unregister_chrdev
⑦ 其他完善:提供设备信息,自动创建设备节点:class_create, device_create
1 #include <linux/module.h> 2 3 #include <linux/fs.h> 4 #include <linux/errno.h> 5 #include <linux/miscdevice.h> 6 #include <linux/kernel.h> 7 #include <linux/major.h> 8 #include <linux/mutex.h> 9 #include <linux/proc_fs.h> 10 #include <linux/seq_file.h> 11 #include <linux/stat.h> 12 #include <linux/init.h> 13 #include <linux/device.h> 14 #include <linux/tty.h> 15 #include <linux/kmod.h> 16 #include <linux/gfp.h> 17 18 /* 1. 确定主设备号 */ 19 static int major = 0; 20 static char kernel_buf[1024]; 21 static struct class *hello_class; 22 23 24 #define MIN(a, b) (a < b ? a : b) 25 26 /* 2. 定义自己的file_operations结构体 */ 27 static struct file_operations hello_drv = { 28 .owner = THIS_MODULE, 29 .open = hello_drv_open, 30 .read = hello_drv_read, 31 .write = hello_drv_write, 32 .release = hello_drv_close, 33 }; 34 35 /* 3. 实现对应的open/read/write等函数,填入file_operations结构体 */ 36 static int hello_drv_open (struct inode *node, struct file *file) 37 { 38 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 39 return 0; 40 } 41 static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) 42 { 43 int err; 44 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 45 err = copy_to_user(buf, kernel_buf, MIN(1024, size)); 46 return MIN(1024, size); 47 } 48 49 static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset) 50 { 51 int err; 52 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 53 err = copy_from_user(kernel_buf, buf, MIN(1024, size)); 54 return MIN(1024, size); 55 } 56 57 58 59 static int hello_drv_close (struct inode *node, struct file *file) 60 { 61 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 62 return 0; 63 } 64 65 /* 4. 把file_operations结构体告诉内核:注册驱动程序 */ 66 /* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */ 67 static int __init hello_init(void) 68 { 69 int err; 70 71 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 72 major = register_chrdev(0, "hello", &hello_drv); /* /dev/hello */ 73 74 75 hello_class = class_create(THIS_MODULE, "hello_class"); 76 err = PTR_ERR(hello_class); 77 if (IS_ERR(hello_class)) { 78 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 79 unregister_chrdev(major, "hello"); 80 return -1; 81 } 82 83 device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */ 84 85 return 0; 86 } 87 88 /* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数 */ 89 static void __exit hello_exit(void) 90 { 91 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 92 device_destroy(hello_class, MKDEV(major, 0)); 93 class_destroy(hello_class); 94 unregister_chrdev(major, "hello"); 95 } 96 97 98 /* 7. 其他完善:提供设备信息,自动创建设备节点 */ 99 100 module_init(hello_init); 101 module_exit(hello_exit); 102 103 MODULE_LICENSE("GPL");
以上是Hello程序的代码。
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <unistd.h> 5 #include <stdio.h> 6 #include <string.h> 7 8 /* 9 * ./hello_drv_test -w abc 10 * ./hello_drv_test -r 11 */ 12 int main(int argc, char **argv) 13 { 14 int fd; 15 char buf[1024]; 16 int len; 17 18 /* 1. 判断参数 */ 19 if (argc < 2) 20 { 21 printf("Usage: %s -w <string>\n", argv[0]); 22 printf(" %s -r\n", argv[0]); 23 return -1; 24 } 25 26 /* 2. 打开文件 */ 27 fd = open("/dev/hello", O_RDWR); 28 if (fd == -1) 29 { 30 printf("can not open file /dev/hello\n"); 31 return -1; 32 } 33 34 /* 3. 写文件或读文件 */ 35 if ((0 == strcmp(argv[1], "-w")) && (argc == 3)) 36 { 37 len = strlen(argv[2]) + 1; 38 len = len < 1024 ? len : 1024; 39 write(fd, argv[2], len); 40 } 41 else 42 { 43 len = read(fd, buf, 1024); 44 buf[1023] = '\0'; 45 printf("APP read : %s\n", buf); 46 } 47 48 close(fd); 49 50 return 0; 51 }
为了更好的测试hello驱动与之匹配的为测试程序。

浙公网安备 33010602011771号