0%

Linux驱动学习日记(17) Linux 驱动文件中各个结构体的关系

  在一份标准 Linux 驱动文件中到处都是结构体,这是一种很工程味的设计哲学。Linux 内核将一切都当对象处理,只不过把 C++ 的 class 换成了 C 的 struct。于是驱动开发看起来就像在拼装一堆对象:谁属于谁、谁调用谁、谁管理谁。今天我们把这几个常见的结构体放在一张地图里理解。

  我们先从用户空间开始想象一条路径

用户程序
-> /dev/xxx 设备文件
-> 内核字符设备
-> 驱动提供的操作函数
-> 具体硬件(gpio、I2C等)

  中间这些结构体,就是这条路径的关键节点。
1、file_operations ———— 驱动的操作说明书
  这是驱动最核心的结构体之一,它本质上是一张函数表,告诉内核如果用户对这个设备执行 open/read/write,该调用什么函数。

1
2
3
4
5
6
struct file_operations {
int (*open)(struct inode *, struct file *);
ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
int (*release)(struct inode *, struct file *);
};

2、cdev ———— 字符设备对象
  Linux 需要知道,这个驱动是一个字符设备,和其对应的 file_operations。这件事由 cdev 结构体管理:

1
2
3
4
5
6
7
8
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
} __randomize_layout;

  其注册过程通常是:

cdev_init(&led.cdev, &gpioled_fops);
cdev_add(&led.cdev, devid, 1);

  两句话先将 gpioled_fops 绑定到 cdev,对应的是设备号为 devid 的设备。

3、class ———— 设备类别
  Linux 设备模型中有一个很重要的层级

/sys/class

例如

/sys/class/leds
/sys/class/input
/sys/class/net

它的创建方式为

class_create(THIS_MODULE, "gpioled");

主要作用是:1、在 /sys/class/ 创建目录。2、给 udev 提供设备信息。3、自动创建设备节点。

4、device ———— 具体设备对象
  class 是类别,device 是具体设备。

device_create(class, NULL, devid, NULL, "gpioled");

  运行完这一句后,系统会生成 /dev/gpioled,同时还会在 /sys/class/gpioled/gpioled 生成对应设备。简单理解:class是分类,device 是实例。类似在 USB 的 class 下有 /dev/ttyUSB0 的设备。

5、device_node ———— 设备树节点
  这个结构体来自设备树系统,驱动会这样找节点:

nd = of_find_node_by_path("/test");

  其作用只有一个:读取设备树中的硬件信息,例如:

test {
    gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;
};

  在驱动中读取后,驱动就知道 LED 接在 GPIO1_IO00。可以说,device_node就是硬件配置数据。

  最终,我们把所有的结构体连起来看,真正的关系应该如下

用户程序
  │
  │ open/read/write
  ▼
file_operations
  │
  ▼
cdev
  │
  ▼
设备号(dev_t)
  │
  ▼
device
  │
  ▼
class

在设备模型中 class 是 device 的父对象。

而硬件信息来自另一条链:

设备树(dts)
    │
    ▼
device_node
    │
    ▼
GPIO/I2C/SPI 等资源

可以这么分类

硬件信息     → device_node
驱动操作     → file_operations
字符设备管理 → cdev
设备模型     → device
设备分类     → class


            用户空间
               │
               ▼
           /dev/gpioled
               │
               ▼
           device
               │
               ▼
            class
               │
               ▼
             cdev
               │
               ▼
        file_operations
               │
               ▼
            驱动代码
               │
               ▼
            GPIO硬件