Linux的sysfs文件系统一般mount在/sys目录。本文主要介绍sysfs文件系统中设备驱动模型的建立过程,内核版本2.6.29。
设备驱动信息主要用来表示设备以及驱动的层次关系,以及处理热插拔等。/sys中与之相关的数据有:
class 代表一类设备,比如mtd、net、tty等等
bus 总线,比如PCI、USB、I2C等
device 代表一个设备
driver 代表一个驱动
以下是一些sysfs中的全局变量:
// /sys/class
struct kset * class_kset = kset_create_and_add("class", NULL, NULL);
// /sys/bus
struct kset * bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
// /sys/devices
struct kset * devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
1. Class
1.1 class的基本结构
struct class {
const char *name;
struct module *owner;
struct class_attribute *class_attrs;
struct device_attribute *dev_attrs;
struct kobject *dev_kobj;
int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
void (*class_release)(struct class *class);
void (*dev_release)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
struct pm_ops *pm;
struct class_private *p;
};
struct class_private {
struct kset class_subsys;
struct list_head class_devices;
struct list_head class_interfaces;
struct kset class_dirs;
struct mutex class_mutex;
struct class *class;
};
class在sysfs中的层次由struct class_private决定。struct class只是class_private的封装。
struct class_private::class_subsys.kobj.kset = class_kset; // 父目录为/sys/class
struct class_private::class_subsys.kobj->name代表这个class在/sys/class中显示的名字
struct class::dev_attrs为设备属性,往class中添加设备的时候,这些属性会自动添加到设备目录下。
1.2 新建class
新建class有两种方法:静态创建和动态创建。
l 静态创建
static struct class i2c_adapter_class = {
.owner = THIS_MODULE,
.name = "i2c-adapter",
.dev_attrs = i2c_adapter_attrs,
.class_attrs = ...
};
int retval = class_register(&i2c_adapter_class);
l 动态创建
i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
class_create分配申请一块空间给class,然后对name、owner和class_release函数赋值,并最终调用class_register。
class_register
根据struct class的值,设置struct class_private
调用add_class_attrs在class中添加属性。
l class attrs
class的属性最终是在/sys/class/<new class>/目录下以文件的形式存在。用户程序可以直接对这些属性进行读写。如果要静态创建属性,可以在定义class时对.class_attrs域赋值,使其指向要添加的attr数组。如果要动态创建。可以通过函数class_create_file添加。
int class_create_file(struct class *cls, const struct class_attribute *attr);
如果是动态创建的属性,需要在模块卸载时调用class_remove_file释放。
如果是静态创建的属性,在调用class_unregister时会自动释放。
2. Bus
2.1 bus的基本结构
struct bus_type {
const char *name;
struct bus_attribute *bus_attrs;
struct device_attribute *dev_attrs;
struct driver_attribute *drv_attrs;
int (*match)(struct device *dev, struct device_driver *drv);
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
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 (*suspend_late)(struct device *dev, pm_message_t state);
int (*resume_early)(struct device *dev);
int (*resume)(struct device *dev);
struct pm_ext_ops *pm;
struct bus_type_private *p;
};
struct bus_type_private {
struct kset subsys;
struct kset *drivers_kset;
struct kset *devices_kset;
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
struct bus_type *bus;
};
与class类似,bus在sysfs中的显示由struct bus_type_private决定,struct bus_type只是一个封装。
struct bus_type_private::subsys.kobj代表/sys/bus/<bus>目录。
struct bus_type_private::subsys.kobj.kset = bus_kset; // 默认父目录为/sys/bus/
struct bus_type_private::subsys.kobj.ktype = &bus_ktype; // bus的属性操作
struct bus_type_private::subsys.kobj.name = <bus在/sys/bus/目录下显示的名字>;
在/sys/bus/目录,每创建成功一个<bus>,都会自动创建两个子目录drivers和devices,分别代表连到此<bus>的设备和驱动。在drivers和devices子目录下,每新建一个driver,会把struct bus_type中的drv_attrs属性赋给那个driver;每创建一个device,会把struct bus_type中dev_attrs赋给那个device。
2.2 新建bus
struct bus_type i2c_bus_type = {
.name = "i2c",
.dev_attrs = i2c_dev_attrs,
.match = i2c_device_match,
.uevent = i2c_device_uevent,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
.suspend = i2c_device_suspend,
.resume = i2c_device_resume,
.bus_attr = …
};
int ret = bus_register(&i2c_bus_type);
int bus_register(struct bus_type *bus);
分配内存给struct bus_type_private;
根据struct bus_type的域设置bus_type_private;
根据.bus_attr设置bus的属性,这些属性在bus_unregister时会被自动释放。(bus属性也可通过bus_create_file动态添加,但所有动态添加的属性都要在卸载时通过bus_remove_file释放。)
3.Device
3.1 Device的基本结构
struct device {
struct klist klist_children;
struct klist_node knode_parent; /* node in sibling list */
struct klist_node knode_driver;
struct klist_node knode_bus;
struct device *parent;
struct kobject kobj;
char bus_id[BUS_ID_SIZE]; /* position on parent bus */
const char *init_name; /* initial name of the device */
struct device_type *type;
unsigned uevent_suppress:1;
struct semaphore sem; /* semaphore to synchronize calls to its driver. */
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this device */
void *driver_data; /* data private to the driver */
void *platform_data; /* Platform specific data, device core doesn't touch it */
struct dev_pm_info power;
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for alloc_coherent mappings as not all hardware supports 64 bit addresses for consistent allocations such descriptors. */
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
/* arch specific additions */
struct dev_archdata archdata;
spinlock_t devres_lock;