Linux设备模型(8)_platform设备作者:蜗蜗 发布于:2014-4-28 10:24 分类:Linux内核分析 1. 前言在Linux设备模型的抽象中,存在着一类称作“Platform Device”的设备,内核是这样描述它们的(Documentation/driver-model/platform.txt):
概括来说,Platform设备包括:基于端口的设备(已不推荐使用,保留下来只为兼容旧设备,legacy);连接物理总线的桥设备;集成在SOC平台上面的控制器;连接在其它bus上的设备(很少见)。等等。 这些设备有一个基本的特征:可以通过CPU bus直接寻址(例如在嵌入式系统常见的“寄存器”)。因此,由于这个共性,内核在设备模型的基础上(device和device_driver),对这些设备进行了更进一步的封装,抽象出paltform bus、platform device和platform driver,以便驱动开发人员可以方便的开发这类设备的驱动。 可以说,paltform设备对Linux驱动工程师是非常重要的,因为我们编写的大多数设备驱动,都是为了驱动plaftom设备。本文我们就来看看Platform设备在内核中的实现。 2. Platform模块的软件架构内核中Platform设备有关的实现位于include/linux/platform_device.h和drivers/base/platform.c两个文件中,它的软件架构如下: 由图片可知,Platform设备在内核中的实现主要包括三个部分: Platform Bus,基于底层bus模块,抽象出一个虚拟的Platform bus,用于挂载Platform设备; 其中Platform Device和Platform Driver会会其它Driver提供封装好的API,具体可参考后面的描述。 3. Platform模块向其它模块提供的API汇整Platform提供的接口包括:Platform Device和Platform Driver两个数据结构,以及它们的操作函数。 3.1 数据结构1. 用于抽象Platform设备的数据结构----“struct platform_device”: 1: /* include/linux/platform_device.h, line 22 */ 2: struct platform_device { 3: const char *name; 4: int id; 5: bool id_auto; 6: struct device dev; 7: u32 num_resources;
8: struct resource *resource; 9:
10: const struct platform_device_id *id_entry; 11:
12: /* MFD cell pointer */ 13: struct mfd_cell *mfd_cell; 14:
15: /* arch specific additions */ 16: struct pdev_archdata archdata; 17: };
2. 用于抽象Platform设备驱动的数据结构----“struct platform_driver”: 1: /* include/linux/platform_device.h, line 173 */ 2: struct platform_driver { 3: int (*probe)(struct platform_device *); 4: int (*remove)(struct platform_device *); 5: void (*shutdown)(struct platform_device *); 6: int (*suspend)(struct platform_device *, pm_message_t state); 7: int (*resume)(struct platform_device *); 8: struct device_driver driver; 9: const struct platform_device_id *id_table; 10: };
3.2 Platform Device提供的APIPlatform Device主要提供设备的分配、注册等接口,供其它driver使用,具体包括: 1: /* include/linux/platform_device.h */ 2: extern int platform_device_register(struct platform_device *); 3: extern void platform_device_unregister(struct platform_device *); 4:
5: extern void arch_setup_pdev_archdata(struct platform_device *); 6: extern struct resource *platform_get_resource(struct platform_device *, 7: unsigned int, unsigned int); 8: extern int platform_get_irq(struct platform_device *, unsigned int); 9: extern struct resource *platform_get_resource_byname(struct platform_device *, 10: unsigned int, 11: const char *); 12: extern int platform_get_irq_byname(struct platform_device *, const char *); 13: extern int platform_add_devices(struct platform_device **, int); 14:
15: extern struct platform_device *platform_device_register_full( 16: const struct platform_device_info *pdevinfo); 17:
18: static inline struct platform_device *platform_device_register_resndata( 19: struct device *parent, const char *name, int id, 20: const struct resource *res, unsigned int num, 21: const void *data, size_t size) 22:
23: static inline struct platform_device *platform_device_register_simple( 24: const char *name, int id, 25: const struct resource *res, unsigned int num) 26:
27: static inline struct platform_device *platform_device_register_data( 28: struct device *parent, const char *name, int id, 29: const void *data, size_t size) 30:
31: extern struct platform_device *platform_device_alloc(const char *name, int id); 32: extern int platform_device_add_resources(struct platform_device *pdev, 33: const struct resource *res, 34: unsigned int num); 35: extern int platform_device_add_data(struct platform_device *pdev, 36: const void *data, size_t size); 37: extern int platform_device_add(struct platform_device *pdev); 38: extern void platform_device_del(struct platform_device *pdev); 39: extern void platform_device_put(struct platform_device *pdev);
3.3 Platform Driver提供的APIPlatform Driver提供struct platform_driver的分配、注册等功能,具体如下: 1: /* include/linux/platform_device.h */ 2:
3: extern int platform_driver_register(struct platform_driver *); 4: extern void platform_driver_unregister(struct platform_driver *); 5:
6: /* non-hotpluggable platform devices may use this so that probe() and 7: * its support may live in __init sections, conserving runtime memory. 8: */ 9: extern int platform_driver_probe(struct platform_driver *driver, 10: int (*probe)(struct platform_device *)); 11:
12: static inline void *platform_get_drvdata(const struct platform_device *pdev) 13:
14: static inline void platform_set_drvdata(struct platform_device *pdev, 15: void *data)
3.4 懒人API又是注册platform device,又是注册platform driver,看着挺啰嗦的。不过内核想到了这点,所以提供一个懒人API,可以同时注册platform driver,并分配一个platform device: 1: extern struct platform_device *platform_create_bundle( 2: struct platform_driver *driver, int (*probe)(struct platform_device *), 3: struct resource *res, unsigned int n_res, 4: const void *data, size_t size);
3.5 Early platform device/driver内核启动时,要完成一定的初始化操作之后,才会处理device和driver的注册及probe,因此在这之前,常规的platform设备是无法使用的。但是在Linux中,有些设备需要尽早使用(如在启动过程中充当console输出的serial设备),所以platform模块提供了一种称作Early platform device/driver的机制,允许驱动开发人员,在开发驱动时,向内核注册可在内核早期启动过程中使用的driver。这些机制提供了如下接口: 1: extern int early_platform_driver_register(struct early_platform_driver *epdrv, 2: char *buf); 3: extern void early_platform_add_devices(struct platform_device **devs, int num); 4:
5: static inline int is_early_platform_device(struct platform_device *pdev) 6: {
7: return !pdev->dev.driver; 8: }
9:
10: extern void early_platform_driver_register_all(char *class_str); 11: extern int early_platform_driver_probe(char *class_str, 12: int nr_probe, int user_only); 13: extern void early_platform_cleanup(void);
4. Platform模块的内部动作解析4.1 Platform模块的初始化Platform模块的初始化是由drivers/base/platform.c中platform_bus_init接口完成的,该接口的实现和动作如下: 1: int __init platform_bus_init(void) 2: {
3: int error; 4:
5: early_platform_cleanup();
6:
7: error = device_register(&platform_bus);
8: if (error) 9: return error; 10: error = bus_register(&platform_bus_type);
11: if (error) 12: device_unregister(&platform_bus);
13: return error; 14: }
4.2 platform device和platform driver的注册结合第3章的描述,platform device和platform driver的注册,由platform_device_add和platform_driver_register两个接口实际实现。其内部动作分别如下。 platform_device_add的内部动作:
platform_driver_register的内部动作:
4.3 platform设备的probe我们在“Linux设备模型(6)_Bus”中讲过,设备的probe,都发生在向指定的bus添加device或者device_driver时,由bus模块的bus_probe_device,或者device_driver模块driver_attach接口触发。这里就不再详细描述了。
原创文章,转发请注明出处。蜗窝科技,www.。 标签: Linux Kernel 设备模型 platform设备 评论: |
|