Linux设备驱动——驱动模型

目录

一、概述

二 、BUS

2.1 说明

2.2 数据抽象

2.3 接口

2.4 实现

三、device

3.1 说明

3.2 数据抽象

3.3 接口

3.4 实现

四、driver

4.1 说明

4.2 数据抽象

4.3 接口

4.4 实现

五、class

5.1 说明

5.2 数据抽象

5.3 接口

5.4 实现

六、小结


一、概述

驱动模型描述的是bus,driver,device三者的关系。

二 、BUS

2.1 说明

 * A bus is a channel between the processor and one or more devices. For the
 * purposes of the device model, all devices are connected via a bus, even if
 * it is an internal, virtual, "platform" bus. Buses can plug into each other.
 * A USB controller is usually a PCI device, for example. The device model
 * represents the actual connections between buses and the devices they control.
 * A bus is represented by the bus_type structure. It contains the name, the
 * default attributes, the bus' methods, PM operations, and the driver core's
 * private data.
 */

2.2 数据抽象

[linux/linux/device.h]

struct bus_type {
	const char		*name;
	const char		*dev_name;
	struct device		*dev_root;
	struct device_attribute	*dev_attrs;	/* use dev_groups instead */
	const struct attribute_group **bus_groups;
	const struct attribute_group **dev_groups;
	const struct attribute_group **drv_groups;

	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 (*online)(struct device *dev);
	int (*offline)(struct device *dev);

	int (*suspend)(struct device *dev, pm_message_t state);
	int (*resume)(struct device *dev);

	int (*num_vf)(struct device *dev);

	const struct dev_pm_ops *pm;

	const struct iommu_ops *iommu_ops;

	struct subsys_private *p;
	struct lock_class_key lock_key;
};

2.3 接口

  • int bus_register(struct bus_type *bus);

2.4 实现

通过分析看一下bus注册后怎么将bus信息通过sysfs构建起来

[drivers/base/bus.c]

int __init buses_init(void)
{
	bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
	if (!bus_kset)
		return -ENOMEM;

	system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
	if (!system_kset)
		return -ENOMEM;

	return 0;
}

根据在Linux设备驱动——驱动模型之kobject/kset中的分析,上面两次调用是顶层的kset,对“bus”来说参数指定为NULL,说明其在/sys的根下,而“system”位于devices_kset下的kset,后面会讲到devices_kset是device顶级kset

[root@localhost ~]# ls /sys/
block  bus  class  dev  devices  firmware  fs  hypervisor  kernel  module  power

[root@localhost ~]# ls /sys/devices/
breakpoint  cpu  LNXSYSTM:00  msr  pci0000:00  platform  pnp0  power  software  system  tracepoint  virtual

接下来分析bus注册及过程中的sys文件系统的变化,假设新注册的总线名称为“new_bus”

int bus_register(struct bus_type *bus)
{

	retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
	if (retval)
		goto out;

	priv->subsys.kobj.kset = bus_kset;
	priv->subsys.kobj.ktype = &bus_ktype;
	priv->drivers_autoprobe = 1;

	retval = kset_register(&priv->subsys);
}

第一个片段,为该bus创建一个kset,所有总线都属于顶级总线kset

另外,在调用kset_registger时,指定了name,ktype,kset(其实就是parent了),这时候,在sys中出现:

  • /sys/bus/new_bus
retval = bus_create_file(bus, &bus_attr_uevent);
if (retval)
	goto bus_uevent_fail;

priv->devices_kset = kset_create_and_add("devices", NULL, &priv->subsys.kobj);
if (!priv->devices_kset) {
	retval = -ENOMEM;
	goto bus_devices_fail;
}

priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);
if (!priv->drivers_kset) {
	retval = -ENOMEM;
	goto bus_drivers_fail;
}

接下来通过bus_create_file创建event文件

  • /sys/bus/new_bus/event

然后通过kset_create_and_add在当前new_bus下创建devices,和drivers的kset

  • /sys/bus/new_bus/devices
  • /sys/bus/new_bus/drivers
	retval = add_probe_files(bus);
	if (retval)
		goto bus_probe_files_fail;

	retval = bus_add_groups(bus, bus->bus_groups);
	if (retval)
		goto bus_groups_fail;

最后通过add_probe_files创建probe和autoprobe

  • /sys/bus/new_bus/drivers_probe
  • /sys/bus/new_bus/drivers_autoprobe

bus_add_groups创建文件属性

