转自:http://hi.baidu.com/396954504/blog/item/556fe8d11ebac5289a502749.html
我们先来看看platform_bus的定义:
struct device platform_bus = { .bus_id = "platform", };
struct bus_type platform_bus_type = { .name = "platform", .dev_attrs = platform_dev_attrs, .match = platform_match, .uevent = platform_uevent, .suspend = platform_suspend, .suspend_late = platform_suspend_late, .resume_early = platform_resume_early, .resume = platform_resume, };
int __init platform_bus_init(void) { int error;
error = device_register(&platform_bus); if (error) return error; error = bus_register(&platform_bus_type); if (error) device_unregister(&platform_bus); return error; } |
platform_bus数据结构描述了platform bus设备,platform_bus_type描述了platform bus总线,它提供了platform总线设备和驱动的匹配函数。platform总线是由函数platform_bus_init(void)初始化的。
对于Linux我们一般的设备驱动程序来说,就像前面Bus一段提到的那样,我们不需要关心platform总线本身,我们只要调用我们的设备和驱动接口就可以了。
如果你想让platform总线来管理设备,那么,你需要先向platform系统注册设备,这个过程是通过下面的函数接口来实现的:
int platform_device_add(struct platform_device *pdev); int platform_device_register(struct platform_device *pdev); |
我们一般需要调用
platform_device_register函数来向系统添加platform设备。这两个函数唯一的差别就是
platform_device_register在添加设备前会初始化platform_device的dev数据成员,它是一个struct device类型数据。当一个platform_device添加到platform总线中后,platform总线就会为它找到匹配的设备驱动程序,很显然,在这之前,你需要向系统注册platform_driver。
我们先来看看platform总线设备驱动的结构:
struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*suspend_late)(struct platform_device *, pm_message_t state); int (*resume_early)(struct platform_device *); int (*resume)(struct platform_device *); struct device_driver driver; };
extern int platform_driver_register(struct platform_driver *); |
很显然,它“继承”自
struct device_driver,同样类似于
struct device_driver,一般我们需要实现probe函数,及指定platform_driver能驱动的设备的名字。
下面这个例子告诉你如何使用platoform总线,这是一个Android Goldfish GPIO驱动程序。它本身就是一个platform设备驱动(goldfish-gpio),同时,它又会向系统注新的设备(android-timed-gpio),这个新设备又被timed_output.c驱动程序驱动。
...... #include <linux/platform_device.h>
struct platform_device timed_gpio_device = { .name = "android-timed-gpio", .id = -1, .dev.platform_data = &timed_gpio_platform_data, };
static int goldfish_gpio_probe(struct platform_device *pdev) { struct goldfish_gpio_data *gpio_data; ...... error = platform_device_register(&timed_gpio_device); ...... return 0; }
static int goldfish_gpio_remove(struct platform_device *pdev) { int i; struct goldfish_gpio_data *gpio_data; ...... platform_device_unregister(&timed_gpio_device); ...... return 0; }
static struct platform_driver goldfish_gpio_driver = { .probe = goldfish_gpio_probe, .remove = goldfish_gpio_remove, .driver = { .name = "goldfish-gpio" } };
static int __init goldfish_gpio_init(void) { return platform_driver_register(&goldfish_gpio_driver); }
static void __exit goldfish_gpio_exit(void) { platform_driver_unregister(&goldfish_gpio_driver); } |
这个新注册的设备(timed_gpio_device)由timed_output驱动管理,通过浏览这段代码,你应该对如何使用platform总线有个全面的了解。(本想把全部code放在这里,但超过最大字数限制!)
static struct class *timed_gpio_class; struct timed_gpio_data { struct device *dev; struct hrtimer timer; spinlock_t lock; unsigned gpio; int max_timeout; u8 active_low; }; ......
static int android_timed_gpio_probe(struct platform_device *pdev) { struct timed_gpio_platform_data *pdata = pdev->dev.platform_data; struct timed_gpio *cur_gpio; struct timed_gpio_data *gpio_data, *gpio_dat; int i, ret = 0; ...... }
static int android_timed_gpio_remove(struct platform_device *pdev) { }
static struct platform_driver android_timed_gpio_driver = { .probe = android_timed_gpio_probe, .remove = android_timed_gpio_remove, .driver = { .name = "android-timed-gpio", .owner = THIS_MODULE, }, };
static int __init android_timed_gpio_init(void) { timed_gpio_class = class_create(THIS_MODULE, "timed_output"); if (IS_ERR(timed_gpio_class)) return PTR_ERR(timed_gpio_class); return platform_driver_register(&android_timed_gpio_driver); }
static void __exit android_timed_gpio_exit(void) { class_destroy(timed_gpio_class); platform_driver_unregister(&android_timed_gpio_driver); } |
Kobject和kset
提到Linux的设备模型,就不得不提kobject和kset这两个内核对象,他们才是Linux内核设备模型的最基础的结构,但讲解他们却是一个枯燥过程,限于篇幅,这个就不作介绍了,请参考Linux文档<documentation/kobject.txt>。
后记
在这里,我们简单的介绍了Linux的设备模型,包括基本总线、设备、驱动的关系,同时也简单的介绍了Linux2.6内核的platform总线。这些内容应该足够让你了解如何使用Linux设备模型来管理设备了。