当前位置: 首页 > wzjs >正文

网站建设 大公司今天合肥刚刚发生的重大新闻

网站建设 大公司,今天合肥刚刚发生的重大新闻,文化传播做网站推广吗,学习java网站开发文章目录 1、前言2、kset、kobject、kobj_type3、统一驱动模型3.1、总线(bus)3.2、设备(device)3.3、驱动(driver) 4、sysfs与热插拔5、子系统6、设备类7、总线与类的关系8、component框架 1、前言 学习参…

文章目录

  • 1、前言
  • 2、kset、kobject、kobj_type
  • 3、统一驱动模型
    • 3.1、总线(bus)
    • 3.2、设备(device)
    • 3.3、驱动(driver)
  • 4、sysfs与热插拔
  • 5、子系统
  • 6、设备类
  • 7、总线与类的关系
  • 8、component框架

1、前言

  1. 学习参考书籍:李山文的《Linux驱动开发进阶》
  2. 本文属于个人学习后的总结,不太具备教学功能。
  3. 之前写过一篇sysfs文件系统的应用,即如何创建/sys目录下的文件属性,可以参考:sysfs统一设备模型-CSDN博客
  4. 之前只知道内核根目录下有一个sys文件夹,又或许我们都尝试过类似的命令如echo 1 > /sys/leds/led0/brightness来控制一个led。然而实际上,sysfs文件系统远比想象的重要,在后续学习spi子系统、i2c子系统、热拔插管理等之前,都应该先对sysfs文件系统有一个深入的理解,sysfs文件系统可以说是一切的根基。

2、kset、kobject、kobj_type

这里引用书中原文,“在Linux中使用kobject表示内核对象,而每个对象有不同的类型——kobj_type,要将这些内核对象联系起来就需要使用粘合剂——kset。每个kobject必须要有类型,即必须有kobj_type,而kset则用来设置每个kobject之间的关系。”

kobject、kobj_type、kset在内核分别有三个数据结构来描述,可以自行在kernel源码中查看。分别是struct kobject、struct kobj_type、struct kset。

在目前这个阶段,我个人觉得倒不需要对这三个核心对象有多么深的理解,我们只需要知道,这个三个核心对象可以通过相关接口函数在/sys目录下创建文件夹和文件。而/sys目录下的这些文件夹和文件又可以清晰表示出内核中存在的总线、设备、驱动、类。

所以可以把这三个核心对象比喻成砖头,而sysfs文件系统是由这些砖头构造出的房子。同时在后续的学习中,会看到kobject、kobj_type、kset的身影的,这里不用纠结。

3、统一驱动模型

在linux中,驱动模型被分为总线(bus)、设备(device)、驱动(driver)三个部分。至于为什么分为这三个部分和计算机的结构有关系。以usb设备为例,当一个usb设备插入电脑时,计算机会通知有设备插入,告知计算机设备类、设备属性以及做一些热插拔相关的事情等。然而计算机对于每一个usb设备都是这样一个流程,因此Linux将其抽象出为一个总线(bus)。在计算机对usb设备枚举结束后,会加载其对应的设备驱动程序,这里的驱动程序就是驱动(driver)。设备就是支持usb协议的设备,在Linux3.x之后,所有设备的描述都在设备树中完成。

3.1、总线(bus)

我们常说的总线设备驱动模型,总线就是指的如platform bus,spi bus,i2c bus。

总线bus在内核中的结构体叫struct bus_type,通过bus_register()来注册总线。

如下是自定义的一个总线:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>            
#include <linux/device.h> 
#include <linux/kobject.h>   
#include <linux/sysfs.h>    static int bus_match(struct device *dev, struct device_driver *drv)
{printk(KERN_INFO"In %s \n", __func__);//match by driver name and device namereturn (strcmp(dev_name(dev), drv->name) == 0);
}static int bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{printk(KERN_INFO "%s hotplug\n",dev_name(dev));return add_uevent_var(env, "MODALIAS=%s", dev_name(dev));
}struct bus_type bus_test_type = {.name  = "bus-test",.match = bus_match,.uevent= bus_uevent,
};
EXPORT_SYMBOL(bus_test_type);static int init_bus_test(void)
{int ret = 0;printk(KERN_INFO "init bus module!\n");ret = bus_register(&bus_test_type);if (ret) {printk(KERN_ERR "bus_register error!\n");return ret;}return ret;
}static void exit_bus_test(void)
{bus_unregister(&bus_test_type);printk(KERN_INFO "exit bus module!\n");
}
module_init(init_bus_test);
module_exit(exit_bus_test);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("1477153217@qq.com");
MODULE_DESCRIPTION("bust test");

3.2、设备(device)

设备device在内核中的结构体叫struct device,通过device_register()来注册设备。

如下是注册一个设备的示例程序,设备注册成功后,会在/sys/devices目录下创建一个名为“dev_test”的文件夹。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>extern struct bus_type bus_test_type;static void dev_test_release(struct device *dev)
{}static struct device dev_test = {.init_name  = "dev_test",.bus        = &bus_test_type,  		// 总线必须初始化,用来与驱动进行匹配.release    = dev_test_release,
};static int __init init_dev_test(void)
{int ret = 0;ret = device_register(&dev_test);if(ret < 0){printk(KERN_ERR "device register error!\n");return ret;        }return ret;
}static void __exit exit_dev_test(void)
{device_unregister(&dev_test);
}module_init(init_dev_test);
module_exit(exit_dev_test);MODULE_LICENSE("GPL");
MODULE_AUTHOR("1477153217@qq.com");
MODULE_DESCRIPTION("device test");

3.3、驱动(driver)

驱动driver在内核中的结构体叫struct device_driver,通过driver_register()来注册设备。

如下是注册一个集合了总线、设备、驱动的示例程序:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>            
#include <linux/device.h> 
#include <linux/device/driver.h>
#include <linux/kobject.h>   
#include <linux/sysfs.h>    static int bus_match(struct device *dev, struct device_driver *drv)
{printk(KERN_INFO"In %s \n", __func__);//match by driver name and device namereturn (strcmp(dev_name(dev), drv->name) == 0);
}static int bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{printk(KERN_INFO "%s hotplug\n", dev_name(dev));return add_uevent_var(env, "MODALIAS=%s", dev_name(dev));
}static int bus_probe(struct device *dev)
{return dev->driver->probe(dev);return 0;
}static int bus_remove(struct device *dev)
{dev->driver->remove(dev);return 0;
}struct bus_type bus_test = 
{.name  = "bus-test",.match = bus_match,.uevent= bus_uevent,.probe = bus_probe,.remove= bus_remove,
};
EXPORT_SYMBOL(bus_test);static int driver_probe(struct device *dev)
{printk(KERN_INFO "driver probe!\n");return 0;
}static int driver_remove(struct device *dev)
{printk(KERN_INFO "driver remove!\n");return 0;
}static struct device_driver driver_test=
{.name = "driver_test",.bus  = &bus_test,.probe = driver_probe,.remove = driver_remove,
};static void dev_test_release(struct device *dev)
{printk(KERN_INFO "device release!\n");
}static struct device dev_test = {.init_name  = "driver_test",.bus        = &bus_test, .release    = dev_test_release,
};static int __init init_driver_test(void)
{int ret = 0;printk(KERN_INFO "init module!\n");ret = bus_register(&bus_test);if (ret) {printk(KERN_ERR "bus register error!\n");return ret;}ret = device_register(&dev_test);if(ret){printk(KERN_ERR "device register error!\n");return ret;        }ret = driver_register(&driver_test);if (ret) {printk(KERN_ERR "driver register error!\n");return ret;}return ret;
}static void __exit exit_driver_test(void)
{driver_unregister(&driver_test);device_unregister(&dev_test);bus_unregister(&bus_test);printk(KERN_INFO "exit module!\n");
}
module_init(init_driver_test);
module_exit(exit_driver_test);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("1477153217@qq.com");
MODULE_DESCRIPTION("driver test");

通常,我们只会实现bus中的probe、remove函数,不会实现driver中的probe、remove函数。但在通常的印象中,我们在编写总线设备驱动时,不是一直都有实现自己的probe和remove函数吗?其实不然,我们只是在自己的结构体中实现了probe和remove,举例如下:

定义自己的driver结构体vm_test_driver,其中包含了device_driver、probe、remove:

实现自己的probe函数:

初始化vm_test_driver结构体:

在bus probe中调用vm_test_driver的probe:

再举个例子,如编写一个i2c设备驱动程序时,这里的i2c_driver也是一个自己的结构体:

4、sysfs与热插拔

Linux热插拔机制依赖于sysfs和devtmpfs这两个文件系统,其中sysfs最为重要。在上面的总线bus示例程序中,bus->uevent函数如下:

static int bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{printk(KERN_INFO "%s hotplug\n", dev_name(dev));return add_uevent_var(env, "MODALIAS=%s", dev_name(dev));
}

这里会将MODALIAS环境变量发送到用户空间,此时udev就可以监听到该值,同时可以通过相应的udev规则来执行相应的动作。具体的热插拔管理会在后续章节继续学习。

5、子系统

在linux中有很多子系统,如spi子系统,i2c子系统,led子系统等。在/sys/class目录下,一个文件夹就代表了一个子系统。相关结构体为struct subsys_private。所有的总线或类实际上就是一个子系统,例如当注册一个spi总线时,此时就会分配一个子系统结构体。

注册类时,也会分配一个subsys_private结构体:

下图展示了subsys_private与bus和class的关系(图片来自李山文的《Linux驱动开发进阶》):

6、设备类

如果有100个设备,那100设备的加入会使/sys/devices目录变得凌乱。为了更清晰的管理设备,linux内核引入了device class,即设备类。设备类可以把具有相同特性的设备归为一类,例如键盘鼠标触摸屏可以归为输入设备。

7、总线与类的关系

(图片来自李山文的《Linux驱动开发进阶》):

下面模拟类似的总线驱动、总线设备、总线子设备、设备、设备驱动之间的关系:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>            
#include <linux/device.h> 
#include <linux/device/driver.h>
#include <linux/kobject.h>   
#include <linux/sysfs.h>    struct class  dummy_class = {.name		= "dummy_master",.owner		= THIS_MODULE,
};static int bus_match(struct device *dev, struct device_driver *drv)
{printk(KERN_INFO"In %s \n", __func__);//match by driver name and device namereturn (strcmp(dev_name(dev), drv->name) == 0);
}static int bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{int ret;printk(KERN_INFO "%s hotplug\n", dev_name(dev));ret = add_uevent_var(env, "THIS_TEST=%s", dev_name(dev));if(ret){return ret;}return add_uevent_var(env, "DEMO=%s", "bus-class-test");
}static int bus_probe(struct device *dev)
{return dev->driver->probe(dev);return 0;
}static int bus_remove(struct device *dev)
{dev->driver->remove(dev);return 0;
}struct bus_type dummy_bus_type = 
{.name  = "dummy_bus",.match = bus_match,.uevent= bus_uevent,.probe = bus_probe,.remove= bus_remove,
};
EXPORT_SYMBOL(dummy_bus_type);static int driver_probe(struct device *dev)
{printk(KERN_INFO "driver probe!\n");return 0;
}static int driver_remove(struct device *dev)
{printk(KERN_INFO "driver remove!\n");return 0;
}static struct device_driver dummy_controller_drv=
{.name = "dummy_controller",.bus  = &dummy_bus_type,.probe = driver_probe,.remove = driver_remove,
};static void dev_release(struct device *dev)
{printk(KERN_INFO "device release!\n");
}static struct device dummy_controller_dev = {.init_name  = "dummy_controller",.bus        = &dummy_bus_type,.release    = dev_release,
};static struct device dummy_0 = {.init_name  = "dummy_0",.release    = dev_release,
};static struct device_driver dummy_device_drv=
{.name = "dummy_device",.bus  = &dummy_bus_type,.probe = driver_probe,.remove = driver_remove,
};static struct device dummy_device_dev = {.init_name  = "dummy_device",.release    = dev_release,
};static int __init init_test(void)
{int ret = 0;printk(KERN_INFO "init module!\n");ret = class_register(&dummy_class);if(ret){printk(KERN_ERR "dummy_class register error!\n");return ret;}ret = bus_register(&dummy_bus_type);			// 注册总线(可以比喻成spi总线)if (ret) {printk(KERN_ERR "dummy_bus_type register error!\n");return ret;}ret = driver_register(&dummy_controller_drv);	// 注册控制器驱动(可以比喻成spi控制器驱动)if (ret) {printk(KERN_ERR "dummy_controller_drv register error!\n");return ret;}ret = driver_register(&dummy_device_drv);		// 注册设备驱动(可以比喻成spi设备驱动)if (ret) {printk(KERN_ERR "dummy_device_drv register error!\n");return ret;}ret = device_register(&dummy_controller_dev);	// 注册控制器设备(可以比喻成设备树中的spi控制器节点)if(ret){printk(KERN_ERR "dummy_controller_dev register error!\n");return ret;        }dummy_0.class = &dummy_class;					dummy_0.parent=&dummy_controller_dev;ret = device_register(&dummy_0);				// 为后续添加的设备注册一个父设备(可以比喻成spidevX.X)if(ret){printk(KERN_ERR "dummy_0 register error!\n");return ret;}dummy_device_dev.parent=&dummy_0;				dummy_device_dev.bus = &dummy_bus_type;dummy_device_dev.devt = MKDEV(103, 1);ret = device_register(&dummy_device_dev);		// 注册设备(可以比喻成设备树中的spi控制器节点下的spi设备节点)if(ret){printk(KERN_ERR "dummy_device_dev register error!\n");return ret;}return ret;
}static void __exit exit_test(void)
{device_unregister(&dummy_device_dev);device_unregister(&dummy_0);device_unregister(&dummy_controller_dev);driver_unregister(&dummy_device_drv);driver_unregister(&dummy_controller_drv);bus_unregister(&dummy_bus_type);class_unregister(&dummy_class);printk(KERN_INFO "exit module!\n");
}module_init(init_test);
module_exit(exit_test);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("1477153217@qq.com");
MODULE_DESCRIPTION("bus class test");

实现了一个总线,设备,驱动的简单例程,例如spi总线、spi控制器驱动、spi设备驱动合一的例程。

8、component框架

可以调整设备驱动的加载顺序。

http://www.dtcms.com/wzjs/87887.html

相关文章:

  • 江油网站制作中国seo排行榜
  • 域名怎样连接到网站图片外链工具
  • 网站宣传册怎么做今日舆情热点
  • 网站加外链找客户资源的软件
  • 邹城市建设局网站深圳seo培训
  • 做个公司网站要多少钱深圳网站设计公司哪家好
  • 深圳网站制作培训百度竞价怎么操作
  • 网站建站那个好网站推广在线
  • 做爰全过程免费的视频网站白云区新闻
  • asp.net企业网站框架怎么优化网站关键词的方法
  • 怎样自己做企业的网站优化绿松石什么意思
  • 怎么创造网站成都关键词seo推广平台
  • 千万不要报培训班学室内设计惠州seo怎么做
  • 云南省城乡住房与建设厅网站百度线上推广
  • 整形美容网站模板免费外链代发平台
  • 泰安网站建设公司带长春网站建设团队
  • 北京网站设计公司排行榜站长工具免费
  • 网站建设有哪些特点搜索引擎推广有哪些平台
  • 东莞网站建设 光龙线上推广方案怎么做
  • 佛山网站建站电商网站seo
  • 自己建立网站后怎么做淘客前端优化
  • 安徽外贸网站建设seo网站优化经理
  • 网站建设的大公司360推广怎么收费
  • 外国人做的甲骨文网站上海培训机构整顿
  • 阿里妈妈网站建设制作教程百度深圳总部
  • 广州网站推广百度云官网登录入口
  • 日本配色网站4414站长平台
  • wordpress 如何汉化福州seo顾问
  • 贵州省人民政府seo网站优化论文
  • apache 做网站北京网站排名推广