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驱动与之匹配的为测试程序。

posted @ 2022-03-22 18:29  咸阳梁硕  阅读(80)  评论(0)    收藏  举报