本系列导航
(一)初识Linux驱动
(二)Linux设备驱动的模块化编程
(三)写一个完整的Linux驱动程序访问硬件并写应用程序进行测试
(四)Linux设备驱动之多个同类设备共用一套驱动
(五)Linux设备驱动模型介绍
(六)Linux驱动子系统-I2C子系统
(七)Linux驱动子系统-SPI子系统
(八)Linux驱动子系统-PWM子系统
(九)Linux驱动子系统-Light子系统
(十)Linux驱动子系统-背光子系统
(十一)Linux驱动-触摸屏驱动
文章目录
1. Linux设备驱动模型产生背景
我们知道,同一个LED灯,在不同的硬件平台上,可能接在不同的GPIO上面,那么你针对某个平台写的LED驱动就不适应于另外一个平台,这个时候从新移植驱动到新的平台还是很麻烦的。但是对于这两个平台的LED驱动基本都是相同的,唯有操作的GPIO不同,比如控制方法一样(亮/灭/闪烁等),硬件的gpio接口不一样。所以为了减小移植驱动的工作量,就提出了总线、设备、驱动的这种设备模型,把驱动相同的部分代码提取出来,作为公共部分(平台驱动driver),而与平台相关的单独放在一起(叫做平台设备device),然后通过一个叫做平台总线的东西将他们关联在一起这样,对于同样的设备在不同平台上的驱动只需要修改平台相关的部分即可。
2. Linux设备驱动模型简单介绍
Linux设备驱动模型之bus、device、driver模型,将驱动划分为三个部分–总线(bus)、设备(device)、驱动(driver),总线可以是物理上存在的总线,比如i2c_bus、spi_bus等,也可以是物理上不存在而虚拟出来的总线(platform_bus),设备代码和驱动代码都挂在(通过指针)对应的总线上面,由总线来统一管理他们,总线如果发现它下面挂的驱动和挂在它下面的设备相匹配,那么就会调用驱动里面相应的函数,来获取设备里面相应的硬件信息,从而来初始化硬件设备。简而言之,这三个东西就是对应三个结构体,那么按照这个模型,写驱动,其实就是填充对应的结构体:
struct bus_type {
const char *name; //bus的名字
const char *dev_name;
struct device *dev_root;
struct device_attribute *dev_attrs; /* use dev_groups instead */
const struct attribute_group **bus_groups;
const struct attribute_group **dev_groups;
const struct attribute_group **drv_groups;
int (*match)(struct device *dev, struct device_driver *drv); //device和driver的匹配函数
...
};
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
const struct device_type *type;
struct bus_type *bus; /* type of bus device is on */ //表示这个device挂在哪个bus下面
struct device_driver *driver; /* which driver has allocated this device */
void *platform_data;
struct device_node *of_node; /* associated device tree node */
...
};
struct device_driver {
const char *name; //driver的名字
struct bus_type *bus; //表示这个driver挂在哪个bus下面
struct module *owner;
const char *mod_name; /* used for built-in modules */
const struct of_device_id *of_match_table;
int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
const struct dev_pm_ops *pm;
...
};
bus_dev_drv模型是一个泛型的概念,根据具体的总线,就会衍生出具体的总线模型,比如i2c总线模型,spi总线模型,platform虚拟总线模型,那么接下来具体讲的就是platform总线模型,后续再说I2C等总线模型:
有些驱动(LED、PWM等)没有挂在具体的总线上面,但是也想使用bus_dev_drv模型,那么就需要虚拟一个bus,我们称为platform_bus_type,那么对应的设备称之为platform_device,继承于或者说派生于struct device结构体(面向对象思想),对应的驱动称之为platform_driver,继承于或者说派生于struct device_driver结构体:
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match, //用来匹配platform_device和对应的platform_driver
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
struct platform_device {
const char *name; //platform_device的名字
int id<