18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * module.c - module sysfs fun for drivers
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#include <linux/device.h>
68c2ecf20Sopenharmony_ci#include <linux/module.h>
78c2ecf20Sopenharmony_ci#include <linux/errno.h>
88c2ecf20Sopenharmony_ci#include <linux/slab.h>
98c2ecf20Sopenharmony_ci#include <linux/string.h>
108c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
118c2ecf20Sopenharmony_ci#include "base.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic char *make_driver_name(struct device_driver *drv)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	char *driver_name;
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci	driver_name = kasprintf(GFP_KERNEL, "%s:%s", drv->bus->name, drv->name);
188c2ecf20Sopenharmony_ci	if (!driver_name)
198c2ecf20Sopenharmony_ci		return NULL;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	return driver_name;
228c2ecf20Sopenharmony_ci}
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic void module_create_drivers_dir(struct module_kobject *mk)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	static DEFINE_MUTEX(drivers_dir_mutex);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	mutex_lock(&drivers_dir_mutex);
298c2ecf20Sopenharmony_ci	if (mk && !mk->drivers_dir)
308c2ecf20Sopenharmony_ci		mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj);
318c2ecf20Sopenharmony_ci	mutex_unlock(&drivers_dir_mutex);
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_civoid module_add_driver(struct module *mod, struct device_driver *drv)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	char *driver_name;
378c2ecf20Sopenharmony_ci	int no_warn;
388c2ecf20Sopenharmony_ci	struct module_kobject *mk = NULL;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (!drv)
418c2ecf20Sopenharmony_ci		return;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (mod)
448c2ecf20Sopenharmony_ci		mk = &mod->mkobj;
458c2ecf20Sopenharmony_ci	else if (drv->mod_name) {
468c2ecf20Sopenharmony_ci		struct kobject *mkobj;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci		/* Lookup built-in module entry in /sys/modules */
498c2ecf20Sopenharmony_ci		mkobj = kset_find_obj(module_kset, drv->mod_name);
508c2ecf20Sopenharmony_ci		if (mkobj) {
518c2ecf20Sopenharmony_ci			mk = container_of(mkobj, struct module_kobject, kobj);
528c2ecf20Sopenharmony_ci			/* remember our module structure */
538c2ecf20Sopenharmony_ci			drv->p->mkobj = mk;
548c2ecf20Sopenharmony_ci			/* kset_find_obj took a reference */
558c2ecf20Sopenharmony_ci			kobject_put(mkobj);
568c2ecf20Sopenharmony_ci		}
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	if (!mk)
608c2ecf20Sopenharmony_ci		return;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* Don't check return codes; these calls are idempotent */
638c2ecf20Sopenharmony_ci	no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module");
648c2ecf20Sopenharmony_ci	driver_name = make_driver_name(drv);
658c2ecf20Sopenharmony_ci	if (driver_name) {
668c2ecf20Sopenharmony_ci		module_create_drivers_dir(mk);
678c2ecf20Sopenharmony_ci		no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,
688c2ecf20Sopenharmony_ci					    driver_name);
698c2ecf20Sopenharmony_ci		kfree(driver_name);
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_civoid module_remove_driver(struct device_driver *drv)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	struct module_kobject *mk = NULL;
768c2ecf20Sopenharmony_ci	char *driver_name;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (!drv)
798c2ecf20Sopenharmony_ci		return;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/* Synchronize with dev_uevent() */
828c2ecf20Sopenharmony_ci	synchronize_rcu();
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	sysfs_remove_link(&drv->p->kobj, "module");
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (drv->owner)
878c2ecf20Sopenharmony_ci		mk = &drv->owner->mkobj;
888c2ecf20Sopenharmony_ci	else if (drv->p->mkobj)
898c2ecf20Sopenharmony_ci		mk = drv->p->mkobj;
908c2ecf20Sopenharmony_ci	if (mk && mk->drivers_dir) {
918c2ecf20Sopenharmony_ci		driver_name = make_driver_name(drv);
928c2ecf20Sopenharmony_ci		if (driver_name) {
938c2ecf20Sopenharmony_ci			sysfs_remove_link(mk->drivers_dir, driver_name);
948c2ecf20Sopenharmony_ci			kfree(driver_name);
958c2ecf20Sopenharmony_ci		}
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci}
98