1 /* 2 * module.c - module sysfs fun for drivers 3 * 4 * This file is released under the GPLv2 5 * 6 */ 7 #include <linux/device.h> 8 #include <linux/module.h> 9 #include <linux/errno.h> 10 #include <linux/slab.h> 11 #include <linux/string.h> 12 #include "base.h" 13 14 static char *make_driver_name(struct device_driver *drv) 15 { 16 char *driver_name; 17 18 driver_name = kasprintf(GFP_KERNEL, "%s:%s", drv->bus->name, drv->name); 19 if (!driver_name) 20 return NULL; 21 22 return driver_name; 23 } 24 25 static void module_create_drivers_dir(struct module_kobject *mk) 26 { 27 static DEFINE_MUTEX(drivers_dir_mutex); 28 29 mutex_lock(&drivers_dir_mutex); 30 if (mk && !mk->drivers_dir) 31 mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj); 32 mutex_unlock(&drivers_dir_mutex); 33 } 34 35 void module_add_driver(struct module *mod, struct device_driver *drv) 36 { 37 char *driver_name; 38 int no_warn; 39 struct module_kobject *mk = NULL; 40 41 if (!drv) 42 return; 43 44 if (mod) 45 mk = &mod->mkobj; 46 else if (drv->mod_name) { 47 struct kobject *mkobj; 48 49 /* Lookup built-in module entry in /sys/modules */ 50 mkobj = kset_find_obj(module_kset, drv->mod_name); 51 if (mkobj) { 52 mk = container_of(mkobj, struct module_kobject, kobj); 53 /* remember our module structure */ 54 drv->p->mkobj = mk; 55 /* kset_find_obj took a reference */ 56 kobject_put(mkobj); 57 } 58 } 59 60 if (!mk) 61 return; 62 63 /* Don't check return codes; these calls are idempotent */ 64 no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); 65 driver_name = make_driver_name(drv); 66 if (driver_name) { 67 module_create_drivers_dir(mk); 68 no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, 69 driver_name); 70 kfree(driver_name); 71 } 72 } 73 74 void module_remove_driver(struct device_driver *drv) 75 { 76 struct module_kobject *mk = NULL; 77 char *driver_name; 78 79 if (!drv) 80 return; 81 82 sysfs_remove_link(&drv->p->kobj, "module"); 83 84 if (drv->owner) 85 mk = &drv->owner->mkobj; 86 else if (drv->p->mkobj) 87 mk = drv->p->mkobj; 88 if (mk && mk->drivers_dir) { 89 driver_name = make_driver_name(drv); 90 if (driver_name) { 91 sysfs_remove_link(mk->drivers_dir, driver_name); 92 kfree(driver_name); 93 } 94 } 95 } 96