Linux设备模型:基础篇
linux提供了新的设备模型:总线(bus)、设备(device)、驱动(driver)。其中总线是处理器与设备之间通道,在设备模型中,所有的设备都通过总线相连;设备是对于一个设备的详细信息描述,驱动是设备的相关驱动。其基本关系如下:bus 相当于一个容器,是device 和device_driver 的管理机构,它包含了一个device 集合和一个driver 集合。其中,device集合包含了挂在该总线下的所有设备,这些设备通过链表链接起来;driver集合包含了挂在该总线下的所有驱动程序,这些驱动程序通过链表链接起来。
sysfs文件系统:
sysfs文件系统是Linux2.6内核引入的,它被看成是与proc、devfs和devpty等同类别的文件系统,sysfs文件系统也是一个虚拟文件系统,它可以产生一个包括所有系统硬件的层级视图,与提供进程和状态信息的proc文件系统十分类似;
sysfs文件系统把链接在系统上的所有设备和总线组织成一个分级的文件系统,它们可以由用户空间存取,并向用户空间导出内核数据结构以及它们的属性等信息.sysfs的一个目的就是展示设备驱动模型中各个组件的层次关系,其顶级目录包括:
1、block:包含系统中所有的块设备;
2、devices:包含系统中所有的设备,并根据设备挂载的总线类型组织成层次关系结构;
3、bus:包含系统中所有的总线类型;
4、drivers:包含系统内核中所有已经注册的设备驱动程序;
5、class:包含系统中所有的设备类型;如,网卡设备、声卡设备、输入设备、输出设备,等等;
设备模型:
从整体上描述,大概模型就如下图所示:

