《Linux Device Drivers》第十四章 Linux 设备型号
- 基本介绍
- 2.6内核设备模型来提供的抽象叙述性描述的一般系统的结构,为了支持各种不同的任务
- 电源管理和系统关机
- 用户空间与通信
- 热插拔设备
- 设备类型
- 2.6内核设备模型来提供的抽象叙述性描述的一般系统的结构,为了支持各种不同的任务
- kobject、kset和子系统
- kobject是组成设备模型的基本结构
- 对象的引用计数
- sysfs表述
- 数据结构关联
- 热插拔事件处理
- kobject基础知识
- <linux/kobject.h>
- 嵌入的kobject
- 内核代码非常少去创建一个单独的kobject对象。kobject用于控制对大型域相关对象的訪问
- kobject的初始化
- 首先将kobject设置为0。通常使用memset
- void kobject_init(struct kobject *kobj);
- int kobject_set_name(struct kobject *kobj, const char *format, …);
- ktype、kset和parent
- 对引用计数的操作
- struct kobject *kobjct_get(struct kobject *kobj);
- void kobject_put(struct kobject *kobj);
- release函数和kobject类型
- void my_object_readse(struct kobject *kobj)
- struct my_object *mine = container_of(kobj, struct my_object, kobj);
- kfree(mine);
- struct kobj_type
- void (*release) (struct kobject *);
- struct sysfs_ops *sysfs_ops;
- struct attribute **default_attrs;
- struct kobj_type *get_ktype(struct kobject *kobj);
- void my_object_readse(struct kobject *kobj)
- kobject层次结构、kset和子系统
- 内核用kobject结构将各个对象连接起来组成一个分层的结构体系,有两种独立的机制用于连接:parent指针和kset
- 在kobject结构的parent成员中,保存了另外一个kobject结构的指针。这个结构表示了分层结构中上一层的节点
- kset
- 一个kset是嵌入同样类型结构的kobject的集合
- kset结构关心提对象的聚焦与集合
- 能够觉得kset是kobject的顶层容器类
- kset总是在sysfs中出现
- 先把kobject的kset成员指向目的kset。然后使用以下函数加入kobject
- int kobject_add(struct kobject *kobj);
- extern int kobject_register(struct kobject *kobj);
- kobject_init和kobject_add的简单组合
- void kobject_del(struct kobject *kobj);
- kset在一个标准的内核链表中保存了它的子节点
- kset上的操作
- void kset_init(struct kset *kset);
- int kset_add(struct kset *kset);
- int kset_register(struct kset *kset);
- void kset_unregister(struct kset *kset);
- 子系统
- 子系统通常显示在sysfs分层结构中的顶层
- 内核中的子系统
- block_subsys(对块设备来说是/sys/block)
- devices_subsys(/sys/devices。设备分层结构的核心)
- 内核所知晓的用于各种总线的特定子系统
- decl_subsys(name, struct kobj_type *type, struct kset_hotplug_ops *hotplug_ops);
- void subsysstem_init(struct subsystem *subsys);
- int subsystem_register(struct subsystem *subsys);
- void subsystem_unregister(struct subsystem *subsys);
- struct subsystem *subsys_get(struct subsystem *subsys);
- void subsys_put(struct subsystem *subsys);
- kobject是组成设备模型的基本结构
- 低层sysfs操作
- kobject是隐藏在sysfs虚拟文件系统后的机制。对于sysfs中的每一个文件夹,内核中都会存在一个相应的kobject
- <linux/sysfs.h>
- sysfs入口
- kobject在sysfs中的入口始终是一个文件夹
- 分配阀给kobject的名字是sysfs中的文件夹名
- sysfs入口在文件夹中的位置相应于kobject的parent指针
- 默认属性
- kobject默认属性保存在kobj_type结构中
- default_attrs成员保存了属性列表
- sysfs_ops提供了实现这些属性的方法
- struct attribute
- char *name
- struct module *owner
- mode_t mode
- 仅仅读:S_IRUGO
- 可写:S_IWUSR
- <linux/stat.h>
- struct sysfs_ops
- ssize_t (*show) (struct kobject * kobj, struct attribute *attr, char *buffer);
- ssize_t (*store) (struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size);
- 非默认属性
- int sysfs_create_file(struct kobject *kobj, struct attribute *attr);
- int sysfs_remove_file(struct kobject *kobj, struct attribute *attr);
- 二进制属性
- struct bin_attribute
- struct attribute attr;
- size_t size;
- ssize_t (*read) (struct kobject *kobj, char *buffer, loff_t pos, size_t size);
- ssize_t (*write) (struct kobject *kobj, char *buffer, loff_t pos, size_t size);
- int sysfs_create_bin_file(struct kobject *kobj, struct bin_attribute *attr);
- int sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
- struct bin_attribute
- 符号链接
- int sysfs_create_link(struct kobject *kobj, struct kobject *target, char *name);
- void sysfs_remove_link(struct kobject *kobj, char *name);
- 热插拔事件的产生
- 一个热插拔事件是从内核空间发送到用户空间的通知。它表明系统配置出现了变化
- 不管kobject被创建还是被删除,都会产生这样的事件
- 热插拔操作
- struct kset_hotplug_ops
- int (*filter) (struct kset *kset, struct kobject *kobj);
- char * (*name) (struct kset *kset, struct kobject *kobj);
- int (*hotplug) (struct kset *kset, struct kobject *kobj, char **envp, int num_envp, char *buffer, int buffer_size);
- 当内核要为指定的kobject产生事件时,都要调用filter函数。假设返回0,将不产生事件
- struct kset_hotplug_ops
- 总线、设备和驱动程序
- 总线
- 总线是处理器与一个或者多个设备之间的通道
- <linux/device.h>
- struct bus_type
- char *name;
- struct subsystem subsys;
- struct kset drivers;
- struct kset devices;
- int (*match) (struct device *dev, struct device_driver *drv);
- struct device *(*add) (struct device *parent, char *bus_id);
- int (*hotplug) (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
- struct bus_type
- 每一个总线都有自己的子系统
- 一个总线包括两个kset。分别代表了总线的驱动程序和插入总线的全部设备
- 总线的注冊
- example
- struct bus_type ldd_bus_type = {.name=”ldd”, .match=ldd_match, .hotplug=ldd_hotplug,};
- ret = bus_register(&ldd_bus_type);
- if (res) return ret;
- void bus_unregister(struct bus_type *bus);
- example
- 总线方法
- 当一个总线上的新设备或者新驱动程序被加入时,会一次或多次调用match函数
- 在为用户空间产生热插拔事件前,hotplug方法同意总线加入环境变量
- 在调用真实的硬件时,match函数通常对设备提供的硬件ID和驱动所支持的ID做某种类型的比較
- 对设备和驱动程序的迭代
- int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn) (struct device *, void *));
- int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void *data, int (*fn)(struct device_driver *, void *));
- 总线属性
- <linux/device.h>
- struct bus_attribute
- struct attribute attr;
- ssize_t (*show) (struct bus_type *bus, char *buf);
- ssize_t (*store) (struct bus_type *bus, const char *buf, size_t count);
- struct bus_attribute
- BUS_ATTR(name, mode, show, store);
- int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);
- void bus_remove_file(struct bus_tyep *bus, struct bus_attribute *attr);
- <linux/device.h>
- 设备
- struct device
- struct device *parent;
- struct kobject kobj;
- char bus_id[BUS_ID_SIZE];
- struct bus_type *bus;
- struct device_driver *driver;
- void *driver_data
- void (*release) (struct device *dev);
- 设备注冊
- int device_register(struct device *dev);
- void device_unregister(struct device *dev);
- 设备属性
- struct device_attribute
- struct attribute attr;
- ssize_t (*show) (struct device *dev, char *buf);
- ssize_t (*store) (struct device *dev, const char *buf, size_t count);
- DEVICE_ATTR(name, mode, show, store);
- int device_create_file(struct device *device, struct device_attribute *entry);
- void device_remove_file(struct device *dev, struct device_attribute *attr);
- struct device_attribute
- 设备结构的嵌入
- device结构中包括了设备模型核心用来模拟系统的信息
- 通常,底层驱动程序并不知道device结构
- struct device
- 设备驱动程序
- struct device_driver
- char *name;
- struct bus_type *bus;
- struct kobject kobj;
- struct list_head devices;
- int (*probe) (struct device *dev);
- int (*remove) (struct device *dev);
- void (*shutdown) (struct device *dev);
- probe是用来查询特定设备是否存在的函数
- 当设备从系统中删除的时候要调用remove函数
- 在关机的时候调用shutdown函数关闭设备
- int driver_register(struct device_driver *drv);
- void driver_unregister(struct device_driver *drv);
- struct driver_attribute
- struct attribute attr;
- ssize_t (*show) (struct device_driver *drv, char *buf);
- ssize_t (*store) (struct device_driver *drv, const char *buf, size_t count);
- int driver_create_file(struct device_driver *drv, struct driver_attribute *attr);
- void driver_remove_file(struct device_driver *drv, struct driver_attribute *attr);
- 驱动程序结构的嵌入
- device_driver结构通常被包括在高层和总结相关的结构中
- struct device_driver
- 总线
- 类
- 类是一个设备的高层视图,它抽象出了低层的实现细节
- 差点儿全部类都显示在/sys/class文件夹中
- /sys/class/net
- /sys/class/input
- /sys/class/tty
- /sys/block
- class_simple接口
- 创建类本身
- struct class_simple *class_simple_create(struct module *owner, char *name);
- 销毁一个简单类
- void class_simple_destroy(struct class_simple *cs);
- 为一个简单类加入设备
- struct class_device *class_simple_device_add(struct class_simple *cs, dev_t devnum, struct device *device, const char *fmt, …);
- int class_simple_set_hotplug(struct class_simple *cs, int (*hotplug) (struct class_device *dev, char **envp, int num_envp, crah *buffer, int buffer_size));
- void class_simple_device_remove(dev_t dev);
- 创建类本身
- 完整的类接口
- 管理类
- struct class
- char *name;
- struct class_attribute *class_attrs;
- struct class_device_attribute *class_dev_attrs;
- int (*hotplug) (struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
- void (*release) (struct class_device *dev);
- void (*class_release) (struct class *class);
- int class_register(struct class *cls);
- void class_unregister(struct class *cls);
- struct class_attribute
- struct attribute attr;
- ssize_t (*show) (struct class *cls, char *buf);
- ssize (*store) (struct class *cls, const char *buf, size_t count);
- CLASS_ATTR(name, mode, show, store);
- int class_create_file(struct class *cls, const struct class_attribute *attr);
- void class_remove_file(struct class *cls, const struct class_attribute *attr);
- struct class
- 类设备
- strict class_device
- struct kobject kobj;
- struct class *class;
- struct device *dev;
- void *class_data;
- char class_id[BUS_ID_SIZE];
- int class_device_register(struct class_device *cd);
- void class_device_unregister(struct class_device *cd);
- int class_device_renmae(struct class_device *cd, char *new_name);
- struct class_device_attribute
- struct attribute attr;
- ssize_t (*show) (struct class_device *cls, char *buf);
- ssize_t (*store) (struct class_device *cls, const char *buf, size_t count);
- CLASS_DEVICE_ATTR(name, mode, show, store);
- int class_deivce_create_file(struct class_device *cls, const struct class_device_attribute *attr);
- void class_device_remove_file(struct class_device *cls, const struct class_device_attribute *attr);
- strict class_device
- 类接口
- struct class_interface
- struct class *class;
- int (*add) (struct class_device *cd);
- void (*remove) (struct class_device *cd);
- int class_interface_register(struct class_interface *intf);
- void class_interface_unregister(struct class_interface *intf);
- struct class_interface
- 管理类
- 各环节的整合
- 加入一个设备
- PCI子系统声明了一个bus_type结构,称为pci_bus_type
- struct bus_type pci_bus_type
- .name = “pci”,
- .match = pci_bus_match,
- .hotplug = pci_hotplug,
- .suspend = pci_device_suspend,
- .resume = pci_device_resume,
- .dev_attrs = pci_dev_attrs,
- struct bus_type pci_bus_type
- 注冊后,将会创建一个sysfs文件夹/sys/bus/pci,当中包括了两个文件夹:devices和drivers
- 全部的PCI驱动程序都必须定义一个pci_driver结构变量。这个结构中包括了一个device_driver结构,在注冊PCI驱动程序时,这个结构将被初始化
- drv->driver.name = drv->name;
- drv->driver.bus = &pci_bus_type;
- drv->driver.probe = pci_device_probe;
- drv->driver.remove = pci_device_remove;
- drv->driver.kobj.ktype = &pci_deiver_kobj_type;
- error = driver_register(&drv->driver);
- 当一个PCI设备被找到时,PCI核心在内存中创建一个pci_dev类型的结构变量
- struct pci_dev
- unsigned int devfn;
- unsigned short vendor;
- unsigned short device;
- unsigned short subsystem_vendor;
- unsigned short subsystem_device;
- unsigned int class;
- struct pci_driver *driver;
- struct device dev;
- 初始化时,device结构变量的parent变量被设置为PCI设备所在的总线设备
- struct pci_dev
- device_register(&dev->dev);
- device_register函数中。驱动程序核心向kobject核心注冊设备的kobject
- 接着设备将被加入到与总线相关的全部设备链表中,遍历这个链表,而且为每一个驱动程序调用该总线的match函数,同一时候指定该设备
- 假设匹配工作圆满完毕,函数向驱动程序核心返回1。驱动程序核心将device结构中的driver指针指向这个驱动程序,然后调用device_driver结构中指定的probe函数
- PCI子系统声明了一个bus_type结构,称为pci_bus_type
- 删除设备
- 调用pci_remove_bus_device函数
- 该函数做些PCI相关的清理工作,然后使用指向pci_dev中的device结构的指针。调用device_unregister函数
- device_unregister函数中。驱动程序核心仅仅是删除了从绑定设备的驱动程序到sysfs文件的符号链接,从内部设备链表中删除了该设备,而且以device结构中的kobject结构指针为參数,调用kobject_del函数
- kobject_del函数删除了设备的kobject引用,假设该引用是最后一个,就要调用该PCI设备的release函数
- 加入驱动程序
- 调用pci_register_driver函数时,一个PCI驱动程序被加入到PCI核心中
- 该函数仅仅是初始化了包括在pci_driver结构中的device_driver结构
- PCI核心用包括在pci_driver结构的device_driver结构指针作为參数。在驱动程序核心内调用driver_register函数
- driver_reigster函数初始化了几个device_driver中的锁。然后调用bus_add_driver函数,该函数按下面步骤操作
- 查找与驱动程序相关的总线
- 依据驱动程序的名字以及相关的总线。创建驱动程序的sysfs文件夹
- 获取总线内部的锁,接着遍历全部向总线注冊的设备。为这些设备调用match函数
- 删除驱动程序
- 调用pci_unregister_driver函数
- 该函数用包括在pci_driver结构中的device_driver结构作为參数。调用驱动程序核心函数driver_unregister
- driver_unregister函数清除在sysfs树中属于驱动程序的sysfs属性
- 遍历全部属于该驱动程序的设备,并为其调用release函数
- 加入一个设备
- 处理固件
- 将固件代码放入驱动程序会使驱动程序代码膨胀,使得固件升级困难,并easy导致许可证问题
- 不要把包括固件的驱动程序放入内核。或者包括在Linux发行版中
- 内核固件接口
- <linux/firmware.h>
- int request_firmware(const struct firmware **fw, char *name, struct device *device);
- struct firmware
- size_t size;
- u8 *data;
- void release_firmware(struct firmware *fw);
- int request_firmware_nowait(struct module *module, char *name, struct device *device, void *context, void (*cont)(const struct firmware *fw, void *context));
- <linux/firmware.h>
- 工作原理
- 固件子系统使用sysfs和热插拔机制工作
- 调用request_firmware时,在/sys/class/firmware下将创建一个文件夹。该文件夹使用设备名作为它的文件夹名。该文件夹包括三个属性
- loading
- 由负责装载固件的用户空间进程设置为1
- data
- 是一个二进制属性,用来接收固件数据
- device
- 该属性是到/sys/devices下对应入口的符号链接
- loading
- 一旦sysfs入口被创建,内核将为设备产生热插拔事件,传递给热插拔处理程序的环境包含一个FIRMWARE变量。它将设置为提供给request_firmware的名字
- 处理程序定位固件文件。使用所提供的属性把固件文件复制到内核,假设不能发现固件文件,处理程序将设置loading属性为-1
- 假设在10秒钟之内不能为固件的请求提供服务。内核将放弃努力并向驱动程序返回错误状态,这个超时值能够通过改动sysfs属性/sys/class/firmware/timeout来改变
- 不能在没有制造商许可的情况下发行设固件准备
版权声明:本文博客原创文章,博客,未经同意,不得转载。
《Linux Device Drivers》第十四章 Linux 设备型号的更多相关文章
- 《Linux Device Drivers》 第十七章 网络驱动程序——note
基本介绍 第三类是标准的网络接口Linux设备,本章介绍的内核,其余的交互网络接口描述 网络接口,必须使用特定的内核数据结构本身注册,与外部分组交换数据线打电话时准备 经常使用的文件上的网络接口操作是 ...
- 《Linux Device Drivers》第十一章 核心数据类型——note
基本介绍 因为Linux多平台特性,不管是哪一个重要驱动力应该是便携 与内核代码相关的核心问题应该是访问的同时是数据项的已知长度.能力和利用不同的处理器 内核使用的数据类型主要分为三类 类似int这种 ...
- 第三十四章 Linux常规练习题(一)参考答案
一.练习题一 1.超级用户(管理员用户)提示符是___#_,普通用户提示符是___$_. 2.linux关机重启的命令有哪些 ? 关机命令 重启命令 shutdown -h now shutdown ...
- 鸟哥的Linux私房菜——第十四章:Bash Shell
视频链接:http://www.bilibili.com/video/av10094012/ 本章目录: 1. Bash shell1.1 什么是 shell ? (我们通过shell与Kernel核 ...
- linux高级管理第十四章--kvm虚拟化
案例 安装kvm所需软件 验证 注:虚拟机要开启虚拟引擎 开启服务 环境准备 安装相关软件包 启动 创建网桥 重启,reboot 安装虚拟机 完成.
- 第十四章 Linux三剑客之老大—awk
一.awk # 擅长取列 计算 数组 函数 编程语言 内部命令 内部变量 NR #行号 $0 #完整的一行内容 $n # n 是数字 表示取出第几列 多列用逗号分割 -F #FS 分隔符的变量 NF ...
- Linux系列教程(十四)——Linux用户和用户组管理之相关配置文件
前面我们介绍了软件包管理.首先介绍了rpm包的相关命令,但是我们发现直接安装rpm包会被其依赖性折磨的不行,然后解决办法是yum在线管理,通过yum命令安装rpm包能自动帮助我们解决依赖性.最后又介绍 ...
- 《Linux命令行与shell脚本编程大全》 第十四章 学习笔记
第十四章:呈现数据 理解输入与输出 标准文件描述符 文件描述符 缩写 描述 0 STDIN 标准输入 1 STDOUT 标准输出 2 STDERR 标准错误 1.STDIN 代表标准输入.对于终端界面 ...
- linux基础-第十四单元 Linux网络原理及基础设置
第十四单元 Linux网络原理及基础设置 三种网卡模式图 使用ifconfig命令来维护网络 ifconfig命令的功能 ifconfig命令的用法举例 使用ifup和ifdown命令启动和停止网卡 ...
随机推荐
- 【Cocos2d-x 粒子系统】火球用手指飞起来
程序: 创建球 sp1 = CCSprite::create("ball.png"); sp1->setPosition(ccp(10, visibleSize.height ...
- postgresql数据库配置csv格式的日志输出
postgresql数据库配置csv格风格日志输出 以下介绍postgresql数据库中关于csv格式日志(pg中一种比較具体的日志输出方式)的设置方法. 1.进入$PGDATA文件夹(pg的安装文件 ...
- Spring与Hibernate整合中,使用OpenSessionInViewFilter后出现sessionFactory未注入问题
近期在知乎看到一句话,保持学习的有一种是你看到了很多其它的牛人,不甘心,真的不甘心. Spring和hibernate整合的时候,jsp页面做展现,发现展现属性出现: org.apache.jaspe ...
- ALSA安装编程指南
ALSA全指南 一.什么是ALSA ALSA是Advanced Linux Sound Architecture,高级Linux声音架构的简称,它在Linux操作系统上提供了音频和MIDI(Mu ...
- Java Web整合开发(80) -- EJB & WebService
1. jdk-6u18-windows-i586-p.execlasspath: .;%JAVA_HOME%lib/tools.jar;%JAVA_HOME%lib/dt.jar;%JAVA_HOME ...
- 【Nginx】开发一个简单的HTTP模块
首先来分析一下HTTP模块是怎样介入Nginx的. 当master进程fork出若干个workr子进程后,每一个worker子进程都会在自己的for死循环中不断调用事件模块: for ( ;; ) { ...
- 《反project核心原则》说明
致亲爱的中国读者: 大家好 !我是<逆向project核心原理> 作者 李承远(ReverseCore). (韩文博客地址:www.reversecore.com) 首先.非常高兴我的 ...
- 【Linux探索之旅】第一部分第五课:Unity桌面,人生若只如初见
内容简介 1.第一部分第五课:Unity桌面,人生若只如初见 2.第一部分第六课预告:Linux如何安装在虚拟机中 Unity桌面,人生若只如初见 不容易啊,经过了前几课的学习,我们认识了Linux是 ...
- WebService 用户名密码验证
原文:WebService 用户名密码验证 在项目开发的过程中,WebService是经常要用的,当调用WebService方法时,需要经过服务的验证才可以调用,一般就是用户名/密码验证,还有一个就是 ...
- SQLServer2008-2012资源及性能监控—CPU使用率监控具体解释
前言: CPU是server中最重要的资源.在数据库server中,CPU的使用情况应该时刻监控以便SQLServer一直处于最佳状态. 本文将会使用可靠性和性能监视器来获取CPU相关的使用统计信息 ...