//
内核版本:2.6.35.7
运行平台:三星s5pv210
//
1、什么是platform(平台)总线?
相对于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 文件中
2、platform总线管理下的2员大将
(1)两个结构体platform_device和platform_driver
对于任何一种Linux设备驱动模型下的总线都由两个部分组成:描述设备相关的结构体和描述驱动相关的结构体
在platform总线下就是platform_device和platform_driver,下面是对两个结构体的各个元素进行分析:
platform_device结构体:(include\linux\platform_device.h)
复制代码
1 struct platform_device { // platform总线设备
2 const char * name; // 平台设备的名字
3 int id; // ID 是用来区分如果设备名字相同的时候(通过在后面添加一个数字来代表不同的设备,因为有时候有这种需求)
4 struct device dev; // 内置的device结构体
5 u32 num_resources; // 资源结构体数量
6 struct resource * resource; // 指向一个资源结构体数组
7
8 const struct platform_device_id *id_entry; // 用来进行与设备驱动匹配用的id_table表
9
10 /* arch specific additions */
11 struct pdev_archdata archdata; // 自留地 添加自己的东西
12 };
复制代码
platform_device结构体中的struct resource结构体分析:
复制代码
1 struct resource { // 资源结构体
2 resource_size_t start; // 资源的起始值,如果是地址,那么是物理地址,不是虚拟地址
3 resource_size_t end; // 资源的结束值,如果是地址,那么是物理地址,不是虚拟地址
4 const char *name; // 资源名
5 unsigned long flags; // 资源的标示,用来识别不同的资源
6 struct resource *parent, *sibling, *child; // 资源指针,可以构成链表
7 };
复制代码
platform_driver结构体:(include\linux\platform_device.h)
复制代码
1 struct platform_driver {
2 int (*probe)(struct platform_device *); // 这个probe函数其实和 device_driver中的是一样的功能,但是一般是使用device_driver中的那个
3 int (*remove)(struct platform_device *); // 卸载平台设备驱动的时候会调用这个函数,但是device_driver下面也有,具体调用的是谁这个就得分析了
4 void (*shutdown)(struct platform_device *);
5 int (*suspend)(struct platform_device *, pm_message_t state);
6 int (*resume)(struct platform_device *);
7 struct device_driver driver; // 内置的device_driver 结构体
8 const struct platform_device_id *id_table; // 该设备驱动支持的设备的列表 他是通过这个指针去指向 platform_device_id 类型的数组
9 };
复制代码
(2)两组接口函数(driver\base\platform.c)
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 *); // 用来卸载我们的设备
3、platform平台总线的初始化
(1)platform平台总线的注册初始化: platform_bus_init
/***********************************************************************/
platform_bus_init
early_platform_cleanup // 进行一些早期的平台清理
device_register // 注册设备 (在/sys/devices/目录下建立 platform目录对应的设备对象 /sys/devices/platform/)
bus_register // 总线注册
/************************************************************************/
(2)相关结构体
复制代码
1 struct bus_type {
2 const char *name; // 总线名字
3 struct bus_attribute *bus_attrs; // 该总线的属性
4 struct device_attribute *dev_attrs; // 该总线下设备的属性
5 struct driver_attribute *drv_attrs; // 该总线下设备驱动的属性
6
7 int (*match)(struct device *dev, struct device_driver *drv); // 该总线下设备与设备驱动的匹配函数
8 int (*uevent)(struct device *dev, struct kobj_uevent_env *env); // 事件函数 热拨插
9 int (*probe)(struct device *dev); // 总线下的 探针函数
10 int (*remove)(struct device *dev);
11 void (*shutdown)(struct device *dev);
12
13 int (*suspend)(struct device *dev, pm_message_t state);
14 int (*resume)(struct device *dev);
15
16 const struct dev_pm_ops *pm