lbx-cnblogs

1、以模块的方式生成设备节点,不需要烧写镜像

2、生成的设备节点在ls /dev/下,可以供上层应用程序打开使用。相当于提供一个访问内核模块的一个接口。对于常见的open函数,操作一个节点设备 /dev/led0,可以按照下面这样,通过这样的方式就可以调用到模块中定义的file ops接口。

open("/dev/led0", O_RDWR);  // 有点类似window下的文件路径,但是led0是一个内核模块设备

 0、查看设备号:

  设备分主设备号和次设备号,主设备号用于区分一大类设备,此设备号区分大类设备号下的不同设备。

  cat  /proc/device   查看主设备号;

  cat  /proc/misc   查看杂项设备的此设备号;

1、杂项设备:可以节省主设备节点(主设备节点有限255),驱动编写也相对简单,并且是必须要编译的;

2、头文件:include/linux/miscdevice.h

3、涉及到的结构体:struct miscdevice 注册的是杂项设备

struct miscdevice  {
        int minor;   // 设备号,一般随机取值,系统分配
        const char *name;  // 生成设备节点的名称,随便取
        const struct file_operations *fops;  // 设备结点文件
        struct list_head list;
        struct device *parent;
        struct device *this_device;
        const char *nodename;
        mode_t mode;
};

4、注册函数、卸载函数;杂项设备注册与卸载

extern int misc_register(struct miscdevice * misc);
extern int misc_deregister(struct miscdevice *misc);

5、上面需要注册结构体中所包含的结构体 const struct file_operations *fops; // 设备结点文件,操作该结构体中的函数,进而读写相应的设备

  对外界提供访问该设备的接口;需要自己实现函数功能;

  上层应用对接该结构体的函数接口;

  在头文件include/linux/miscdevice.h

const struct file_operations    *i_fop;
    struct file_operations {
        struct module *owner;              // 模块属于者
        loff_t (*llseek) (struct file *, loff_t, int);   //  定位函数
        ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);  // 读操作
        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);   // 写操作
        ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
        ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
        int (*readdir) (struct file *, void *, filldir_t);
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
...  // 包含非常多,只列举常用的

6、常用的结构体变量:

.owner = THIS_MODULE   // 使用宏定义
.open  
.release   
.unlocked_ioctl() 对GPIO的操作  应用向节点串参数

