platform device和driver之间的关系
2018年04月16日
⁄ 综合
⁄ 共 23375字 ⁄ 字号
小 中 大
-
内核中的platform driver机制需要将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样可以提高驱动和资源管理的独立性。本文的目的就是希望弄清楚platform device和driver之间的关系。
-
1.1 相关数据结构
-
1.1.1 device
-
这个结构体定义为:
-
struct device {
-
struct klist klist_children;
-
struct klist_node knode_parent;
-
struct klist_node knode_driver;
-
struct klist_node knode_bus;
-
struct device *parent;
-
-
struct kobject kobj;
-
char bus_id[BUS_ID_SIZE];
-
struct device_type *type;
-
unsigned is_registered:1;
-
unsigned uevent_suppress:1;
-
struct device_attribute uevent_attr;
-
struct device_attribute *devt_attr;
-
-
struct semaphore sem;
-
-
-
-
struct bus_type * bus;
-
struct device_driver *driver;
-
-
void *driver_data;
-
void *platform_data;
-
-
struct dev_pm_info power;
-
-
#ifdef CONFIG_NUMA
-
int numa_node;
-
#endif
-
u64 *dma_mask;
-
u64 coherent_dma_mask;
-
-
-
-
-
-
struct list_head dma_pools;
-
-
struct dma_coherent_mem *dma_mem;
-
-
-
struct dev_archdata archdata;
-
-
spinlock_t devres_lock;
-
struct list_head devres_head;
-
-
-
struct list_head node;
-
struct class *class;
-
dev_t devt;
-
struct attribute_group **groups;
-
-
void (*release)(struct device * dev);
-
};
-
这个结构体有点复杂,不过我们暂时用不了这么多。
-
-
-
-
1.1.2 resource
-
这个结构体定义为:
-
-
-
-
-
struct resource {
-
resource_size_t start;
-
resource_size_t end;
-
const char *name;
-
unsigned long flags;
-
struct resource *parent, *sibling, *child;
-
};
-
在这个结构体中,start和end的意义将根据flags中指定的资源类型进行解释。内核对资源进行了分类,一共有四种类型:
-
#define IORESOURCE_IO 0x00000100 /* Resource type */
-
#define IORESOURCE_MEM 0x00000200
-
#define IORESOURCE_IRQ 0x00000400
-
#define IORESOURCE_DMA 0x00000800
-
对于DM9000来说,其定义的资源如下:
-
static struct resource dm9000_bfin_resources[] = {
-
{
-
.start = 0x2C000000,
-
.end = 0x2C000000 + 0x7F,
-
.flags = IORESOURCE_MEM,
-
}, {
-
.start = IRQ_PF10,
-
.end = IRQ_PF10,
-
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-
},
-
};
-
也就是说,它定义了两种类型的资源。从这里也可以看出resource结构体里面的name成员没有太大的用处。
-
-
1.1.3 platform_device
-
这个结构体定义为:
-
struct platform_device {
-
const char * name;
-
u32 id;
-
struct device dev;
-
u32 num_resources;
-
struct resource * resource;
-
};
-
它对device加了一层包装,添加了resource的内容。看看DM9000的定义:
-
static struct platform_device dm9000_bfin_device = {
-
.name = "dm9000",
-
.id = -1,
-
.num_resources = ARRAY_SIZE(dm9000_bfin_resources),
-
.resource = dm9000_bfin_resources,
-
};
-
注意这里的name。
-
1.1.4 device_driver
-
这个结构体定义为:
-
struct device_driver {
-
const char * name;
-
struct bus_type * bus;
-
-
struct kobject kobj;
-
struct klist klist_devices;
-
struct klist_node knode_bus;
-
-
struct module * owner;
-
const char * mod_name;
-
struct module_kobject * mkobj;
-
-
int (*probe) (struct device * dev);
-
int (*remove) (struct device * dev);
-
void (*shutdown) (struct device * dev);
-
int (*suspend) (struct device * dev, pm_message_t state);
-
int (*resume) (struct device * dev);
-
};
-
-
-
1.1.5 platform_driver
-
这个结构体定义为:
-
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;
-
};
-
它在device_driver的基础上封装了几个操作函数。
-
1.1.6 bus_type
-
这个结构体定义为:
-
struct bus_type {
-
const char * name;
-
struct module * owner;
-
-
struct kset subsys;
-
struct kset drivers;
-
struct kset devices;
-
struct klist klist_devices;
-
struct klist klist_drivers;
-
-
struct blocking_notifier_head bus_notifier;
-
-
struct bus_attribute * bus_attrs;
-
struct device_attribute * dev_attrs;
-
struct driver_attribute * drv_attrs;
-
struct bus_attribute drivers_autoprobe_attr;
-
struct bus_attribute drivers_probe_attr;
-
-
int (*match)(struct device * dev, struct device_driver * drv);
-
int (*uevent)(struct device *dev, char **envp,
-
int num_envp, char *buffer, int buffer_size);
-
int (*probe)(struct device * dev);
-
int (*remove)(struct device * dev);
-
void (*shutdown)(struct device * dev);
-
-
int (*suspend)(struct device * dev, pm_message_t state);
-
int (*suspend_late)(struct device * dev, pm_message_t state);
-
int (*resume_early)(struct device * dev);
-
int (*resume)(struct device * dev);
-
-
unsigned int drivers_autoprobe:1;
-
};
-
-
-
-
1.2 资源注册
-
在arch/blackfin/mach-bf561/boards/ezkit.c中有这样的代码:
-
static int __init ezkit_init(void)
-
{
-
int ret;
-
-
printk(KERN_INFO "%s(): registering device resources/n", __func__);
-
-
ret = platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices));
-
if (ret < 0)
-
return ret;
-
-
return 0;
-
}
-
-
arch_initcall(ezkit_init);
-
这里使用了arch_initcall来对ezkit_init函数进行调用次序的限制,而驱动的加载通常是使用module_init进行限制的,因此ezkit_init函数将先于驱动加载。
-
在这里ezkit_devices的定义为:
-
static struct platform_device *ezkit_devices[] __initdata = {
-
&dm9000_bfin_device,
-
…………
-
};
-
1.2.1 platform_add_devices
-
这个函数比较简单:
-
-
-
-
-
-
int platform_add_devices(struct platform_device **devs, int num)
-
{
-
int i, ret = 0;
-
-
for (i = 0; i < num; i++) {
-
ret = platform_device_register(devs[i]);
-
if (ret) {
-
while (--i >= 0)
-
platform_device_unregister(devs[i]);
-
break;
-
}
-
}
-
-
return ret;
-
}
-
为这个数组中的每个元素调用platform_device_register,如果出错则注销此前注册的所有platform device。
-
1.2.2 platform_device_register
-
这个函数的实现为:
-
-
-
-
-
-
int platform_device_register(struct platform_device * pdev)
-
{
-
device_initialize(&pdev->dev);
-
return platform_device_add(pdev);
-
}
-
也比较简单,先调用device_initialize初始化platform_device::dev,这里仅仅是对device结构体的成员赋初值,略过它不做分析。接下来的关键是platform_device_add。
-
1.2.3 platform_device_add
-
这个函数定义为:
-
-
-
-
-
-
-
-
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.%u", 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;
-
}
-
在这个函数里做了两件关键的事情,一个是注册device设备,它将device::bus指定为platform_bus_type。另一个是注册resource。看下面的这几行代码:
-
if (!p) {
-
if (r->flags & IORESOURCE_MEM)
-
p = &iomem_resource;
-
else if (r->flags & IORESOURCE_IO)
-
p = &ioport_resource;
-
}
-
对照DM9000的资源定义:
-
static struct resource dm9000_bfin_resources[] = {
-
{
-
.start = 0x2C000000,
-
.end = 0x2C000000 + 0x7F,
-
.flags = IORESOURCE_MEM,
-
}, {
-
.start = IRQ_PF10,
-
.end = IRQ_PF10,
-
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-
},
-
};
-
它的中断资源并没有进行注册。
-
1.2.4 device_add
-
这一函数定义为:
-
-
-
-
-
-
-
-
-
-
-
-
int device_add(struct device *dev)
-
{
-
……………………..
-
-
if ((error = device_add_attrs(dev)))
-
goto AttrsError;
-
if ((error = device_pm_add(dev)))
-
goto PMError;
-
if ((error = bus_add_device(dev)))
-
goto BusError;
-
…………………..
-
}
-
这里有一个关键调用bus_add_device,它将把dev添加到platform_bus_type这一全局变量中的列表。
-
1.2.5 bus_add_device
-
这个函数定义为:
-
-
-
-
-
-
-
-
int bus_add_device(struct device * dev)
-
{
-
struct bus_type * bus = get_bus(dev->bus);
-
int error = 0;
-
-
if (bus) {
-
pr_debug("bus %s: add device %s/n", bus->name, dev->bus_id);
-
error = device_add_attrs(bus, dev);
-
if (error)
-
goto out_put;
-
error = sysfs_create_link(&bus->devices.kobj,
-
&dev->kobj, dev->bus_id);
-
if (error)
-
goto out_id;
-
error = sysfs_create_link(&dev->kobj,
-
&dev->bus->subsys.kobj, "subsystem");
-
if (error)
-
goto out_subsys;
-
error = make_deprecated_bus_links(dev);
-
if (error)
-
goto out_deprecated;
-
}
-
return 0;
-
-
out_deprecated:
-
sysfs_remove_link(&dev->kobj, "subsystem");
-
out_subsys:
-
sysfs_remove_link(&bus->devices.kobj, dev->bus_id);
-
out_id:
-
device_remove_attrs(bus, dev);
-
out_put:
-
put_bus(dev->bus);
-
return error;
-
}
-
注意当执行到此函数时dev->bus指向platform_bus_type这一全局变量,因而这一函数将把dev添加到platform_bus_type的链表中。
-
-
-
1.3 驱动注册
-
下面是DM9000网卡的驱动加载代码:
-
static int __init
-
dm9000_init(void)
-
{
-
printk(KERN_INFO "%s Ethernet Driver/n", CARDNAME);
-
-
return platform_driver_register(&dm9000_driver);
-
}
-
module_init(dm9000_init);
-
很简单的代码,直接调用platform_driver_register注册驱动,这里dm9000_driver的定义为:
-
static struct platform_driver dm9000_driver = {
-
.driver = {
-
.name = "dm9000",
-
.owner = THIS_MODULE,
-
},
-
.probe = dm9000_probe,
-
.remove = dm9000_drv_remove,
-
.suspend = dm9000_drv_suspend,
-
.resume = dm9000_drv_resume,
-
};
-
-
1.3.1 platform_driver_register
-
这个函数定义为:
-
-
-
-
-
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);
-
}
-
注意由于DM9000的platform_driver中指定了probe,remove,suspend,resume这四个函数,因此device_driver结构体中的这几个函数指针将进行初始化设置。最后再调用driver_register注册driver成员,有点奇怪,怎么就抛弃了platform_driver呢?
-
1.3.2 driver_register
-
这个函数定义为:
-
-
-
-
-
-
-
-
-
int driver_register(struct device_driver * drv)
-
{
-
if ((drv->bus->probe && drv->probe) ||
-
(drv->bus->remove && drv->remove) ||
-
(drv->bus->shutdown && drv->shutdown)) {
-
printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods/n", drv->name);
-
}
-
klist_init(&drv->klist_devices, NULL, NULL);
-
return bus_add_driver(drv);
-
}
-
当函数执行到这里的时候,drv->bus指向的是platform_bus_type这一全局变量。
-
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,
-
};
-
-
1.3.3 bus_add_driver
-
这个函数定义为:
-
-
-
-
-
-
int bus_add_driver(struct device_driver *drv)
-
{
-
struct bus_type * bus = get_bus(drv->bus);
-
int error = 0;
-
-
if (!bus)
-
return -EINVAL;
-
-
pr_debug("bus %s: add driver %s/n", bus->name, drv->name);
-
error = kobject_set_name(&drv->kobj, "%s", drv->name);
-
if (error)
-
goto out_put_bus;
-
drv->kobj.kset = &bus->drivers;
-
if ((error = kobject_register(&drv->kobj)))
-
goto out_put_bus;
-
-
if (drv->bus->drivers_autoprobe) {
-
error = driver_attach(drv);
-
if (error)
-
goto out_unregister;
-
}
-
klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
-
module_add_driver(drv->owner, drv);
-
-
error = driver_add_attrs(bus, drv);
-
if (error) {
-
-
printk(KERN_ERR "%s: driver_add_attrs(%s) failed/n",
-
__FUNCTION__, drv->name);
-
}
-
error = add_bind_files(drv);
-
if (error) {
-
-
printk(KERN_ERR "%s: add_bind_files(%s) failed/n",
-
__FUNCTION__, drv->name);
-
}
-
-
return error;
-
out_unregister:
-
kobject_unregister(&drv->kobj);
-
out_put_bus:
-
put_bus(bus);
-
return error;
-
}
-
当函数执行到此的时候,drv->bus将指向platform_bus_type这一全局变量,而这一全局变量的drivers_autoprobe成员在bus_register这一全局初始化函数中设置为1。因此这里将调用driver_attach函数,注意此时传递进去的参数drv指向的是dm9000_driver的driver成员。
-
1.3.4 driver_attach
-
这一函数定义为:
-
-
-
-
-
-
-
-
-
-
int driver_attach(struct device_driver * drv)
-
{
-
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
-
}
-
很简单,转向bus_for_each_dev。
-
1.3.5 bus_for_each_dev
-
这一函数定义为:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
int bus_for_each_dev(struct bus_type * bus, struct device * start,
-
void * data, int (*fn)(struct device *, void *))
-
{
-
struct klist_iter i;
-
struct device * dev;
-
int error = 0;
-
-
if (!bus)
-
return -EINVAL;
-
-
klist_iter_init_node(&bus->klist_devices, &i,
-
(start ? &start->knode_bus : NULL));
-
while ((dev = next_device(&i)) && !error)
-
error = fn(dev, data);
-
klist_iter_exit(&i);
-
return error;
-
}
-
简单枚举此总线上注册的device,然后为其调用__driver_attach函数,试图将一个device和传递进来的driver相匹配。
-
1.3.6 __driver_attach
-
这一函数定义为:
-
static int __driver_attach(struct device * dev, void * data)
-
{
-
struct device_driver * drv = data;
-
-
-
-
-
-
-
-
-
-
-
-
if (dev->parent)
-
down(&dev->parent->sem);
-
down(&dev->sem);
-
if (!dev->driver)
-
driver_probe_device(drv, dev);
-
up(&dev->sem);
-
if (dev->parent)
-
up(&dev->parent->sem);
-
-
return 0;
-
}
-
很简单,转而调用driver_probe_device进行驱动的匹配。
-
1.3.7 driver_probe_device
-
这个函数定义为:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
int driver_probe_device(struct device_driver * drv, struct device * dev)
-
{
-
int ret = 0;
-
-
if (!device_is_registered(dev))
-
return -ENODEV;
-
if (drv->bus->match && !drv->bus->match(dev, drv))
-
goto done;
-
-
pr_debug("%s: Matched Device %s with Driver %s/n",
-
drv->bus->name, dev->bus_id, drv->name);
-
-
ret = really_probe(dev, drv);
-
-
done:
-
return ret;
-
}
-
此时的drv->bus指向platform_bus_type这一全局变量,而它的match函数为platform_match,且让我们看看它是如何确定device和driver是否匹配的。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
static int platform_match(struct device * dev, struct device_driver * drv)
-
{
-
struct platform_device *pdev = container_of(dev, struct platform_device, dev);
-
-
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
-
}
-
也就是说,它通过比较pdev->name和drv->name是否匹配来决定。
-
对于DM9000的驱动来说,这里的pdev指向dm9000_bfin_device,看看它的初始值:
-
static struct platform_device dm9000_bfin_device = {
-
.name = "dm9000",
-
.id = -1,
-
.num_resources = ARRAY_SIZE(dm9000_bfin_resources),
-
.resource = dm9000_bfin_resources,
-
};
-
再看drv,其指向dm9000_driver这一变量中的driver成员。
-
static struct platform_driver dm9000_driver = {
-
.driver = {
-
.name = "dm9000",
-
.owner = THIS_MODULE,
-
},
-
.probe = dm9000_probe,
-
.remove = dm9000_drv_remove,
-
.suspend = dm9000_drv_suspend,
-
.resume = dm9000_drv_resume,
-
};
-
在进行了正确的名称匹配之后,将调用really_probe进行硬件检测。
-
1.3.8 really_probe
-
这一函数定义为:
-
static int really_probe(struct device *dev, struct device_driver *drv)
-
{
-
int ret = 0;
-
-
atomic_inc(&probe_count);
-
pr_debug("%s: Probing driver %s with device %s/n",
-
drv->bus->name, drv->name, dev->bus_id);
-
WARN_ON(!list_empty(&dev->devres_head));
-
-
dev->driver = drv;
-
if (driver_sysfs_add(dev)) {
-
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed/n",
-
__FUNCTION__, dev->bus_id);
-
goto probe_failed;
-
}
-
-
if (dev->bus->probe) {
-
ret = dev->bus->probe(dev);
-
if (ret)
-
goto probe_failed;
-
} else if (drv->probe) {
-
ret = drv->probe(dev);
-
if (ret)
-
goto probe_failed;
-
}
-
-
driver_bound(dev);
-
ret = 1;
-
pr_debug("%s: Bound Device %s to Driver %s/n",
-
drv->bus->name, dev->bus_id, drv->name);
-
goto done;
-
-
probe_failed:
-
devres_release_all(dev);
-
driver_sysfs_remove(dev);
-
dev->driver = NULL;
-
-
if (ret != -ENODEV && ret != -ENXIO) {
-
-
printk(KERN_WARNING
-
"%s: probe of %s failed with error %d/n",
-
drv->name, dev->bus_id, ret);
-
}
-
-
-
-
-
ret = 0;
-
done:
-
atomic_dec(&probe_count);
-
wake_up(&probe_waitqueue);
-
return ret;
-
}
-
此时的drv->bus指向platform_bus_type这一全局变量,其probe回调函数没有指定,而drv->probe函数则指向dm9000_probe。因此转向dm9000_probe执行,并将dm9000_bfin_device做为参数传递进去。
-
1.4 结论
-
platform device和driver分别向platform_bus_type这一中介注册,并通过名称进行相互间的匹配。很是有点婚姻中介的味道,还有点对暗号的神秘,呵呵!