基本设备结构¶
请参阅 struct device
的内核文档。
编程接口¶
发现设备的总线驱动程序使用此接口向核心注册设备
int device_register(struct device * dev);
总线应初始化以下字段
parent
name
bus_id
bus
当设备的引用计数变为 0 时,它将从核心中移除。可以使用以下方式调整引用计数
struct device * get_device(struct device * dev);
void put_device(struct device * dev);
get_device()
将返回指向传递给它的 struct device
的指针,如果引用计数不为 0 (如果它已经在被移除的过程中)。
驱动程序可以使用以下方式访问设备结构中的锁
void lock_device(struct device * dev);
void unlock_device(struct device * dev);
属性¶
struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
};
设备驱动程序可以通过 sysfs 导出设备的属性。
有关 sysfs 如何工作的更多信息,请参阅 sysfs - 用于导出内核对象的_文件系统。
正如 你可能永远不想了解的关于 kobject、kset 和 ktype 的一切 中解释的那样,设备属性必须在生成 KOBJ_ADD uevent 之前创建。实现这一点的唯一方法是定义一个属性组。
属性使用名为 DEVICE_ATTR 的宏声明
#define DEVICE_ATTR(name,mode,show,store)
示例:
static DEVICE_ATTR(type, 0444, type_show, NULL);
static DEVICE_ATTR(power, 0644, power_show, power_store);
辅助宏可用于 mode 的常见值,因此以上示例可以简化为:
static DEVICE_ATTR_RO(type);
static DEVICE_ATTR_RW(power);
这将声明两个类型为 struct device_attribute
的结构体,分别名为 ‘dev_attr_type’ 和 ‘dev_attr_power’。这两个属性可以按如下方式组织成一个组
static struct attribute *dev_attrs[] = {
&dev_attr_type.attr,
&dev_attr_power.attr,
NULL,
};
static struct attribute_group dev_group = {
.attrs = dev_attrs,
};
static const struct attribute_group *dev_groups[] = {
&dev_group,
NULL,
};
对于单个组的常见情况,有一个辅助宏可用,因此可以使用以下方式声明以上两个结构体:
ATTRIBUTE_GROUPS(dev);
然后,可以通过在调用 device_register()
之前,在 struct device
中设置组指针,将此组数组与设备关联起来
dev->groups = dev_groups;
device_register(dev);
device_register()
函数将使用 ‘groups’ 指针创建设备属性,并且 device_unregister()
函数将使用此指针删除设备属性。
警告:虽然内核允许在任何时候调用设备的 device_create_file()
和 device_remove_file()
,但用户空间对何时创建属性有严格的期望。当在内核中注册新设备时,会生成一个 uevent 来通知用户空间(如 udev)有新设备可用。如果在设备注册后添加属性,则不会通知用户空间,并且用户空间将不知道新的属性。
这对于需要在驱动程序探测时为设备发布其他属性的设备驱动程序非常重要。如果设备驱动程序仅在传递给它的设备结构上调用 device_create_file()
,则永远不会通知用户空间新的属性。