linux设备模型浅析之设备篇
时间:2025-03-10
时间:2025-03-10
linux系统设备模型
Linux设备模型浅析之设备篇
本文属本人原创,欢迎转载,转载请注明出处。由于个人的见识和能力有限,不可能面面俱到,也可能存在谬误,敬请网友指出,本人的邮箱是yzq.seen@http://,博客是http://Linux设备模型,仅仅看理论介绍,比如LDD3的第十四章,会感觉太抽象不易理解,而通过阅读内核代码就更具体更易理解,所以结合理论介绍和内核代码阅读能够更快速的理解掌握linux设备模型。这一序列的文章的目的就是在于此,看这些文章之前最好能够仔细阅读LDD3的第十四章。大部分device和driver都被包含在一个特定bus中,platform_device和platform_driver就是如此,包含在 platform_bus_type中。这里就以对platform_bus_type的调用为主线,浅析platform_device的注册过程,从而理解linux设备模型。platform_bus_type用于关联SOC的 platform device和 platform driver,比如在内核linux-2.6.29中所有S3C2410中的 platform device都保存在devs.c中。这里就以S3C2410 RTC为例。在文章的最后贴有一张针对本例的device model图片,可在阅读本文章的时候作为参照。
一、S3C2410 RTC的platform device定义在arch/arm/plat-s3c24xx/devs.c中,如下:static struct resource s3c_rtc_resource[] = {
[0] = {
.start = S3C24XX_PA_RTC,
.end = S3C24XX_PA_RTC + 0xff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_RTC,
.end = IRQ_RTC,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_TICK,
.end = IRQ_TICK,
.flags = IORESOURCE_IRQ
}
};
struct platform_device s3c_device_rtc = {
.name = "s3c2410-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_rtc_resource),
.resource = s3c_rtc_resource,
};
把它们添加在arch/arm/mach-s3c2440/ mach- smdk2440.c中,如下:
static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
linux系统设备模型
&s3c_device_i2c0,
&s3c_device_iis,
& s3c_device_rtc
};
系统初始化的时候会调用drivers/base/platform.c里的platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices))将其注册到platform_bus_type,最终被添加到device hierarchy。platform_add_devices()调用了platform_device_register(),而后者又先后调用了
device_initialize()和platform_device_add()。有必要对platform_bus_type的定义作一番注释,其定义如下:
struct bus_type platform_bus_type = {
.name= "platform",// bus的名字,将会生成/sys/bus/platform目录
/* 该属性文件将产生在所有 platform_bus_type类型的设备目录下,文件名为"modalias” */.dev_attrs= platform_dev_attrs,
.match= platform_match,// 用于drive与device匹配的例程
.uevent= platform_uevent,// 用于输出环境变量,与属性文件“uevent”相关
.pm= PLATFORM_PM_OPS_PTR, // 电源管理方面
};
代码中,
1. 通过bus_register(&platform_bus_type)将platform_bus_type 注册到总线模块。本例中,当cat /sys/device/platform/s3c2410-rtc/modalias时将会打印出"platform:s3c2410-wdt",从
platform_dev_attrs的具体实现中你就能看出来。当cat /sys/device/platform/s3c2410-rtc/uevent时将会打印出”DRIVER=s3c2410-wdt MODALIAS=platform:s3c2410-wdt”,从 platform_uevent 的具体实现中你就能看出来。
二、下面解析device_initialize()和platform_device_add()两个例程,它们分别定义在drivers/base/core.c和drivers/base/platform.c中。
device_initialize()的代码如下:
void device_initialize(struct device *dev)
{
dev->kobj.kset = devices_kset;// 设置其指向的kset容器
kobject_init(&dev->kobj, &device_ktype);// 初始化 kobj,将 device_ktype传递给它
klist_init(&dev->klist_children, klist_children_get,
klist_children_put);// 初试化klist
INIT_LIST_HEAD(&dev->dma_pools);
init_MUTEX(&dev->sem);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
device_init_wakeup(dev, 0);
device_pm_init(dev);// 初试化电源管理
set_dev_node(dev, -1);
}
代码中,
1. devices_kset是所有dev的kset,也就是所有dev都被链接在该kset下,其在初试化例程devices_init()中通过调用kset_create_and_add("devices", &device_uevent_ops, NULL)来创建。由于参数parent=NULL ,所以生成/sys/devices 目录。这里说明下kobj,kset结构体中包含有一个
linux系统设备模型
kobj,一个kobj生成一个目录,在这里就是”devices "目录,通过调用kobject_add_internal()例程生成。所以从dev->kobj.kset = devices_kset 可以看出,该dev.kobj添加到了devices_kset容器中,所的kobj都归属于一个特定的kset。关于kset,kobj,ktype,kref的关系可以参考书LDD3的第十四章,在第370页有一张说明kobj和kset关系的图(英文版)。
2. kobject_init(&dev->kobj, &device_ktype)用于初始化 dev->kobj中变量的参数,如ktype、kref、entry和state*等。初试化例程devices_init()还会调用kobject_create_and_add()例程生成/sys/dev、/sys/dev/block和/sys/dev/char目录。
3. 其他初始化。
platform_device_add代码如下:
int platform_device_add(struct platform_device *pdev)
{
int i, ret = 0;
if (!pdev)
return -EINVAL;
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus; // 设置为 platform_bus device
pdev->dev.bus = &platform_bus_type; // 设 …… 此处隐藏:16849字,全部文档内容请下载后查看。喜欢就下载吧 ……