Linux驱动学*(4-字符设备-自动创建字符设备并读写)

发布时间:2021-07-24 09:59:15

上一节我们主要讲解了手动创建字符设备节点并访问,但是感觉太过于麻烦,因此,我们这一节主要讲解如何自动创建字符设备并进行读写操作,以及讲解编写字符设备驱动的框架
不过在此之前,我们先不上代码,先了解一下基本的概念。


1、设备号dev_t

设备号为设备驱动模块程序在Linux系统中唯一识别号。其为32bits的无符号整数, 一个设备号分成主设备号和次设备号两部分:(Linux2.6版本的设备号)
主号12bits 次号20bits
一般情况下主设备号为一种设备类型,次设备号为这类设备的具体一个设备。
MKDEV(ma,mi);将ma主设备号和次设备号合成一个32bit的完整设备号;
MAJOR(dev);从一个设备号中提取出主设备号;
MINOR(dev);从一个设备号中提取次设备号;


2、struct cdev字符设备控制块

字符设备控制块struct cdev是字符设备的核心,内核就是通过对其的挂接和卸载完成字符设备工作。


3、字符设备函数操作集struct file_operations


利用struct file_operations声明实体,然后对相应的函数给出实现体,最后将该实体赋给cdev中ops的成员。


4、代码展示

看了些理论感觉很无聊,我们还是先上点代码吧
模块代码
cdevAPI.c


#include "include/kmodlue.h"

//协议声明
MODULE_LICENSE("GPL");

//声明一个节点名作为模块输入参数
//其将在/dev目录下被创建。
static char *DeviceNodeName = "ss";
module_param(DeviceNodeName, charp, 0600);
MODULE_PARM_DESC(DeviceNodeName, "The default value is "ss"");



dev_t dev; //存放设备号,因该理解为主设备号
struct cdev cdev; //字符设备控制块
int dsn; //次设备号起始值
int acount_of_devices; //声明次设备号数量,即具体设备数量
//To define a pointer of device class 定义一个设备类型指针
struct class *D_class;
//To define a pointer of device 定义一个设备
struct device *D_device;
//Show it in(显示在) /proc/devices file
#define DeviceName "Chr_dev"
//Show it in(显示在) /sys/class/ dir.
#define DeviceNameClass "Chr_dev_class"

#define MEM_SIZE 20 //声明内核内存空间大小
unsigned char *mem_datas; //内核内存空间指针


