(六)Linux之设备驱动模型(续)
前面我们学习了杂项设备驱动模型、早期经典字符设备驱动模型,这一小节来讲解Linux中的标准字符设备驱动。
目录
- (一)为什么引入标准字符设备驱动模型
- (二)相关接口
- (三)注册流程
- (四)程序示例
(一)为什么引入标准字符设备驱动模型
前面讲解了杂项设备驱动模型和早期经典设备驱动模型,但是他们都存在不足之处
杂项设备存在的不足: 主设备号固定为10,最多设备为0-255个次设备号,设备号有限
早期经典驱动模型不足: 早期经典的字符设备主设备号为0-255除10外,但是申请一次主设备号,该设备号下的所有次设备号(0-255)均属于同一设备,且不会在申请同时创建节点文件,需要手动创建
出于以上的不足之处,内核中对驱动模型进行了升级,引入了标准字符设备驱动模型
标准字符设备驱动模型: 标准字符设备驱动模型中对设备号进行了数据的规定,规定设备号为一个32位的无符号整型数据
(二)相关接口
(1)int cdev_add(struct cdev *p, dev_t dev, unsigned count)这个函数是添加到字符设备系统中,注册标准字符设备驱动。
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{p->dev = dev;p->count = count;return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}//第一个参数结构体原型
struct cdev {struct kobject kobj; //不关心struct module *owner; //一般赋值为THIS_MODULEconst struct file_operations *ops; //文件操作结构体struct list_head list; //dev_t dev; //设备号unsigned int count; //表示申请设备号的数量
};
(2)struct cdev 结构体可以手动静态初始化,但是我们通常使用动态申请,本篇文章主要介绍动态相关的函数。
struct cdev *cdev_alloc(void);//动态申请struct cdev结构体 的内存void cdev_init(struct cdev *, const struct file_operations *);//初始化struct cdev结构体
(3)删除标准字符设备接口
void cdev_del(struct cdev *);
(4)设备号合成相关的接口
1.自己指定主次设备号,通过MKDEV合成dev_t dev=MKDEV(major,minor);2.静态申请int register_chrdev_region(dev_t from, unsigned count, const char *name)3.动态申请
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
{struct char_device_struct *cd;cd = __register_chrdev_region(0, baseminor, count, name);if (IS_ERR(cd))return PTR_ERR(cd);*dev = MKDEV(cd->major, cd->baseminor);return 0;
}
(5)创建设备节点 device_create
struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
{va_list vargs;struct device *dev;va_start(vargs, fmt);dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);va_end(vargs);return dev;
}
(6)设备类struct class 创建
#define class_create(owner, name) \
({ \static struct lock_class_key __key; \__class_create(owner, name, &__key); \
})
(7)标准字符设备驱动注销cdev_del
void cdev_del(struct cdev *p)
{cdev_unmap(p->dev, p->count);kobject_put(&p->kobj);
}
(8)注销设备号unregister_chrdev_region()
void unregister_chrdev_region(dev_t from, unsigned count)
{dev_t to = from + count;dev_t n, next;for (n = from; n < to; n = next) {next = MKDEV(MAJOR(n)+1, 0);if (next > to)next = to;kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));}
}
(9)销毁设备类:
void class_destroy(struct class *cls)
{if ((cls == NULL) || (IS_ERR(cls)))return;class_unregister(cls);
}
(10)销毁设备节点: device_destroy(struct class *class, dev_t devt)
void device_destroy(struct class *class, dev_t devt)
{struct device *dev;dev = class_find_device(class, NULL, &devt, __match_devt);if (dev) {put_device(dev);device_unregister(dev);}
}
(11)释放cdev空间:
static inline void kfree(void *p)
{free(p);
}
(三)注册流程
(1)定义struct cdev 结构体指针
struct cdev *cdev =NULL
(2)申请cdev结构体空间并初始化
cdev = cdev_alloc();//动态申请空间
cdev_init(cdev,&fop);//fop为struct file_operations类型的结构体
(3)申请设备号–动态
dev_t dev=0;
int ret =alloc_chrdev_region(&dev,0, CDEVCOUNT, CDEVNAME);
(4)将字符设备添加到系统
ret =cdev_add(cdev,dev, CDEVCOUNT);
(5)创建设备类
struct class * cdevclass =NULL;//定义设备节点类接构体cdevclass = class_create(THIS_MODULE, INODENAME)
(6)添加设备节点
reate(cdevclass, NULL, dev, NULL, "mydevice",);
(四)程序示例
chrdev.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>#define CDEVCOUNT 5
#define CDEVNAME "cdevdevice"
#define INODENAME "mycdev"
int i=0;
dev_t dev=0;
struct cdev * cdev =NULL;
struct class * cdevclass =NULL;int cdev_open (struct inode *node, struct file *file)
{printk("cdev_open is install\n");return 0;
}
ssize_t cdev_read (struct file *fp, char __user *buf, size_t size, loff_t *offset)
{printk("cdev_read is install\n");return 0;
}
ssize_t cdev_write (struct file *fp, const char __user * buf, size_t size, loff_t *offset)
{printk("cdev_write is install\n");return 0;
}
int cdev_release (struct inode *node, struct file *fp)
{printk("cdev_release is install\n");return 0;
}
struct file_operations fop={.open=cdev_open,.read=cdev_read,.write=cdev_write,.release=cdev_release,
};void mycdev_add()
{//1.申请设备号--动态int ret =alloc_chrdev_region(&dev,0, CDEVCOUNT, CDEVNAME);if(ret)return ;//初始化cdev结构体cdev = cdev_alloc();if(!cdev){goto out; }cdev_init(cdev,&fop);//添加字符设备到系统中ret =cdev_add(cdev,dev, CDEVCOUNT);if(ret){goto out1;}//创建设备类cdevclass = class_create(THIS_MODULE, INODENAME);if(IS_ERR(cdevclass)){goto out2;}
for (i=0;i<CDEVCOUNT;i++)device_create(cdevclass, NULL, dev+i, NULL, "mydevice%d",i);out:unregister_chrdev_region(dev,CDEVCOUNT); return ;out1:unregister_chrdev_region(dev,CDEVCOUNT);kfree(cdev);return ;
out2:cdev_del(cdev);unregister_chrdev_region(dev,CDEVCOUNT);kfree(cdev);return ;
}static int __init dev_module_init(void)
{mycdev_add();printk("this is dev_module_init \n");return 0;
}static void __exit dev_module_cleanup(void)
{device_destroy(cdevclass, dev);class_destroy(cdevclass);cdev_del(cdev);unregister_chrdev_region(dev, CDEVCOUNT);kfree(cdev);printk("this is dev_module_cleanup\n");
}module_init(dev_module_init);
module_exit(dev_module_cleanup);
MODULE_LICENSE("GPL");
Makefile
CFLAG =-C
TARGET = chrdev
TARGET1 = chr_app
KERNEL = /mydriver/linux-3.5
obj-m += $(TARGET).oall:make $(CFLAG) $(KERNEL) M=$(PWD)arm-linux-gcc -o $(TARGET1) $(TARGET1).c
clean:make $(CFLAG) $(KERNEL) M=$(PWD) clean
chr_app.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(int argc, char *argv[])
{int fd= open(argv[1],O_RDWR);if(fd== -1){perror("open");return -1;}write(fd,"hell",4);close(fd);return 0;
}
关于上面的驱动程序都是建立在前面的模块化编程的基础上编写的,不懂的往前看前面的博客就行了,演示一下效果
本文章仅供学习交流用禁止用作商业用途,文中内容来水枂编辑,如需转载请告知,谢谢合作
微信公众号:zhjj0729
微博:文艺to青年
(六)Linux之设备驱动模型(续)相关推荐
- linux设备模型 字符设备,Linux 字符设备驱动模型之框架解说
一.软件操作硬件设备模型 在进行嵌入式开发的过程中,在常做的事情就是驱动配置硬件设 备,然后根据功能需求使用硬件设备,实现功能的逻辑.如下图为其 相互之间的关系. 如上图所示: 驱动程序:主要作为操作 ...
- LINUX I2C设备驱动模型分析之二 总线部分分析
上一章我们对I2C模块做了总体框架的分析,本章我们主要分析下I2C模块的总线部分,主要涉 及总线初始化.总线相关属性.总线相关接口函数处理等几部分 I2c bus的定义 I2c bus的定义如下,主要 ...
- (五)Linux之设备驱动模型
目录 (一)Linux内核驱动简介 (二)杂项设备驱动模型 (1)相关接口 (2)杂项设备注册过程 (三)早期经典字符设备驱动模型 (1)相关接口 (2)杂项设备注册过程 (二)杂项和早期经典的区别 ...
- linux平台设备驱动模型是什么意思,Linux设备驱动模型之我理解
点击(此处)折叠或打开 /* my_bus.c */ #include #include #include #include #include #include "my_bus.h&qu ...
- linux字符设备文件的打开操作,Linux字符设备驱动模型之字符设备初始化
因为Linux字符设备驱动主要依赖于struct cdev结构,原型为: 所以我们需要对所使用到的结构成员进行配置,驱动开发所使用到的结构成员分别为:[unsigned int count;].[de ...
- LINUX SPI设备驱动模型分析之二 SPI总线模块分析
上一篇文章我们简要介绍了SPI驱动模块,本章我们详细说明一下spi总线.设备.驱动模块的注册.注销以及这几个模块之间的关联. SPI总线的注册 spi模块也是基于LINUX设备-总线-驱动模型进行开发 ...
- Linux字符设备驱动模型
版本 颁布日期 修订章节 0.1 2015.08.13 撰写草稿 0.2 2015.12.07 整合字符型设备驱动 0.3 2015.12.07 整理文档,尚未验证驱动源码 0.4 2016.02.2 ...
- linux设备驱动模型-linux驱动开发第5部分-朱有鹏-专题视频课程
linux设备驱动模型-linux驱动开发第5部分-4285人已学习 课程介绍 本课程是linux驱动开发的第5个课程,主要内容是linux的设备驱动模型,包括总线.类.设备.驱动等概 ...
- Linux Platform平台设备驱动模型
Linux总线设备驱动模型主要包含总线.设备.驱动三个部分. 现实总线:一个现实的Linux设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI.USB.I2C.SPI等的设备而言,这自然不是问 ...
最新文章
- iOS边练边学--CALayer,非根层隐式动画,钟表练习
- 水晶报表-横向设计页面,设置网格高度
- SQL Server2012 安装方法
- Java中的HashMap和Hashtable有什么区别?
- 宝洁侮辱女性?其公众号发文 “女人脚臭是男人的5倍”,官方回应了...
- java与jsp的关系_浅谈servlet与jsp的关系
- Item08. 多级指针(Pointers to Pointers)
- 北航计算机组成原理课程设计-2021秋 PreProject-MIPS-入门简介
- 计算机已被锁定请联系管理员,win7电脑开机收到提示“您的账户已被停用,请向系统管理员咨询”怎么办?...
- ASP.NET删除服务器端文件,asp.net删除服务器上的文件
- 论文笔记—RGB-D SLAM in Dynamic Environments Using Static Point Weighting
- 全国大学生英语竞赛总结
- python数据分析师前景及待遇怎么样_数据分析师未来五年发展前景怎么样?
- 高德地图api的使用
- 经典利用永恒之蓝漏洞对Windows操作系统进行攻击
- 以匠心守初心!百望云荣膺人民网“第十九届人民匠心飞跃奖”
- 【机器学习】使用Matlab和CNN完成回归任务
- ireport4.5在JVM中添加新字体解决方案(Font ‘標楷體‘ is not available to the JVM. See the Javadoc for more details.)
- 用计算机代码选址的优点,计算机机房选址原则
- 计算机硬件的最低配置,Windows7系统的最低硬件配置要求是什么
热门文章
- deepin linux 2014 硬盘安装教程,Linux Deepin的硬盘安装
- Elasticsearch7.15.2 mysql8.0.26 logstash-input-jdbc 数据增量索引构建
- RuoYi-Cloud 部署篇_01(linux环境 mysql+nginx版本)
- Centos7 安装docker-compose
- 正则表达式简单语法及常用正则表达式
- 第11篇:Flowable-BPMN部署常见问题没有对ACT_RE_PROCDEF表进行插入操作
- tomcat9控制台中文乱码
- cmd下pip安装mysql_Windows下使用pip安装mysql-python
- python中idle怎么打开_为什么我的python脚本只打开IDLE?
- java hashmap读,java – ConcurrentHashmap – 读取和删除