Linux系统驱动(四)自动创建设备节点

自动创建设备节点

(一)创建设备节点的机制

1. mknod

将驱动编译到内核中,在内核启动时驱动自动被安装执行

2.devfs(2.4内核)

3. udev(2.6内核至今)

  • 注:hotplug --- 热插拔

(二)API

1. 向上提交目录

c 复制代码
#include <linux/device.h>
struct class * class_create(owner, name)
功能:向上提交目录
参数:
 @owner:THIS_MODULE 这个宏和模块安装卸载相关,并且会记录模块的引用计数值。
 @name:目录名
返回值:成功返回结构体指针,失败返回错误码指针
  • 补:
  • 通过IS_ERR(cls)来判断是否失败。该宏定义在在cls是错误码指针时返回真,否则为假
  • 当cls是错误码指针时,可以通过PTR_ERR(cls)来获得失败返回的错误码

2. 销毁目录

c 复制代码
#include <linux/device.h>
void class_destroy(struct class *cls)
功能:销毁向上提交目录后产生的结构体
参数:
	@cls:结构体指针
返回值:无

3. 向上提交创建节点的信息

c 复制代码
struct device *device_create(struct class *class, struct device *parent,
        dev_t devt, void *drvdata, const char *fmt,...)
功能:向上提交创建节点的信息
参数:
 @class:指向目录的句柄
 @parent:填写为NULL
 @devt:设备号 (241,0)=>(241<<20|0)
        MKDEV(major,minor) //将主和次设备号合成设备号
  		MAJOR(devno);  //从设备号中获取主设备号
  		MINOR(devno);  //从设备号中获取次设备号
 @drvdata:驱动的私有数据,一般填写为NULL。
 @fmt,...:创建节点的名字  "myled%d",i
返回值:成功返回结构体指针,失败返回错误码指针
  • 注:
  • MKDEV(ma,mi) 将主次设备号拼接成设备号
  • MAJOR(devno) 从设备号中获取主设备号
  • MINOR(devno) 从设备号中获取次设备号

4. 销毁节点的信息

c 复制代码
void device_destroy(struct class *class, dev_t devt)
功能:销毁节点的信息
参数:
 @class:指向目录的句柄
 @devt:设备号 (241,0)=>(241<<20|0)
返回值:无

5. IS_ERR(cls)的实现机制

(三)使用示例

功能需求 :在上一篇驱动的基础上加入自动创建设备节点,而无需使用mknod来手动创建
需求分析

设备文件是需要在应用层的open函数就需要使用,因此在驱动中自动创建节点就必须要在mydev_open函数之前实现,因此在mydev_init函数中进行自动创建设备节点,在mydev_exit函数中进行销毁创建的设备节点
代码实现 (此处只展示有修改的代码部分):
LED.c

c 复制代码
static int __init myioctl_init(void){
    //入口注册设备
    major=register_chrdev(0,CHRNAME,&myfops); //第一个参数为0,表示由系统分配主设备号,此时返回值就是系统分配的主设备号
    if(major < 0){//说明出错,返回了错误码,错误码均为负数
        pr_err("register_chrdev error:%d\n",major);
        return major; //失败返回错误码
    }
    printk("major=%d\n",major);
    //向上提交目录
    mycls = class_create(THIS_MODULE,"class_name");
    if(IS_ERR(mycls)){//成功返回结构体指针,失败返回错误码指针
        //为真则说明是错误码指针
        pr_err("class create error:%ld\n",PTR_ERR(mycls));
        return PTR_ERR(mycls); //出错返回错误码
    }
    //向上提交节点信息
    mydev = device_create(mycls,NULL,MKDEV(major,0),NULL,"myioctl");
    if(IS_ERR(mydev)){//成功返回结构体指针,失败返回错误码指针
        //为真则说明是错误码指针
        pr_err("class create error:%ld\n",PTR_ERR(mydev));
        return PTR_ERR(mydev); //出错返回错误码
    }
    return 0; //成功返回0
}

static void __exit myioctl_exit(void){
    //销毁节点信息
    device_destroy(mycls,MKDEV(major,0));
    //销毁目录信息
    class_destroy(mycls);
    //出口销毁设备
    unregister_chrdev(major,CHRNAME);
}
相关推荐
mCell33 分钟前
从删库到跑路?这50个Linux命令能保你职业生涯
linux·windows·macos
杰克逊的日记36 分钟前
GPU运维常见问题处理
linux·运维·gpu
誰能久伴不乏2 小时前
Linux系统调用概述与实现:深入浅出的解析
linux·运维·服务器
程序员学习随笔2 小时前
Linux进程深度解析(2):fork/exec写时拷贝性能优化与exit资源回收机制(进程创建和销毁)
linux·运维·服务器
mmoyula2 小时前
【RK3568 PWM 子系统(SG90)驱动开发详解】
android·linux·驱动开发
-SGlow-2 小时前
MySQL相关概念和易错知识点(2)(表结构的操作、数据类型、约束)
linux·运维·服务器·数据库·mysql
代码改变世界ctw3 小时前
Linux内核设计与实现 - 第14章 块I/O层
linux·运维·服务器
van叶~5 小时前
Linux网络-------1.socket编程基础---(TCP-socket)
linux·网络·tcp/ip
风吹落叶花飘荡5 小时前
Ubuntu系统 系统盘和数据盘扩容具体操作
linux·运维·ubuntu
zoulingzhi_yjs6 小时前
haproxy配置详解
linux·云原生