platform总线是linux2.6内核加入的一种虚拟总线。platform机制的本身使用并不复杂,由两部分组成:platform_device和platform_driver。
platform驱动与传统的设备驱动模型相比,优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序使用这些资源时使用统一的接口,这样提高了程序的可移植性。
通过platform机制开发底层设备驱动的流程:
定义platform_device ---> 注册platform_device ---> 定义platform_driver ---> 注册platform_driver
1. 平台设备
struct platform_device {
const char *name; // 设备名
int id; // 设备编号,配合设备名使用
struct device dev;
u32 num_resources;
struct resource *resource; // 设备资源
};
struct resource {
resource_size_t start; // 资源的起始物理地址
resource_size_t end; // 资源的结束物理地址
const char *name; // 资源的名称
unsigned long flags; // 资源的类型,如MEM,IO,IRQ类型
struct resource *parent, *sibling, *child; // 资源链表指针
};
/**
* platform_device_alloc
* @name: base name of the device we're adding
* @id: instance id
*
* Create a platform device object which can have other objects attached
* to it, and which will have attached objects freed when it is released.
*/
struct platform_device *platform_device_alloc(const char *name, int id) // name:设备名;id:设备id,一般为-1
{
struct platform_object *pa;
pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL);
if (pa) {
strcpy(pa->name, name);
pa->pdev.name = pa->name;
pa->pdev.id = id;
device_initialize(&pa->pdev.dev);
pa->pdev.dev.release = platform_device_release;
}
return pa ? &pa->pdev : NULL;
}
/**
* platform_device_add - add a platform device to device hierarchy
* @pdev: platform device we're adding
*
* This is part 2 of platform_device_register(), though may be called
* separately _iff_ pdev was allocated by platform_device_alloc().
*/
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;
pdev->dev.bus = &platform_bus_type;
if (pdev->id != -1)
snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
pdev->id);
else
strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL)
r->name = pdev->dev.bus_id;
p = r->parent;
if (!p) {
if (r->flags & IORESOURCE_MEM)
p = &iomem_resource;
else if (r->flags & IORESOURCE_IO)
p = &ioport_resource;
}
if (p && insert_resource(p, r)) {
printk(KERN_ERR
"%s: failed to claim resource %d\n",
pdev->dev.bus_id, i);
ret = -EBUSY;
goto failed;
}
}
pr_debug("Registering platform device '%s'. Parent at %s\n",
pdev->dev.bus_id, pdev->dev.parent->bus_id);
ret = device_add(&pdev->dev);
if (ret == 0)
return ret;
failed:
while (--i >= 0)
if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))
release_resource(&pdev->resource[i]);
return ret;
}
static struct resource s3c_wdt_resource1 = {
.start = 0x44100000,
.end = 0x44200000,
.flags = IORESOURCE_MEM,
};
static resource s3c_wdt_resource2 = {
.start = 20,
.end = 20,
.flags = IORESOURCE_IRQ,
};
/**
* platform_get_resource - get a resource for a device
* @dev: platform device
* @type: resource type
* @num: resource index
*/
struct resource *
platform_get_resource(struct platform_device *dev, unsigned int type,
unsigned int num)
{
int i;
for (i = 0; i < dev->num_resources; i++) {
struct resource *r = &dev->resource[i];
if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|
IORESOURCE_IRQ|IORESOURCE_DMA))
== type)
if (num-- == 0)
return r;
}
return NULL;
}
参数:
dev:资源所属的设备
type:获取的资源类型
num:所要获取资源类型的序号
如:platform_get_resource(pdev, IORESOURCE_IRQ, 0); // 获取中断号,获取第0个中断号资源(即第1个)
2. 平台驱动
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;
};
/**
* platform_driver_register
* @drv: platform driver structure
*/
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
if (drv->suspend)
drv->driver.suspend = platform_drv_suspend;
if (drv->resume)
drv->driver.resume = platform_drv_resume;
return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(platform_driver_register);
/**
* platform_driver_unregister
* @drv: platform driver structure
*/
void platform_driver_unregister(struct platform_driver *drv)
{
driver_unregister(&drv->driver);
}
EXPORT_SYMBOL_GPL(platform_driver_unregister);
实例:
plat_dev.c
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/platform_device.h>
MODULE_AUTHOR("gzliu");
MODULE_LICENSE("Dual BSD/GPL");
static struct platform_device *my_device;
static int __init my_device_init(void)
{
int ret = 0;
/* 分配结构 */
my_device = platform_device_alloc("my_dev", -1);
/*注册设备*/
ret = platform_device_add(my_device);
/*注册失败,释放相关内存*/
if (ret)
platform_device_put(my_device);
return ret;
}
static void my_device_exit(void)
{
platform_device_unregister(my_device);
}
module_init(my_device_init);
module_exit(my_device_exit);
plat_drv.c
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/platform_device.h>
MODULE_AUTHOR("David Xie");
MODULE_LICENSE("Dual BSD/GPL");
static int my_probe(struct device *dev)
{
printk("Driver found device which my driver can handle!\n");
return 0;
}
static int my_remove(struct device *dev)
{
printk("Driver found device unpluged!\n");
return 0;
}
static struct platform_driver my_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.owner = THIS_MODULE,
.name = "my_dev",
},
};
static int __init my_driver_init(void)
{
/*注册平台驱动*/
return platform_driver_register(&my_driver);
}
static void my_driver_exit(void)
{
platform_driver_unregister(&my_driver);
}
module_init(my_driver_init);
module_exit(my_driver_exit);