虽然看了上面一篇转载的《使用/sys/访问系统》对总线,驱动,设备都讲得比较细但还是没有太多的感觉。在此就先把自己今天所学回忆一下。

为了满足新的要求,linux2.6提供了新的设备模型:总线、驱动、设备。基本关系简要的概括如下:
驱动核心可以注册多种类型的总线。
每种总线下面可以挂载许多设备。(通过kset devices)
每种总线下可以用很多设备驱动。(通过包含一个kset drivers)}
每个驱动可以处理一组设备。按照我的理解就是所有的设备都挂载到总线上,当加载驱动时,驱动就支总线上找到自己对应的设备。或者先把驱动加载上,来了一个设备就去总线找驱动。

一:总线

  总线是处理器与设备之间通道,在设备模型中,所有的设备都通过总线相连

(1)bus_type.
struct bus_type {
 const char  * name;//设备名称

struct bus_type {
 const char  * name;//设备名称

 struct subsystem subsys;//代表自身
 struct kset  drivers;   //当前总线的设备驱动集合
 struct kset  devices; //所有设备集合
 struct klist  klist_devices;
 struct klist  klist_drivers;

 struct bus_attribute * bus_attrs;//总线属性
 struct device_attribute * dev_attrs;//设备属性
 struct driver_attribute * drv_attrs;

 int  (*match)(struct device * dev, struct device_driver * drv);//设备驱动匹配函数
 int  (*uevent)(struct device *dev, char **envp,   
      int num_envp, char *buffer, int buffer_size);//热拔插事件
 int  (*probe)(struct device * dev);
 int  (*remove)(struct device * dev);
 void  (*shutdown)(struct device * dev);
 int  (*suspend)(struct device * dev, pm_message_t state);
 int  (*resume)(struct device * dev);
};

在后面的实例当中用到了里面的两个成员

1:const char *name;

2: 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 {
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);
};
BUS_ATTR(name, mode, show, store);
这个宏声明一个结构, 产生它的名子通过前缀字符串 bus_attr_ 到给定的名子.
任何属于一个总线的属性应当明确使用 bus_create_file 来创建:
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr); 
属性也可被去除, 使用:
void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr); 
lddbus 驱动创建一个简单属性文件, 再次, 包含源码版本号. show 方法和 bus_attribute 结构设置如下:
static ssize_t show_bus_version(struct bus_type *bus, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", Version);
}
这个总线属性现目前为止我还没有发现它的作用。

(4)总线实例:

其实在这个程序中操作很简单:

1:首先是要准备一个总线bus_type.也就是定义一个bus_type,然后给它填上一些成员。

定义如下:

struct bus_type my_bus_type = {
 .name = "my_bus",
 .match = my_match,
};

这里就对其两个成员赋值了。一个是名称。另一个则是匹配函数:

static int my_match(struct device *dev, struct device_driver *driver)
{
 return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
}

这是匹配的逻辑则是设备的名字与驱动的名字一样。

准备好了总线后就在模块初始化函数中注册:

        /*注册总线*/
 ret = bus_register(&my_bus_type);
 if (ret)
  return ret;

然后在模块退出函数中注解总线:

总线操作完后还要为总线创建属性文件:

static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);这句话就定义了一个总线属性文件。BUS_ATTR宏的定义如下:

bus_unregister(&my_bus_type);

#define BUS_ATTR(_name, _mode, _show, _store) \
struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)

show_bus_version定义如下:

static ssize_t show_bus_version(struct bus_type *bus, char *buf)
{
 return snprintf(buf, PAGE_SIZE, "%s\n", Version);
}

定义好之后就是调用 函数创建文件

 /*创建属性文件*/ 
 if (bus_create_file(&my_bus_type, &bus_attr_version))
  printk(KERN_NOTICE "Fail to create version attribute!\n");

总线本身也是要对应一个设备的。还要为总线创建设备。

static void my_bus_release(struct device *dev)
{
 printk(KERN_DEBUG "my bus release\n");
}
 
struct device my_bus = {
 .bus_id   = "my_bus0",
 .release  = my_bus_release
};

 /*注册总线设备*/
 ret = device_register(&my_bus);
 if (ret)
  printk(KERN_NOTICE "Fail to register device:my_bus!\n");

可是这是有疑问,我还没有找到这个总线设备,和刚才的总线的联系。

源代码:

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>

MODULE_AUTHOR("David Xie");
MODULE_LICENSE("Dual BSD/GPL");

static char *Version = "$Revision: 1.9 $";

static int my_match(struct device *dev, struct device_driver *driver)
{
 return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
}

static void my_bus_release(struct device *dev)
{
 printk(KERN_DEBUG "my bus release\n");
}
 
