在 Linux 设备驱动 开发中,驱动程序(Driver) 需要与 硬件设备(Device) 进行匹配,以便正确加载并控制设备。Linux 提供了多种设备与驱动匹配机制,不同类型的设备使用不同的匹配方法。
1. 设备与驱动匹配的几种方法
Linux 主要通过以下几种方式进行设备与驱动的匹配:
- 总线匹配(Bus Matching)
- 设备树匹配(Device Tree Matching)
- 平台设备匹配(Platform Device Matching)
- I2C/SPI 设备匹配
- USB 设备匹配
- PCI 设备匹配
- OF(Open Firmware)设备树匹配
- 热插拔(Hotplug)机制匹配
不同的匹配方式适用于不同的总线和设备类型。
2. 设备与驱动匹配机制详解
(1) 总线匹配(Bus Matching)
适用于: 所有挂载在 总线(如 PCI、USB、I2C、SPI、Platform 总线) 上的设备。
匹配方式:
- 总线(Bus) 负责管理设备和驱动,并调用
match()
方法匹配驱动与设备。 - 匹配规则 由各个总线(
bus_type
)定义,如 PCI、USB、I2C 等总线。
示例:定义总线匹配规则
struct bus_type my_bus_type = {.name = "my_bus",.match = my_bus_match, // 设备与驱动匹配函数
};
匹配函数:
int my_bus_match(struct device *dev, struct device_driver *drv) {return !strcmp(dev->name, drv->name);
}
该匹配方式用于系统所有总线级设备匹配。
(2) 设备树匹配(Device Tree Matching)
适用于: ARM、嵌入式平台,依赖 设备树(Device Tree, DT) 进行设备描述。
匹配方式:
- 设备树 DTS 中定义设备,并使用
compatible
字段标识。 - 驱动程序中定义
of_device_id
表,Linux 内核根据compatible
进行匹配。
示例:DTS 设备描述
soc {uart@10000000 {compatible = "myvendor,my-uart";reg = <0x10000000 0x100>;};
};
示例:驱动匹配
static const struct of_device_id my_uart_dt_ids[] = {{ .compatible = "myvendor,my-uart" },{},
};
MODULE_DEVICE_TABLE(of, my_uart_dt_ids);static struct platform_driver my_uart_driver = {.probe = my_uart_probe,.driver = {.name = "my_uart",.of_match_table = my_uart_dt_ids, // 设备树匹配},
};
关键点:
compatible
在设备树和驱动中必须匹配。of_match_table
指定设备树匹配表。
(3) 平台设备匹配(Platform Device Matching)
适用于: 无标准总线的设备(如 SoC 内部设备)。
匹配方式:
- 在
platform_device
结构体中定义设备名称。 - 在
platform_driver
结构体中定义驱动名称,进行匹配。
示例:定义平台设备
struct platform_device my_device = {.name = "my_platform_device",
};
示例:定义平台驱动
static struct platform_driver my_driver = {.driver = {.name = "my_platform_device",},.probe = my_probe,
};
关键点:
- 设备的
.name
必须与 驱动的.driver.name
一致。 platform_driver_register()
进行注册。
(4) I2C/SPI 设备匹配
适用于: I2C、SPI 总线上的设备(如传感器、EEPROM)。
I2C 设备匹配
匹配方式:
- I2C 设备通过
i2c_board_info
结构体静态注册。 - I2C 驱动匹配
i2c_device_id
或of_device_id
。
示例:I2C 设备
static struct i2c_board_info my_i2c_device = {I2C_BOARD_INFO("my_i2c_dev", 0x50),
};
示例:I2C 驱动
static const struct i2c_device_id my_i2c_ids[] = {{ "my_i2c_dev", 0 },{},
};
MODULE_DEVICE_TABLE(i2c, my_i2c_ids);static struct i2c_driver my_i2c_driver = {.driver = { .name = "my_i2c_dev" },.id_table = my_i2c_ids, // 设备 ID 匹配
};
SPI 设备匹配
匹配方式:
- SPI 设备通过
spi_board_info
静态注册。 - SPI 驱动匹配
spi_device_id
。
示例:SPI 设备
static struct spi_board_info my_spi_device = {.modalias = "my_spi_dev",
};
示例:SPI 驱动
static const struct spi_device_id my_spi_ids[] = {{ "my_spi_dev", 0 },{},
};
MODULE_DEVICE_TABLE(spi, my_spi_ids);static struct spi_driver my_spi_driver = {.driver = { .name = "my_spi_dev" },.id_table = my_spi_ids, // 设备 ID 匹配
};
(5) USB 设备匹配
适用于: USB 设备,如 U 盘、键盘、鼠标。
匹配方式:
- USB 设备具有 VID(厂商 ID) 和 PID(产品 ID),驱动程序中使用
usb_device_id
进行匹配。
示例:USB 设备匹配
static const struct usb_device_id my_usb_ids[] = {{ USB_DEVICE(0x1234, 0x5678) }, // VID: 0x1234, PID: 0x5678{},
};
MODULE_DEVICE_TABLE(usb, my_usb_ids);static struct usb_driver my_usb_driver = {.name = "my_usb_driver",.probe = my_usb_probe,.id_table = my_usb_ids, // USB 设备匹配
};
(6) PCI 设备匹配
适用于: PCI 设备,如显卡、网卡。
匹配方式:
- PCI 设备具有 Vendor ID(厂商 ID) 和 Device ID(设备 ID),驱动程序使用
pci_device_id
进行匹配。
示例:PCI 设备匹配
static const struct pci_device_id my_pci_ids[] = {{ PCI_DEVICE(0x8086, 0x1234) }, // Intel 设备{},
};
MODULE_DEVICE_TABLE(pci, my_pci_ids);static struct pci_driver my_pci_driver = {.name = "my_pci_driver",.id_table = my_pci_ids, // PCI 设备匹配
};
总结
匹配方式 | 适用设备 | 关键匹配字段 |
---|---|---|
总线匹配 | 所有设备 | bus.match |
设备树匹配 | ARM、嵌入式 | compatible |
平台设备 | SoC 内部设备 | .name |
I2C 设备 | 传感器 | i2c_device_id |
SPI 设备 | Flash、传感器 | spi_device_id |
USB 设备 | U 盘、鼠标 | usb_device_id |
PCI 设备 | 显卡、网卡 | pci_device_id |
在实际开发中,选择合适的匹配方式能提高驱动程序的兼容性和可移植性。