一、 注册字符类设备

• 分配内存空间函数kmalloc
        – 分配连续的虚拟地址,用于小内存分配。在include/linux/slab.h文件中。
        – 参数1:申请的内存大小(最大128K),
        – 参数2:GFP_KERNEL,代表优先权,内存不够可以延迟分配
• 清空内存空间的数据函数memset
        – 可以清空内存空间,也就是全部写为0
        – 参数1:内存地址
        – 参数2:0
        – 参数3:内存长度

• 字符设备初始化函数cdev_init
        – 在头文件include/linux/cdev.h中
        – 参数1:cdev字符设备文件结构体
        – 参数2:file_operations结构体
        – 注册设备本质是向linux设备文件中添加数据,这些数据需要初始化
• 字符设备注册函数cdev_add
        – 在头文件include/linux/cdev.h中
        – 参数1:cdev字符设备文件结构体
        – 参数2:设备号
        – 参数3:设备范围大小
        – 向系统注册设备,也就是向linux系统添加数据

• 卸载设备函数cdev_del
        – 参数1:cdev结构体
        – 移除字符设备

二、生成字符类设备节点

• 函数class_create创建class类文件
        – 参数1:一般是THIS_MODULE
        – 参数2:设备名称
        – 创建一个设备类,用于设备节点文件的创建
        – 返回一个class结构体变量
• class结构体变量
        – class是设备驱动模型中通用的设备类结构
        – 在头文件include/linux/device.h的280行

• 创建设备节点函数device_create
        – 头文件include/linux/device.h中
        – 参数1:设备所属于的类
        – 参数2:设备的父设备,NULL
        – 参数3:设备号
        – 参数4:设备数据,NULL
        – 参数4:设备名称
• 摧毁设备节点函数device_destroy
        – 参数1:设备所属于的类
        – 参数2:设备号

• 老版本:创建设备class函数class_device_create(已作废)
        – 头文件include/linux/device.h中
        – 参数1:class结构体变量
        – 参数2:父设备NULL
        – 参数3:dev_t设备号
        – 参数4:数据NULL
        – 参数5:设备节点名称
• 释放设备class函数class_destroy(已作废)
        – 参数1:myclass

三、代码

