首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux设备驱动模型-Driver

Linux设备驱动模型-Driver

作者头像
DragonKingZhu
发布2020-03-24 14:35:02
4.2K0
发布2020-03-24 14:35:02
举报

前言

linux将所有的驱动抽象为struct device_driver结构。这样设计可以方便驱动程序更好编写,在编写驱动的时候只需要将此结构嵌入到具体的驱动中即可。

比如常见的结构: struct platform_driver结构

struct platform_driver {
	int (*probe)(struct platform_device *);
	int (*remove)(struct platform_device *);
	void (*shutdown)(struct platform_device *);
	int (*suspend)(struct platform_device *, pm_message_t state);
	int (*resume)(struct platform_device *);
	struct device_driver driver;
	const struct platform_device_id *id_table;
	bool prevent_deferred_probe;
};

可以看到device_driver结构嵌入到platform_driver

数据结构

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 */

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

name: 设备驱动的名称

bus: 设备驱动所属的总线

owner: 设备驱动的owner,通常为THIS_MODULE

suppress_bind_attrs: 通过sysfs操作设备驱动的bind/unbind,用来使能/关闭设备与驱动的自动匹配

of_device_id: device_tree中使用,用于匹配设备。

probe,remove: 当设备匹配/移除的时候,会调用设备驱动的probe/remove函数。

shutdown,suspend, resume: 代表设备驱动在调用管理的时候的回调函数。

groups: 设备驱动的属性。

p: 设备驱动的私有数据结构,通常可以将驱动的信息放入此结构中。

内核使用driver_attribute结构代表设备驱动的属性

struct driver_attribute {
	struct attribute attr;
	ssize_t (*show)(struct device_driver *driver, char *buf);
	ssize_t (*store)(struct device_driver *driver, const char *buf,
			 size_t count);
};

设备驱动的属性,同样通过注册,最后调用到驱动的show和store函数。

和设备一样,内核也为设备驱动定义了一些驱动的宏属性,方便定义驱动属性。

#define DRIVER_ATTR(_name, _mode, _show, _store) \
	struct driver_attribute driver_attr_##_name = __ATTR(_name, _mode, _show, _store)
#define DRIVER_ATTR_RW(_name) \
	struct driver_attribute driver_attr_##_name = __ATTR_RW(_name)
#define DRIVER_ATTR_RO(_name) \
	struct driver_attribute driver_attr_##_name = __ATTR_RO(_name)
#define DRIVER_ATTR_WO(_name) \
	struct driver_attribute driver_attr_##_name = __ATTR_WO(_name)

设备驱动相关函数

  • driver_register(注册一个驱动到系统)
int driver_register(struct device_driver *drv)
{
	int ret;
	struct device_driver *other;

	BUG_ON(!drv->bus->p);                               //确定bus->p是否存在,不存在则会产生panic

	if ((drv->bus->probe && drv->probe) ||              //警告信息,有新驱动的时候出出现此log。
	    (drv->bus->remove && drv->remove) ||
	    (drv->bus->shutdown && drv->shutdown))
		printk(KERN_WARNING "Driver '%s' needs updating - please use "
			"bus_type methods\n", drv->name);

	other = driver_find(drv->name, drv->bus);          //已经注册过的话,就打印已经注册的信息。
	if (other) {
		printk(KERN_ERR "Error: Driver '%s' is already registered, "
			"aborting...\n", drv->name);
		return -EBUSY;
	}

	ret = bus_add_driver(drv);                        //添加驱动到具体的bus
	if (ret)
		return ret;
	ret = driver_add_groups(drv, drv->groups);        //添加驱动的属性
	if (ret) {
		bus_remove_driver(drv);
		return ret;
	}
	kobject_uevent(&drv->p->kobj, KOBJ_ADD);           //使用uevent机制,通知上层添加新的驱动

	return ret;
}

A: 通过驱动的名称在所属的总线上查找,判断总线上是否已经有此驱动,防止重复注册。

struct device_driver *driver_find(const char *name, struct bus_type *bus)
{
	struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
	struct driver_private *priv;

	if (k) {
		/* Drop reference added by kset_find_obj() */
		kobject_put(k);
		priv = to_driver(k);
		return priv->driver;
	}
	return NULL;
}

通过kset_find_obj函数,在drivers_set中查找是否已经注册,已经注册返回具体的驱动,如果没有注册返回NULL。

