diff options
| author | Patrick Mochel <mochel@geena.pdx.osdl.net> | 2002-05-24 02:04:42 -0700 |
|---|---|---|
| committer | Patrick Mochel <mochel@geena.pdx.osdl.net> | 2002-05-24 02:04:42 -0700 |
| commit | cfff1d8f5243e04c7d04d36ec7e559b5c41eeb9f (patch) | |
| tree | d7dfaf1a524709842ae19883a6525d13780fdd04 | |
| parent | 3e8c3286fd62cb9da5c77f8d56935acb1262de62 (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.c | 124 | ||||
| -rw-r--r-- | include/linux/device.h | 24 |
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; |
