在驱动模型的基础上,就可以构建实际的设备驱动了,这里以platform总线来进行介绍,因为platform总线具有代表性,platform不是一个实际的总线,它是虚拟出来的,所以在设备上的任何硬件驱动都可以挂在这条总线上,最典型的就是设备上的控制器模块都是挂在platform总线上的
1. platform总线注册
1.1 platform_bus_type
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
1.2 platform总线注册
在系统初始化的时候会进行总线的注册
(drivers/base/platform.c)
int __init platform_bus_init(void)
{
int error;
early_platform_cleanup();
error = device_register(&platform_bus);-----------platform作为设备注册
if (error)
return error;
error = bus_register(&platform_bus_type);--------platform总线注册
if (error)
device_unregister(&platform_bus);
of_platform_register_reconfig_notifier();
return error;
}
2. platform设备注册
2.1 struct platform_device
(include/linux/platform_device.h)
struct platform_device {
const char *name;---------------------设备名字
int id;----------------------------设备ID
bool id_auto;
struct device dev;-------------------嵌入的device结构体
u32 num_resources;-----------------设备资源数
struct resource *resource;-------------设备资源
const struct platform_device_id *id_entry;
char *driver_override; /* Driver name to force a match */
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
2.2 platform_device_register
platform设备注册的函数为:
(include/linux/platform_device.h)
extern int platform_device_register(struct platform_device *);
该函数首先把platform_device添加到/sys/device目录下,真正的注册在下面函数中:
(drivers/base/platform.c)
int platform_device_add(struct platform_device *pdev)
{
int i, ret;
if (!pdev)
return -EINVAL;
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;---------设置父设备为platform_bus
pdev->dev.bus = &platform_bus_type;-----------所属总线为platform_bus
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;
}---------------------------------------------设置name
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));
ret = device_add(&pdev->dev);-------------------device注册
if (ret == 0)
return ret;
......
}
3. platform驱动注册
3.1 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;---------------------嵌入的device_driver结构体
const struct platform_device_id *id_table;
bool prevent_deferred_probe;
};
3.2 设备驱动注册
(include/linux/platform_device.h)
#define platform_driver_register(drv) \
__platform_driver_register(drv, THIS_MODULE)
int __platform_driver_register(struct platform_driver *drv,
struct module *owner)
{
drv->driver.owner = owner;
drv->driver.bus = &platform_bus_type;-------------所属总线为platform_bus
drv->driver.probe = platform_drv_probe;
drv->driver.remove = platform_drv_remove;
drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver);-------------驱动注册
}
最主要的来看下驱动初始化函数platform_drv_probe
static int platform_drv_probe(struct device *_dev)
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
int ret;
ret = of_clk_set_defaults(_dev->of_node, false);
if (ret < 0)
return ret;
ret = dev_pm_domain_attach(_dev, true);
if (ret != -EPROBE_DEFER) {
if (drv->probe) {
ret = drv->probe(dev);-----------------调用到具体设备的初始化函数probe
if (ret)
dev_pm_domain_detach(_dev, true);
} else {
/* don't fail if just dev_pm_domain_attach failed */
ret = 0;
}
}
if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
dev_warn(_dev, "probe deferral not supported\n");
ret = -ENXIO;
}
return ret;
}