B: 将具体的驱动添加到所属的总线,这是注册驱动的核心函数。

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);       //申请driver_private内存
	if (!priv) {
		error = -ENOMEM;
		goto out_put_bus;
	}
	klist_init(&priv->klist_devices, NULL, NULL);                     
	priv->driver = drv;                               //将驱动存放到driver_private的driver中
	drv->p = priv;                                    //存放priv到device_driver的p中
	priv->kobj.kset = bus->p->drivers_kset;           //设置kset
	error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,              
				     "%s", drv->name);     //初始化和添加一个kobject
	if (error)
		goto out_unregister;

	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);   //添加驱动到klist_driver链表中
	if (drv->bus->p->drivers_autoprobe) {                       //驱动所属的bus是否支持自动probe
		error = driver_attach(drv);                         //如果支持,则调用attach函数,这个函数在device中已经分析过
		if (error)
			goto out_unregister;
	}
	module_add_driver(drv->owner, drv);                        

	error = driver_create_file(drv, &driver_attr_uevent);         //创建驱动的Uevent属性
	if (error) {
		printk(KERN_ERR "%s: uevent attr (%s) failed\n",
			__func__, drv->name);
	}
	error = driver_add_groups(drv, bus->drv_groups);             //创建bus下的驱动属性
	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;
}
  • driver_unregister(从系统中移除一个驱动)
void driver_unregister(struct device_driver *drv)
{
	if (!drv || !drv->p) {
		WARN(1, "Unexpected driver unregister!\n");
		return;
	}
	driver_remove_groups(drv, drv->groups);        //移除驱动的属性
	bus_remove_driver(drv);                        //从所属的bus下移除该驱动
}
void bus_remove_driver(struct device_driver *drv)
{
	if (!drv->bus)
		return;

	if (!drv->suppress_bind_attrs)     //移除bind/unbind的属性
		remove_bind_files(drv);
	driver_remove_groups(drv, drv->bus->drv_groups); //移除设备属性
	driver_remove_file(drv, &driver_attr_uevent);    //移除uevent属性
	klist_remove(&drv->p->knode_bus);                //移除驱动节点,从klist_driver链表中
	pr_debug("bus: '%s': remove driver %s\n", drv->bus->name, drv->name);
	driver_detach(drv);                              //解除设备与驱动联系
	module_remove_driver(drv);
	kobject_put(&drv->p->kobj);                      //驱动引用计数减1
	bus_put(drv->bus);                               //总线引用计数减1
}

重点看下设备与对应的驱动是如何解除联系的。

void driver_detach(struct device_driver *drv)
{
	struct device_private *dev_prv;
	struct device *dev;

	for (;;) {
		spin_lock(&drv->p->klist_devices.k_lock);              //加锁,防止别的驱动也在做相似的操作
		if (list_empty(&drv->p->klist_devices.k_list)) {       //如果设备链表为空,直接返回
			spin_unlock(&drv->p->klist_devices.k_lock);
			break;
		}
		dev_prv = list_entry(drv->p->klist_devices.k_list.prev,  //对设备链表中的每个设备,调用__device_release_drive函数
				     struct device_private,
				     knode_driver.n_node);
		dev = dev_prv->device;
		get_device(dev);
		spin_unlock(&drv->p->klist_devices.k_lock);

		if (dev->parent)	/* Needed for USB */
			device_lock(dev->parent);
		device_lock(dev);
		if (dev->driver == drv)
			__device_release_driver(dev);
		device_unlock(dev);
		if (dev->parent)
			device_unlock(dev->parent);
		put_device(dev);
	}
}

接下来分析__device_release_driver函数

static void __device_release_driver(struct device *dev)
{
	struct device_driver *drv;

	drv = dev->driver;
	if (drv) {
		pm_runtime_get_sync(dev);    

		driver_sysfs_remove(dev);     //从sysfs中移除该驱动的信息

		if (dev->bus)                 //调用bus下的通知机制,发送unbind_driver消息
			blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
						     BUS_NOTIFY_UNBIND_DRIVER,
						     dev);

		pm_runtime_put_sync(dev);

		if (dev->bus && dev->bus->remove)
			dev->bus->remove(dev);          //调用bus下的remove函数
		else if (drv->remove)                   //调用该驱动的remove函数
			drv->remove(dev);
		devres_release_all(dev);               //释放该设备所占用的资源
		dev->driver = NULL;
		dev_set_drvdata(dev, NULL);
		klist_remove(&dev->p->knode_driver);     
		if (dev->bus)
			blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
						     BUS_NOTIFY_UNBOUND_DRIVER,
						     dev);

	}
} 
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 数据结构
  • 设备驱动相关函数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档