1. 程式人生 > >linux核心之class介紹(一)

linux核心之class介紹(一)

class的概念
class是裝置的更高層檢視,抽象出了底層的實現細節.驅動程式會區分SCSI硬碟和ATA硬碟,但在class層他們都是
硬碟.classes幫助使用者空間只需要知道這些是什麼裝置,而不需要關心他們是怎麼連線和工作的.(A class is a higher-level view of a device that abstracts out low-level implementation details. Drivers may see a SCSI disk or an ATA disk, but,at the class level, they are all simply disks. Classes allow user space to work with devices based on what they do, rather than how they are connected or how they work.)

class結構體
include\linux\Device.h

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 kobject			*dev_kobj;

	int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
	char *(*devnode)(struct device *dev, mode_t *mode);

	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);

	const struct kobj_ns_type_operations *ns_type;
	const void *(*namespace)(struct device *dev);

	const struct dev_pm_ops *pm;

	struct subsys_private *p;
};

@name: Name of the class.

	error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);

該名字用於設定subsys_private.subsys.kobj的名字,也就是子系統的目錄名,如:sys/class/name

@owner: The module owner.
表示該class所屬的module

@class_attrs: Default attributes of this class.
表示class預設的屬性,在class註冊時建立

	error = add_class_attrs(class_get(cls));

@dev_attrs: Default attributes of the devices belong to the class.
@dev_bin_attrs: Default binary attributes of the devices belong to the class.
以上dev_attrs,dev_bin_attrs是裝置相關的屬性,在裝置新增到該class時在裝置目錄需要建立的屬性檔案

static int device_add_attrs(struct device *dev)
{
	struct class *class = dev->class;
	const struct device_type *type = dev->type;
	int error;

	if (class) { // 如果定義了class,新增class的裝置屬性檔案dev_attrs,dev_bin_attrs
		error = device_add_attributes(dev, class->dev_attrs);
		if (error)
			return error;
		error = device_add_bin_attributes(dev, class->dev_bin_attrs);
		if (error)
			goto err_remove_class_attrs;
	}
	.............
}

@dev_kobj: The kobject that represents this class and links it into the hierarchy.
dev_kobj是kobject指標,指向sysfs_dev_char_kobj(sys/dev/char),表示屬於該class的裝置在sys/dev/char目錄

	/* set the default /sys/dev directory for devices of this class */
	if (!cls->dev_kobj)
		cls->dev_kobj = sysfs_dev_char_kobj;// sys/dev/char

sysfs_dev_char_kobj在這裡建立,代表/sys/dev/char目錄:

int __init devices_init(void)
{
	// 建立/sys/devices目錄
	devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
	if (!devices_kset)
		return -ENOMEM;
	// 建立/sys/dev目錄
	dev_kobj = kobject_create_and_add("dev", NULL);
	if (!dev_kobj)
		goto dev_kobj_err;
	// 建立/sys/dev/block目錄
	sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
	if (!sysfs_dev_block_kobj)
		goto block_kobj_err;
	// 建立/sys/dev/char目錄
	sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
	if (!sysfs_dev_char_kobj)
		goto char_kobj_err;

	return 0;

 char_kobj_err:
	kobject_put(sysfs_dev_block_kobj);
 block_kobj_err:
	kobject_put(dev_kobj);
 dev_kobj_err:
	kset_unregister(devices_kset);
	return -ENOMEM;
}

@dev_uevent: Called when a device is added, removed from this class, or a
few other things that generate uevents to add the environment
variables.
device加入class或從class移除,或者一些其它事件發生時呼叫uevent來新增環境變數
driver/base/core.c

static int dev_uevent(struct kset *kset, struct kobject *kobj,
		      struct kobj_uevent_env *env)
{
	struct device *dev = to_dev(kobj);
	int retval = 0;

	/* add device node properties if present */
	if (MAJOR(dev->devt)) {
		const char *tmp;
		const char *name;
		mode_t mode = 0;

		add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
		add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
		name = device_get_devnode(dev, &mode, &tmp);
		if (name) {
			add_uevent_var(env, "DEVNAME=%s", name);
			kfree(tmp);
			if (mode)
				add_uevent_var(env, "DEVMODE=%#o", mode & 0777);
		}
	}

	if (dev->type && dev->type->name)
		add_uevent_var(env, "DEVTYPE=%s", dev->type->name);

	if (dev->driver)
		add_uevent_var(env, "DRIVER=%s", dev->driver->name);

	/* have the bus specific function add its stuff */
	if (dev->bus && dev->bus->uevent) {
		retval = dev->bus->uevent(dev, env);
		if (retval)
			pr_debug("device: '%s': %s: bus uevent() returned %d\n",
				 dev_name(dev), __func__, retval);
	}

	/* have the class specific function add its stuff */
	if (dev->class && dev->class->dev_uevent) { // 呼叫所屬class->dev_uevent
		retval = dev->class->dev_uevent(dev, env);
		if (retval)
			pr_debug("device: '%s': %s: class uevent() "
				 "returned %d\n", dev_name(dev),
				 __func__, retval);
	}

	/* have the device type specific function add its stuff */
	if (dev->type && dev->type->uevent) {
		retval = dev->type->uevent(dev, env);
		if (retval)
			pr_debug("device: '%s': %s: dev_type uevent() "
				 "returned %d\n", dev_name(dev),
				 __func__, retval);
	}

	return retval;
}

static const struct kset_uevent_ops device_uevent_ops = {
	.filter =	dev_uevent_filter,
	.name =		dev_uevent_name,
	.uevent =	dev_uevent,
};

int __init devices_init(void)
{
	// 建立/sys/devices目錄
	devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
	if (!devices_kset)
		return -ENOMEM;
	.......
}

@devnode: Callback to provide the devtmpfs.
用於返回device裝置節點的相對路徑

@class_release: Called to release this class.
用於釋放class

@dev_release: Called to release the device.
用於釋放device

@suspend: Used to put the device to sleep mode, usually to a low power
state.
用於讓裝置進入睡眠模式,通常是低功耗模式

@resume: Used to bring the device from the sleep mode.
讓裝置退出睡眠模式

@ns_type: Callbacks so sysfs can detemine namespaces.
sysfs用於確定名稱空間(namespaces)

@namespace: Namespace of the device belongs to this class.

@pm: The default device power management operations of this class.
電源管理用的函式集合

@p: The private data of the driver core, no one other than the
driver core can touch this.
p指向subsys_private結構體,用於儲存歸屬該class的device和driver連結串列:

struct subsys_private {
	struct kset subsys; // the struct kset that defines this subsystem
	struct kset *devices_kset; // the list of devices associated

	struct kset *drivers_kset; // the list of drivers associated
	struct klist klist_devices;// the klist to iterate over the @devices_kset
	struct klist klist_drivers;// the klist to iterate over the @drivers_kset
	struct blocking_notifier_head bus_notifier;//the bus notifier list for anything that cares about things on this bus.
	unsigned int drivers_autoprobe:1;
	struct bus_type *bus;//pointer back to the struct bus_type that this structure is associated with.

	struct list_head class_interfaces;// list of class_interfaces associated
	struct kset glue_dirs;//"glue" directory to put in-between the parent device to  avoid namespace conflicts
	struct mutex class_mutex;//mutex to protect the children, devices, and interfaces lists.
	struct class *class; // pointer back to the struct class that this structure is associated with.
};