以下结构已经删除,使用struct device替代[3]。

struct class_device {
    struct kobject kobj;
    struct class *class;
    struct device *dev;
    void *class_data;
    char class_id[BUS_ID_SIZE];
};
int class_device_register(struct class_device *cd);
void class_device_unregister(struct class_device *cd);
struct class_interface {
    struct class *class;
    int (*add)(struct class_device *cd);
    void (*remove)(struct class_device *cd);
};

三、Linux设备驱动逻辑结构

这里以virtio驱动为例展示了其加载的过程,内部函数调用栈比较深,数据结构之间的关系也是错综复杂,好在对于现有的驱动开发过程可以忽略这些内部实现的细节。

<strong>一、什么是Linux设备驱动模型?</strong>-LMLPHP

如上图virio_net_driver的注册过程如下:

register_vitio_driver

|-> driver_register

|-> bus_add_driver

| |-> kobject_init_and_add -> kobject_init -> kobject_init_internal -> kref_init

| | |-> kobject_add_varg -> kobject_set_name_vargs

| | |-> kobject_add_internal -> create_dir

| |-> klist_and_tail

| |-> module_add_driver

| |-> driver_create_file

| |-> driver_add_group

|-> driver_add_group -> sysfs_create_group -> internal_create_group

|-> kobject_uevent -> kobject_uevent_env

1.2.1 首先为struct device_driver对象初始化driver_private对象

1.2.2 然后为driver_private对象初始化klist对象

1.2.3 然后初始化kobject对象,并调用create_dir创建在sysfs中的目录节点和属性文件

1.2.4 初始化driver_private中的klist_node对象

1.2.5 操作driver_private的module_kobject对象,对两个kobject对象之间建立符号链接,创建驱动目录

1.3 操作device_driver的attiribute_group对象,为驱动设置相应的属性

1.4 最后调用kobject_uevent发送事件通知用户空间

四、示例

参考4中有一个kset的示例,其编译执行后的效果如下图所示,为在/sys/kernel目录下创建一个kset_example目录,包含bar、baz、foo三个目录,每个目录下都有相同的三个文件。

<strong>一、什么是Linux设备驱动模型?</strong>-LMLPHP

参考[5]中是一个字符设备的驱动示例,编译完成后的效果如下图,在/proc/devices文件中可以看到注册的字符设备文件。/dev下的设备需要通过命令mknod /dev/scull0 c 241 0来创建。

<strong>一、什么是Linux设备驱动模型?</strong>-LMLPHP

05-18 09:31