Commit f371ab1c authored by Patrick Mochel's avatar Patrick Mochel Committed by Patrick Mochel

Beef up centralized driver mgmt:

- add name, bus, lock, refcount, bus_list, devices, and dir fields to struct
- add release callback to be called when  refcount hits 0
- add helpers for registration and refcounting
- create directory for driver in bus's directory
parent 1f5bbbe4
O_TARGET := base.o O_TARGET := base.o
obj-y := core.o sys.o interface.o fs.o power.o bus.o obj-y := core.o sys.o interface.o fs.o power.o bus.o \
driver.o
export-objs := core.o fs.o power.o sys.o bus.o export-objs := core.o fs.o power.o sys.o bus.o driver.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
/*
* driver.c - centralized device driver management
*
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/errno.h>
#include "base.h"
/**
* driver_make_dir - create a driverfs directory for a driver
* @drv: driver in question
*/
static int driver_make_dir(struct device_driver * drv)
{
drv->dir.name = drv->name;
return device_create_dir(&drv->dir,&drv->bus->driver_dir);
}
/**
* driver_register - register driver with bus
* @drv: driver to register
*
* Add to bus's list of devices
*/
int driver_register(struct device_driver * drv)
{
if (!drv->bus)
return -EINVAL;
pr_debug("Registering driver '%s' with bus '%s'\n",drv->name,drv->bus->name);
get_bus(drv->bus);
atomic_set(&drv->refcount,2);
rwlock_init(&drv->lock);
write_lock(&drv->bus->lock);
list_add(&drv->bus_list,&drv->bus->drivers);
write_unlock(&drv->bus->lock);
driver_make_dir(drv);
put_driver(drv);
return 0;
}
/**
* put_driver - decrement driver's refcount and clean up if necessary
* @drv: driver in question
*/
void put_driver(struct device_driver * drv)
{
if (!atomic_dec_and_lock(&drv->refcount,&device_lock))
return;
spin_unlock(&device_lock);
if (drv->bus) {
pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name);
write_lock(&drv->bus->lock);
list_del_init(&drv->bus_list);
write_unlock(&drv->bus->lock);
driverfs_remove_dir(&drv->dir);
put_bus(drv->bus);
}
if (drv->release)
drv->release(drv);
}
EXPORT_SYMBOL(driver_register);
EXPORT_SYMBOL(put_driver);
...@@ -84,17 +84,48 @@ extern void put_bus(struct bus_type * bus); ...@@ -84,17 +84,48 @@ extern void put_bus(struct bus_type * bus);
struct device_driver { struct device_driver {
char * name;
struct bus_type * bus;
rwlock_t lock;
atomic_t refcount;
list_t bus_list;
list_t devices;
struct driver_dir_entry dir;
int (*probe) (struct device * dev); int (*probe) (struct device * dev);
int (*remove) (struct device * dev, u32 flags); int (*remove) (struct device * dev, u32 flags);
int (*suspend) (struct device * dev, u32 state, u32 level); int (*suspend) (struct device * dev, u32 state, u32 level);
int (*resume) (struct device * dev, u32 level); int (*resume) (struct device * dev, u32 level);
void (*release) (struct device_driver * drv);
}; };
extern int driver_register(struct device_driver * drv);
static inline struct device_driver * get_driver(struct device_driver * drv)
{
BUG_ON(!atomic_read(&drv->refcount));
atomic_inc(&drv->refcount);
return drv;
}
extern void put_driver(struct device_driver * drv);
extern int driver_for_each_dev(struct device_driver * drv, void * data,
int (*callback)(struct device * dev, void * data));
struct device { struct device {
struct list_head g_list; /* node in depth-first order list */ struct list_head g_list; /* node in depth-first order list */
struct list_head node; /* node in sibling list */ struct list_head node; /* node in sibling list */
struct list_head bus_list; /* node in bus's list */ struct list_head bus_list; /* node in bus's list */
struct list_head driver_list;
struct list_head children; struct list_head children;
struct device * parent; struct device * parent;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment