【linux kenrel】Linuxカーネルデバイスドライバの登録とアンインストールについてまとめた記事です

1.オープニング

driver_register()Linux ドライバーの開発では、と の関数に必ず触れることになりますがdriver_unregister()、この記事では、これら 2 つの関数の具体的な実装をカーネル ソース コードの観点から見ていきます。Linux カーネル ソース コード (/drivers/) ディレクトリには、(spi、I2c、net) などの特定のタイプのデバイス ドライバー フレームワークが配置されます。これらのフレームワークのコアのほとんどはdriver_register()関数を呼び出します。これら 2 つの関数のプロトタイプは次のとおりです。

int driver_register(struct device_driver *drv);
void driver_unregister(struct device_driver *drv);

関数のパラメータはstruct device_driver次のように定義されています (include/linux/device.h)。

struct device_driver {
    
    
	const char		*name;					//设备驱动的名称
	struct bus_type		*bus;			 //驱动程序的设备所属的总线

	struct module		*owner;		 //模块所有者
	const char		*mod_name;	  //用于内置模块

	bool suppress_bind_attrs;	 /* 是否通过sysfs禁用绑定/取消绑定 */

	const struct of_device_id	*of_match_table;	//设备树匹配表
	const struct acpi_device_id	*acpi_match_table;	 //acpi匹配表

    //具体的回调函数指针
	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;//驱动核心的私有数据,除了驱动核心,其他都不可以操作它
};

2、driver_register関数

driver_register()busバスにドライバーを登録する関数です。関数は次のように定義されています (/drivers/base/driver.c)。

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

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

	if ((drv->bus->probe && drv->probe) ||
	    (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);
	if (ret)
		return ret;
	ret = driver_add_groups(drv, drv->groups);
	if (ret) {
    
    
		bus_remove_driver(drv);
		return ret;
	}
    //通过发送KOBJ_ADD事件通知用户空间
	kobject_uevent(&drv->p->kobj, KOBJ_ADD);

	return ret;
}

上記のコードの 8 ~ 12 行目は、drv->bus->probe、drv->probe、drv->bus->remove、drv->remove、drv->bus->shutdown、drv->shutdown が指定されているかどうかを決定します。 。

driver_find()14 ~ 19 行目は、指定されたバスの運転手を見つけるために電話をかけます。driver_find に渡されるパラメータは次のとおりです:驱动名称および be 扫描驱动的bus总线該当するドライバ名のドライバが見つかった場合には、ドライバが登録されていることが証明されて関数が返され、そうでない場合には、以降のドライバの登録動作が行われる。

コードの 21 行目はbus_add_driver()ドライバー登録の中核となる操作関数で、次のように定義されています (/drivers/base/bus.c)。

int bus_add_driver(struct device_driver *drv)
{
    
    
	struct bus_type *bus;
	struct driver_private *priv;
	int error = 0;
	//获取device_driver设备驱动中的bus总线
	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;
    //初始化驱动程序kobj,并将其添加到内核对象树中
	error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
				     "%s", drv->name);
	if (error)
		goto out_unregister;
	//将klist_drivers驱动添加到knode_bus链表的尾部
	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
	if (drv->bus->p->drivers_autoprobe) {
    
    
        //尝试将驱动程序绑定到设备
		error = driver_attach(drv);
		if (error)
			goto out_unregister;
	}
    //为驱动程序创建模块对象。
	module_add_driver(drv->owner, drv);
    
	//为驱动程序创建sysfs文件
	error = driver_create_file(drv, &driver_attr_uevent);
	if (error) {
    
    
		printk(KERN_ERR "%s: uevent attr (%s) failed\n",
			__func__, drv->name);
	}
    //创建bus->drv_groups属性组
	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;

out_unregister:
	kobject_put(&priv->kobj);
	kfree(drv->p);
	drv->p = NULL;
out_put_bus:
	bus_put(bus);
	return error;
}

3、driver_unregister関数

driver_unregister()この関数はシステムからドライバーを削除するために使用され、次のように定義されます (/drivers/base/driver.c)。

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

上記のコードの 7 行目は、driver_remove_groups()sysfs ファイル システムから属性グループを削除するよう呼び出していますdrv->groups

コードの 8 行目は、bus_remove_driver()既知のバスからドライバーを削除するために呼び出します。この関数は次のように定義されています (/drivers/base/bus.c)。

void bus_remove_driver(struct device_driver *drv)
{
    
    
	if (!drv->bus)
		return;

	if (!drv->suppress_bind_attrs)
		remove_bind_files(drv);
    //移除drv->groups组
	driver_remove_groups(drv, drv->bus->drv_groups);
    //将驱动从sysfs文件系统中移除
	driver_remove_file(drv, &driver_attr_uevent);
    //移除knode_bus链表
	klist_remove(&drv->p->knode_bus);
	pr_debug("bus: '%s': remove driver %s\n", drv->bus->name, drv->name);
    //从控制的设备中分离驱动程序
	driver_detach(drv);
    //从驱动中内核模块中移除
	module_remove_driver(drv);
    //减少对drv->p->kobj对象的引用计数
	kobject_put(&drv->p->kobj);
    //减少对drv->bus总线对象的引用计数
	bus_put(drv->bus);
}

4.終了

driver_register()(4-1) Linux カーネルのほとんどのドライバー フレームワークでは、関数と関数が使用されますdriver_unregister()が、この記事では、これら 2 つの関数をソース コードの観点から分析します。包括的なカーネル内のほとんどのドライバー フレームワークの構造とコード記述は、それぞれのドライバー フレームワーク名に従って適切にカプセル化されています。たとえば、次の図に示すように:
画像の説明を追加してください

(4-2) デバイスドライバは静的に割り当てられる構造体です。システム内には複数のデバイスが存在する可能性がありますが、struct device_driverドライバーは (特定のデバイス インスタンスではなく) 全体として表されます。struct device_driverしたがって、タイプのデバイス ドライバー変数を初期化するときに、名前フィールドとバス フィールドを初期化する必要があります。内部的に適切にリンクできるように、devclass フィールドも初期化する必要があります。さらに、できるだけ多くのコールバック関数を初期化する必要があります (例: プローブ、削除、シャットダウン、サスペンド、再開)。

(4-3) ドライバーは、バス固有のドライバー定義にジェネリックを含める必要がありますstruct device_driverたとえば、次は次pci_driverのドライバーです。

struct pci_driver {
    
    
       const struct pci_device_id *id_table;
       struct device_driver	  driver;
};

おすすめ

転載: blog.csdn.net/iriczhao/article/details/124283698#comments_27686200