summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mochel <mochel@geena.pdx.osdl.net>2002-05-24 02:04:42 -0700
committerPatrick Mochel <mochel@geena.pdx.osdl.net>2002-05-24 02:04:42 -0700
commitcfff1d8f5243e04c7d04d36ec7e559b5c41eeb9f (patch)
treed7dfaf1a524709842ae19883a6525d13780fdd04
parent3e8c3286fd62cb9da5c77f8d56935acb1262de62 (diff)
Introduce struct bus_type for describing types of buses
Define bus_register for bus registration Define get_bus and put_bus for bus refcounting
-rw-r--r--drivers/base/bus.c124
-rw-r--r--include/linux/device.h24
2 files changed, 148 insertions, 0 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
new file mode 100644
index 000000000000..fedeb05973c9
--- /dev/null
+++ b/drivers/base/bus.c
@@ -0,0 +1,124 @@
+/*
+ * bus.c - bus driver management
+ *
+ * Copyright (c) 2002 Patrick Mochel
+ * 2002 Open Source Development Lab
+ *
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+
+
+static LIST_HEAD(bus_driver_list);
+
+static struct driver_dir_entry bus_dir = {
+ name: "bus",
+ mode: (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO),
+};
+
+/**
+ * bus_add_device - add device to bus
+ * @dev: device being added
+ *
+ * Add the device to its bus's list of devices.
+ * Create a symlink in the bus's 'devices' directory to the
+ * device's physical location.
+ * Try and bind the device to a driver.
+ */
+int bus_add_device(struct device * dev)
+{
+ if (dev->bus) {
+ get_bus(dev->bus);
+ write_lock(&dev->bus->lock);
+ list_add_tail(&dev->bus_list,&dev->bus->devices);
+ write_unlock(&dev->bus->lock);
+ }
+ return 0;
+}
+
+/**
+ * bus_remove_device - remove device from bus
+ * @dev: device to be removed
+ *
+ * Remove symlink from bus's directory.
+ * Delete device from bus's list.
+ */
+void bus_remove_device(struct device * dev)
+{
+ if (dev->bus) {
+ write_lock(&dev->bus->lock);
+ list_del_init(&dev->bus_list);
+ write_unlock(&dev->bus->lock);
+ put_bus(dev->bus);
+ }
+}
+
+static int bus_make_dir(struct bus_type * bus)
+{
+ int error;
+ bus->dir.name = bus->name;
+
+ error = device_create_dir(&bus->dir,&bus_dir);
+ if (!error) {
+ bus->device_dir.name = "devices";
+ device_create_dir(&bus->device_dir,&bus->dir);
+
+ bus->driver_dir.name = "drivers";
+ device_create_dir(&bus->driver_dir,&bus->dir);
+ }
+ return error;
+}
+
+
+int bus_register(struct bus_type * bus)
+{
+ spin_lock(&device_lock);
+ rwlock_init(&bus->lock);
+ INIT_LIST_HEAD(&bus->devices);
+ INIT_LIST_HEAD(&bus->drivers);
+ list_add_tail(&bus->node,&bus_driver_list);
+ atomic_set(&bus->refcount,2);
+ spin_unlock(&device_lock);
+
+ pr_debug("bus type '%s' registered\n",bus->name);
+
+ /* give it some driverfs entities */
+ bus_make_dir(bus);
+ put_bus(bus);
+
+ return 0;
+}
+
+void put_bus(struct bus_type * bus)
+{
+ if (!atomic_dec_and_lock(&bus->refcount,&device_lock))
+ return;
+ list_del_init(&bus->node);
+ spin_unlock(&device_lock);
+
+ /* remove driverfs entries */
+ driverfs_remove_dir(&bus->driver_dir);
+ driverfs_remove_dir(&bus->device_dir);
+ driverfs_remove_dir(&bus->dir);
+
+ /* tell the driver it can go away now */
+ if (bus->release)
+ bus->release();
+}
+
+static int __init bus_init(void)
+{
+ /* make 'bus' driverfs directory */
+ return driverfs_create_dir(&bus_dir,NULL);
+}
+
+subsys_initcall(bus_init);
+
+EXPORT_SYMBOL(bus_for_each_dev);
+EXPORT_SYMBOL(bus_add_device);
+EXPORT_SYMBOL(bus_remove_device);
+EXPORT_SYMBOL(bus_register);
+EXPORT_SYMBOL(put_bus);
diff --git a/include/linux/device.h b/include/linux/device.h
index ccfd221d5dcd..970b974918d6 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -55,6 +55,29 @@ enum {
struct device;
+
+struct bus_type {
+ char * name;
+ rwlock_t lock;
+ atomic_t refcount;
+
+ list_t node;
+ list_t devices;
+};
+
+
+extern int bus_register(struct bus_type * bus);
+
+static inline struct bus_type * get_bus(struct bus_type * bus)
+{
+ BUG_ON(!atomic_read(&bus->refcount));
+ atomic_inc(&bus->refcount);
+ return bus;
+}
+
+extern void put_bus(struct bus_type * bus);
+
+
struct device_driver {
int (*probe) (struct device * dev);
int (*remove) (struct device * dev, u32 flags);
@@ -66,6 +89,7 @@ struct device_driver {
struct device {
struct list_head g_list; /* node in depth-first order list */
struct list_head node; /* node in sibling list */
+ struct list_head bus_list; /* node in bus's list */
struct list_head children;
struct device * parent;