struct device my_bus = {
 .bus_id   = "my_bus0",
 .release  = my_bus_release
};

struct bus_type my_bus_type = {
 .name = "my_bus",
 .match = my_match,
};

EXPORT_SYMBOL(my_bus);
EXPORT_SYMBOL(my_bus_type);

/*
 * Export a simple attribute.
 */
static ssize_t show_bus_version(struct bus_type *bus, char *buf)
{
 return snprintf(buf, PAGE_SIZE, "%s\n", Version);
}

static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);

static int __init my_bus_init(void)
{
 int ret;
        
        /*注册总线*/
 ret = bus_register(&my_bus_type);
 if (ret)
  return ret;
  
 /*创建属性文件*/ 
 if (bus_create_file(&my_bus_type, &bus_attr_version))
  printk(KERN_NOTICE "Fail to create version attribute!\n");
 
 /*注册总线设备*/
 ret = device_register(&my_bus);
 if (ret)
  printk(KERN_NOTICE "Fail to register device:my_bus!\n");
  
 return ret;
}

static void my_bus_exit(void)
{
 device_unregister(&my_bus);
 bus_unregister(&my_bus_type);
}

module_init(my_bus_init);
module_exit(my_bus_exit);

二:设备:

1:device结构体

struct device {

struct device  * parent; //父设备,一般一个bus也对应一个设备。
struct kobject kobj;//代表自身
char bus_id[BUS_ID_SIZE]; 
struct bus_type * bus;  /* 所属的总线 */
struct device_driver *driver; /* 匹配的驱动*/

void  *driver_data; /* data private to the driver 指向驱动 */
 void  *platform_data; /* Platform specific data,由驱动定义并使用*/

///更多字段忽略了

};

注册设备:int device_register(sruct device *dev)

注销设备:void device_unregister(struct device *dev);

2:设备属性:

sysfs 中的设备入口可有属性. 相关的结构是:
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);
结果结构通过前缀 dev_attr_ 到给定名子上来命名. 属性文件的实际管理使用通常的函数对来处理:
int device_create_file(struct device *device, struct device_attribute *entry);
void device_remove_file(struct device *dev, struct device_attribute *attr);
struct bus_type 的 dev_attrs 成员指向一个缺省的属性列表, 这些属性给添加到总线的每个设备创建.

3:创建设备实例:

创建设备和创建总线基本一样这里只贴出程序:

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>

MODULE_AUTHOR("David Xie");
MODULE_LICENSE("Dual BSD/GPL");

extern struct device my_bus; 
extern struct bus_type my_bus_type;

/* Why need this ?*/
static void my_dev_release(struct device *dev)

 
}

struct device my_dev = {
 .bus = &my_bus_type,//与总线接上关系 
 .parent = &my_bus,//与总线设备接上关系
 .release = my_dev_release,
};

/*
 * Export a simple attribute.
 */
static ssize_t mydev_show(struct device *dev,struct device_attribute *attr, char *buf)
{
 return sprintf(buf, "%s\n", "This is my device!");
}

static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);

static int __init my_device_init(void)
{
 int ret = 0;
        
        /* 初始化设备 */
 strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE);
        
        /*注册设备*/
 device_register(&my_dev);
  
 /*创建属性文件*/
 device_create_file(&my_dev, &dev_attr_dev);
 
 return ret;

}

static void my_device_exit(void)
{
 device_unregister(&my_dev);
}

module_init(my_device_init);
module_exit(my_device_exit);

三:设备驱动:

在总线上挂载了设备后就要为其准备驱动程序。

驱动程序的实现与设备的实现类似,代码如下:

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>

MODULE_AUTHOR("David Xie");
MODULE_LICENSE("Dual BSD/GPL");

extern struct bus_type my_bus_type;

static int my_probe(struct device *dev)
{
    printk("Driver found device which my driver can handle!\n");
    return 0;
}

static int my_remove(struct device *dev)
{
    printk("Driver found device unpluged!\n");
    return 0;
}

struct device_driver my_driver = {
 .name = "my_dev",//对应的设备名称
 .bus = &my_bus_type,//挂载的总线
 .probe = my_probe,//这个函数就是在找到与自己对应的设备时被调用。
        .remove = my_remove,
};

/*
 * Export a simple attribute.
 */
static ssize_t mydriver_show(struct device_driver *driver, char *buf)
{
 return sprintf(buf, "%s\n", "This is my driver!");
}

static DRIVER_ATTR(drv, S_IRUGO, mydriver_show, NULL);

static int __init my_driver_init(void)
{
 int ret = 0;
        
        /*注册驱动*/
 driver_register(&my_driver);
  
 /*创建属性文件*/
 driver_create_file(&my_driver, &driver_attr_drv);
 
 return ret;

}