从图中可以看出,Linux设备模型就是"总线、设备、驱动、类"这四个概念之前的相互关系;这也是Linux2.6内核抽象出来的用于管理系统中所有设备的模型图;
简单地描述设备模型的层次关系如下:
1、驱动核心中可以注册多种类型的总线(bus_type);
2、每一种类型的总线下面可以挂载许多设备(kset,device);
3、每一种类型的总线可以使用很多设备驱动(kset,device_driver);
4、每一个驱动程序可以管理一组设备;
这种基本关系的建立源于实际系统中各种总线、设备、驱动、类结构的抽象;
Linux设备模型中的总线、设备、驱动和类之间环环相扣的复杂关系可以满足内核日益发展的的需要;对智能电源管理、热插拔以及即插即用的支持要求也越来越高;
1、关于总线bus
(1)bus的结构体
struct bus_type,该结构体中有个函数指针成员:int (*match)(struct device * dev, struct device_driver * drv); 这个函数指针非常重要,当一个新的设备或驱动被添加到一个总线时会被调用,是建立总线上设备与驱动的桥梁。
(2)总线的操作:
注册:int bus_register(struct bus_type * bus)
注销:void bus_unregister(struct bus_type *bus);
(3)总线属性 bus_attribute
struct bus_attribute BUS_ATTR(name, mode, show, store);
这个宏声明一个结构, 产生它的名子通过前缀字符串 bus_attr_ 到给定的名字(bus_attr_name),然后利用bus_create_file来创建总线属性
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);
参数中的attr,即为bus_attr_name。
2、关于device
(1)在底层,一个设备对于一个设备结构体struct device
(2)设备的操作
注册设备:int device_register(sruct device *dev)
注销设备:void device_unregister(struct device *dev);
(3)设备属性:
sysfs 中的设备入口可有属性. 相关的结构是:
struct device_attribute这个属性结构可在编译时建立, 使用宏:
DEVICE_ATTR(name, mode, show, store);
结果结构通过前缀 dev_attr_ 到给定名子上来命名. 属性文件的实际管理使用通常的函数对来处理:
int device_create_file(struct device *device, struct device_attribute *entry);
void device_remove_file(struct device *dev, struct device_attribute *attr);
3、关于driver
(1)driver结构体为struct device_driver
(2)驱动程序的操作
驱动程序的注册int driver_register(struct device_driver *drv);
驱动程序的注销void driver_unregister(struct device_driver *drv);
(3)驱动程序的属性
struct driver_attribute DRIVER_ATTR(_name,_mode,_show,_store) /*属性文件创建的方法:*/
int driver_create_file(struct device_driver * drv, struct driver_attribute * attr);//创建设备驱动的属性
void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr);//删除设备驱动的属性
简单例子:
/* my_bus.h */
extern struct bus_type my_bus_type;
struct my_driver {
char *version;
struct module *module;
struct device_driver driver;
struct driver_attribute version_attr;
};
#define to_my_driver(drv) container_of(drv, struct my_driver, driver) struct my_device {
char *name;
struct my_driver *driver;
struct device device;
};
#define to_my_device(dev) container_of(dev, struct my_device, device) /* interface to device. */
extern int register_my_device(struct my_device *);
extern void unregister_my_device(struct my_device *); /* interface to driver. */
extern int register_my_driver(struct my_driver *);
extern void unregister_my_driver(struct my_driver *); /* my_bus.c */
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include "my_bus.h" MODULE_LICENSE("Dual BSD/GPL"); #define MYBUS "mybus: "
#define PRINT(x...) printk(KERN_ALERT MYBUS x); static char *Version = "$Revision: 1.9 $"; static ssize_t show_bus_version(struct bus_type *bus, char *buf)
{
PRINT("%s\n", __func__);
return snprintf(buf, PAGE_SIZE, "my_bus: %s\n", Version);
} static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL); static void my_bus_release(struct device *dev)
{
PRINT("%s\n", __func__);
} static int my_bus_match(struct device *dev, struct device_driver *drv)
{
struct my_device *device = to_my_device(dev);
PRINT("%s\n", __func__);
return !strncmp(device->name, drv->name, strlen(drv->name));
} static int my_bus_hotplug(struct device *dev, struct kobj_uevent_env *env){
PRINT("%s\n", __func__);
return ;
} struct bus_type my_bus_type = {
.name = "my_bus",
.match = my_bus_match,
.uevent = my_bus_hotplug
}; static struct device my_bus = {
.init_name = "my_bus0",
.release = my_bus_release
}; /* interface to device. */
int register_my_device(struct my_device *device)
{
PRINT("%s\n", __func__);
device->device.bus = &my_bus_type;
device->device.parent = &my_bus;
device->device.release = my_bus_release;
//strncpy(device->device.bus_id, device->name, BUS_ID_SIZE);
return device_register(&device->device);
}
EXPORT_SYMBOL(register_my_device); void unregister_my_device(struct my_device *device)
{
PRINT("%s\n", __func__);
device_unregister(&device->device);
}
EXPORT_SYMBOL(unregister_my_device); static ssize_t show_version(struct device_driver *driver, char *buf)
{
struct my_driver *drv = to_my_driver(driver);
PRINT("%s\n", __func__);
sprintf(buf, "%s\n", drv->version);
return strlen(buf);
} /* interface to driver. */
int register_my_driver(struct my_driver *driver)
{
int ret = ;
PRINT("%s\n", __func__);
driver->driver.bus = &my_bus_type;
ret = driver_register(&driver->driver);
if (ret) {
PRINT("%s, driver_register %s failed!!!\n", __func__, driver->driver.name);
return ret;
}
driver->version_attr.attr.name = "version";
//driver->version_attr.attr.owner = driver->module;
driver->version_attr.attr.mode = S_IRUGO;
driver->version_attr.show = show_version;
return driver_create_file(&driver->driver, &driver->version_attr);
}
EXPORT_SYMBOL(register_my_driver); void unregister_my_driver(struct my_driver *driver)
{
PRINT("%s\n", __func__);
driver_unregister(&driver->driver);
}
EXPORT_SYMBOL(unregister_my_driver); static int __init my_bus_init(void)
{
int ret = ;
ret = bus_register(&my_bus_type);
if (ret) {
PRINT("%s, bus_register failed!\n", __func__);
goto bus_register_failed;
}
ret = bus_create_file(&my_bus_type, &bus_attr_version);
if (ret) {
PRINT("%s, bus_create_file failure...!\n", __func__);
goto bus_create_file_failed;
}
ret = device_register(&my_bus);
if (ret) {
PRINT("%s, device_register failure...!\n", __func__);
goto device_register_failed;
}
PRINT("%s, bus & device register succeed!\n", __func__);
return ;
device_register_failed:
bus_create_file_failed:
bus_unregister(&my_bus_type);
bus_register_failed:
return ret;
} static void __exit my_bus_exit(void)
{
PRINT("%s!\n", __func__);
device_unregister(&my_bus);
bus_unregister(&my_bus_type);
} module_init(my_bus_init);
module_exit(my_bus_exit); /* 我的设备 my_device.c */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include "my_bus.h"
#define MYDEVICE "my-device: "
#define PRINT(x...) printk(KERN_ALERT MYDEVICE x); MODULE_LICENSE("Dual BSD/GPL"); static struct my_device device =
{
.name = "hunk_device",
.device = {
.init_name = "my_device",
}
}; static int __init my_device_init(void)
{
int ret = ;
PRINT("%s\n", __func__);
ret = register_my_device(&device);
if (ret) {
PRINT("%s failure..!\n", __func__);
return ret;
}
return ;
} static void __exit my_device_exit(void)
{
PRINT("%s\n", __func__);
unregister_my_device(&device);
} module_init(my_device_init);
module_exit(my_device_exit); /* 我的驱动 my_driver.c */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include "my_bus.h"
#define MYDRIVER "my-driver: "
#define PRINT(x...) printk(KERN_ALERT MYDRIVER x); MODULE_LICENSE("Dual BSD/GPL"); static struct my_driver driver =
{
.module = THIS_MODULE,
.driver = {
.name = "hunk_device",
.owner = THIS_MODULE
}
}; static int __init my_driver_init(void)
{
int ret = ;
PRINT("%s\n", __func__);
ret = register_my_driver(&device);
if (ret) {
PRINT("%s failure..!\n", __func__);
return ret;
}
return ;
} static void __exit my_driver_exit(void)
{
PRINT("%s\n", __func__);
unregister_my_driver(&device);
} module_init(my_driver_init);
module_exit(my_driver_exit);
Linux设备模型:基础篇的更多相关文章
- Linux 设备模型浅析之 uevent 篇(2)
Linux 设备模型浅析之 uevent 篇 本文属本人原创,欢迎转载,转载请注明出处.由于个人的见识和能力有限,不可能面 面俱到,也可能存在谬误,敬请网友指出,本人的邮箱是 yzq.seen@gma ...
- linux设备模型:扩展篇
Linux设备模型组件:总线 一.定义:总线是不同IC器件之间相互通讯的通道;在计算机中,一个总线就是处理器与一个或多个不同外设之间的通讯通道;为了设备模型的目的,所有的设备都通过总线相互连接,甚至 ...
- Linux设备模型之kobject
阿辉原创,转载请注明出处 参考文档:LDD3-ch14.内核文档Documentation/kobject.txt,本文中使用到的代码均摘自Linux-3.4.75 ----------------- ...
- linux设备模型_转
建议原博文查看,效果更佳. 转自:http://www.cnblogs.com/wwang/category/269350.html Linux设备模型 (1) 随着计算机的周边外设越来越丰富,设备管 ...
- Linux设备模型 学习总结
看LDD3中设备模型一章,觉得思维有些混乱.这里从整体的角度来理理思路.本文从四个方面来总结一些内容: 1.底层数据结构:kobject,kset.2.linux设备模型层次关系:bus_type,d ...
- Linux设备模型——设备驱动模型和sysfs文件系统解读
本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的.在分析过程中,本文将以platform总线和spi主控制器的 ...
- Linux 设备模型之 (kobject、kset 和 Subsystem)(二)
问题描写叙述:前文我们知道了/sys是包括内核和驱动的实施信息的,用户能够通过 /sys 这个接口.用户通过这个接口能够一览内核设备的全貌.本文将从Linux内核的角度来看一看这个设备模型是怎样构建的 ...
- Linux设备模型(总结)
转:http://www.360doc.com/content/11/1219/16/1299815_173418267.shtml 看了一段时间的驱动编程,从LDD3的hello wrod到后来的字 ...
- Linux设备模型(热插拔、mdev 与 firmware)【转】
转自:http://www.cnblogs.com/hnrainll/archive/2011/06/10/2077469.html 转自:http://blog.chinaunix.net/spac ...
随机推荐
- (转)Eclipse配置GitHub代码库(以Windows7为例)
原文地址:http://blog.csdn.net/twlkyao/article/details/26340685 1.安装Git 首先安装git.这里只讲Windows环境下安装Git方法. 从G ...
- 第二节,TensorFlow 使用前馈神经网络实现手写数字识别
一 感知器 感知器学习笔记:https://blog.csdn.net/liyuanbhu/article/details/51622695 感知器(Perceptron)是二分类的线性分类模型,其输 ...
- vs2013配置opencv2.4.13
此方法配置简单,方便易行,解压opencv2.4.13后得到opencv文件夹,进行如下步骤: 1.添加环境变量 用户变量,新建,变量名opencv,值D:\opencv\build 系统变量,Pat ...
- 1.C和C++的区别
C和C++的区别 C语言语法简单,但使用不易 C++语法非常庞大复杂,但使用方便,更注重的是它的编程思想(面向对象). 一.第一个C++程序 1.文件扩展名 C++源文件扩展名 .cpp,C ...
- (大数)Computer Transformation hdu1041
Computer Transformation Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/ ...
- Windows计划任务提示 0xE0434352 错误
写了一个计划任务每周去跑一个程序,但是并没有跑,报错是 0xE0434352,应该是没有找到路径(计划任务这么菜的吗)... 解决办法:双击启动程序 写上你当前程序的起始路径 然后在运行一下,就成功了
- 使用MedleyText与Syncthink自建云笔记
随着学习加深,做的笔记越来越多,而使用云笔记怕万一平台关闭(如360网盘啥的)还需要导出笔记费时费力,并且多平台兼容性未知.还是自己搭建放心省事. MedleyText介绍 MedleyText为ma ...
- Dubbo协议
参考dubbo官方文档http://dubbo.apache.org/zh-cn/docs/user/references/protocol/dubbo.html dubbo共支持如下几种通信协议: ...
- ELF文件解析(二):ELF header详解
上一篇讲了ELF文件的总体布局,以及section和segment的概念.按照计划,今天继续讲 ELF header. 讲新的内容之前,先更正一个错误:上一篇中讲section header tabl ...
- beef框架使用
http://resources.infosecinstitute.com/beef-part-2/ http://resources.infosecinstitute.com/beef-part-1 ...