关注微信公众号:Linux 内核拾遗
文章来源:https://mp.weixin.qq.com/s/4Bl0j2dJx4rEx1MrSWMoYA
1 设备文件
设备文件不是普通的文件,它提供了一种便利的方式来访问系统资源,而不需要应用开发者了解底层设备的工作原理。与大多数 Unix 系统一样,设备驱动程序本身就是 Linux 内核的一部分。
从应用程序角度来看,它表现得跟文件一样,允许程序从中读取数据、写入数据以及进行内存映射等。
从内核角度看,当设备文件被访问的时候,内核需要识别访问的 I/O 请求并将其传递给设备驱动程序,由设备驱动执行某些操作以完成请求的处理。
所有的设备文件都保存在/dev/目录下。
设备文件通常在系统初始化的时候创建,设备文件关联的设备可以是真实的硬件设备,例如/dev/ttyS0、/dev/hda1 等;也可以是伪设备,例如/dev/null,所有往/dev/null 的写请求都会被丢弃。
2 创建设备文件
有两种创建设备文件的方式:手动创建和自动创建。
2.1 手动创建设备文件
mknod 命令可以手动创建一个设备文件:
mknod -m <permissions> <name> <device type> <major> <minor>
复制代码
说明:
name:设备文件名,即/dev/<name>;
device type:设备类型,c - 字符设备,b - 块设备;
<major>:<minor>:设备驱动程序的主/次设备号;
-m <permissions>:设备文件权限,跟普通文件类似。
这种方式允许任何人创建设备文件,并且可以在设备驱动加载之后再创建。
2.1.1 完整示例
manually_device_file.c
#include<linux/kernel.h>#include<linux/init.h>#include<linux/module.h>#include <linux/kdev_t.h>#include <linux/fs.h> dev_t dev = 0;
static int __init my_init(void){ if((alloc_chrdev_region(&dev, 0, 1, "manually_dev")) <0){ pr_err("Cannot allocate major number for device\n"); return -1; } pr_info("Kernel Module Inserted\n"); return 0;}static void __exit my_exit(void){ unregister_chrdev_region(dev, 1); pr_info("Kernel Module Removed\n");}
module_init(my_init);module_exit(my_exit); MODULE_LICENSE("GPL");MODULE_AUTHOR("feifei <feifei@gmail.com>");MODULE_DESCRIPTION("Simple linux device driver");MODULE_VERSION("1.1");
复制代码
编译后往内核插入模块,通过 mknod 手动创建设备文件:
2.2 自动创建设备文件
udev 是 Linux 内核中的设备管理器,它能够在/dev 目录下自动创建或者移除设备节点,自动创建的设备文件都会被 udev 管理起来。
基本的使用步骤如下:
引用头文件"linux/device.h"和"linux/kdev_t/h";
创建 struc class;
使用前面 sruct class 创建设备。
2.2.1 创建 struct class
可以通过 class_create 为设备驱动创建对应的 struct class,对应到/sys/class 下面的一个结构,后续可以使用 class_destroy 来销毁 struc class:
struct class * class_create(struct module *owner, const char *name);void class_destroy (struct class * cls);
复制代码
2.2.2 创建设备
可以通过 device_create 创建字符设备,并注册到指定的 struct class,相应地会在/sys/device 下面创建对应的结构。
struct device *device_create(struct *class, struct device *parent, dev_t dev, void * drvdata, const char *fmt, ...);void device_destroy (struct class * class, dev_t devt);
复制代码
说明:
2.2.3 完整示例
dynamically_device_file.c
#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/kdev_t.h>#include <linux/fs.h>#include <linux/err.h>#include <linux/device.h> dev_t dev = 0;static struct class *dev_class;
static int __init my_init(void){ if((alloc_chrdev_region(&dev, 0, 1, "my_dev")) <0){ pr_err("Cannot allocate major number for device\n"); return -1; } pr_info("Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
dev_class = class_create(THIS_MODULE,"my_class"); if(IS_ERR(dev_class)){ pr_err("Cannot create the struct class for device\n"); goto r_class; }
if(IS_ERR(device_create(dev_class,NULL,dev,NULL,"my_device"))){ pr_err("Cannot create the Device\n"); goto r_device; } pr_info("Kernel Module Inserted\n"); return 0;
r_device: class_destroy(dev_class); r_class: unregister_chrdev_region(dev,1); return -1;}
static void __exit my_exit(void){ device_destroy(dev_class,dev); class_destroy(dev_class); unregister_chrdev_region(dev, 1); pr_info("Kernel Module Removed\n");} module_init(my_init);module_exit(my_exit); MODULE_LICENSE("GPL");MODULE_AUTHOR("feifei <feifei@gmail.com>");MODULE_DESCRIPTION("Simple linux device driver");MODULE_VERSION("1.2");
复制代码
编译完成后插入内核模块,可以看到/dev 相面自动创建了对应的设备文件:
关注微信公众号:Linux 内核拾遗
文章来源:https://mp.weixin.qq.com/s/4Bl0j2dJx4rEx1MrSWMoYA
评论