linux驱动如何对应硬件
linux驱动如何对应硬件详细介绍
在 Linux 系统中,驱动程序与硬件的对应关系通过一套复杂的设备模型和匹配机制实现,核心涉及硬件识别、驱动匹配、资源分配和通信控制。以下是关键机制和流程的详细解析:
一、Linux 设备模型的核心架构
Linux 通过 总线(Bus)- 设备(Device)- 驱动(Driver) 三层模型管理硬件,所有硬件设备和驱动都挂载在特定总线上(如 PCI、USB、Platform 总线等)。总线作为中间层,负责设备与驱动的匹配和通信。
二、硬件识别与驱动匹配的关键步骤
1.
设备信息描述
- 静态配置(设备树 / DTS):
现代嵌入式设备通过设备树(Device Tree)描述硬件参数(如寄存器地址、中断号、引脚配置等)。驱动通过解析设备树节点(of_device_id)获取硬件信息,例如:cmy_device_of_idscompatible
of my_device_of_ids
- 动态枚举(如 PCI/USB 总线):
对于 PCI/USB 等即插即用设备,硬件通过寄存器上报厂商 ID(VID)、设备 ID(DID),驱动通过id_table声明支持的设备 ID 列表:cmy_pci_idspci my_pci_ids
2.
驱动注册与设备发现
- 驱动注册:
驱动通过module_init宏向内核注册,声明支持的总线类型和匹配规则。例如 Platform 驱动注册:cmy_driverprobe my_probe
remove my_remove
driver
name
of_match_table my_device_of_ids
my_driver
- 设备枚举:
系统启动或热插拔时,总线遍历设备(如扫描 PCI 插槽、USB 端口),为每个设备创建struct device实例,并在sysfs(如/sys/bus/platform/devices/)中生成设备节点。
3.
匹配机制
总线调用match()函数匹配设备与驱动,优先级如下:
- 设备树兼容字符串:优先匹配
compatible字段(如"vendor,device-name")。 - ID 列表:如 PCI/USB 的 VID/DID,或 Platform 驱动的设备名称(
driver.name与设备节点名称匹配)。 - 通用匹配:若以上均不匹配,部分总线(如 Platform)允许通过名称直接匹配。
匹配成功后,总线调用驱动的probe函数,传递struct device指针,驱动在此函数中完成硬件初始化(如申请 IO 端口、中断、内存映射等)。
三、驱动与硬件的通信方式
1.
硬件资源访问
- 内存映射(ioremap):
将设备寄存器的物理地址映射到内核虚拟地址空间,通过指针直接读写:c__iomem reg_base devresourcestart resource_sizeu32 value reg_base OFFSET
- 中断处理:
通过request_irq()注册中断处理函数,响应硬件中断事件:cirq_num my_irq_handler dev
2.
设备文件与用户空间交互
- 字符设备 / 块设备:
驱动通过register_chrdev()注册设备号,用户空间通过open("/dev/my_device", O_RDWR)访问,驱动实现file_operations中的read/write/ioctl等方法处理用户请求。 - 网络设备:
注册网络设备结构体struct net_device,通过协议栈(如 TCP/IP)发送 / 接收数据,用户空间通过socket()接口操作。
四、动态加载与热插拔(udev 机制)
- 驱动模块动态加载:
用户通过modprobe命令加载驱动模块(.ko文件),模块中的module_init自动向总线注册驱动,触发设备匹配(若对应设备已存在)。 - udev 响应:
设备插入时,内核通过uevent通知 udev,udev 根据/sys中的设备信息(如 VID/DID、设备树兼容字符串)查找对应的驱动(可能触发模块加载),并在/dev下创建设备节点(如/dev/ttyUSB0)。
五、关键数据结构与工具链
- 核心结构体:
struct device:描述硬件设备,包含资源(地址、中断号等)和总线信息。struct device_driver:描述驱动,包含probe/remove函数和匹配规则(ID 列表或设备树兼容表)。struct resource:描述硬件资源(如 IO 端口、内存区域、中断号),通过dev->resource数组传递给驱动。
- 调试工具:
dmesg:查看驱动 probe/remove 日志。sysfs:通过/sys/bus/<bus>/devices/和/sys/bus/<bus>/drivers/查看设备与驱动匹配状态。lspci/lsusb:枚举 PCI/USB 设备,查看 VID/DID。device-tree-compiler:编译设备树文件(.dts→.dtb),dtc -I dtb -O dts -o out.dts /proc/device-tree反编译内核设备树。
六、示例:简单 Platform 驱动匹配流程
- 设备树节点(位于
arch/arm/boot/dts/my-board.dts):dtsmy_device@1234 {compatible = "vendor,my-device";
reg = <0x12340000 0x1000>; // 寄存器基址和大小
interrupts = <IRQ_GPIO 17 0x2>; // 中断号和触发方式
};
- 驱动匹配:
驱动的of_device_id包含"vendor,my-device",系统启动时解析设备树,创建 Platform 设备,总线匹配成功后调用probe函数,驱动从设备树中获取reg和interrupts参数,初始化硬件。
总结
Linux 驱动与硬件的对应关系本质是基于总线的双向匹配过程:
- 硬件通过设备树或 ID 声明自身属性;
- 驱动通过注册匹配规则(ID 列表或设备树兼容字符串)声明支持的设备;
- 总线作为中介,通过匹配机制建立驱动与设备的关联,最终在
probe函数中完成硬件初始化和资源分配。
理解这一过程的关键是掌握设备模型、匹配规则和资源访问接口,同时结合具体总线(如 PCI、Platform)和设备类型(字符 / 块 / 网络设备)深入学习对应的驱动框架。