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