/*包含初始化宏定义的头文件,代码中的module_init和module_exit在此文件中*/
#include <linux/init.h>
/*包含初始化加载模块的头文件,代码中的MODULE_LICENSE在此头文件中*/
#include <linux/module.h>
/*定义module_param module_param_array的头文件*/
#include <linux/moduleparam.h>
/*定义module_param module_param_array中perm的头文件*/
#include <linux/stat.h>
/*三个字符设备函数*/
#include <linux/fs.h>
/*MKDEV转换设备号数据类型的宏定义*/
#include <linux/kdev_t.h>
/*定义字符设备的结构体*/
#include <linux/cdev.h>
/*分配内存空间函数头文件*/
#include <linux/slab.h>/*包含函数device_create 结构体class等头文件*/
#include <linux/device.h>#define DEVICE_NAME "chardevnode"
#define DEVICE_MINOR_NUM 2
#define DEV_MAJOR 0
#define DEV_MINOR 0
#define REGDEV_SIZE 3000MODULE_LICENSE("Dual BSD/GPL");
/*声明是开源的,没有内核版本限制*/
MODULE_AUTHOR("iTOPEET_dz");
/*声明作者*/int numdev_major = DEV_MAJOR;
int numdev_minor = DEV_MINOR;/*输入主设备号*/
module_param(numdev_major,int,S_IRUSR);
/*输入次设备号*/
module_param(numdev_minor,int,S_IRUSR);static struct class *myclass;struct reg_dev
{char *data;unsigned long size;struct cdev cdev;
};
struct reg_dev *my_devices;struct file_operations my_fops = {.owner = THIS_MODULE,
};/*设备注册到系统*/
static void reg_init_cdev(struct reg_dev *dev,int index){int err;int devno = MKDEV(numdev_major,numdev_minor+index);/*数据初始化*/cdev_init(&dev->cdev,&my_fops);dev->cdev.owner = THIS_MODULE;dev->cdev.ops = &my_fops;/*注册到系统*/err = cdev_add(&dev->cdev,devno,1);if(err){printk(KERN_EMERG "cdev_add %d is fail! %d\n",index,err);}else{printk(KERN_EMERG "cdev_add %d is success!\n",numdev_minor+index);}
}static int scdev_init(void)
{int ret = 0,i;dev_t num_dev;printk(KERN_EMERG "numdev_major is %d!\n",numdev_major);printk(KERN_EMERG "numdev_minor is %d!\n",numdev_minor);if(numdev_major){num_dev = MKDEV(numdev_major,numdev_minor);ret = register_chrdev_region(num_dev,DEVICE_MINOR_NUM,DEVICE_NAME); // 静态注册设备号}else{/*动态注册设备号*/ret = alloc_chrdev_region(&num_dev,numdev_minor,DEVICE_MINOR_NUM,DEVICE_NAME);/*获得主设备号*/numdev_major = MAJOR(num_dev);printk(KERN_EMERG "adev_region req %d !\n",numdev_major);}if(ret<0){printk(KERN_EMERG "register_chrdev_region req %d is failed!\n",numdev_major);     }myclass = class_create(THIS_MODULE,DEVICE_NAME); // 创建class类 “ls /sys/class/”查看my_devices = kmalloc(DEVICE_MINOR_NUM * sizeof(struct reg_dev),GFP_KERNEL); // 申请内存空间if(!my_devices){ret = -ENOMEM;goto fail;}memset(my_devices,0,DEVICE_MINOR_NUM * sizeof(struct reg_dev));/*设备初始化*/for(i=0;i<DEVICE_MINOR_NUM;i++){my_devices[i].data = kmalloc(REGDEV_SIZE,GFP_KERNEL); // 申请设备数据空间memset(my_devices[i].data,0,REGDEV_SIZE);/*设备注册到系统*/reg_init_cdev(&my_devices[i],i); /*创建设备节点*/device_create(myclass,NULL,MKDEV(numdev_major,numdev_minor+i),NULL,DEVICE_NAME"%d",i); //  “ls /dev”查看}printk(KERN_EMERG "scdev_init!\n");/*打印信息,KERN_EMERG表示紧急信息*/return 0;fail:/*注销设备号*/unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);printk(KERN_EMERG "kmalloc is fail!\n");return ret;
}static void scdev_exit(void)
{int i;printk(KERN_EMERG "scdev_exit!\n");/*除去字符设备*/for(i=0;i<DEVICE_MINOR_NUM;i++){cdev_del(&(my_devices[i].cdev));/*摧毁设备节点函数d*/device_destroy(myclass,MKDEV(numdev_major,numdev_minor+i));kfree(my_devices[i].data);}/*释放设备class*/class_destroy(myclass);/*释放内存*/kfree(my_devices);unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);
}module_init(scdev_init);
/*初始化函数*/
module_exit(scdev_exit);
/*卸载函数*/

四、运行