static void my_driver_exit(void)
{
 driver_unregister(&my_driver);
}

module_init(my_driver_init);
module_exit(my_driver_exit);

LINUX设备模型BUS,DEVICE,DRIVER相关推荐

  1. linux设备模型bus,device,driver,(kobject、ktype、kset,bus_type、device、device_driver)

    1.1Linux设备驱动模型简介 1.什么是设备驱动模型 (1)类class.总线bus(负责将设备和驱动挂接起来).设备devices.驱动driver(可以看到在驱动源码中,不管是什么样的驱动,都 ...

  2. Linux设备模型、平台设备驱动、设备树(device tree)、GPIO子系统以及pinctrl子系统介绍

    文章目录 一.Linux设备模型介绍 (1)设备驱动模型总体介绍 (2)设备驱动模型文件表现 (3)设备驱动模型工作原理 [1]总线 [2]设备 [3]驱动 [4]注册流程 二.平台设备驱动介绍 (1 ...

  3. Linux设备模型(9)_device resource management ---devm申请空间【转】

    转自:http://www.wowotech.net/linux_kenrel/device_resource_management.html 1. 前言蜗蜗建议,每一个Linux驱动工程师,都能瞄一 ...

  4. Linux设备模型之platform设备

    Linux设备模型之platform设备 1. Platform模块的软件架构 2. Platform设备 2.1 platform_device原型 2.2 注册添加device 2.2.1 pla ...

  5. linux设备驱动目录,Linux设备模型(5)_device和device driver

    Linux设备模型(5)_device和device driver 作者:wowo 发布于:2014-4-2 19:28 分类:统一设备模型 1. 前言 device和device driver是Li ...

  6. linux设备驱动——bus、device、driver加载顺序与匹配流程

    文章目录 1. 前言 2. 概念 2.1. 数据结构 2.2. probe函数 3. bus.device.driver加载顺序 3.1. 加载方式 3.2. 加载顺序 4. device.drive ...

  7. linux设备模型:bus概念及pci_bus分析

    上一篇<<linux设备模型:kset及设备驱动抽象类(class)分析>>中分析了kset容器.class设备驱动抽象框架.class_kset用于类(class)的热插拔事 ...

  8. Linux设备模型(热插拔、mdev 与 firmware)

    转自:http://blog.chinaunix.net/space.php?uid=20543672&do=blog&cuid=460882 热插拔 有 2 个不同角度来看待热插拔: ...

  9. Linux通常把设备对象抽象为,linux 设备模型(1)

    设备模型(一) 一.概述 从2.6内核引入了sysfs文件系统,与proc, devfs, devpty同类别,属于虚拟的文件系统.目的是展示设备驱动模型中各组件的层次关系,第一层目录:block, ...

最新文章

  1. ubuntu LAMP安装
  2. 来来来!DD带大家一起赢台MacBook Pro回家过年!
  3. apache服务器配置证书方法!
  4. 《系统集成项目管理工程师》必背100个知识点-10项目可行性研究阶段
  5. spark sql 1.2.0 测试
  6. Asp.net中服务端控件事件是如何触发的(笔记)
  7. 一种业界通用的响应式布局解决方法
  8. oracle服务器重启后监听启动
  9. 前后端分离的思考与实践(二)
  10. Node.js Path 模块
  11. 【Python成长之路】Python爬虫 --requests库爬取网站乱码(\xe4\xb8\xb0\xe5\xa)的解决方法【华为云分享】
  12. 布局的几种方式(静态布局、自适应布局、流式布局、响应式布局、弹性布局)...
  13. 〖免杀〗.net程序一键免杀Win10 20H2 Defender
  14. QQ浏览器的历史记录在那 QQ浏览器查看浏览历史的方法
  15. 网页做服务器的监控界面,服务器监控页面
  16. idea光标移至行尾快捷键——End键不能移至行尾的解决办法
  17. CHD-5.3.6集群安装
  18. 产品设计如何鼓励用户上传头像?
  19. 今日早报,365资讯简报12条,热点新闻早知道
  20. 微信开通检测平台应如何选择?

热门文章

  1. boost::mpl模块实现set相关的测试程序
  2. boost::mp11::mp_rename相关用法的测试程序
  3. boost::filesystem模块Microsoft TCHAR 的使用示例的测试程序
  4. GDCM:gdcm::ImplicitDataElement的测试程序
  5. boost::convert模块实现算法的测试程序
  6. ITK:应用SIN图像过滤器
  7. ITK:轮廓空间对象
  8. VTK:PolyData之ThresholdCells
  9. VTK:图片之PickPixel
  10. OpenCV进口重建Import Reconstruction