7、实验代码devicenode_linux_module.c,生成设备结点 hello_ctl123

  1 // 驱动注册所需头文件 包含结构体,注册和卸载所需的函数
  2 #include <linux/platform_device.h>
  3 #include <linux/module.h>
  4 #include <linux/init.h>
  5 #include <linux/miscdevice.h>  // 注册杂项设备头文件
  6 #include <linux/fs.h>    // 设备结点文件
  7 
  8 #define DRIVER_NAME "hello_ctl"
  9 #define DEVICE_NAME "hello_ctl123"
 10 
 11 
 12 MODULE_LICENSE("Dual BSD/GPL"); 
 13 MODULE_AUTHOR("TOPEET");
 14 
 15 static int hello_open(struct inode *node, struct file *f)
 16 {
 17     printk(KERN_EMERG "\t func hello open\n");
 18     return 0;
 19 }
 20 
 21 static int hello_release(struct inode *node, struct file *f)
 22 {
 23     printk(KERN_EMERG "\t hello release\n");
 24     return 0;
 25 }
 26 
 27 static long hello_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
 28 {
 29     printk(KERN_EMERG "\t hello ioctl\n");
 30     printk("hello_ioctl cmd is %d ...arg is %d\n",cmd,arg);
 31     return 0;
 32 }
 33 
 34 // 文件操作,对应生成的设备结点具体如何操作
 35 static struct file_operations hello_ops = {
 36     .owner = THIS_MODULE,
 37     .open = hello_open,
 38     //   int (*open) (struct inode *, struct file *);
 39     .release = hello_release,
 40     // int (*release) (struct inode *, struct file *);
 41     .unlocked_ioctl = hello_ioctl,
 42     //  long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);long);
 43 
 44 };
 45 
 46 static struct miscdevice  hello_dev = {
 47     .minor = MISC_DYNAMIC_MINOR,  // 自动分配ID
 48     .name = DEVICE_NAME,  // 设备结点名称
 49     .fops = &hello_ops,   // 结构体
 50 };
 51 
 52 // int (*probe)(struct platform_device *);
 53 // 初始化相关动作
 54 static int hello_probe(struct platform_device *p)
 55 {
 56     printk(KERN_EMERG "\t initialized\n");
 57     misc_register(&hello_dev);  //2、 杂项设备注册
 58     return 0;
 59 }
 60 //  int (*remove)(struct platform_device *);
 61 static int hello_remove(struct platform_device *p)
 62 {
 63     printk(KERN_EMERG "\t hello_ct123 removed\n");
 64     misc_deregister(&hello_dev);
 65     return 0;
 66 }
 67 // int (*suspend)(struct platform_device *, pm_message_t state);
 68 static int hello_suspend(struct platform_device *p, pm_message_t state)
 69 {
 70     return 0;    
 71 }
 72 //  int (*resume)(struct platform_device *);
 73 static int hello_resume(struct platform_device *p)
 74 {
 75     return 0;    
 76 }
 77 //  void (*shutdown)(struct platform_device *);
 78 static void hello_shutdown(struct platform_device *p)
 79 {
 80         
 81 }
 82 
 83 // 3、结构体数据初始化
 84 // 注册驱动传入的结构体
 85 struct platform_driver hello_driver = {
 86     .probe = hello_probe,    // 用于初始化模块
 87     .remove = hello_remove,  // 移除模块时,执行的动作
 88     .suspend = hello_suspend,// 模块挂起时,执行的动作
 89     .resume = hello_resume,  // 挂起的模块,恢复运行执行动作
 90     .shutdown = hello_shutdown,
 91     .driver = {
 92         .name = DRIVER_NAME, // 驱动名称
 93         .owner = THIS_MODULE,// 驱动所有者,THIS_MODULE宏定义
 94     },
 95 }; 
 96 // 2、模块初始化相关实现         
 97 // 模块的入口函数 加载模块执行动作     
 98 static int hello_init(void)
 99 {
100     int DriverState;
101     printk(KERN_EMERG "HELLO WORLD enter!\n");
     // 平台驱动注册
102 DriverState = platform_driver_register(&hello_driver); // 注册驱动 转而执行初始化动作 103 printk(KERN_EMERG "\tDriverState is %d\n", DriverState); // 注册驱动执行状态 104 105 return 0; 106 } 107 // 模块退出函数 卸载模块所执行 108 static void hello_exit(void) 109 { 110 printk(KERN_EMERG "HELLO WORLD exit!\n"); 111 platform_driver_unregister(&hello_driver); // 卸载驱动函数 112 } 113 114 //1、 入口函数module_nint 115 module_init(hello_init); 116 module_exit(hello_exit);

上面调用流程

8、测试结果,使用ls dev//  查看生成的设备结点

[root@iTOP-4412]# ./mnt/disk/app_hello.o                                                           
[  234.644663]   func hello open
[  234.646263]   hello ioctl
[  234.648756] hello_ioctl cmd is 1 ...arg is 6
[  234.653025]   hello release
App open /dev/hello_ctl123 success   // 执行顺兴,貌似内核优先级比较高

9、需要注意,设备、驱动注册都是嵌入到内中的,生成设备结点则是面向应用;

10、编写简单的应用,调用设备结点App_hello_ctl123

 1 #include <stdio.h>
 2 #include <sys/types.h> 
 3 #include <sys/stat.h> 
 4 #include <fcntl.h>  
 5 #include <unistd.h>  
 6 #include <sys/ioctl.h>
 7 
 8 int main(void)
 9 {
10     int fd;
11     char* hello_node = "/dev/hello_ctl123";
12     fd = open(hello_node,O_RDWR|O_NDELAY); // 非阻塞打开
13     if(fd < 0){
14         printf("func open app %s failed\n",hello_node);
15         return -1;
16     }else{
17         printf("App open %s success\n",hello_node);
18         ioctl(fd,1,6);  // 应用程序向驱动传值
19     }
20     close(fd);
21     return 0;
22 }

11、设备结点、驱动注册、设备注册

  设备结点面向上层应用程序;驱动注册和设备注册需要嵌入到linux内核中;

12、简化上面的生成设备结点代码,devicenode_Samp.c

 1 #include <linux/platform_device.h>
 2 #include <linux/module.h>
 3 #include <linux/init.h>
 4 #include <linux/miscdevice.h>  // 注册杂项设备头文件
 5 #include <linux/fs.h>    // 设备结点文件
 6 
 7 #define DEVICE_NAME "hello_ctl123"
 8 
 9 
10 MODULE_LICENSE("Dual BSD/GPL"); 
11 MODULE_AUTHOR("TOPEET");
12 
13 static int hello_open(struct inode *node, struct file *f)
14 {
15     printk(KERN_EMERG "\t func hello open\n");
16     return 0;
17 }
18 
19 static int hello_release(struct inode *node, struct file *f)
20 {
21     printk(KERN_EMERG "\t hello release\n");
22     return 0;
23 }
24 
25 static long hello_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
26 {
27     printk(KERN_EMERG "\t hello ioctl\n");
28     printk("hello_ioctl cmd is %d ...arg is %d\n",cmd,arg);
29     return 0;
30 }
31 
32 // 文件操作,对应生成的设备结点具体如何操作
33 static struct file_operations hello_ops = {
34     .owner = THIS_MODULE,
35     .open = hello_open,
36     //   int (*open) (struct inode *, struct file *);
37     .release = hello_release,
38     // int (*release) (struct inode *, struct file *);
39     .unlocked_ioctl = hello_ioctl,
40     //  long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);long);
41 
42 };
43 
44 static struct miscdevice  hello_dev = {
45     .minor = MISC_DYNAMIC_MINOR,  // 自动分配ID
46     .name = DEVICE_NAME,  // 设备结点名称
47     .fops = &hello_ops,   // 结构体
48 };
49 
50 // 2、模块初始化相关实现         
51 // 模块的入口函数 加载模块执行动作     
52 static int hello_init(void)
53 {
54     int DriverState;
55     printk(KERN_EMERG "HELLO WORLD enter!\n");
56     DriverState = misc_register(&hello_dev);
57     printk(KERN_EMERG "\tDriverState is %d\n", DriverState); // 注册驱动执行状态
58     
59     return 0;
60 }
61 // 模块退出函数  卸载模块所执行
62 static void hello_exit(void)
63 {
64     printk(KERN_EMERG "HELLO WORLD exit!\n");
65     misc_deregister(&hello_dev);
66 }
67 
68 //1、 入口函数module_nint
69 module_init(hello_init);
70 module_exit(hello_exit);

 

平台驱动注册

分类:

技术点:

相关文章: