《Linux设备驱动开发详解(第3版)》 第6章 Linux设备驱动模型
·
6.1 设备驱动模型概述
设备驱动模型是Linux内核中用于管理设备驱动的一种架构,它提供了一种统一的方式来描述设备、驱动及其之间的关系,目的是简化驱动开发,提高代码的可维护性和可移植性。这部分通常以理论介绍为主,较少直接涉及代码。
6.2 kobject
kobject 是 Linux 设备驱动模型的基础数据结构,用于表示内核对象,它包含了对象的引用计数、名称以及与 sysfs 文件系统的关联等信息。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
// 定义一个全局的 kobject 结构体
struct kobject *my_kobj;
// 模块初始化函数
static int __init kobject_init(void) {
// 创建一个 kobject 实例
my_kobj = kobject_create_and_add("my_kobject", kernel_kobj);
if (!my_kobj) {
// 如果创建失败,打印错误信息
printk(KERN_ERR "Failed to create kobject\n");
return -ENOMEM;
}
printk(KERN_INFO "kobject created successfully\n");
return 0;
}
// 模块退出函数
static void __exit kobject_exit(void) {
if (my_kobj) {
// 释放 kobject 及其相关资源
kobject_put(my_kobj);
printk(KERN_INFO "kobject removed successfully\n");
}
}
module_init(kobject_init);
module_exit(kobject_exit);
MODULE_LICENSE("GPL");
6.3 kset
kset 是一组 kobject 的集合,它提供了一种将相关 kobject 组织在一起的方式,并且可以作为一个整体在 sysfs 中呈现。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/kset.h>
// 定义一个全局的 kset 结构体
struct kset *my_kset;
// 模块初始化函数
static int __init kset_init(void) {
// 创建一个 kset 实例,该 kset 位于 kernel_kobj 下
my_kset = kset_create_and_add("my_kset", NULL, kernel_kobj);
if (!my_kset) {
// 如果创建失败,打印错误信息
printk(KERN_ERR "Failed to create kset\n");
return -ENOMEM;
}
printk(KERN_INFO "kset created successfully\n");
return 0;
}
// 模块退出函数
static void __exit kset_exit(void) {
if (my_kset) {
// 释放 kset 及其相关资源
kset_unregister(my_kset);
printk(KERN_INFO "kset removed successfully\n");
}
}
module_init(kset_init);
module_exit(kset_exit);
MODULE_LICENSE("GPL");
6.4 ktype
ktype 定义了 kobject 的操作方法,包括释放函数、sysfs 文件系统的操作方法等,它描述了一类 kobject 的行为。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
// 定义 kobject 的释放函数
static void my_kobj_release(struct kobject *kobj) {
// 这里可以进行一些资源清理操作
printk(KERN_INFO "my_kobj is being released\n");
}
// 定义 ktype 结构体
static struct kobj_type my_ktype = {
.release = my_kobj_release,
};
// 模块初始化函数
static int __init ktype_init(void) {
struct kobject *kobj;
// 创建一个 kobject 实例,并关联到 my_ktype
kobj = kobject_create();
if (!kobj) {
printk(KERN_ERR "Failed to create kobject\n");
return -ENOMEM;
}
kobj->ktype = &my_ktype;
kobject_set_name(kobj, "my_kobject");
// 将 kobject 添加到 sysfs 中
if (kobject_add(kobj, kernel_kobj, NULL)) {
kobject_put(kobj);
printk(KERN_ERR "Failed to add kobject to sysfs\n");
return -ENOMEM;
}
printk(KERN_INFO "kobject with ktype created and added successfully\n");
return 0;
}
// 模块退出函数
static void __exit ktype_exit(void) {
struct kobject *kobj = kobject_find(kernel_kobj, "my_kobject");
if (kobj) {
kobject_del(kobj);
kobject_put(kobj);
printk(KERN_INFO "kobject with ktype removed successfully\n");
}
}
module_init(ktype_init);
module_exit(ktype_exit);
MODULE_LICENSE("GPL");
6.5 bus、device 和 driver
- bus:表示设备所连接的总线类型,如 PCI、USB 等。它管理着总线上的设备和驱动,并负责设备和驱动的匹配。
- device:代表具体的硬件设备,它包含了设备的属性和与驱动的关联。
- driver:是控制设备的软件代码,它实现了对设备的操作方法。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/platform_device.h>
// 定义一个虚拟的平台设备结构体
static struct platform_device my_platform_device = {
.name = "my_platform_device",
.id = -1,
};
// 定义一个虚拟的平台驱动结构体
static struct platform_driver my_platform_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = "my_platform_driver",
},
};
// 平台驱动的 probe 函数,当设备和驱动匹配时被调用
static int my_probe(struct platform_device *pdev) {
printk(KERN_INFO "my_platform_driver: Probing device %s\n", pdev->name);
return 0;
}
// 平台驱动的 remove 函数,当设备从系统移除时被调用
static int my_remove(struct platform_device *pdev) {
printk(KERN_INFO "my_platform_driver: Removing device %s\n", pdev->name);
return 0;
}
// 模块初始化函数
static int __init bus_device_driver_init(void) {
int ret;
// 注册平台设备
ret = platform_device_register(&my_platform_device);
if (ret) {
printk(KERN_ERR "Failed to register platform device\n");
return ret;
}
// 注册平台驱动
ret = platform_driver_register(&my_platform_driver);
if (ret) {
platform_device_unregister(&my_platform_device);
printk(KERN_ERR "Failed to register platform driver\n");
return ret;
}
printk(KERN_INFO "Platform device and driver registered successfully\n");
return 0;
}
// 模块退出函数
static void __exit bus_device_driver_exit(void) {
platform_driver_unregister(&my_platform_driver);
platform_device_unregister(&my_platform_device);
printk(KERN_INFO "Platform device and driver unregistered successfully\n");
}
module_init(bus_device_driver_init);
module_exit(bus_device_driver_exit);
MODULE_LICENSE("GPL");
6.6 设备驱动模型中的 sysfs 文件系统
sysfs 是一种基于内存的文件系统,它将内核中的对象以文件和目录的形式呈现给用户空间,方便用户查看和操作设备的属性。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
// 定义一个全局的 kobject 结构体
struct kobject *my_kobj;
// 定义一个用于 sysfs 文件操作的 show 函数
static ssize_t my_attribute_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) {
return sprintf(buf, "This is a sample attribute value\n");
}
// 定义一个用于 sysfs 文件操作的 store 函数
static ssize_t my_attribute_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) {
printk(KERN_INFO "Received data: %.*s\n", (int)count, buf);
return count;
}
// 定义一个 kobj_attribute 结构体
static struct kobj_attribute my_attribute = __ATTR(my_attr, 0644, my_attribute_show, my_attribute_store);
// 模块初始化函数
static int __init sysfs_init(void) {
int ret;
// 创建一个 kobject 实例
my_kobj = kobject_create_and_add("my_kobject", kernel_kobj);
if (!my_kobj) {
printk(KERN_ERR "Failed to create kobject\n");
return -ENOMEM;
}
// 在 kobject 下创建一个 sysfs 文件
ret = sysfs_create_file(my_kobj, &my_attribute.attr);
if (ret) {
kobject_put(my_kobj);
printk(KERN_ERR "Failed to create sysfs file\n");
return ret;
}
printk(KERN_INFO "sysfs file created successfully\n");
return 0;
}
// 模块退出函数
static void __exit sysfs_exit(void) {
if (my_kobj) {
// 删除 sysfs 文件
sysfs_remove_file(my_kobj, &my_attribute.attr);
kobject_put(my_kobj);
printk(KERN_INFO "sysfs file and kobject removed successfully\n");
}
}
module_init(sysfs_init);
module_exit(sysfs_exit);
MODULE_LICENSE("GPL");
6.7 设备驱动模型中的热插拔
热插拔是指在系统运行时,设备可以动态地插入或移除。内核通过一些机制来处理热插拔事件,例如在设备插入时自动加载驱动,在设备移除时卸载驱动。以下是一个简单的示意代码,展示如何注册一个热插拔操作回调函数(实际的热插拔处理涉及更多底层机制和硬件交互)。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/pm.h>
// 热插拔操作回调函数
static int my_hotplug(struct device *dev, enum hotplug_type type, unsigned int *hotplug_cmds) {
if (type == HOTPLUG_EVENT_ADD) {
printk(KERN_INFO "Device %s added\n", dev->kobj.name);
} else if (type == HOTPLUG_EVENT_REMOVE) {
printk(KERN_INFO "Device %s removed\n", dev->kobj.name);
}
return 0;
}
// 模块初始化函数
static int __init hotplug_init(void) {
struct device *dev;
// 获取一个设备指针(这里假设已有一个设备,实际可能需要通过其他方式获取)
dev = get_device(...);
if (!dev) {
printk(KERN_ERR "Failed to get device\n");
return -ENODEV;
}
// 注册热插拔操作回调函数
register_hotplug_notifier(dev, my_hotplug);
printk(KERN_INFO "Hotplug notifier registered successfully\n");
return 0;
}
// 模块退出函数
static void __exit hotplug_exit(void) {
struct device *dev;
dev = get_device(...);
if (dev) {
// 注销热插拔操作回调函数
unregister_hotplug_notifier(dev, my_hotplug);
printk(KERN_INFO "Hotplug notifier unregistered successfully\n");
}
}
module_init(hotplug_init);
module_exit(hotplug_exit);
MODULE_LICENSE("GPL");
6.8 platform 设备驱动模型
platform 设备驱动模型是一种用于连接系统设备和驱动的抽象模型,常用于嵌入式系统中,设备和驱动通过平台总线进行匹配。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/platform_device.h>
// 定义一个平台设备资源结构体
static struct resource my_platform_device_resources[] = {
[0] = {
.start = 0x10000000,
.end = 0x10000fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_NUM, // 假设已定义 IRQ_NUM
.end = IRQ_NUM,
.flags = IORESOURCE_IRQ,
},
};
// 定义一个虚拟的平台设备结构体
static struct platform_device my_platform_device = {
.name = "my_platform_device",
.id = -1,
.num_resources = ARRAY_SIZE(my_platform_device_resources),
.resource = my_platform_device_resources,
};
// 定义一个平台驱动结构体
static struct platform_driver my_platform_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = "my_platform_driver",
},
};
// 平台驱动的 probe 函数,当设备和驱动匹配时被调用
static int my_probe(struct platform_device *pdev) {
struct resource *res;
// 获取设备的内存资源
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
printk(KERN_ERR "Failed to get memory resource\n");
return -ENXIO;
}
// 获取设备的中断资源
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
printk(KERN_ERR "Failed to get IRQ resource\n");
return -ENXIO;
}
printk(KERN_INFO "my_platform_driver: Probing device %s\n", pdev->name);
return 0;
}
// 平台驱动的 remove 函数,当设备从系统移除时被调用
static int my_remove(struct platform_device *pdev) {
printk(KERN_INFO "my_platform_driver: Removing device %s\n", pdev->name);
return 0;
}
// 模块初始化函数
static int __init platform_driver_init(void) {
int ret;
// 注册平台设备
ret = platform_device_register(&my_platform_device);
if (ret) {
printk(KERN_ERR "Failed to register platform device\n");
return ret;
}
// 注册平台驱动
ret = platform_driver_register(&my_platform_driver);
if (ret) {
platform_device_unregister(&my_platform_device);
printk(KERN_ERR "Failed to register platform driver\n");
return ret;
}
printk(KERN_INFO "Platform device and driver registered successfully\n");
return 0;
}
// 模块退出函数
static void __exit platform_driver_exit(void) {
platform_driver_unregister(&my_platform_driver);
platform_device_unregister(&my_platform_device);
printk(KERN_INFO "Platform device and driver unregistered successfully\n");
}
module_init(platform_driver_init);
module_exit(platform_driver_exit);
MODULE_LICENSE("GPL");
以上代码详细展示了 Linux 设备驱动模型各个部分的基本实现和使用方法,实际应用中会根据具体需求进行更复杂的扩展和优化。
更多推荐
所有评论(0)