关注微信公众号: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
评论