三.设备(device)
/***系统中的每个设备都是一个struct device对象,内核为容纳所有这些设备定义了一个kset-->devices_kset,
****作为系统中所有struct device类型内核对象的容器,内核将系统中的设备分为两大类:block和char
****每一个类对应内核对象,分别为sysfs_dev_block_kobj和sysfs_dev_char_kobj,
****block和char内核对象的上级内核对象为dev_kobj,
*/
/*设备结构*/
struct device {
struct device *parent; /*当前设备的父设备*/
struct device_private *p; /*structure to hold the private to the driver core portions of the device structure*/
/*指向设备驱动相关的数据*/
struct kobject kobj; /*内核对象*/
const char *init_name; /* initial name of the device,内核会把init_name设置成kobj成员的名称,表项为一个目录 */
struct device_type *type;
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
dev_t devt; /* dev_t, creates the sysfs "dev" */
struct class *class;
};
/*设备初始化--*/
void device_initialize(struct device *dev)
{
dev->kobj.kset = devices_kset; devices_kset 在devices_init 中初始化
kobject_init(&dev->kobj, &device_ktype); //kobj_type定义了一组sysfs文件系统相关的操作函数和属性
mutex_init(&dev->mutex);
}
/*注册设备*/
int device_register(struct device *dev)
{
device_initialize(dev);
return device_add(dev);
}
/*注册核心函数*/
int device_add(struct device *dev)
{
struct device *parent = NULL;
struct class_interface *class_intf;
int error = -EINVAL;
dev = get_device(dev);
if (!dev)
goto done;
if (dev->init_name) {
dev_set_name(dev, "%s", dev->init_name);
dev->init_name = NULL;
}
if (!dev_name(dev)) {
error = -EINVAL;
goto name_error;
}
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
parent = get_device(dev->parent);
setup_parent(dev, parent);
/* first, register with generic layer. */
/* we require the name to be set before, and pass NULL */
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);//-->1.建立kobject对象间层次关系,2.在sysfs文件系统中建立一个目录
if (error)
goto Error;
error = device_create_file(dev, &uevent_attr); //为dev->kobject建立属性文件uevent_attr
if (error)
goto attrError;
if (MAJOR(dev->devt)) { //如果设备号不为空,就创建设备文件dev
error = device_create_file(dev, &devt_attr);//为dev->kobject建立属性文件devt_attr
if (error)
goto ueventattrError;
error = device_create_sys_dev_entry(dev);//create symlink between two objects(dev->koobj && dev->class->dev_kobj or sysfs_dev_char_kobj;)
if (error)
goto devtattrError;
devtmpfs_create_node(dev); //在dev 目录文件下生成设备节点
}
/*建立符号链接
* sysfs_create_link - create symlink between two objects.
* @kobj: object whose directory we're creating the link in.
* @target: object we're pointing to.
* @name: name of the symlink.
*int sysfs_create_link(struct kobject *kobj, struct kobject *target, const char *name)
*{
******return sysfs_do_create_link(kobj, target, name, 1);
*}
**/
error = device_add_class_symlinks(dev); //建立符号链接,主要是class中的内核对象和dev中的内核对象
if (error)
goto SymlinkError;
error = device_add_attrs(dev); /*创建设备属性文件*/
if (error)
goto AttrsError;
/**
* bus_add_device - add device to bus
* @dev: device being added
*
* - Add device's bus attributes.
* - Create links to device's bus.
* - Add the device to its bus's list of devices.
*----struct device_private(重点操作对象)
**/
error = bus_add_device(dev);
error = dpm_sysfs_add(dev);
/**
* device_pm_add - Add a device to the PM core's list of active devices.
* @dev: Device to add to the list.
**/
device_pm_add(dev);
/* Notify clients of device addition. This call must come
* after dpm_sysf_add() and before kobject_uevent().
**/
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
/**
* kobject_uevent - notify userspace by sending an uevent
*
* @action: action that is happening
* @kobj: struct kobject that the action is happening to
**/
---kobject_uevent(&dev->kobj, KOBJ_ADD);
/**
* bus_probe_device - probe drivers for a new device
* @dev: device to probe
*
* - Automatically probe for a driver if the bus allows it.
*-->priv->drivers_autoprobe = 1;-->bus_register()
**/
---bus_probe_device(dev);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children); /*和父内核对象建立联系*/
if (dev->class) { /*添加到设备类中*/
mutex_lock(&dev->class->p->class_mutex);
/* tie the class to the device */
klist_add_tail(&dev->knode_class,
&dev->class->p->klist_devices);
/* notify any interfaces that the device is here */
list_for_each_entry(class_intf,
&dev->class->p->class_interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
mutex_unlock(&dev->class->p->class_mutex);
}
}
/**************************************关于class类*****************************/
/**关于class(device classes)--相对于设备device,class是一种更高层次的抽象,
用于对设备进行功能上的划分,有时候也被称为设备类。
linux设备模型引入类class,是将其用来作为具有同类型功能设备的一个容器.
*/
struct class {
const char *name; /*设备类名字*/
struct module *owner; /*拥有该类的模块的指针*/
struct class_attribute *class_attrs; /*类的属性*/
struct device_attribute *dev_attrs; /*设备的属性*/
struct bin_attribute *dev_bin_attrs; /*struct bin_attribute在struct attribute的基础上,
/*增加了read、write等函数,因此它所生成的sysfs文件可以用任何方式读写*/
struct kobject *dev_kobj; /*设备的内核对象*/
struct subsys_private *p; /*类的私有数据--->bus的私有数据*/
};
**/
在系统初始化期间,调用class_init() 产生类的顶层kset-->class_kset--->/sys/class/
int __init classes_init(void)
{
class_kset = kset_create_and_add("class", NULL, NULL);
if (!class_kset)
return -ENOMEM;
return 0;
}
常用操作:
/*用来创建设备类,并添加到/sys/class/目录下*/
struct class *__class_create(struct module *owner, const char *name,struct lock_class_key *key);
/*销毁设备类*/
void class_destroy(struct class *cls);
/****************************关于设备的创建*************************************/
/*创建设备-->在驱动中通常被屏蔽*/ --->创建设备-->注册设备
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)
--->struct device *device_create_vargs(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt,
va_list args)
{
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
dev->devt = devt;
dev->class = class; /*指明设备所在的类*/
dev->parent = parent;
dev->release = device_create_release;
dev_set_drvdata(dev, drvdata);
retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
retval = device_register(dev); /*注册设备*/
return dev;
}
/*销毁设备*/
void device_destroy(struct class *class, dev_t devt)
{
struct device *dev;
dev = class_find_device(class, NULL, &devt, __match_devt);/*通过class设备类找到dev*/
if (dev) {
put_device(dev);
device_unregister(dev); /*销毁设备*/
}
}