Linux 驱动框架---设备文件devfs
设备文件系统
Linux引入了虚拟文件系统,从而使设备的访问可以像访问普通文件系统一样。因此在内核中描述打开文件的数据inode中的rdev成员用来记录设备文件对应到的设备号。设备文件也由一个对应的file_operations 数据对象,用来描述设备的操作接口。设备文件系统最早是采用devfs实现的,但是后来因为种种原因在2.6以后的内核中已经将其废弃而转而使用udev,他来本质上是没有区别都是在设备添加到系统中时在/dev目录下产生设备文件(机制相同),但是不同的是策略devfs的策略是将设备文件的创建过程放在了内核空间,而udev的策略是由内核提供机制而用户空间提供策略从而完成设备的创建,所以现在设备文件管理由两个软件可用分别是PC平台上的udev和嵌入式平台上的mdev。
devfs
接口均已经废弃,不在详细探究。
devfs_handle_t devfs_mk_dir(devfs_handle_t dir,const char* name,void* info);
devfs_handle_t devfs_register(devfs_handle_t de,const char* name,unsigned int flag,uinsigned int major,unsigned int minor,umode_t mode,void* ops,void* info);
devfs_handle_t devfs_unregister(devfs_handle_t de);
udev(mdev)
与devfs不同udev完全工作在用户空间,而内核通过netlink机制将,设备添加过程的相关信息通过netlink发送到用户空间的udev程序,netlink机制可以不理解是一种特殊的socket进程通讯方式,用户空间的udev接收到设备添加的信息后将完成设备文件的创建和设备文件操作接口等相关的配置和初始化操作。进而用户空间程序就能像访问普通文件一样访问设备了。
关于file和inode数据结构在内核中的探究
比较好奇设备文件在被多个用户进程打开后后续fops操作接口的file和inode是同一个还是个进程单独一个,因为file中还由一个private_data成员在驱动编程中是比较重要的所以接下来进行专门的验证。
编写一个虚拟的设备驱动如下
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
//file open operation function
static int char_drv_open(struct inode *inode , struct file *filp)
{
printk(KERN_EMERG "inode:%08x file:%08x\n",inode,filp);
printk(KERN_EMERG "private_data:%08x\n",filp->private_data);
printk(KERN_EMERG "inode:%08x\n",inode);
filp->private_data = 0x5A5A5A5A;
return 0;
}
//file read operation function
static int char_drv_read(struct file *filp , char __user *buf , size_t cnt , loff_t *offt)
{
return 0;
}
//file write operation function
static int char_drv_write(struct file *filp,const char __user *buf , size_t cnt , loff_t *offt)
{
return 0;
}
//file close operation function
static int char_drv_release(struct inode *inode , struct file *filp)
{
return 0;
}
//file operation function struct
static struct file_operations my_test_fop=
{
.owner = THIS_MODULE,
.open = char_drv_open,
.read = char_drv_read,
.write = char_drv_write,
.release = char_drv_release
};
/* 设备结构体 */
struct test_dev
{
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */
struct device *device; /* 设备 */
int major; /* 主设备号 */
int minor; /* 次设备号 */
};
#define NEWCHRLED_CNT 1 /* 设备号个数 */
#define NEWCHRLED_NAME "newchrdev" /* 名字 */
struct test_dev test_char_dev;
//module init function
static int __init char_drv_test_init(void)
{
//same hardware init
//apply device num
alloc_chrdev_region(&test_char_dev.devid, 0, NEWCHRLED_CNT,NEWCHRLED_NAME);
test_char_dev.major = MAJOR(test_char_dev.devid); /* 获取主设备号 */
test_char_dev.minor = MINOR(test_char_dev.devid); /* 获取次设备号 */
printk(KERN_EMERG "major:%d minor:%d\n",test_char_dev.major ,test_char_dev.minor);
//init dev struct
cdev_init(&test_char_dev.cdev,&my_test_fop);
//add dev to system
cdev_add(&test_char_dev.cdev ,test_char_dev.devid ,NEWCHRLED_CNT );
//build class
test_char_dev.class = class_create(THIS_MODULE,"test2");
if (IS_ERR(test_char_dev.class))
{
return PTR_ERR(test_char_dev.class);
}
//build device
test_char_dev.device = device_create(test_char_dev.class,NULL ,test_char_dev.devid,NULL,"test2");
if (IS_ERR(test_char_dev.device))
{
return PTR_ERR(test_char_dev.device);
}
return 0;
}
//module uninstall function
static void __exit char_drv_test_exit(void)
{
/* 注销字符设备 */
cdev_del(&test_char_dev.cdev);
/* 删除 cdev */
unregister_chrdev_region(test_char_dev.devid, NEWCHRLED_CNT);
device_destroy(test_char_dev.class, test_char_dev.devid);
class_destroy(test_char_dev.class);
}
//module function band
module_init(char_drv_test_init);
module_exit(char_drv_test_exit);
//license and author
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Smile");
编写应用程序如下:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int fd = open("/dev/fileinode",O_RDWR);
if(fd<0)
{
perror("open");
}
getc(stdin);
return 0;
}
结论
经过实验验证,设备文件每打开一次,内核都会在内核空间创建file对象而inode是指向同一数据块。具体输出如下:
//安装模块
[ 466.459870] major:250 minor:0
//第一次执行
[ 534.073202] inode:f437da00 file:f02cea80
[ 534.073205] private_data:00000000
[ 534.073207] inode:f437da00
//第二次执行
[ 548.632708] inode:f437da00 file:f02bd000
[ 548.632712] private_data:00000000
[ 548.632713] inode:f437da00
Linux 驱动框架---设备文件devfs的更多相关文章
- Linux 驱动框架---i2c驱动框架
i2c驱动在Linux通过一个周的学习后发现i2c总线的驱动框架还是和Linux整体的驱动框架是相同的,思想并不特殊比较复杂的内容如i2c核心的内容都是内核驱动框架实现完成的,今天我们暂时只分析驱动开 ...
- Linux 驱动框架---input子系统框架
前面从具体(Linux 驱动框架---input子系统)的工作过程学习了Linux的input子系统相关的架构知识,但是前面的学习比较实际缺少总结,所以今天就来总结一下输入子系统的架构分层,站到远处来 ...
- Linux 驱动框架---input子系统
input 子系统也是作为内核的一个字符设备模块存在的,所以他也是字符设备自然也会有字符设备的文件接口.input子系统的注册过程主要分为两步,先注册了一个input class然后再注册一个字符设备 ...
- Linux 驱动框架---platform驱动框架
Linux系统的驱动框架主要就是三个主要部分组成,驱动.总线.设备.现在常见的嵌入式SOC已经不是单纯的CPU的概念了,它们都会在片上集成很多外设电路,这些外设都挂接在SOC内部的总线上,不同与IIC ...
- Linux 驱动框架---net驱动框架
这一篇主要是学习网络设备驱动框架性的东西具体的实例分析可以参考Linux 驱动框架---dm9000分析 .Linux 对于网络设备的驱动的定义分了四层分别是网络接口层对上是IP,ARP等网络协议,因 ...
- Linux驱动框架之misc类设备驱动框架
1.何为misc设备 (1)misc中文名就是杂项设备\杂散设备,因为现在的硬件设备多种多样,有好些设备不好对他们进行一个单独的分类,所以就将这些设备全部归属于 杂散设备,也就是misc设备,例如像a ...
- Linux 驱动框架---cdev字符设备驱动和misc杂项设备驱动
字符设备 Linux中设备常见分类是字符设备,块设备.网络设备,其中字符设备也是Linux驱动中最常用的设备类型.因此开发Linux设备驱动肯定是要先学习一下字符设备的抽象的.在内核中使用struct ...
- Linux 驱动框架---linux 设备
Linux 设备 Linux驱动中的三大主要基础成员主要是设备,总线和驱动.今天先来从设备开始分析先把设备相关的数据结构放到这里方便后面看到来查,其中有些进行了简单的注释. struct device ...
- Linux驱动框架之framebuffer驱动框架
1.什么是framebuffer? (1)framebuffer帧缓冲(一屏幕数据)(简称fb)是linux内核中虚拟出的一个设备,framebuffer向应用层提供一个统一标准接口的显示设备.帧缓冲 ...
随机推荐
- 理解Go的多态实现
总结两点: 在Go中,定义一个interface类型,该类型说明了它有哪些方法.使用时,在函数中,将该interface类型作为函数的形参,任意一个实现了interface类型的实参都能作为该inte ...
- 手把手做一个基于vue-cli的组件库(上篇)
基于vue-cli4的ui组件库,先贴个最终效果吧,步骤有点多,准备分上下篇,上篇:如何做一个初步的组件.下篇:编写说明文档及页面优化.开工. GitHub源码地址:https://github.co ...
- 阿里云弹性公网IP那些事 阿里云云栖号 6月1日 弹性公网IP是独立的公网IP资源,可以绑定到阿里云专有网络VPC类型的ECS、NAT网关、私网负载均衡SLB上,并可以动态解绑,实现公网IP和ECS、NAT网关、SLB的解耦,满足灵活管理的要求。阿里云弹性公网IP那些事 阿里云云栖号 6月1日 弹性络VPC类型的E
阿里云弹性公网IP那些事 阿里云云栖号 6月1日 弹性公网IP是独立的公网关.私网负载均衡SLB上,并可以动态解绑,实现公网IP和ECS.NAT网关.SLB的解耦,满足灵活管理的要求.
- Kubernetes TensorFlow 默认 特定 集群管理器 虚拟化技术
Our goal is to foster an ecosystem of components and tools that relieve the burden of running applic ...
- tarjan复习笔记 双连通分量,强连通分量
声明:图自行参考割点和桥QVQ 双连通分量 如果一个无向连通图\(G=(V,E)\)中不存在割点(相对于这个图),则称它为点双连通图 如果一个无向连通图\(G=(V,E)\)中不存在割边(相对于这个图 ...
- 急~为啥我指定的的maven依赖版本没有生效?不是最短路径原则吗?
女朋友他们项目用了 spring-boot,以 spring-boot-parent 作为 parent: <parent> <groupId>org.springframew ...
- H5Slides幻灯演示系统
H5Slides幻灯演示系统基于HTML5的幻灯片编辑,播放的工具. 通过HTML5的技术,可以在浏览器上进行编辑.传播.控制幻灯片. 选择样板模式 添加新的页面 特点 它是HTML5的! 不需要臃肿 ...
- Chrome标签整理
程序人生 设计素材类网站 关于生活 求职相关网站 Web前端 科技新闻相关网站 优秀资源内含丰富学习资料 项目实例视频资料等 面试简历相关 适合初学者自学的编程网站 国内优秀博客 由于平时经常浏览一些 ...
- 遇到的一个bug
/// <summary> /// 检测玩家是否在机器人的球形碰撞体内,这个碰撞体是机器人的侦测范围,玩家在内部会进行视野检测和声音检测 /// </summary> priv ...
- WPF 之 INotifyPropertyChanged 接口的使用 (一)
一.INotifyPropertyChanged 的基本概念 INotifyPropertyChanged 的作用:通知客户端属性值已经更改.详细信息见:INotifyPropertyChange ...