那什么情况可以使用platform driver机制编写驱动呢?
我的理解是只要和内核本身运行依赖性不大的外围设备(换句话说只要不在内核
运行所需的一个最小系统之内的设备),相对独立的,拥有各自独自的资源(addresses and
IRQs),都可以用platform_driver实现。如:lcd,usb,uart等,都可以用platfrom_driver写,而
timer,irq等最小系统之内的设备则最好不用platfrom_driver机制,实际上内核实现也是这样的。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int __init kernel_init(void * unused) ->do_basic_setup()函数->driver_init();
//这个函数的各个init倒是很有意思,是窥探内核设备和驱动的好切入点。
/**
* driver_init - initialize driver model.
*
* Call the driver model init functions to initialize their
* subsystems. Called early from init/main.c.
*/
void __init driver_init(void)
{
/* These are the core pieces */
devices_init();
buses_init();
classes_init();
firmware_init();
hypervisor_init();
/* These are also core pieces, but must come after the
* core core pieces.
*/
platform_bus_init();
system_bus_init();
cpu_dev_init();
memory_dev_init();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
platform bus的注册platform bus注册是通过platform_bus_init函数完成的,该函数定义在drivers/base/platform.c文件中,其内容如下:
int __init platform_bus_init(void)
{
int error;
//调用device_register注册了一个“platform”的device,以后注册的所有platform设备均以这个“platform”设备为父设备
error = device_register(&platform_bus);
if (error)
return error;
//调用bus_register注册总线platform_bus_type。
error = bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
return error;
}
//////////////////////////////////////////////////////////////////
platform_bus定义在drivers/base/platform.c文件中,其内容如下:
struct device platform_bus = {
.bus_id = "platform",
};
platform_bus_type定义在drivers/base/platform.c文件中,其内容如下:
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = PLATFORM_PM_OPS_PTR,
};
////////////////////////////////////////////////////////////////////////////
platform_match函数定义在drivers/base/platform.c文件中,其内容如下:
2.6.28内核如下:
/**
* platform_match - bind platform device to platform driver.
* @dev: device.
* @drv: driver.
*
* Platform device IDs are assumed to be encoded like this:
* "", where is a short description of the type of
* device, like "pci" or "floppy", and is the enumerated
* instance of the device, like '0' or '42'. Driver IDs are simply
* "". So, extract the from the platform_device structure,
* and compare it against the name of the driver. Return whether they match
* or not.
*/
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev;
pdev = container_of(dev, struct platform_device, dev);
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}
Linux kernel release 3.x
/**
* platform_match - bind platform device to platform driver.
* @dev: device.
* @drv: driver.
*
* Platform device IDs are assumed to be encoded like this:
* "
", where is a short description of the type of
* device, like "pci" or "floppy", and is the enumerated
* instance of the device, like '0' or '42'. Driver IDs are simply
* "". So, extract the from the platform_device structure,
* and compare it against the name of the driver. Return whether they match
* or not.
*/
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* When driver_override is set, only bind to the matching driver */
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
//后退或撤退 到驱动名字匹配
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
注册一个paltform_device通过调用platform_device_register函数完成,该函数定义在drivers/base/platform.c文件中,其内容如下:
/**
* platform_device_register - add a platform-level device
* @pdev: platform device we're adding
*/
int platform_device_register(struct platform_device *pdev)
{
//调用device_initialize初始化platform_device.dev。
device_initialize(&pdev->dev);
//调用platform_device_add函数,该函数定义在drivers/base/platform.c文件中
return platform_device_add(pdev);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
platform_device_add函数,该函数定义在drivers/base/platform.c文件中
/**
* 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;
if (!pdev)
return -EINVAL;
//如果platform_device没有指定父设备,则设置pdev->dev.parent为platform_bus,即“platform”设备。
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
//指定bus类型为platform_bus_type。
pdev->dev.bus = &platform_bus_type;
//根据不同情况设置设备名
switch (pdev->id) {
default:
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
break;
case PLATFORM_DEVID_NONE:
dev_set_name(&pdev->dev, "%s", pdev->name);
break;
case PLATFORM_DEVID_AUTO:
/*
* Automatically allocated device ID. We mark it as such so
* that we remember it must be freed, and we append a suffix
* to avoid namespace collision with explicit IDs.
*/
ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
if (ret < 0)
goto err_out;
pdev->id = ret;
pdev->id_auto = true;
dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
break;
}
//调用insert_resource函数将platform_device的资源插入到资源树中。
for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL)
r->name = dev_name(&pdev->dev);
p = r->parent;
if (!p) {
if (resource_type(r) == IORESOURCE_MEM)
p = &iomem_resource;
else if (resource_type(r) == IORESOURCE_IO)
p = &ioport_resource;
}
if (p && insert_resource(p, r)) {
dev_err(&pdev->dev, "failed to claim resource %d\n", i);
ret = -EBUSY;
goto failed;
}
}
pr_debug("Registering platform device '%s'. Parent at %s\n",
dev_name(&pdev->dev), dev_name(pdev->dev.parent));
//调用device_add将platform_device对应的device注册到sysfs系统中。
ret = device_add(&pdev->dev);
if (ret == 0)
return ret;
failed:
if (pdev->id_auto) {
ida_simple_remove(&platform_devid_ida, pdev->id);
pdev->id = PLATFORM_DEVID_AUTO;
}
while (--i >= 0) {
struct resource *r = &pdev->resource[i];
unsigned long type = resource_type(r);
if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
release_resource(r);
}
err_out:
return ret;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
platform driver的注册platform driver是通过struct platform_driver结构体来描述的,该结构体定义在include/linux/platform_device.h文件中,其内容如下:
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 (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
bool prevent_deferred_probe;
};
/////////////////////////////////////////////////////////////////////////////////////////////
platform_driver的注册是通过调用platform_driver_register函数完成的,该函数定义在drivers/base/platform.c文件中,其内容如下:
/**
* 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;
if (drv->pm)
drv->driver.pm = &drv->pm->base;
//调用driver_register注册platform_driver.driver
return driver_register(&drv->driver);
}
阅读(1044) | 评论(0) | 转发(0) |