linux设备驱动模型一上层容器之driver

备驱动程序 使计算机系统可以与设备进行通信的一个软件组。在大多数情况下,驱动程序也会对硬件进行操作以便将数据传送给设备。有些设备,尤其是 PC 兼容机上的一些视频示配器,在系统中没有安装正确的设备驱动程序时,这些设备将无法正常工作.

首先还是看一下其结构:

struct device_driver {
	const char		*name; //名字
	struct bus_type		*bus;//其所在的bus

	struct module		*owner;//表示实现设备驱动程序的模块
	const char		*mod_name;	//模块名

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

#if defined(CONFIG_OF)
	const struct of_device_id	*of_match_table;
#endif

	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;//私有属性
};

struct driver_private {
	struct kobject kobj;//代表driver自身
	struct klist klist_devices;//可以操控的设备链表
	struct klist_node knode_bus;//挂接到bus的节点
	struct module_kobject *mkobj; //模块相关
	struct device_driver *driver; //回指该driver
};
driver_private存放kob相关的数据

结构中有五个回调函数,这五个回调函数用于处理热插拔、即插即用和电源管理。 当总线设备驱动程序发现一个可能有它处理的设备时就会调用probe方法,相应的函数将会探测硬件,从而对该设备进行更进一步的检查。如果该device_driver对象的pribe()方法的返回值是一个负数,那就意味这该驱动不能邦定到此设备上,那么就要释放所有为该device_driver对象分配的资源。 当移走一个可热插拔的设备时驱动程序会调用remove方法,而驱动程序本身被卸载时,它所处理的每个设备也会调用remove方法。
当内核必须更改设备的供电状态时,设备驱动会调用shutdown、suspend和resume三个方法。其中shutdown方法会停止对设备供电。suspend方法是将设备切换到低功耗状态,此方法中的state参数即要设置的状态,pm_message_t被定义在linux/include/linux/pm.h中,
typedef struct pm_message {
       int event;
 }pm_message_t;
 
可取的状态有:
#define PM_EVENT_ON 0
  /*驱动器恢复工作,开始相应硬盘和软件请求*/
#define PM_EVENT_FREEZE 1
 /*停止对设备的操作以便保存一致的映象,但是不能再进入低功耗状态,也不能发出唤醒事件*/
#define PM_EVENT_SUSPEND 2 /*为即将到来的系统状态进入低功耗状态,在适当的时候可以唤醒*/
#define PM_EVENT_PRETHAW 3 /*为系统从一个较早的PM_EVENT_FREEZE保存的映象中恢复过来 做准备*/


driver方面的主要函数也跟device一样,也是注册的函数driver_register,下面来看看这个函数

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

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

	if ((drv->bus->probe && drv->probe) ||   //driver和bus的同名操作函数如果同时存在,会出现警告
	    (drv->bus->remove && drv->remove) ||   //并且会优先选用bus的
	    (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);  //进入bus的driver链表,确认该driver是否已经注册
	if (other) {
		put_driver(other);					//找到了再减少引用计数,并且报错退出
		printk(KERN_ERR "Error: Driver '%s' is already registered, "
			"aborting...\n", drv->name);
		return -EBUSY;
	}

	ret = bus_add_driver(drv); //如果没有注册,那么把该driver加入所在bus,并生成文件夹和链接
	if (ret)
		return ret;
	ret = driver_add_groups(drv, drv->groups);//添加attribute_group
	if (ret)
		bus_remove_driver(drv);
	return ret;
}
大部分工作在 bus_add_driver()例程中完成

driver_find()例程通过驱动所属bus 的driver 容器drivers_kset 来查找

struct device_driver *driver_find(const char *name, struct bus_type *bus)
{
	struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);//bus->p->drivers_kset代表bus下的driver目录,此处会遍历bus的driver链表,通过driver内嵌的kobj名字比较
	struct driver_private *priv;

	if (k) {
		priv = to_driver(k); 
		return priv->driver; //如果找到同名的kobj那么返回该driver
	}
	return NULL;
}
通过kset_find_obj(bus->p->drivers_kset, name)查找该driver 的kobj

struct kobject *kset_find_obj(struct kset *kset, const char *name)
{
	struct kobject *k;
	struct kobject *ret = NULL;

	spin_lock(&kset->list_lock);
	list_for_each_entry(k, &kset->list, entry) {//遍历bus下的driver链表,获取kobj
		if (kobject_name(k) && !strcmp(kobject_name(k), name)) {// 比较name字符
			ret = kobject_get(k);// 如果找到就增加引用并返回
			break;
		}
	}
	spin_unlock(&kset->list_lock);
	return ret;
}
显然,所有同类型的driver 都注册到了 一个bus->p->drivers_kset->list 中,所以可通过其查找已经注册的driver