//API的打开程序接口
int cdev_open(struct inode *i, struct file *filp)
{
//将ChrDevp指针赋值给filp->private_data,也就是今后,
//函数struct file *参数中的filp->private_data也指向mem_datas所指向的空间。
filp->private_data = mem_datas;
printk(KERN_INFO "The device was openned by the AP!
");
return 0;
}

//API的关闭程序接口
int cdev_close(struct inode *i, struct file *filp)
{
filp->private_data = NULL;
printk(KERN_INFO "The device was closed by the AP!
");
return 0;
}





//定义AP程序操作接口
struct file_operations cdev_fops = {
.owner = THIS_MODULE,
.open = cdev_open,
.release = cdev_close,
};



//mount fuction 挂载函数
static int __init chr_dev_init(void)
{
int rst = 0;
dsn = 3;
acount_of_devices = 1;
//动态申请设备号
rst = alloc_chrdev_region(&dev, dsn, acount_of_devices, DeviceName);
if(rst < 0)
{
rst = -1;
printk(KERN_INFO "Fail:alloc_chrdev_region()
");
goto Exit_1;

}
//To init the cdev blk 初始化字符控制快
cdev_init(&cdev,&cdev_fops);
cdev.owner = THIS_MODULE;
//添加设备快
rst = cdev_add(&cdev, dev, dsn+1);
if(rst < 0)
{
rst = -2;
printk(KERN_INFO "Fail:cdev_add()
");
goto Exit_2;
}
//创建设备类型
D_class = class_create(THIS_MODULE, DeviceNameClass);
if(IS_ERR(D_class))
{
rst = -3;
printk(KERN_INFO "Fail:class_create()
");
goto Exit_3;
}
//创建设备节点
D_device = device_create(D_class, NULL, dev, NULL, DeviceNodeName);
if(IS_ERR(D_device))
{
rst = -4;
printk(KERN_INFO "Fail:device_create()
");
goto Exit_4;
}

//创建内核数据空间
mem_datas = kmalloc(MEM_SIZE, GFP_KERNEL);
if(IS_ERR(mem_datas))
{
rst = -5;
printk(KERN_INFO "Fail:kmalloc() for ChrDevp->mem_datas
");
goto Exit_5;
}
//Inited is success! and exit. 初始化成功
//rst = 0;
printk(KERN_INFO "The device module was mounted by the kernel!,the device number maj:%d and min: %d
",
MAJOR(dev), MINOR(dev));
goto Exit_1;

Exit_5:
//销毁设备节点
device_destroy(D_class, dev);

Exit_4:
//销毁设备类型
class_destroy(D_class);

Exit_3:
//删除设备块
cdev_del(&cdev);

Exit_2:
//注销设备号
unregister_chrdev_region(dev, acount_of_devices);


Exit_1://程序退出,初始化结束
return rst;
}

//umount fuction 卸载函数
static void __exit chr_dev_exit(void)
{
//释放内核内存空间
kfree(mem_datas);
//销毁设备节点
device_destroy(D_class, dev);
//销毁设备类型
class_destroy(D_class);
//删除设备块
cdev_del(&cdev);
//注销设备号
unregister_chrdev_region(dev, acount_of_devices);
printk(KERN_INFO "The device module was umounted by the kernel!
");
}

//封装模块挂载函数
module_init(chr_dev_init);
//封装模块卸载函数
module_exit(chr_dev_exit);

应用程序代码
testap.c


#include
#include
#include
int main(int c, char **v)
{
int fp = open("/dev/ss",O_RDWR);
if(fp < 0)
{
printf("Error,device no exists!
");
return -1;
}
printf("Openning success!
");

sleep(3);

printf("Closing success!
");
close(fp);
return 0;
}

Makefile


include目录里面的文件
include/cmd.h


#ifndef __CMD_H__
#define __CMD_H__

#define MAGIC 0x34

#define OPEN_LED 1
#define CLOSE_LED 2

#define IO_OPEN_LED _IO(MAGIC, OPEN_LED)
#define IO_CLOSE_LED _IO(MAGIC, CLOSE_LED)


#endif

include/kmodule.h


#ifndef __KMODULE_H__
#define __KMODULE_H__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#endif

由于之前装载、卸载模块已经说明很多次,因此,这里不再进行说明,如果有不明白的地方,请参考以前的教程。


5、函数简要说明

一、动态分配设备号函数:
int alloc_register_region(dev_t *dev, unsigned basemonor, unsigned count, const char *name);
返回值:0表示成功,非0表示失败。
输入参数:
dev,存放获得的设备号,指针方式传入;
baseminor,第一个次设备号,;
count,总共次设备号数量;
name,被分配的设备或驱动名称。


二、创建设备类型目录及相应配置函数:
struct class *class_create(owner, name);
返回值:为struct class指针,可用IS_ERR()函数来判断返回是否成功。
输入参数:
owner ,一般使用THIS_MODULE参数;
name,设备类型名称。
会在/sys/class中创建name参数的目录及一些文件。


三、自动创建设备节点函数:
struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, …);
返回值:struct device *指针,可用IS_ERR()函数来判断返回是否成功。
class,为用class_create()得到的指针;
parent,指向父级设备,一般可以为NULL;
devt,设备号;
drvdata,为回调函数,或携带数据,一般为NULL;
fmt,为设备类型名称。
自动会在/dev目录下创建fmt设备节点。


四、删除设备节点函数:
void device_destroy(struct class *class, dev_t devt);
返回参数:空。
输入参数:
class,要删除设备节点所属的设备类型;
devt,要删除的设备号。


五、删除设备类型函数:
void class_destroy(struct class *cls);
返回值:空。
输入参数:
cls,要删除的设备类型。


六、开发字符设备并读写的框架流程

初始化
1、动态申请设备号 alloc_register_region
2、初始化字符设备块 cdev_init
3、向内核添加设备块 cdev_add
4、创建设备类型 class_create
5、创建设备节点 device_create
6、创建内核数据空间 kmalloc


卸载
1、释放内核内存空间 kfree
2、销毁设备节点 device_destroy
3、销毁设备类型 class_destroy
4、注销设备号 unregister_chrdev_region


我们在insmod模块的时候,模块初始化会自动创建设备节点。通过设备节点,应用程序就可以进行正常的数据操作了。read write open close等等

相关文档

  • 溜冰的周记参考
  • 喝水减肥法 三天喝水减肥法 喝水甩脂轻松瘦
  • 火安全常识
  • 描写雪的句子诗句
  • 可爱的兔子
  • 市长在市农产品市场准入制度启动仪式上的讲话
  • 2020年安徽宿州初级会计师考试时间定了 有变动
  • 队列队形比赛作文
  • 华擎主板怎么样
  • 依泉喷雾是咸的吗?依泉喷雾为什么是咸的?
  • oppoa57多大屏幕尺寸
  • beatspro充电盒的按钮干嘛的
  • word视图的显示方式
  • 儿童减肥好方法
  • 奔跑吧林依晨是哪一期奔跑吧热巴林依晨变暴力姐妹花是哪期
  • 家乡特产作文450字
  • 什锦豆腐煲的做法步骤
  • 教师转正个人自我鉴定怎么写
  • 英语作文开头技巧指导大全
  • Android中Handler的使用方法??在子线程中更新界面
  • bose耳机煲机方法
  • 三线城市创业项目
  • 电脑上e没有了怎么办
  • 高级会计师《高级会计实务》冲刺试题
  • iOS中高级面试题
  • 对计科核心课程的关系的总结
  • 凯恩斯用什么来解释有效需求不足
  • 如何判断ACTIVEX控件是否下载
  • 无违规从教保证书
  • 艺术教育是什么专业艺术教育需要强化教育艺术
  • 猜你喜欢

  • Angular强大的指令
  • 六年级下册数学试题- 第一单元测试卷 北师大版(2014秋)(无答案)
  • 牛津英语4A英语单词复*题
  • 苹果5s手机坏了怎么办啊
  • Web应用威胁建模与定量评估
  • 小学二年级写人作文《我家的小菜园》100字
  • 人教版八年级物理下册教案:9.2 液体的压强
  • 【最新文档】小学少先队工作总结报告-范文word版 (2页)
  • 中国网络广告市场竞争调研与投资价值评估报告(2013-2017)
  • 衡水市人民政府关于表彰全市消防工作先进单位和先进个人的决定
  • 考研数学选择题解题方法
  • 运筹学-02-线性规划的图解法
  • 2021-05-16
  • 高考数学冲刺:复习错题效率高及中档题拿分点
  • 厨房美食菜谱:香软南瓜馒头的做法
  • 人教初中地理七上《1第1节 地球和地球仪》PPT课件 (2)
  • 中国钥匙模行业市场前景分析预测报告(目录)
  • 旅游英语旅游英语31104
  • 二年级语文上册《古诗诵读早发白帝城》教学设计沪教版
  • stream/ngx_stream_ssl_preread_module-nginx中文参考手册
  • 八年级英语下册单元同步测试题-Unit 3 What were you doing when the UFO arrived
  • 低温乙烯再液化冷却系统的工艺控制技术
  • 日本专利信息服务模式研究
  • 浅谈小型农村水利工程建设与管理问题
  • 安徽省小学《教育教学知识与能力》:教学重难点设计考试试卷
  • 湖北省建设厅关于批准武汉江南钻井工程有限公司等2家企业工程勘
  • 沧州鸿富化工产品有限公司(企业信用报告)- 天眼查
  • 计网TCP连接管理(三次握手、四次握手)
  • 金蝶工资管理系统
  • 基于GSM模块的LED警示灯-文档资料
  • 2019年六年级上册数学能力测试竞赛卷(苏教版)
  • 精编2019届高三化学上学期第一次月考试题附答案
  • 注册安全工程师《安全生产法及相关法律知识》全真模拟考试试题 含答案
  • 九里区代理发表职称论文发表-土建地地工程结构实体高高质量检测必要性论文的题目
  • “十三五”重点项目-螺丝车刀项目申请报告
  • unity中UI的学习笔记Text
  • 股权激励协议书(员工干股激励)
  • 简历精简自我评价
  • 成都市一木缘家具有限公司企业信用报告-天眼查
  • 2019初中八年级人教版地理暑假作业语文
  • 【推荐】校园的四季作文
  • 无线蓝牙数据模块在健康医疗设备领域的应用方案
  • 电脑版