十五、linux 注册字符类设备和生成节点相关推荐

  1. Linux驱动(14)--字符类设备与驱动

    字符类设备 1. 静态申请字符类设备号 1.1 所需函数与头文件 1.2 源码与注释 1.3 运行结果 2. 动态申请字符类设备号 2.1 所需函数与头文件 2.2 源码与注释 2.3 运行结果 3. ...

  2. 4412 字符类设备的设备号

    一.静态申请字符类设备号 字符类设备函数在文件"include/linux/fs.h"中 内核提供了三个函数来注册一组字符设备编号,这三个函数分别是 register_chrdev ...

  3. linux驱动 — switch_dev类设备的使用

    前言 在项目中碰到有人用switch_dev_register注册了switch_dev类设备,并且应用层能读到它的状态信息,感觉挺好奇,于是网上搜了些资料,自个又琢磨了一下,算是理解了,现在整理一下 ...

  4. J2EE进阶(十五)MyEclipse反向工程实现从数据库反向生成实体类之Hibernate方式[申明:来源于网络]...

    J2EE进阶(十五)MyEclipse反向工程实现从数据库反向生成实体类之Hibernate方式[申明:来源于网络] 地址:http://blog.csdn.net/sunhuaqiang1/arti ...

  5. Inno Setup入门(十五)——Inno Setup类参考(1)

    Inno Setup入门(十五)--Inno Setup类参考(1) nno setup脚本能够支持许多的类,这些类使得安装程序的功能得到很大的加强,通过对这些类的使用,将会创建出许多让人惊奇的安装程 ...

  6. 有趣的HTML实例(十五) 注册登录界面(css+js)

    我并不是每次吃完饭就看电视,有时我边吃边看电视,生活中有些改变会增加乐趣. --<加菲猫> 目录 一.前言 二.往期作品回顾 三.作品介绍 四.本期代码介绍 五.效果显示 六.编码实现 i ...

  7. centos 计算器_Linux学习之CentOS(十五)--Linux常用命令之bc、man、shutdown...

    在写这篇随笔时,翻看了一下上一篇随笔的写作日期,发现已经是4月8号了,时间已经过了11天了!!!过了这么久没有更新Linux学习系列的随笔了,是因为我又松懈了Linux的学习了吗?不是的!!!是因为最 ...

  8. linux内核字符驱动设备,Linux学习笔记——linux内核字符设备驱动-Go语言中文社区...

    尝试在树莓派安装的raspbian系统上进行linux字符设备驱动 1.更新安装kernel header源码 sudo apt-get update sudo apt-get install ras ...

  9. 使用“override”声明的成员函数不能重写基类成员_C++日志(三十五)虚基类与其子类的构造函数...

    第三十四篇日志中提到,子类对象调用父类同名的函数时需要使用作用域标识符进行限定,这是在任何继承情况下都可以使用的普适方法. 问题引入: 考虑一种特殊的情况:子类全部或部分的基类(称为中间基类)同是继承 ...

最新文章

  1. this is incompatible with sql_mode=only_full_group_by
  2. everytime you feel nervous
  3. Linux驱动编程 step-by-step (二) 简单字符设备驱动
  4. 基础-栈队列简单测试
  5. RTX3090深度学习环境配置(PyTorch1.8)
  6. mysql5.7json查询_MySql5.7 json查询
  7. php获取悉尼时间,php在使用澳大利亚/悉尼时区时给出错误答案
  8. 如何快速学会java编程?
  9. 英国鬼死于狭隘和傲慢,中国鬼死于听天由命和漫不经心--《我的团长我的团》兰晓龙...
  10. casio wrist怎么调时间_价格便宜量也足,小米有品TIMEROLLS COB时间轨迹石英腕表体验...
  11. gif跟随ProgressBar一起动/pk进度条gif特效
  12. 华为手机屏幕锁屏时间设置_华为手机锁屏时间怎么设置?
  13. C语言编译器字母怎么输入,c语言编译器怎么使用,c语言编译器下载使用教程
  14. 按键精灵python插件_按键精灵必须掌握的命令之插件命令
  15. ubuntu 安装qq
  16. Google NIK插件的介绍及使用
  17. 好用的组件Vue Tags Input 输入框标签
  18. 局域网雨云蠕虫病毒的处理
  19. 【深度学习原理第1篇】前馈神经网络,感知机,BP神经网络
  20. MATLAB矩阵行列

热门文章

  1. 使用sublime text 2开发Javacript和jQuery
  2. SQL Server 2005之PIVOT/UNPIVOT行列转换
  3. Silverlight 2 相关文章汇总
  4. UA SIE545 优化理论基础4 对偶理论简介3 强对偶
  5. C#获取和设置环境变量
  6. ARC下带CF前缀的类型与OC类型转换
  7. PHP代码为什么不能直接保存HTML文件——PHP生成静态页面教程
  8. 代码压缩、生成二维码
  9. 和菜鸟一起学证券投资之股市常见概念公式1
  10. java.函数参数太多,Java方法参数太多怎么办—Part 2—引入参数对象,javapart