内核文档driver-model/platform.txt翻译

来源:互联网 发布:作曲软件哪个好 编辑:程序博客网 时间:2024/04/27 12:10
平台设备和驱动
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
查看<linux/platform_device.h>中定义的驱动模型的接口platform_device platform_driver.
这个伪总线使用最小限度的结构来连接总线上的设备,比如集成外围设备的SOC处理器,或者一些传统的电脑互联的总线;而不是像正式规定好的大的PCI或者USB总线

平台设备
~~~~~~~~~~~~~~~~
平台设备在系统中是以独立的实体出现的。这包括传统的基于port的设备和主机到外设总线的桥,大多数集成到SOC平台上的控制器。他们的共同点是都直接由CPU总线寻址。一个平台设备极少情况下会通过一段其它类型的总线连接;但是它的寄存器仍然可以被直接寻址。

平台设备有名字,用来绑定驱动和一些资源,比如地址和中断

struct platform_device {
    const char    *name;
    u32        id;
    struct device    dev;
    u32        num_resources;
    struct resource    *resource;
};

平台驱动
~~~~~~~~~~~~~~~~
平台驱动遵循标准驱动模型的管理,发现和列举设备都是在驱动外进行,驱动只提供probe()和remove()方法。他们使用标准规定提供电源管理和关机通知。

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;
};

注意,probe()通常应该确定特定设备硬件确实存在;有时,平台创建的代码没办法确认。这种探测可以使用设备资源,包括时钟和平台数据。

平台驱动用正常的方式注册它们自己:

    int platform_driver_register(struct platform_driver *drv);

或者,在通常情况下,如果设备不是热插拔的,probe()子例程可以位于init段来减少驱动的运行时内存占用。

设备枚举
~~~~~~~~~~~~~~~~~~
平台特定(板上特定)的创建代码会注册平台设备:

    int platform_device_register(struct platform_device *pdev);

    int platform_add_devices(struct platform_device **pdevs, int ndev);

通常的规则是,仅仅注册那些已经存在的设备,但是某些情况下会有特例。比如,一个内核可能被配置一个外部网络适配器,这个适配器可能不再所有板上都适用,或者也会和没有挂在任何外围设备上的集成控制器一起工作。

在某些情况下,启动固件会导出板上支持的设备的表。如果没有这些表,系统建立代码为特定目标板建立一个内核经常是唯一的建立正确设备的方法。这些板特定的内核在嵌入和普通系统开发中很常见。

在许多情况下,和平台设备有关的内存和中断资源不足够让设备的驱动工作。板建立代码经常会提供额外的信息,并使用设备的platform_data域来持有额外的信息。

嵌入式系统一个平台设备经常需要一个或者多个时钟,它们通常都是关闭的(为了节省电).系统建立过程也会将那些时钟和设备联系起来,clk_get(&pdev->dev, clock_name) 按需要返回给它们。

传统驱动: 设备探测
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
一些驱动并没有完全转化到驱动模型中,因为他们有时是作为一个非驱动的角色:驱动注册它的设备而不是把工作留给系统去做。这些驱动不能被热插拔和冷插拔,因为这些机制需要设备建立在不同系统组件中而不是在驱动中。

这样做唯一的理由是兼容旧的系统设计,比如最早的IBM PC机,依赖于易错的"探测硬件"模型来设置硬件。新的系统大部分都舍弃了这个模型,而使用总线级别的对动态配置的支持(PCI,USB),或者启动固件提供的设备表(比如,x86 上的 PNPACPI)。有关什么出现在什么地方的冲突选项太多,甚至一些操作系统的都可能在这个地方犯糊涂。

这中类型的驱动并不鼓励使用。如果你更新这个驱动,请把设备枚举移到一个更合适的位置,在驱动的外部。这些通常会被清除,因为这些驱动会已经有正常模式,比如使用PNP创建设备节点或者通过平台设备创建。

依然有一些API支持传统驱动。避免使用这些调用除了那些不充分热插拔驱动。

    struct platform_device *platform_device_alloc(
            const char *name, int id);
你可以使用上面的函数来动态分配一个设备。你可以用资源和platform_device_register来初始化它。一个更好的解决方法通常是:
    struct platform_device *platform_device_register_simple(
            const char *name, int id,
            struct resource *res, unsigned int nres);
你可以一步达到这个效果。


设备命名和驱动绑定
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
platform_device.dev.bus_id是设备典型的名称。
它有两部分组成:
    * platform_device.name  用来匹配驱动
    * platform_device.id   设备实例号,或者-1


这些并置的,所以name/id "serial"/0 指示 bus-id "serial.0","serial/3"指示bus_id "serial.3";这些都会使用平台驱动"serial".
然而"my_rtc"/-1会是bus_id "my_rtc"(没有实例号)并且使用名为"my_rtc"的平台驱动。

驱动绑定是驱动核心自动完成的,调用驱动probe()在找到驱动和设备的match之后。如果probe()成功,驱动和设备就被绑定。这里有三种不同的找到匹配:
    - 无论何时注册一个设备,那个总线的驱动都会检查match.平台设备会在系统启动时就被注册。
    - 当用platform_driver_register注册驱动时,所有未绑定的总线上的设备都会被检查是否匹配。驱动通常在启动的稍晚时间或者通过模块加载注册。
    - 用platform_driver_probe()来注册驱动和platform_driver_register()一样,除了驱动不会被检测被如果其它设备注册了(这是Ok的,因为这些接口只用于那些不支持热插拔的设备)。


早先的平台设备和驱动
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
早先的平台接口为平台设备和驱动提供平台数据在系统启动的早期。这个代码是建立在early_param()命令行解析并且可以被很早就执行。

例子:"earlyprintk"类早期串行控制台的六个步骤
Example: "earlyprintk" class early serial console in 6 steps

1.注册早期平台设备数据
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这个体系结构代码注册平台设备和数据使用函数early_platform_add_devices().在早期串行控制的情况下,这些应该是对串口的硬件配置。这个时间点的设备注册会匹配早期的平台驱动

2.解析内核命令行
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这个体系代码调用parse_early_param()来解析内核命令行。这回执行所有的early_param()回调函数。用户特定的早期平台设备会在这个时刻被注册。对于早期串行控制台的情况,用户可以在内核命令行确定端口"earlyprintk=serial.0"。如果id是-1,那么这个点和id就可以被忽略。

3.安装属于确定类的早期平台设备驱动
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这个体系代码可选的强制属于确定类的平台驱动使用early_platform_driver_register_all()来注册。第二步中用户特定的设备有对这些的优先权。这个步骤被串行驱动的例子忽略,因为早期串行驱动代码应该失效,除非用户在内核命令行上有特定的端口。

4.早期平台驱动注册
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
内编的平台驱动使用early_platform_init()在第2和3步间自动注册。串行驱动例子应该使用early_platform_init("earlyprintk", &platform_driver).

5.探测属于某个确定类的早期平台驱动
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
该体系代码调用early_platform_driver_probe()来匹配注册过的和带有早期平台设备驱动的确定类有关系的早期平台设备。匹配的设备会被probed().这一步可以在早期启动的任意步执行。只要有可能,那么对于串行端口的情况很好。

6.在早期的的平台设备驱动probe()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
该体系代码需要对早期启动非常关心,特别是对内存分配和中断注册。probe()内的代码可以使用is_early_platform_device()来检查它是否在早期平台设备或者普通平台设备的时间调用。早期串行驱动在这个步骤调用register_console().


详细信息请见<linux/platform_device.h>
0 0