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驱动为例展示了其加载的过程,内部函数调用栈比较深,数据结构之间的关系也是错综复杂,好在对于现有的驱动开发过程可以忽略这些内部实现的细节。
如上图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三个目录,每个目录下都有相同的三个文件。
参考[5]中是一个字符设备的驱动示例,编译完成后的效果如下图,在/proc/devices文件中可以看到注册的字符设备文件。/dev下的设备需要通过命令mknod /dev/scull0 c 241 0来创建。