Linux设备模型:基础篇
linux提供了新的设备模型:总线(bus)、设备(device)、驱动(driver)。其中总线是处理器与设备之间通道,在设备模型中,所有的设备都通过总线相连;设备是对于一个设备的详细信息描述,驱动是设备的相关驱动。其基本关系如下:bus 相当于一个容器,是device 和device_driver 的管理机构,它包含了一个device 集合和一个driver 集合。其中,device集合包含了挂在该总线下的所有设备,这些设备通过链表链接起来;driver集合包含了挂在该总线下的所有驱动程序,这些驱动程序通过链表链接起来。
sysfs文件系统:
sysfs文件系统是Linux2.6内核引入的,它被看成是与proc、devfs和devpty等同类别的文件系统,sysfs文件系统也是一个虚拟文件系统,它可以产生一个包括所有系统硬件的层级视图,与提供进程和状态信息的proc文件系统十分类似;
sysfs文件系统把链接在系统上的所有设备和总线组织成一个分级的文件系统,它们可以由用户空间存取,并向用户空间导出内核数据结构以及它们的属性等信息.sysfs的一个目的就是展示设备驱动模型中各个组件的层次关系,其顶级目录包括:
1、block:包含系统中所有的块设备;
2、devices:包含系统中所有的设备,并根据设备挂载的总线类型组织成层次关系结构;
3、bus:包含系统中所有的总线类型;
4、drivers:包含系统内核中所有已经注册的设备驱动程序;
5、class:包含系统中所有的设备类型;如,网卡设备、声卡设备、输入设备、输出设备,等等;
设备模型:
从整体上描述,大概模型就如下图所示:
从图中可以看出,Linux设备模型就是"总线、设备、驱动、类"这四个概念之前的相互关系;这也是Linux2.6内核抽象出来的用于管理系统中所有设备的模型图;
简单地描述设备模型的层次关系如下:
1、驱动核心中可以注册多种类型的总线(bus_type);
2、每一种类型的总线下面可以挂载许多设备(kset,device);
3、每一种类型的总线可以使用很多设备驱动(kset,device_driver);
4、每一个驱动程序可以管理一组设备;
这种基本关系的建立源于实际系统中各种总线、设备、驱动、类结构的抽象;
Linux设备模型中的总线、设备、驱动和类之间环环相扣的复杂关系可以满足内核日益发展的的需要;对智能电源管理、热插拔以及即插即用的支持要求也越来越高;
1、关于总线bus
(1)bus的结构体
struct bus_type,该结构体中有个函数指针成员:int (*match)(struct device * dev, struct device_driver * drv); 这个函数指针非常重要,当一个新的设备或驱动被添加到一个总线时会被调用,是建立总线上设备与驱动的桥梁。
(2)总线的操作:
注册:int bus_register(struct bus_type * bus)
注销:void bus_unregister(struct bus_type *bus);
(3)总线属性 bus_attribute
struct bus_attribute BUS_ATTR(name, mode, show, store);
这个宏声明一个结构, 产生它的名子通过前缀字符串 bus_attr_ 到给定的名字(bus_attr_name),然后利用bus_create_file来创建总线属性
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);
参数中的attr,即为bus_attr_name。
2、关于device
(1)在底层,一个设备对于一个设备结构体struct device
(2)设备的操作
注册设备:int device_register(sruct device *dev)
注销设备:void device_unregister(struct device *dev);
(3)设备属性:
sysfs 中的设备入口可有属性. 相关的结构是:
struct device_attribute这个属性结构可在编译时建立, 使用宏:
DEVICE_ATTR(name, mode, show, store);
结果结构通过前缀 dev_attr_ 到给定名子上来命名. 属性文件的实际管理使用通常的函数对来处理:
int device_create_file(struct device *device, struct device_attribute *entry);
void device_remove_file(struct device *dev, struct device_attribute *attr);
3、关于driver
(1)driver结构体为struct device_driver
(2)驱动程序的操作
驱动程序的注册int driver_register(struct device_driver *drv);
驱动程序的注销void driver_unregister(struct device_driver *drv);
(3)驱动程序的属性
struct driver_attribute DRIVER_ATTR(_name,_mode,_show,_store) /*属性文件创建的方法:*/
int driver_create_file(struct device_driver * drv, struct driver_attribute * attr);//创建设备驱动的属性
void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr);//删除设备驱动的属性
简单例子:
/* my_bus.h */ extern struct bus_type my_bus_type; struct my_driver { char *version; struct module *module; struct device_driver driver; struct driver_attribute version_attr; }; #define to_my_driver(drv) container_of(drv, struct my_driver, driver) struct my_device { char *name; struct my_driver *driver; struct device device; }; #define to_my_device(dev) container_of(dev, struct my_device, device) /* interface to device. */ extern int register_my_device(struct my_device *); extern void unregister_my_device(struct my_device *); /* interface to driver. */ extern int register_my_driver(struct my_driver *); extern void unregister_my_driver(struct my_driver *); /* my_bus.c */ #include <linux/module.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> #include "my_bus.h" MODULE_LICENSE("Dual BSD/GPL"); #define MYBUS "mybus: " #define PRINT(x...) printk(KERN_ALERT MYBUS x); static char *Version = "$Revision: 1.9 $"; static ssize_t show_bus_version(struct bus_type *bus, char *buf) { PRINT("%s\n", __func__); return snprintf(buf, PAGE_SIZE, "my_bus: %s\n", Version); } static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL); static void my_bus_release(struct device *dev) { PRINT("%s\n", __func__); } static int my_bus_match(struct device *dev, struct device_driver *drv) { struct my_device *device = to_my_device(dev); PRINT("%s\n", __func__); return !strncmp(device->name, drv->name, strlen(drv->name)); } static int my_bus_hotplug(struct device *dev, struct kobj_uevent_env *env){ PRINT("%s\n", __func__); return 0; } struct bus_type my_bus_type = { .name = "my_bus", .match = my_bus_match, .uevent = my_bus_hotplug }; static struct device my_bus = { .init_name = "my_bus0", .release = my_bus_release }; /* interface to device. */ int register_my_device(struct my_device *device) { PRINT("%s\n", __func__); device->device.bus = &my_bus_type; device->device.parent = &my_bus; device->device.release = my_bus_release; //strncpy(device->device.bus_id, device->name, BUS_ID_SIZE); return device_register(&device->device); } EXPORT_SYMBOL(register_my_device); void unregister_my_device(struct my_device *device) { PRINT("%s\n", __func__); device_unregister(&device->device); } EXPORT_SYMBOL(unregister_my_device); static ssize_t show_version(struct device_driver *driver, char *buf) { struct my_driver *drv = to_my_driver(driver); PRINT("%s\n", __func__); sprintf(buf, "%s\n", drv->version); return strlen(buf); } /* interface to driver. */ int register_my_driver(struct my_driver *driver) { int ret = 0; PRINT("%s\n", __func__); driver->driver.bus = &my_bus_type; ret = driver_register(&driver->driver); if (ret) { PRINT("%s, driver_register %s failed!!!\n", __func__, driver->driver.name); return ret; } driver->version_attr.attr.name = "version"; //driver->version_attr.attr.owner = driver->module; driver->version_attr.attr.mode = S_IRUGO; driver->version_attr.show = show_version; return driver_create_file(&driver->driver, &driver->version_attr); } EXPORT_SYMBOL(register_my_driver); void unregister_my_driver(struct my_driver *driver) { PRINT("%s\n", __func__); driver_unregister(&driver->driver); } EXPORT_SYMBOL(unregister_my_driver); static int __init my_bus_init(void) { int ret = 0; ret = bus_register(&my_bus_type); if (ret) { PRINT("%s, bus_register failed!\n", __func__); goto bus_register_failed; } ret = bus_create_file(&my_bus_type, &bus_attr_version); if (ret) { PRINT("%s, bus_create_file failure...!\n", __func__); goto bus_create_file_failed; } ret = device_register(&my_bus); if (ret) { PRINT("%s, device_register failure...!\n", __func__); goto device_register_failed; } PRINT("%s, bus & device register succeed!\n", __func__); return 0; device_register_failed: bus_create_file_failed: bus_unregister(&my_bus_type); bus_register_failed: return ret; } static void __exit my_bus_exit(void) { PRINT("%s!\n", __func__); device_unregister(&my_bus); bus_unregister(&my_bus_type); } module_init(my_bus_init); module_exit(my_bus_exit); /* 我的设备 my_device.c */ #include <linux/module.h> #include <linux/init.h> #include <linux/string.h> #include <linux/kernel.h> #include <linux/device.h> #include "my_bus.h" #define MYDEVICE "my-device: " #define PRINT(x...) printk(KERN_ALERT MYDEVICE x); MODULE_LICENSE("Dual BSD/GPL"); static struct my_device device = { .name = "hunk_device", .device = { .init_name = "my_device", } }; static int __init my_device_init(void) { int ret = 0; PRINT("%s\n", __func__); ret = register_my_device(&device); if (ret) { PRINT("%s failure..!\n", __func__); return ret; } return 0; } static void __exit my_device_exit(void) { PRINT("%s\n", __func__); unregister_my_device(&device); } module_init(my_device_init); module_exit(my_device_exit); /* 我的驱动 my_driver.c */ #include <linux/module.h> #include <linux/init.h> #include <linux/string.h> #include <linux/kernel.h> #include <linux/device.h> #include "my_bus.h" #define MYDRIVER "my-driver: " #define PRINT(x...) printk(KERN_ALERT MYDRIVER x); MODULE_LICENSE("Dual BSD/GPL"); static struct my_driver driver = { .module = THIS_MODULE, .driver = { .name = "hunk_device", .owner = THIS_MODULE } }; static int __init my_driver_init(void) { int ret = 0; PRINT("%s\n", __func__); ret = register_my_driver(&device); if (ret) { PRINT("%s failure..!\n", __func__); return ret; } return 0; } static void __exit my_driver_exit(void) { PRINT("%s\n", __func__); unregister_my_driver(&device); } module_init(my_driver_init); module_exit(my_driver_exit);