Linux platform子系统【1】-PLATFORM(平台)总线详解
Linux platform子系统【2】-PLATFORM注册(struct device)platform_bus
Linux 设备模型【2】- kobject
Linux 设备模型【3】- uevnet
Linux 设备模型【8】- bus
Linux 设备模型【9】- CLASS
Linux 设备模型【10】- Bus, Class, Device和Device Driver的概念
platform虚拟平台总线驱动分析总结
https://blog.csdn.net/weixin_40237571/article/details/110877523
相对于USB、PCI、I2C、SPI等物理总线来说,platform总线是一种虚拟、抽象出来的总线,实际中并不存在这样的总线。
platform总线呢?Linux设备驱动模型为了保持设备驱动的统一性而虚拟出来的总线。因为对于usb设备、i2c设备、pci设备、spi设备等等,他们与cpu的通信都是直接挂在相应的总线下面与我们的cpu进行数据交互的,但是在我们的嵌入式系统当中,并不是所有的设备都能够归属于这些常见的总线,在嵌入式系统里面,SoC系统中集成的独立的外设控制器、挂接在SoC内存空间的外设却不依附与此类总线。所以Linux驱动模型为了保持完整性,将这些设备挂在一条虚拟的总线上(platform总线),而不至于使得有些设备挂在总线上,另一些设备没有挂在总线上。platform总线相关代码:driver\base\platform.c 文件
相关结构体定义:include\linux\platform_device.h 文件中
platform_device和platform_driver对于任何一种Linux设备驱动模型下的总线都由两个部分组成:描述设备相关的结构体和描述驱动相关的结构体在platform总线下就是platform_device和platform_driver,下面是对两个结构体的各个元素进行分析:
platform_device结构体:(include\linux\platform_device.h)
struct platform_device { // platform总线设备
const char * name; // 平台设备的名字
int id; // ID 是用来区分如果设备名字相同的时候(通过在后面添加一个数字来代表不同的设备,因为有时候有这种需求)
struct device dev; // 内置的device结构体
u32 num_resources; // 资源结构体数量
struct resource * resource; // 指向一个资源结构体数组
const struct platform_device_id *id_entry; // 用来进行与设备驱动匹配用的id_table表
/* arch specific additions */
struct pdev_archdata archdata; // 自留地 添加自己的东西
};
platform_device结构体中的struct resource结构体分析:
struct resource { // 资源结构体
resource_size_t start; // 资源的起始值,如果是地址,那么是物理地址,不是虚拟地址
resource_size_t end; // 资源的结束值,如果是地址,那么是物理地址,不是虚拟地址
const char *name; // 资源名
unsigned long flags; // 资源的标示,用来识别不同的资源
struct resource *parent, *sibling, *child; // 资源指针,可以构成链表
};
platform_driver结构体:(include\linux\platform_device.h)
struct platform_driver {
int (*probe)(struct platform_device *); // 这个probe函数其实和 device_driver中的是一样的功能,但是一般是使用device_driver中的那个
int (*remove)(struct platform_device *); // 卸载平台设备驱动的时候会调用这个函数,但是device_driver下面也有,具体调用的是谁这个就得分析了
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver; // 内置的device_driver 结构体
const struct platform_device_id *id_table; // 该设备驱动支持的设备的列表 他是通过这个指针去指向 platform_device_id 类型的数组
};
int platform_driver_register(struct platform_driver *); // 用来注册我们的设备驱动
void platform_driver_unregister(struct platform_driver *); // 用来卸载我们的设备驱动
int platform_device_register(struct platform_device *); // 用来注册我们的设备
void platform_device_unregister(struct platform_device *); // 用来卸载我们的设备
platform_bus_init b start_kernel //head-common.S
start_kernel(void){
rest_init(void) // /init/mai.c
}
rest_init(void) // /init/mai.c
kernel_init // /init/mai.c
kernel_init_freeable // /init/main.c
do_basic_setup // /init/main.c
driver_init // /init/init.c
platform_bus_init
early_platform_cleanup // 进行一些早期的平台清理
device_register // 注册设备 (在/sys/devices/目录下建立 platform目录对应的设备对象 /sys/devices/platform/)
bus_register // 总线注册
这个问题起是就是在解决
platform_bus_type 是系统开启就会分配好的数据结构
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
int __init buses_init(void)
{
static struct kset *bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
}
platform_bus_init(void)
-->bus_register(&platform_bus_type);
struct subsys_private {
struct kset subsys;
}
struct bus_type {
struct subsys_private *p;
}
priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
priv->bus = &platform_bus_type;
bus->p = (struct subsys_private*)priv;
priv->subsys.kobj.kset = bus_kset; /*设置本子系统对象所属集合*/
priv->subsys.kobj.ktype = &bus_ktype;/*所属集合的操作方式和属性*/
-->kset_register(&priv->subsys); /*注册子系统,注册到那里去了*/
/*kobject_add_internal(&(priv->subsys)->kobj)*/
-->err = kobject_add_internal(&k->kobj)(struct kobject *kobj); /*以内核对象的方式注册*/
{
/*如果所属集合不为空,且无父对象,所属集合(/sys/bus)为父对象*/
if (kobj->kset) { /*priv->subsys.kobj.kset = bus_kset*/
if (!parent)
parent = kobject_get(&kobj->kset->kobj); /*kobject_get(bus_kset->kobj)*/
kobj_kset_join(kobj); /*kobj_kset_join(&priv->subsys->kobj)*/
{
/* add the kobject to its kset's list */
/*list_add_tail(&(&priv->subsys)->entry, &(priv->subsys->kset)->list);*/
list_add_tail(&kobj->entry, &kobj->kset->list);
/*
struct kobject {
const char *name;
struct list_head entry;
}
*/
}
kobj->parent = parent;
}
}
最终以 priv的形式贮存在bus_kset的list中
(struct subsys_private) priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
-->priv->bus = (struct bus_type *)platform_bus_type


