/*
* bus.c - bus driver management
*
* Copyright (c) 2002-3 Patrick Mochel
* Copyright (c) 2002-3 Open Source Development Labs
*
* This file is released under the GPLv2
*
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/string.h>
#include "base.h"
#include "power/power.h"
#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
#define to_bus(obj) container_of(obj, struct bus_type, subsys.kobj)
/*
* sysfs bindings for drivers
*/
#define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr)
#define to_driver(obj) container_of(obj, struct device_driver, kobj)
static int __must_check bus_rescan_devices_helper(struct device *dev,
void *data);
static void bus_put(struct bus_type *bus)
{
kset_put(&bus->subsys);
}
static ssize_t
drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
{
struct driver_attribute * drv_attr = to_drv_attr(attr);
struct device_driver * drv = to_driver(kobj);
ssize_t ret = -EIO;
if (drv_attr->show)
ret = drv_attr->show(drv, buf);
return ret;
}
static ssize_t
drv_attr_store(struct kobject * kobj, struct attribute * attr,
const char * buf, size_t count)
{
struct driver_attribute * drv_attr = to_drv_attr(attr);
struct device_driver * drv = to_driver(kobj);
ssize_t ret = -EIO;
if (drv_attr->store)
ret = drv_attr->store(drv, buf, count);
return ret;
}
static struct sysfs_ops driver_sysfs_ops = {
.show = drv_attr_show,
.store = drv_attr_store,
};
static void driver_release(struct kobject * kobj)
{
/*
* Yes this is an empty release function, it is this way because struct
* device is always a static object, not a dynamic one. Yes, this is
* not nice and bad, but remember, drivers are code, reference counted
* by the module count, not a device, which is really data. And yes,
* in the future I do want to have all drivers be created dynamically,
* and am working toward that goal, but it will take a bit longer...
*
* But do not let this example give _anyone_ the idea that they can
* create a release function without any code in it at all, to do that
* is almost always wrong. If you have any questions about this,
* please send an email to <greg@kroah.com>
*/
}
static struct kobj_type ktype_driver = {
.sysfs_ops = &driver_sysfs_ops,
.release = driver_release,
};
/*
* sysfs bindings for buses
*/
static ssize_t
bus_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
{
struct bus_attribute * bus_attr = to_bus_attr(attr);
struct bus_type * bus = to_bus(kobj);
ssize_t ret = 0;
if (bus_attr->show)
ret = bus_attr->show(bus, buf);
return ret;
}
static ssize_t
bus_attr_store(struct kobject * kobj, struct attribute * attr,
const char * buf, size_t count)
{
struct bus_attribute * bus_attr = to_bus_attr(attr);
struct bus_type * bus = to_bus(kobj);
ssize_t ret = 0;
if (bus_attr->store)
ret = bus_attr->store(bus, buf, count);
return ret;
}
static struct sysfs_ops bus_sysfs_ops = {
.show = bus_attr_show,
.store = bus_attr_store,
};
int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
{
int error;
if (get_bus(bus)) {
error = sysfs_create_file(&bus->subsys.kobj, &attr->attr);
bus_put(bus);
} else
error = -EINVAL;
return error;
}
void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
{
if (get_bus(bus)) {
sysfs_remove_file(&bus->subsys.kobj, &attr->attr);
bus_put(bus);
}
}
static struct kobj_type bus_ktype = {
.sysfs_ops = &bus_sysfs_ops,
};
static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
if (ktype == &bus_ktype)
return 1;
return 0;
}
static struct kset_uevent_ops bus_uevent_ops = {
.filter = bus_uevent_filter,
};
static decl_subsys(bus, &bus_ktype, &bus_uevent_ops);
#ifdef CONFIG_HOTPLUG
/* Manually detach a device from its associated driver. */
static int driver_helper(struct device *dev, void *data)
{
const char *name = data;
if (strcmp(name, dev->bus_id) == 0)
return 1;
return 0;
}
static ssize_t driver_unbind(struct device_driver *drv,
const