Linux 即插即用文档

作者:

Adam Belay <ambx1@neo.rr.com>

上次更新时间:

2002 年 10 月 16 日

概述

即插即用提供了一种检测和设置传统设备或以其他方式不可配置的设备的资源的方法。Linux 即插即用层为兼容的驱动程序提供这些服务。

用户界面

Linux 即插即用用户界面提供了一种为不支持 Linux 即插即用的传统驱动程序和用户级别驱动程序激活 PnP 设备的方法。用户界面集成到 sysfs 中。

除了标准的 sysfs 文件外,以下文件也会在每个设备的目录中创建:- id - 显示支持的 EISA ID 列表 - options - 显示可能的资源配置 - resources - 显示当前分配的资源并允许更改资源

激活设备

# echo "auto" > resources

这将调用自动资源配置系统来激活设备

手动激活设备

# echo "manual <depnum> <mode>" > resources

<depnum> - the configuration number
<mode> - static or dynamic
         static = for next boot
         dynamic = now

禁用设备

# echo "disable" > resources

示例

假设您需要激活软盘控制器。

  1. 更改到正确的目录,在我的例子中是 /driver/bus/pnp/devices/00:0f

    # cd /driver/bus/pnp/devices/00:0f
    # cat name
    PC standard floppy disk controller
    
  2. 检查设备是否已激活

    # cat resources
    DISABLED
    
  • 注意字符串 “DISABLED”。这意味着设备未激活。

  1. 检查设备可能的配置(可选)

    # cat options
    Dependent: 01 - Priority acceptable
        port 0x3f0-0x3f0, align 0x7, size 0x6, 16-bit address decoding
        port 0x3f7-0x3f7, align 0x0, size 0x1, 16-bit address decoding
        irq 6
        dma 2 8-bit compatible
    Dependent: 02 - Priority acceptable
        port 0x370-0x370, align 0x7, size 0x6, 16-bit address decoding
        port 0x377-0x377, align 0x0, size 0x1, 16-bit address decoding
        irq 6
        dma 2 8-bit compatible
    
  2. 现在激活设备

    # echo "auto" > resources
    
  3. 最后检查设备是否已激活

    # cat resources
    io 0x3f0-0x3f5
    io 0x3f7-0x3f7
    irq 6
    dma 2
    

还有一系列内核参数

pnp_reserve_irq=irq1[,irq2] ....
pnp_reserve_dma=dma1[,dma2] ....
pnp_reserve_io=io1,size1[,io2,size2] ....
pnp_reserve_mem=mem1,size1[,mem2,size2] ....

统一即插即用层

所有即插即用驱动程序、协议和服务都会在一个名为即插即用层的中心位置汇合。该层负责 PnP 驱动程序和 PnP 协议之间的信息交换。因此,它会自动将命令转发到正确的协议。这使得编写 PnP 驱动程序变得容易得多。

以下函数可从即插即用层获得

pnp_get_protocol

将使用次数加一

pnp_put_protocol

将使用次数减一

pnp_register_protocol

使用此函数注册新的 PnP 协议

pnp_unregister_protocol

使用此函数从即插即用层中删除 PnP 协议

pnp_register_driver

将 PnP 驱动程序添加到即插即用层

这包括驱动程序模型集成,成功返回零,失败返回负错误编号;如果您需要知道有多少设备绑定到驱动程序,请计算对 .add() 方法的调用

pnp_unregister_driver

从即插即用层中删除 PnP 驱动程序

即插即用协议

本节包含有关 PnP 协议开发人员的信息。

以下协议目前在计算领域中可用

  • PNPBIOS

    用于串行和并行端口等系统设备。

  • ISAPNP

    为 ISA 总线提供 PnP 支持

  • ACPI

    在其众多用途中,ACPI 提供了有关系统级设备的信息。

它旨在取代 PNPBIOS。Linux 即插即用目前不支持它,但计划在不久的将来支持。

Linux PnP 协议的要求:1. 该协议必须使用 EISA ID 2. 该协议必须通知 PnP 层设备的当前配置

  • 设置资源的能力是可选的,但首选。

以下是 PnP 协议相关函数

pnp_add_device

使用此函数将 PnP 设备添加到 PnP 层

仅当 pnp_dev 结构中设置了所有需要的值时才调用此函数

pnp_init_device

调用此函数以初始化 PnP 结构

pnp_remove_device

调用此函数以从即插即用层中删除设备。如果设备仍在使用,则将失败。将自动释放设备和相关结构使用的内存

pnp_add_id

将 EISA ID 添加到指定设备支持的 ID 列表中

有关更多信息,请查阅诸如 /drivers/pnp/pnpbios/core.c 等协议的源代码。

Linux 即插即用驱动程序

本节包含有关 Linux PnP 驱动程序开发人员的信息。

新方法

  1. 首先列出支持的 EISA ID

    例如

    static const struct pnp_id pnp_dev_table[] = {
            /* Standard LPT Printer Port */
            {.id = "PNP0400", .driver_data = 0},
            /* ECP Printer Port */
            {.id = "PNP0401", .driver_data = 0},
            {.id = ""}
    };
    

    请注意,字符 'X' 可以用作函数部分(最后四个字符)的通配符。

    例如

    /* Unknown PnP modems */
    {       "PNPCXXX",              UNKNOWN_DEV     },
    

    可以选择定义支持的 PnP 卡 ID。例如

    static const struct pnp_id pnp_card_table[] = {
            {       "ANYDEVS",              0       },
            {       "",                     0       }
    };
    
  2. 可以选择定义探测和删除函数。如果驱动程序已经有一种可靠的方法来检测资源(例如 parport_pc 驱动程序),则不定义这些函数可能是有意义的。

    例如

    static int
    serial_pnp_probe(struct pnp_dev * dev, const struct pnp_id *card_id, const
                    struct pnp_id *dev_id)
    {
    . . .
    

    例如

    static void serial_pnp_remove(struct pnp_dev * dev)
    {
    . . .
    

    有关更多信息,请参阅 /drivers/serial/8250_pnp.c。

  3. 创建一个驱动程序结构

    例如

    static struct pnp_driver serial_pnp_driver = {
            .name           = "serial",
            .card_id_table  = pnp_card_table,
            .id_table       = pnp_dev_table,
            .probe          = serial_pnp_probe,
            .remove         = serial_pnp_remove,
    };
    
    • name 和 id_table 不能为 NULL。

  4. 注册驱动程序

    例如

    static int __init serial8250_pnp_init(void)
    {
            return pnp_register_driver(&serial_pnp_driver);
    }
    

旧方法

创建了一系列兼容性函数,以便轻松转换 ISAPNP 驱动程序。它们应该仅作为临时解决方案。

它们如下

struct pnp_dev *pnp_find_dev(struct pnp_card *card,
                             unsigned short vendor,
                             unsigned short function,
                             struct pnp_dev *from)