class.c

来自「linux 内核源代码」· C语言 代码 · 共 893 行 · 第 1/2 页

C
893
字号
static struct kset_uevent_ops class_uevent_ops = {	.filter =	class_uevent_filter,	.name =		class_uevent_name,	.uevent =	class_uevent,};static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops);static int class_device_add_attrs(struct class_device * cd){	int i;	int error = 0;	struct class * cls = cd->class;	if (cls->class_dev_attrs) {		for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) {			error = class_device_create_file(cd,							 &cls->class_dev_attrs[i]);			if (error)				goto Err;		}	} Done:	return error; Err:	while (--i >= 0)		class_device_remove_file(cd,&cls->class_dev_attrs[i]);	goto Done;}static void class_device_remove_attrs(struct class_device * cd){	int i;	struct class * cls = cd->class;	if (cls->class_dev_attrs) {		for (i = 0; attr_name(cls->class_dev_attrs[i]); i++)			class_device_remove_file(cd,&cls->class_dev_attrs[i]);	}}static int class_device_add_groups(struct class_device * cd){	int i;	int error = 0;	if (cd->groups) {		for (i = 0; cd->groups[i]; i++) {			error = sysfs_create_group(&cd->kobj, cd->groups[i]);			if (error) {				while (--i >= 0)					sysfs_remove_group(&cd->kobj, cd->groups[i]);				goto out;			}		}	}out:	return error;}static void class_device_remove_groups(struct class_device * cd){	int i;	if (cd->groups) {		for (i = 0; cd->groups[i]; i++) {			sysfs_remove_group(&cd->kobj, cd->groups[i]);		}	}}static ssize_t show_dev(struct class_device *class_dev, char *buf){	return print_dev_t(buf, class_dev->devt);}static struct class_device_attribute class_devt_attr =	__ATTR(dev, S_IRUGO, show_dev, NULL);static ssize_t store_uevent(struct class_device *class_dev,			    const char *buf, size_t count){	kobject_uevent(&class_dev->kobj, KOBJ_ADD);	return count;}static struct class_device_attribute class_uevent_attr =	__ATTR(uevent, S_IWUSR, NULL, store_uevent);void class_device_initialize(struct class_device *class_dev){	kobj_set_kset_s(class_dev, class_obj_subsys);	kobject_init(&class_dev->kobj);	INIT_LIST_HEAD(&class_dev->node);}int class_device_add(struct class_device *class_dev){	struct class *parent_class = NULL;	struct class_device *parent_class_dev = NULL;	struct class_interface *class_intf;	int error = -EINVAL;	class_dev = class_device_get(class_dev);	if (!class_dev)		return -EINVAL;	if (!strlen(class_dev->class_id))		goto out1;	parent_class = class_get(class_dev->class);	if (!parent_class)		goto out1;	parent_class_dev = class_device_get(class_dev->parent);	pr_debug("CLASS: registering class device: ID = '%s'\n",		 class_dev->class_id);	/* first, register with generic layer. */	error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);	if (error)		goto out2;	if (parent_class_dev)		class_dev->kobj.parent = &parent_class_dev->kobj;	else		class_dev->kobj.parent = &parent_class->subsys.kobj;	error = kobject_add(&class_dev->kobj);	if (error)		goto out2;	/* add the needed attributes to this device */	error = sysfs_create_link(&class_dev->kobj,				  &parent_class->subsys.kobj, "subsystem");	if (error)		goto out3;	error = class_device_create_file(class_dev, &class_uevent_attr);	if (error)		goto out3;	if (MAJOR(class_dev->devt)) {		error = class_device_create_file(class_dev, &class_devt_attr);		if (error)			goto out4;	}	error = class_device_add_attrs(class_dev);	if (error)		goto out5;	if (class_dev->dev) {		error = sysfs_create_link(&class_dev->kobj,					  &class_dev->dev->kobj, "device");		if (error)			goto out6;	}	error = class_device_add_groups(class_dev);	if (error)		goto out7;	error = make_deprecated_class_device_links(class_dev);	if (error)		goto out8;	kobject_uevent(&class_dev->kobj, KOBJ_ADD);	/* notify any interfaces this device is now here */	down(&parent_class->sem);	list_add_tail(&class_dev->node, &parent_class->children);	list_for_each_entry(class_intf, &parent_class->interfaces, node) {		if (class_intf->add)			class_intf->add(class_dev, class_intf);	}	up(&parent_class->sem);	goto out1; out8:	class_device_remove_groups(class_dev); out7:	if (class_dev->dev)		sysfs_remove_link(&class_dev->kobj, "device"); out6:	class_device_remove_attrs(class_dev); out5:	if (MAJOR(class_dev->devt))		class_device_remove_file(class_dev, &class_devt_attr); out4:	class_device_remove_file(class_dev, &class_uevent_attr); out3:	kobject_del(&class_dev->kobj); out2:	if(parent_class_dev)		class_device_put(parent_class_dev);	class_put(parent_class); out1:	class_device_put(class_dev);	return error;}int class_device_register(struct class_device *class_dev){	class_device_initialize(class_dev);	return class_device_add(class_dev);}/** * class_device_create - creates a class device and registers it with sysfs * @cls: pointer to the struct class that this device should be registered to. * @parent: pointer to the parent struct class_device of this new device, if any. * @devt: the dev_t for the char device to be added. * @device: a pointer to a struct device that is assiociated with this class device. * @fmt: string for the class device's name * * This function can be used by char device classes.  A struct * class_device will be created in sysfs, registered to the specified * class. * A "dev" file will be created, showing the dev_t for the device, if * the dev_t is not 0,0. * If a pointer to a parent struct class_device is passed in, the newly * created struct class_device will be a child of that device in sysfs. * The pointer to the struct class_device will be returned from the * call.  Any further sysfs files that might be required can be created * using this pointer. * * Note: the struct class passed to this function must have previously * been created with a call to class_create(). */struct class_device *class_device_create(struct class *cls,					 struct class_device *parent,					 dev_t devt,					 struct device *device,					 const char *fmt, ...){	va_list args;	struct class_device *class_dev = NULL;	int retval = -ENODEV;	if (cls == NULL || IS_ERR(cls))		goto error;	class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL);	if (!class_dev) {		retval = -ENOMEM;		goto error;	}	class_dev->devt = devt;	class_dev->dev = device;	class_dev->class = cls;	class_dev->parent = parent;	class_dev->release = class_device_create_release;	class_dev->uevent = class_device_create_uevent;	va_start(args, fmt);	vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args);	va_end(args);	retval = class_device_register(class_dev);	if (retval)		goto error;	return class_dev;error:	kfree(class_dev);	return ERR_PTR(retval);}void class_device_del(struct class_device *class_dev){	struct class *parent_class = class_dev->class;	struct class_device *parent_device = class_dev->parent;	struct class_interface *class_intf;	if (parent_class) {		down(&parent_class->sem);		list_del_init(&class_dev->node);		list_for_each_entry(class_intf, &parent_class->interfaces, node)			if (class_intf->remove)				class_intf->remove(class_dev, class_intf);		up(&parent_class->sem);	}	if (class_dev->dev) {		remove_deprecated_class_device_links(class_dev);		sysfs_remove_link(&class_dev->kobj, "device");	}	sysfs_remove_link(&class_dev->kobj, "subsystem");	class_device_remove_file(class_dev, &class_uevent_attr);	if (MAJOR(class_dev->devt))		class_device_remove_file(class_dev, &class_devt_attr);	class_device_remove_attrs(class_dev);	class_device_remove_groups(class_dev);	kobject_uevent(&class_dev->kobj, KOBJ_REMOVE);	kobject_del(&class_dev->kobj);	class_device_put(parent_device);	class_put(parent_class);}void class_device_unregister(struct class_device *class_dev){	pr_debug("CLASS: Unregistering class device. ID = '%s'\n",		 class_dev->class_id);	class_device_del(class_dev);	class_device_put(class_dev);}/** * class_device_destroy - removes a class device that was created with class_device_create() * @cls: the pointer to the struct class that this device was registered * with. * @devt: the dev_t of the device that was previously registered. * * This call unregisters and cleans up a class device that was created with a * call to class_device_create() */void class_device_destroy(struct class *cls, dev_t devt){	struct class_device *class_dev = NULL;	struct class_device *class_dev_tmp;	down(&cls->sem);	list_for_each_entry(class_dev_tmp, &cls->children, node) {		if (class_dev_tmp->devt == devt) {			class_dev = class_dev_tmp;			break;		}	}	up(&cls->sem);	if (class_dev)		class_device_unregister(class_dev);}struct class_device * class_device_get(struct class_device *class_dev){	if (class_dev)		return to_class_dev(kobject_get(&class_dev->kobj));	return NULL;}void class_device_put(struct class_device *class_dev){	if (class_dev)		kobject_put(&class_dev->kobj);}int class_interface_register(struct class_interface *class_intf){	struct class *parent;	struct class_device *class_dev;	struct device *dev;	if (!class_intf || !class_intf->class)		return -ENODEV;	parent = class_get(class_intf->class);	if (!parent)		return -EINVAL;	down(&parent->sem);	list_add_tail(&class_intf->node, &parent->interfaces);	if (class_intf->add) {		list_for_each_entry(class_dev, &parent->children, node)			class_intf->add(class_dev, class_intf);	}	if (class_intf->add_dev) {		list_for_each_entry(dev, &parent->devices, node)			class_intf->add_dev(dev, class_intf);	}	up(&parent->sem);	return 0;}void class_interface_unregister(struct class_interface *class_intf){	struct class * parent = class_intf->class;	struct class_device *class_dev;	struct device *dev;	if (!parent)		return;	down(&parent->sem);	list_del_init(&class_intf->node);	if (class_intf->remove) {		list_for_each_entry(class_dev, &parent->children, node)			class_intf->remove(class_dev, class_intf);	}	if (class_intf->remove_dev) {		list_for_each_entry(dev, &parent->devices, node)			class_intf->remove_dev(dev, class_intf);	}	up(&parent->sem);	class_put(parent);}int __init classes_init(void){	int retval;	retval = subsystem_register(&class_subsys);	if (retval)		return retval;	/* ick, this is ugly, the things we go through to keep from showing up	 * in sysfs... */	kset_init(&class_obj_subsys);	if (!class_obj_subsys.kobj.parent)		class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;	return 0;}EXPORT_SYMBOL_GPL(class_create_file);EXPORT_SYMBOL_GPL(class_remove_file);EXPORT_SYMBOL_GPL(class_register);EXPORT_SYMBOL_GPL(class_unregister);EXPORT_SYMBOL_GPL(class_create);EXPORT_SYMBOL_GPL(class_destroy);EXPORT_SYMBOL_GPL(class_device_register);EXPORT_SYMBOL_GPL(class_device_unregister);EXPORT_SYMBOL_GPL(class_device_initialize);EXPORT_SYMBOL_GPL(class_device_add);EXPORT_SYMBOL_GPL(class_device_del);EXPORT_SYMBOL_GPL(class_device_get);EXPORT_SYMBOL_GPL(class_device_put);EXPORT_SYMBOL_GPL(class_device_create);EXPORT_SYMBOL_GPL(class_device_destroy);EXPORT_SYMBOL_GPL(class_device_create_file);EXPORT_SYMBOL_GPL(class_device_remove_file);EXPORT_SYMBOL_GPL(class_device_create_bin_file);EXPORT_SYMBOL_GPL(class_device_remove_bin_file);EXPORT_SYMBOL_GPL(class_interface_register);EXPORT_SYMBOL_GPL(class_interface_unregister);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?