以i2c为例,看下bus注册后的结构:

[root@localhost ~]# tree /sys/bus/i2c/
/sys/bus/i2c/
├── devices
├── drivers
│   └── dummy
│       ├── bind
│       ├── module -> ../../../../module/i2c_core
│       ├── uevent
│       └── unbind
├── drivers_autoprobe
├── drivers_probe
└── uevent

kset的情况画了个图:

相同颜色代表属于一个kset。

三、device

3.1 说明

* At the lowest level, every device in a Linux system is represented by an
 * instance of struct device. The device structure contains the information
 * that the device model core needs to model the system. Most subsystems,
 * however, track additional information about the devices they host. As a
 * result, it is rare for devices to be represented by bare device structures;
 * instead, that structure, like kobject structures, is usually embedded within
 * a higher-level representation of the device.
 */

3.2 数据抽象

[include/linux/device.h]

struct device {
	struct device		*parent;

	struct device_private	*p;

	struct kobject kobj;
	const char		*init_name; /* initial name of the device */
	const struct device_type *type;

	struct mutex		mutex;	/* mutex 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		*platform_data;	/* Platform specific data, device
					   core doesn't touch it */
	void		*driver_data;	/* Driver data, set and get with
					   dev_set/get_drvdata */
	struct dev_links_info	links;
	struct dev_pm_info	power;
	struct dev_pm_domain	*pm_domain;

#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
	struct irq_domain	*msi_domain;
#endif
#ifdef CONFIG_PINCTRL
	struct dev_pin_info	*pins;
#endif
#ifdef CONFIG_GENERIC_MSI_IRQ
	struct list_head	msi_list;
#endif

#ifdef CONFIG_NUMA
	int		numa_node;	/* NUMA node this device is close to */
#endif
	const struct dma_map_ops *dma_ops;
	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. */
	unsigned long	dma_pfn_offset;

	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 */
#ifdef CONFIG_DMA_CMA
	struct cma *cma_area;		/* contiguous memory area for dma
					   allocations */
#endif
	/* arch specific additions */
	struct dev_archdata	archdata;

	struct device_node	*of_node; /* associated device tree node */
	struct fwnode_handle	*fwnode; /* firmware device node */

	dev_t			devt;	/* dev_t, creates the sysfs "dev" */
	u32			id;	/* device instance */

	spinlock_t		devres_lock;
	struct list_head	devres_head;

	struct klist_node	knode_class;
	struct class		*class;
	const struct attribute_group **groups;	/* optional groups */

	void	(*release)(struct device *dev);
	struct iommu_group	*iommu_group;
	struct iommu_fwspec	*iommu_fwspec;

	bool			offline_disabled:1;
	bool			offline:1;
};

3.3 接口

  • int device_register(struct device *dev);
  • struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);

3.4 实现

[driver/base/core.c]

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

在device初始化时,创建devices_kset容器,这在/sys/下建立devices文件夹,接着是dev,在dev下建立block,char文件夹

[root@localhost ~]# ls /sys/
block  bus  class  dev  devices  firmware  fs  hypervisor  kernel  module  power

[root@localhost ~]# ls /sys/dev
block  char

接下来看设备是如何注册的,假设设备名称new_device

[driver/base/core.c]

int device_register(struct device *dev)
{
	device_initialize(dev);
	return device_add(dev);
}

device是基于kobject的,我们看它是如何操作的:

void device_initialize(struct device *dev)
{
	dev->kobj.kset = devices_kset;  /* 注意这 */
	kobject_init(&dev->kobj, &device_ktype);
	INIT_LIST_HEAD(&dev->dma_pools);
	mutex_init(&dev->mutex);
	lockdep_set_novalidate_class(&dev->mutex);
	spin_lock_init(&dev->devres_lock);
	INIT_LIST_HEAD(&dev->devres_head);
	device_pm_init(dev);
	set_dev_node(dev, -1);

	INIT_LIST_HEAD(&dev->links.consumers);
	INIT_LIST_HEAD(&dev->links.suppliers);
	dev->links.status = DL_DEV_NO_DRIVER;
}

可以看出,这里指定了ktype,并且该device的parent默认为顶级device下的kset

上述片段,展示了初始化基类kobj的过程,名称遵循dev->init_name, dev->bus->dev_name的过程

  • /sys/devices/new_device

