Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/base/module.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* module.c - module sysfs fun for drivers
4
*/
5
#include <linux/device.h>
6
#include <linux/module.h>
7
#include <linux/errno.h>
8
#include <linux/slab.h>
9
#include <linux/string.h>
10
#include "base.h"
11
12
static char *make_driver_name(const struct device_driver *drv)
13
{
14
char *driver_name;
15
16
driver_name = kasprintf(GFP_KERNEL, "%s:%s", drv->bus->name, drv->name);
17
if (!driver_name)
18
return NULL;
19
20
return driver_name;
21
}
22
23
static void module_create_drivers_dir(struct module_kobject *mk)
24
{
25
static DEFINE_MUTEX(drivers_dir_mutex);
26
27
mutex_lock(&drivers_dir_mutex);
28
if (mk && !mk->drivers_dir)
29
mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj);
30
mutex_unlock(&drivers_dir_mutex);
31
}
32
33
int module_add_driver(struct module *mod, const struct device_driver *drv)
34
{
35
char *driver_name;
36
struct module_kobject *mk = NULL;
37
int ret;
38
39
if (!drv)
40
return 0;
41
42
if (mod)
43
mk = &mod->mkobj;
44
else if (drv->mod_name) {
45
/* Lookup or create built-in module entry in /sys/modules */
46
mk = lookup_or_create_module_kobject(drv->mod_name);
47
if (mk) {
48
/* remember our module structure */
49
drv->p->mkobj = mk;
50
/* lookup_or_create_module_kobject took a reference */
51
kobject_put(&mk->kobj);
52
}
53
}
54
55
if (!mk)
56
return 0;
57
58
ret = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module");
59
if (ret)
60
return ret;
61
62
driver_name = make_driver_name(drv);
63
if (!driver_name) {
64
ret = -ENOMEM;
65
goto out_remove_kobj;
66
}
67
68
module_create_drivers_dir(mk);
69
if (!mk->drivers_dir) {
70
ret = -EINVAL;
71
goto out_free_driver_name;
72
}
73
74
ret = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, driver_name);
75
if (ret)
76
goto out_remove_drivers_dir;
77
78
kfree(driver_name);
79
80
return 0;
81
82
out_remove_drivers_dir:
83
sysfs_remove_link(mk->drivers_dir, driver_name);
84
85
out_free_driver_name:
86
kfree(driver_name);
87
88
out_remove_kobj:
89
sysfs_remove_link(&drv->p->kobj, "module");
90
return ret;
91
}
92
93
void module_remove_driver(const struct device_driver *drv)
94
{
95
struct module_kobject *mk = NULL;
96
char *driver_name;
97
98
if (!drv)
99
return;
100
101
sysfs_remove_link(&drv->p->kobj, "module");
102
103
if (drv->owner)
104
mk = &drv->owner->mkobj;
105
else if (drv->p->mkobj)
106
mk = drv->p->mkobj;
107
if (mk && mk->drivers_dir) {
108
driver_name = make_driver_name(drv);
109
if (driver_name) {
110
sysfs_remove_link(mk->drivers_dir, driver_name);
111
kfree(driver_name);
112
}
113
}
114
}
115
116