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