再来看下bus_add_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); //取得其所在bus的指针经,增加对 bus 的引用
	if (!bus)
		return -EINVAL;

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

	priv = kzalloc(sizeof(*priv), GFP_KERNEL); //开始初始化这个driver的私有成员,这个结构体中存放着kobj相关的数据
	if (!priv) {
		error = -ENOMEM;
		goto out_put_bus;
	}
	klist_init(&priv->klist_devices, NULL, NULL);//设备操作函数清空,设备链表初始化
	priv->driver = drv;// 反向指向包含其的 drv,以便后续使用
	drv->p = priv;		// 将 priv保存到 device_driver
	priv->kobj.kset = bus->p->drivers_kset;//kset指定到bus下面drivers_kset容器
	error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,  //建立层次结构和属性文件
				     "%s", drv->name);
	if (error)
		goto out_unregister;

	if (drv->bus->p->drivers_autoprobe) {//bus的自动匹配如果设置为真,
		error = driver_attach(drv);		//那么到bus的devices上去匹配设备
		if (error)
			goto out_unregister;
	}
	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);//把driver挂接到bus的driver链表,方便后续快速查找 driver
	module_add_driver(drv->owner, drv);//将driver添加到module模块

	error = driver_create_file(drv, &driver_attr_uevent);//以下添加该driver相关属性文件
	if (error) {
		printk(KERN_ERR "%s: uevent attr (%s) failed\n",
			__func__, drv->name);
	}
	error = driver_add_attrs(bus, drv);//添加 bus 的公有属性文件
	if (error) {
		/* How the hell do we get out of this pickle? Give up */
		printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
			__func__, drv->name);
	}
	/* 如果配置了”CONFIG_HOTPLUG",则生成“bind”和"unbind”属性文件,可用于手动匹
		配和移除 device与driver 之间的关联 */
	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);
		}
	}

	kobject_uevent(&priv->kobj, KOBJ_ADD);// 通过 uevent 设置几个环境变量并通知用户空间,以便调用程序来完成相关设置
	return 0;

out_unregister:
	kobject_put(&priv->kobj);
	kfree(drv->p);
	drv->p = NULL;
out_put_bus:
	bus_put(bus);
	return error;
}
bus_register()例程注册 bus(本例是platform_bus_type)的时候,除了生成该 bus的kset 容器 subsys,还生成 devices_kset和drivers_kset容器,都包含在struct bus_type_private 里。

driver_attach()例程从bus中查找匹配的 device

int driver_attach(struct device_driver *drv)
{
	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);//遍历bus的设备链表找到合适的设备就调用__driver_attachNULL表示从头开始遍历
}
对比下前面device的时候是

ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); 
是不一样的。

继续往下看bus_for_each_dev

int bus_for_each_dev(struct bus_type *bus, struct device *start,
		     void *data, int (*fn)(struct device *, void *))
{
	struct klist_iter i;
	struct device *dev;
	int error = 0;

	if (!bus)
		return -EINVAL;

	klist_iter_init_node(&bus->p->klist_devices, &i, //进入bus的devices链表
			     (start ? &start->p->knode_bus : NULL));
	while ((dev = next_device(&i)) && !error)//设备存在则调用fn即__driver_attach进行匹配
		error = fn(dev, data);
	klist_iter_exit(&i);
	return error;
}
再来看下回调到的__driver_attach

static int __driver_attach(struct device *dev, void *data)
{
	struct device_driver *drv = data;

	/*
	 * Lock device and try to bind to it. We drop the error
	 * here and always return 0, because we need to keep trying
	 * to bind to devices and some drivers will return an error
	 * simply if it didn't support the device.
	 *
	 * driver_probe_device() will spit a warning if there
	 * is an error.
	 */

	if (!driver_match_device(drv, dev)) //进行匹配
		return 0;

	if (dev->parent)	/* Needed for USB */
		device_lock(dev->parent);
	device_lock(dev);
	if (!dev->driver)//如果设备没有指定driver那么需要初始化匹配到的这个设备
		driver_probe_device(drv, dev);
	device_unlock(dev);
	if (dev->parent)
		device_unlock(dev->parent);

	return 0;
}
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
	int ret = 0;

	if (!device_is_registered(dev))//判断该设备是否已经注册
		return -ENODEV;

	pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
		 drv->bus->name, __func__, dev_name(dev), drv->name);

	pm_runtime_get_noresume(dev);
	pm_runtime_barrier(dev);
	ret = really_probe(dev, drv);// 这里真正开始调用用户在 device_driver 中注册的 probe()例程
	pm_runtime_put_sync(dev);

	return ret;
}
到really_probe后,就回到了前面的device注册的时候一样的了,这里可以回过去看看


最后 看下调用流程图:



你可能感兴趣的:(linux设备驱动模型一上层容器之driver)