接下来是:

	error = device_create_file(dev, &dev_attr_uevent);
	error = device_add_class_symlinks(dev);
	error = device_add_attrs(dev);
	error = bus_add_device(dev);
	error = dpm_sysfs_add(dev);
	device_pm_add(dev);
  • bus_add_device 将device加入到对应的bus中klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);

最后:

	if (MAJOR(dev->devt)) {
		error = device_create_file(dev, &dev_attr_dev);
		if (error)
			goto DevAttrError;

		error = device_create_sys_dev_entry(dev);
		if (error)
			goto SysEntryError;

		devtmpfs_create_node(dev);
	}


	if (dev->bus)
		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
					     BUS_NOTIFY_ADD_DEVICE, dev);

	kobject_uevent(&dev->kobj, KOBJ_ADD);
	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->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->interfaces, node)
			if (class_intf->add_dev)
				class_intf->add_dev(dev, class_intf);
		mutex_unlock(&dev->class->p->mutex);
}

上面的函数我们重点关注bus_probe_device->device_initial_probe->__device_attach:

[driver/base/Dd.c]

static int __device_attach(struct device *dev, bool allow_async)
{
	int ret = 0;

	device_lock(dev);
	if (dev->driver) {
		if (device_is_bound(dev)) {
			ret = 1;
			goto out_unlock;
		}
		ret = device_bind_driver(dev);
		if (ret == 0)
			ret = 1;
		else {
			dev->driver = NULL;
			ret = 0;
		}
	} else {
		struct device_attach_data data = {
			.dev = dev,
			.check_async = allow_async,
			.want_async = false,
		};
        ...

		ret = bus_for_each_drv(dev->bus, NULL, &data,
					__device_attach_driver);
        ...
	}
out_unlock:
	device_unlock(dev);
	return ret;
}

上面的函数是设备注册的核心——寻找并绑定对应的驱动,看下匹配driver的过程__device_attach_driver

首先进行driver_match_device,这个就是bus上的match

static inline int driver_match_device(struct device_driver *drv,
				      struct device *dev)
{
	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

如果driver和device成功的match,接下来就要driver_probe_device

static int really_probe(struct device *dev, struct device_driver *drv)
{
...
re_probe:
	dev->driver = drv;

    ...
	if (driver_sysfs_add(dev)) {
		printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
			__func__, dev_name(dev));
		goto probe_failed;
	}

   ...
	if (dev->bus->probe) {
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {
		ret = drv->probe(dev);
		if (ret)
			goto probe_failed;
	}
  ...
	driver_bound(dev);
    ...
}
  • 关键步骤dev->driver = drv 此时device和driver就绑定在一起了!
  • 接下来按照优先级执行dev->bus->probe, drv->probe

四、driver

4.1 说明

 * The device driver-model tracks all of the drivers known to the system.
 * The main reason for this tracking is to enable the driver core to match
 * up drivers with new devices. Once drivers are known objects within the
 * system, however, a number of other things become possible. Device drivers
 * can export information and configuration variables that are independent
 * of any specific device.
 */

4.2 数据抽象

[include/linux/device.h]

struct device_driver {
	const char		*name;
	struct bus_type		*bus;

	struct module		*owner;
	const char		*mod_name;	/* used for built-in modules */

	bool suppress_bind_attrs;	/* disables bind/unbind via sysfs */
	enum probe_type probe_type;

	const struct of_device_id	*of_match_table;
	const struct acpi_device_id	*acpi_match_table;

	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 (*resume) (struct device *dev);
	const struct attribute_group **groups;

	const struct dev_pm_ops *pm;

	struct driver_private *p;
};

4.3 接口

