Linux platform设备和驱动
Linux platform设备和驱动
platform 设备与驱动一. 概述
platform设备和驱动与linux设备模型密切相关。platform在linux设备模型中,其实就是一种虚拟总线没有对应的硬件结构。它的主要作用就是管理系统的外设资源,比如io内存,中断信号线。现在大多数处理器芯片都是soc,如s3c2440,它包括处理器内核(arm920t)和系统的外设(lcd接口,nandflash接口等)。linux在引入了platform机制之后,内核假设所有的这些外设都挂载在platform虚拟总线上,以便进行统一管理。
二. platform 总线1. 在系统中platform对应的文件drivers/base/platform.c,它不是作为一个模块注册到内核的,关键的注册总线的函数由系统初始化部分,对应/init/main.c中的do_basic_setup函数间接调用。这里可以看出platform非常重要,要在系统其他驱动加载之前注册。下面分析platform总线注册函数
- int __init platform_bus_init(void)
- {
- int error;
- early_platform_cleanup();
- error = device_register(&platform_bus);
- //总线也是设备,所以也要进行设备的注册
- if (error)
- return error;
- error = bus_register(&platform_bus_type);
- //注册platform_bus_type总线到内核
- if (error)
- device_unregister(&platform_bus);
- return error;
- }
2. platform_bus_type 总线结构与设备结构
(1) platform总线 设备结构
- struct device platform_bus = {
- .init_name = "platform",
- };
(2) platform总线 总线结构
- struct bus_type platform_bus_type = {
- .name = "platform",
- .dev_attrs = platform_dev_attrs,
- .match = platform_match,
- .uevent = platform_uevent,
- .pm = &platform_dev_pm_ops,
- };
platform_match match函数,这个函数在当属于platform的设备或者驱动注册到内核时就会调用,完成设备与驱动的匹配工作。
platform_uevent 热插拔操作函数
三. platform 设备
1. platform_device 结构
- struct platform_device {
- const char * name;
- int id;
- struct device dev;
- u32 num_resources;
- struct resource * resource;
- struct platform_device_id *id_entry;
- /* arch specific additions */
- struct pdev_archdata archdata;
- };
- struct resource {
- resource_size_t start;
- resource_size_t end;
- const char *name;
- unsigned long flags;
- struct resource *parent, *sibling, *child;
- };
2. 设备注册函数 platform_device_register
- int platform_device_register(struct platform_device *pdev)
- {
- device_initialize(&pdev->dev);
- return platform_device_add(pdev);
- }
- 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;
- //可以看出,platform设备的父设备一般都是platform_bus,所以注册后的platform设备都出现在/sys/devices/platform_bus下
- pdev->dev.bus = &platform_bus_type;
- //挂到platform总线上
- if (pdev->id != -1)
- dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
- else
- dev_set_name(&pdev->dev, "%s", pdev->name);
- //设置设备名字,这个名字与/sys/devices/platform_bus下的名字对应
- 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)) {
- printk(KERN_ERR
- "%s: failed to claim resource %d\n",
- dev_name(&pdev->dev), i);
- ret = -EBUSY;
- goto failed;
- }
- }
- //上面主要是遍历设备所占用的资源,找到对应的父资源,如果没有定义,那么根据资源的类型,分别赋予iomem_resource和ioport_resource,然后调用insert_resource插入资源。
- //这样系统的资源就形成了一个树形的数据结构,便于系统的管理
- pr_debug("Registering platform device '%s'. Parent at %s\n",
- dev_name(&pdev->dev), dev_name(pdev->dev.parent));
- ret = device_add(&pdev->dev);
- //注册到设备模型中
- if (ret == 0)
- return ret;
- failed:
- 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);
- }
- return ret;
- }
|
评论暂时关闭