mknod命令创建节点(手动创建)
#1. 节点创建命令的格式
mknod NAME TYPE MAJOR MINOR
#NAME:节点文件的名称
#TYPE:节点文件的类型
# c 字符设备文件
# b 块设备文件
#MAJOR 主设备号
#MINOR 次设备号
#2. 实例:创建一个字符设备文件节点:名称为(/dev/mychar0),主设备号为243,次设备为0
mknod /dev/mychar0 c 243 0
代码实现节点的创建(自动创建)
/**
* [device_create 创建设备节点文件,并注册到系统中(根文件系统)]
* @param class [指向的该设备对应的结构体指针]
* @param parent [默认可以使用NULL表示]
* @param devt [是创建设备节点对应的设备号(包含主设备号和次设备号)]
* @param drvdata [给传递数据参数;默认使用NULL表示]
* @param fmt [可变参数,表示设备节点的名称]
* @return [成功返回设备节点的指针;识别返回使用ERR_PTR()能够查看的错误信息]
*/
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...);
/*
参数:
class 指针对象的创建
owner:使用THIS_MODULE
name:对象名称
返回值:
成功返回struct class 结构体指针对象(设备节点对象);失败返回NULL
*/
#define class_create(owner, name)
错误处理函数
static inline void * __must_check ERR_PTR(long error) /* 将long类型数据转换为指针数据 */
{
return (void *) error;
}
static inline long __must_check PTR_ERR(const void *ptr) /* 将指针数据转换为long类型数据 */
{
return (long) ptr;
}
static inline long __must_check IS_ERR(const void *ptr) /* 判断错误是否指向 */
{
return IS_ERR_VALUE((unsigned long)ptr);
}
释放
/*
设备节点的释放
参数:
cls表示节点对象指针;
dev_t:设备节点号
*/
extern void device_destroy(struct class *cls, dev_t devt);
/*
设备节点对象的释放
cls指针指向的对象就是需要释放的对象
*/
extern void class_destroy(struct class *cls);
实例
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
static dev_t dev_num;/* dev_num存储申请成功的设备号 */
static unsigned int count = 4;/* 次设备的数量 */
static struct cdev *cdev_p;/* 字符设备注册结构体指针 */
static struct class *class_p;
static struct device *device_p;
int my_char_driver_open(struct inode *inode_p, struct file *file_p)
{
printk(KERN_INFO "my char driver open success\n");
return 0;
}
int my_char_driver_release(struct inode *inode_p, struct file *file_p)
{
printk(KERN_INFO "my char driver release success\n");
return 0;
}
const struct file_operations fops =
{
.owner = THIS_MODULE,
.open = my_char_driver_open,
.release = my_char_driver_release
};
/* 定义模块加载入口函数 */
static int __init my_char_driver_init(void)
{
int ret = 0;
/* 1. 申请设备号:手动申请(给定主设备号和起始次设备号)/动态申请(返回设备号) */
ret = alloc_chrdev_region(&dev_num, 0, count, "chrdev");/* 动态申请设备号 */
if (ret != 0)
{
goto err0;
}
/* 2. 注册设备到系统中,有系统统一调度管理 */
/* 2.1 申请字符设备注册结构体空间*/
cdev_p = cdev_alloc();
if (cdev_p == NULL)
{
ret = - ENOMEM;
goto err1;
}
/* 2.2 初始化字符数设备结构体空间中的操作方法集 */
cdev_init(cdev_p, &fops);
/* 2.3 添加字符设备结构体到系统中,由系统统一调度管理 */
ret = cdev_add(cdev_p, dev_num, count);
if (ret != 0)
{
goto err2;
}
/* 3. 创建设备节点(可选:一般都会加上) */
/* 3.1 创建节点对象 */
class_p = class_create(THIS_MODULE, "mychar");
if (IS_ERR(class_p))
{
ret = - ENOMEM;
goto err3;
}
int i;
for (i = 0; i < count; i++) /* 由于驱动可以管理多个设备文件,需要循环创建设备文件 */
{
char drv_name[20] = {0};
sprintf(drv_name, "mychar%d", i);
/* 3.2 创建设备节点 */
device_p = device_create(class_p, NULL, MKDEV(MAJOR(dev_num), i), NULL, drv_name);
if (IS_ERR(device_p))
{
ret = - ENOMEM;
goto err4;
}
}
printk(KERN_INFO "my char driver : <major: %d, minor: %d> init success\n", MAJOR(dev_num), MINOR(dev_num));
return 0;
err4:
/* 释放创建成功的设备节点 */
for (i--; i >= 0; i--)
device_destroy(class_p, MKDEV(MAJOR(dev_num), i));
/* 释放设备节点对象 */
class_destroy(class_p);
err3:
err2:
/* 释放字符设备结构体空间 */
cdev_del(cdev_p);
err1:
/* 释放设备号 */
unregister_chrdev_region(dev_num, count);
err0:
return ret;
}
/* 定义模块卸载入口函数 */
static void __exit my_char_driver_exit(void)
{
/* 释放设备节点 */
int i;
for (i = 0; i < count; i++)
device_destroy(class_p, MKDEV(MAJOR(dev_num), i));
/* 释放设备节点对象 */
class_destroy(class_p);
/* 释放字符设备结构体空间 */
cdev_del(cdev_p);
/* 释放设备号 */
unregister_chrdev_region(dev_num, count);
printk(KERN_INFO "my char driver exit success\n");
}
module_init(my_char_driver_init);/* 声明模块加载入口函数 */
module_exit(my_char_driver_exit);/* 声明模块卸载入口函数 */
MODULE_LICENSE("GPL");
网友评论