  • int driver_register(struct device_driver *drv)

4.4 实现

具体看一下:

int driver_register(struct device_driver *drv)
{
	int ret;
	struct device_driver *other;

	BUG_ON(!drv->bus->p);

    ...
	other = driver_find(drv->name, drv->bus);

	ret = bus_add_driver(drv);

	ret = driver_add_groups(drv, drv->groups);

	kobject_uevent(&drv->p->kobj, KOBJ_ADD);

	return ret;
}

driver_find确定当前driver有没有注册过

int bus_add_driver(struct device_driver *drv)
{
	struct bus_type *bus;
	struct driver_private *priv;
	int error = 0;

	bus = bus_get(drv->bus);
	if (!bus)
		return -EINVAL;

	pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		error = -ENOMEM;
		goto out_put_bus;
	}
	klist_init(&priv->klist_devices, NULL, NULL);
	priv->driver = drv;
	drv->p = priv;
	priv->kobj.kset = bus->p->drivers_kset;
	error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
				     "%s", drv->name);
	if (error)
		goto out_unregister;

	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
	if (drv->bus->p->drivers_autoprobe) {
		if (driver_allows_async_probing(drv)) {
			pr_debug("bus: '%s': probing driver %s asynchronously\n",
				drv->bus->name, drv->name);
			async_schedule(driver_attach_async, drv);
		} else {
			error = driver_attach(drv);
			if (error)
				goto out_unregister;
		}
	}
	module_add_driver(drv->owner, drv);

	error = driver_create_file(drv, &driver_attr_uevent);
	if (error) {
		printk(KERN_ERR "%s: uevent attr (%s) failed\n",
			__func__, drv->name);
	}
	error = driver_add_groups(drv, bus->drv_groups);
	if (error) {
		/* How the hell do we get out of this pickle? Give up */
		printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
			__func__, drv->name);
	}

	if (!drv->suppress_bind_attrs) {
		error = add_bind_files(drv);
		if (error) {
			/* Ditto */
			printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
				__func__, drv->name);
		}
	}

	return 0;
}

简单列一下函数做的几件事:

  1. 分配driver_private,在对应bus_type的driver下建立文件
  2. driver纳入bus_type的管理
  3. driver_attach,这些内容在device中已经说过了。

五、class

5.1 说明

 /*
 * 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是更高层次对设备的抽象。

5.2 数据抽象

[inclde/linux/device.h]

struct class {
	const char		*name;
	struct module		*owner;

	const struct attribute_group	**class_groups;
	const struct attribute_group	**dev_groups;
	struct kobject			*dev_kobj;

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

	void (*class_release)(struct class *class);
	void (*dev_release)(struct device *dev);

	int (*shutdown_pre)(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;
};

5.3 接口

  • class_register

5.4 实现

[driver/base/class.c]

int __init classes_init(void)
{
	class_kset = kset_create_and_add("class", NULL, NULL);
	if (!class_kset)
		return -ENOMEM;
	return 0;
}

再来看class的注册:

int __class_register(struct class *cls, struct lock_class_key *key)
{
	struct subsys_private *cp;
	int error;

	pr_debug("device class '%s': registering\n", cls->name);

	cp = kzalloc(sizeof(*cp), GFP_KERNEL);
	if (!cp)
		return -ENOMEM;
	klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put);
	INIT_LIST_HEAD(&cp->interfaces);
	kset_init(&cp->glue_dirs);
	__mutex_init(&cp->mutex, "subsys mutex", key);
	error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);
	if (error) {
		kfree(cp);
		return error;
	}

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

#if defined(CONFIG_BLOCK)
	/* let the block class directory show up in the root of sysfs */
	if (!sysfs_deprecated || cls != &block_class)
		cp->subsys.kobj.kset = class_kset;
#else
	cp->subsys.kobj.kset = class_kset;
#endif
	cp->subsys.kobj.ktype = &class_ktype;
	cp->class = cls;
	cls->p = cp;

	error = kset_register(&cp->subsys);
	if (error) {
		kfree(cp);
		return error;
	}
	error = class_add_groups(class_get(cls), cls->class_groups);
	class_put(cls);
	error = add_class_attrs(class_get(cls));
	class_put(cls);
	return error;
}

六、小结

上面描述了驱动模型各个部件之间的关系,实际上就是完成在特定bus_type下,device和driver的attach在一起,这是通过match行为完成的,随后执行probe的过程,这个过程发生在:

  1. 设备注册
  2. 驱动注册

具体来说,device的attach就是遍历bus下所有的driver,执行driver->bus->match匹配对应的driver。driver的attach则是遍历bus下所有的设备,同样执行driver->bus->match匹配对应的device。无论从哪个角度进行attach,一旦match成功就将device->driver指向具体的driver。此时代表二者attach完成。

attach完成,也反应在sysfs上:

static int driver_sysfs_add(struct device *dev)
{
	int ret;

	if (dev->bus)
		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
					     BUS_NOTIFY_BIND_DRIVER, dev);

	ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
			  kobject_name(&dev->kobj));
	if (ret == 0) {
		ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
					"driver");
		if (ret)
			sysfs_remove_link(&dev->driver->p->kobj,
					kobject_name(&dev->kobj));
	}
	return ret;
}

可以看到,主要建立了两个软连接,这里用图进行说明:

这之后,调用probe进一步对device进行探测。

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值