Linux的总线设备驱动模型
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux的总线设备驱动模型
裸机编写驱动⽐较⾃由,按照⼿册实现其功能即可,每个⼈写出来都有很⼤不同;
⽽Linux中还需要按照Linux的驱动模型来编写,也就是需要按照“模板”来写,写出来的驱动就⽐较统⼀。
⼀、 Linux采⽤总线设备驱动模型。
主要包含总线、设备、驱动三个部分。
总线:最先注册,有⼏个重要的回调函数,例如match函数⽤于匹配device和driver。
设备:设备的物理信息,例如设备名、物理地址、中断号等;
驱动:设备的驱动程序和设备名等信息,例如初始化函数、波特率设置函数、启动停⽌函数、中断函数等。
现实中,很多设备都是接在总线上的,例如SPI Flash接在SPI总线上,EEPROM接在I2C总线上。
但也有很多芯⽚内部设备没有挂在总线上,例如UART、SPI控制器。
为了统⼀使⽤Linux总线设备驱动模型,内核中定义了⼀个虚拟总线platform_bus_type,将这些设备(叫做平台设备)注册到该虚拟总线上统⼀管理。
⼆、Linux驱动注册顺序(总线、设备、驱动三者关系)
1、注册总线 xxx_bus_type:
在系统初始化阶段,会⾸先向内核注册各种常⽤的总线类型,⽐如pci, usb, spi, i2c, platform等等。
有两个重要的链表挂在bus上,⼀个是设备device链表,⼀个是驱动driver链表。
它包含的最关键的函数:match()⽤于匹配device和driver。
//例⼦:
static int __init spi_init(void)
{
int status;
printk("@@ spi_init :spi_bus_type\n");
buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
if (!buf) {
status = -ENOMEM;
goto err0;
}
status = bus_register(&spi_bus_type);
if (status < 0)
goto err1;
status = class_register(&spi_master_class);
if (status < 0)
goto err2;
return 0;
err2:
bus_unregister(&spi_bus_type);
err1:
kfree(buf);
buf = NULL;
err0:
return status;
}
2、注册设备:将系统设备注册进内核的对应总线上,⼤多是调⽤xxx_device_regisger注册。
(xxx_device_regisger:将⾃⼰加到xxx总线的device链表,然后使⽤总线bus匹配对应的driver )
3、注册驱动:将系统设备的driver注册进内核的对应总线上:⼤多是调⽤xxx_drvier_register()注册。
(xxx_drvier_register:将⾃⼰加到xxx总线的driver链表,然后使⽤总线bus匹配对应的device )
2和3很多是在同⼀个函数中注册的,所以⼀起举例:
例⼦1:
platform_driver_register(&uart_driver); //将uart的driver注册到platform_bus上;
platform_device_register(&uart_device); //将uart的device注册到platform_bus上;
例⼦2:
SPI Master控制器:drivers/spi/my_spi_master.c
platform_device_register(&dw_spi0_device); //注册device
platform_driver_probe(&dw_spi0_driver, dw_spi0_probe); //1、注册driver
//2、spi_new_device⼦函数会注册SPI Flash的device到spi总线上;
//3、这⾥实现Master和Flash的绑定,即flash要使⽤哪个控制器控制;
例⼦3:
SPI Flash:drivers/mtd/gd25q_spi.c
spi_register_driver(&spi_flash_drv); //注册SPI Flash的driver到spi总线
上⾯⼏个例⼦的device和driver都成功注册后,对应总线的match回调函数会成功匹配driver和device,
并调⽤driver的probe函数完成设备初始化。
可以看到,不同设备的device和driver注册位置可能不同、注册顺序可能不同、注册函数名可能不同!!
4、设备和驱动的匹配:
⽼版内核的匹配⼤部分是看device和driver的name属性是否相同;新版使⽤设备树的内核中,是根据程序中driver的compatible 与设备树节点的compatible 是否相同来匹配!
match的⼯作是由总线(bus)来完成。
在xxx_device_register()或xxx_drvier_register(),即设备或驱动注册的时候,都会引发总线调⽤⾃⼰的match函数来寻找是否挂载有与该设备(或驱动)名字匹配的驱动(或设备);
如果只注册了设备或者只注册了驱动,总线会判定匹配失败,则暂时不会调⽤driver中的probe函数进⾏初始化等操作;要等到设备、驱动都注册成功并匹配绑定后才会调⽤。