Commit 21a16f65 authored by Patrick Mochel's avatar Patrick Mochel

Merge master.kernel.org:/home/mochel/BK/linux-2.5

into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-sync
parents 83ca4c7e 4b4a837f
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);
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/kmod.h> /* for hotplug_path */ #include <linux/kmod.h> /* for hotplug_path */
extern struct list_head pci_drivers;
extern int pci_announce_device(struct pci_driver *drv, struct pci_dev *dev); extern int pci_announce_device(struct pci_driver *drv, struct pci_dev *dev);
#ifndef FALSE #ifndef FALSE
...@@ -61,7 +60,7 @@ pci_announce_device_to_drivers(struct pci_dev *dev) ...@@ -61,7 +60,7 @@ pci_announce_device_to_drivers(struct pci_dev *dev)
{ {
struct list_head *ln; struct list_head *ln;
for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) { for(ln=pci_bus_type.drivers.next; ln != &pci_bus_type.drivers; ln=ln->next) {
struct pci_driver *drv = list_entry(ln, struct pci_driver, node); struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
if (drv->remove && pci_announce_device(drv, dev)) if (drv->remove && pci_announce_device(drv, dev))
break; break;
......
...@@ -10,8 +10,6 @@ ...@@ -10,8 +10,6 @@
* Registration of PCI drivers and handling of hot-pluggable devices. * Registration of PCI drivers and handling of hot-pluggable devices.
*/ */
LIST_HEAD(pci_drivers);
/** /**
* pci_match_device - Tell if a PCI device structure has a matching PCI device id structure * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
* @ids: array of PCI device id structures to search in * @ids: array of PCI device id structures to search in
...@@ -61,6 +59,57 @@ pci_announce_device(struct pci_driver *drv, struct pci_dev *dev) ...@@ -61,6 +59,57 @@ pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
return ret; return ret;
} }
static int pci_device_probe(struct device * dev)
{
int error = 0;
struct pci_driver * drv = list_entry(dev->driver,struct pci_driver,driver);
struct pci_dev * pci_dev = list_entry(dev,struct pci_dev,dev);
if (drv->probe)
error = drv->probe(pci_dev,NULL);
printk("%s: returning %d\n",__FUNCTION__,error);
return error > 0 ? 0 : -ENODEV;
}
static int pci_device_remove(struct device * dev, u32 flags)
{
struct pci_dev * pci_dev = list_entry(dev,struct pci_dev,dev);
if (dev->driver) {
struct pci_driver * drv = list_entry(dev->driver,struct pci_driver,driver);
if (drv->remove)
drv->remove(pci_dev);
}
return 0;
}
static int pci_device_suspend(struct device * dev, u32 state, u32 level)
{
struct pci_dev * pci_dev = (struct pci_dev *)list_entry(dev,struct pci_dev,dev);
int error = 0;
if (pci_dev->driver) {
if (level == SUSPEND_SAVE_STATE && pci_dev->driver->save_state)
error = pci_dev->driver->save_state(pci_dev,state);
else if (level == SUSPEND_POWER_DOWN && pci_dev->driver->suspend)
error = pci_dev->driver->suspend(pci_dev,state);
}
return error;
}
static int pci_device_resume(struct device * dev, u32 level)
{
struct pci_dev * pci_dev = (struct pci_dev *)list_entry(dev,struct pci_dev,dev);
if (pci_dev->driver) {
if (level == RESUME_POWER_ON && pci_dev->driver->resume)
pci_dev->driver->resume(pci_dev);
}
return 0;
}
/** /**
* pci_register_driver - register a new pci driver * pci_register_driver - register a new pci driver
* @drv: the driver structure to register * @drv: the driver structure to register
...@@ -73,15 +122,25 @@ pci_announce_device(struct pci_driver *drv, struct pci_dev *dev) ...@@ -73,15 +122,25 @@ pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
int int
pci_register_driver(struct pci_driver *drv) pci_register_driver(struct pci_driver *drv)
{ {
struct pci_dev *dev;
int count = 0; int count = 0;
struct pci_dev * dev;
/* initialize common driver fields */
drv->driver.name = drv->name;
drv->driver.bus = &pci_bus_type;
drv->driver.probe = pci_device_probe;
drv->driver.resume = pci_device_resume;
drv->driver.suspend = pci_device_suspend;
drv->driver.remove = pci_device_remove;
/* register with core */
count = driver_register(&drv->driver);
list_add_tail(&drv->node, &pci_drivers);
pci_for_each_dev(dev) { pci_for_each_dev(dev) {
if (!pci_dev_driver(dev)) if (!pci_dev_driver(dev))
count += pci_announce_device(drv, dev); pci_announce_device(drv, dev);
} }
return count; return count ? count : 1;
} }
/** /**
...@@ -97,16 +156,21 @@ pci_register_driver(struct pci_driver *drv) ...@@ -97,16 +156,21 @@ pci_register_driver(struct pci_driver *drv)
void void
pci_unregister_driver(struct pci_driver *drv) pci_unregister_driver(struct pci_driver *drv)
{ {
struct pci_dev *dev; list_t * node;
list_del(&drv->node); node = drv->driver.devices.next;
pci_for_each_dev(dev) {
if (dev->driver == drv) { while (node != &drv->driver.devices) {
if (drv->remove) struct device * dev = list_entry(node,struct device,driver_list);
drv->remove(dev); struct pci_dev * pci_dev = list_entry(dev,struct pci_dev,dev);
dev->driver = NULL;
} if (drv->remove)
drv->remove(pci_dev);
pci_dev->driver = NULL;
dev->driver = NULL;
list_del_init(&dev->driver_list);
} }
put_driver(&drv->driver);
} }
static struct pci_driver pci_compat_driver = { static struct pci_driver pci_compat_driver = {
...@@ -134,36 +198,6 @@ pci_dev_driver(const struct pci_dev *dev) ...@@ -134,36 +198,6 @@ pci_dev_driver(const struct pci_dev *dev)
return NULL; return NULL;
} }
static int pci_device_suspend(struct device * dev, u32 state, u32 level)
{
struct pci_dev * pci_dev = (struct pci_dev *)list_entry(dev,struct pci_dev,dev);
int error = 0;
if (pci_dev->driver) {
if (level == SUSPEND_SAVE_STATE && pci_dev->driver->save_state)
error = pci_dev->driver->save_state(pci_dev,state);
else if (level == SUSPEND_POWER_DOWN && pci_dev->driver->suspend)
error = pci_dev->driver->suspend(pci_dev,state);
}
return error;
}
static int pci_device_resume(struct device * dev, u32 level)
{
struct pci_dev * pci_dev = (struct pci_dev *)list_entry(dev,struct pci_dev,dev);
if (pci_dev->driver) {
if (level == RESUME_POWER_ON && pci_dev->driver->resume)
pci_dev->driver->resume(pci_dev);
}
return 0;
}
struct device_driver pci_device_driver = {
suspend: pci_device_suspend,
resume: pci_device_resume,
};
struct bus_type pci_bus_type = { struct bus_type pci_bus_type = {
name: "pci", name: "pci",
}; };
......
...@@ -18,8 +18,6 @@ ...@@ -18,8 +18,6 @@
LIST_HEAD(pci_root_buses); LIST_HEAD(pci_root_buses);
LIST_HEAD(pci_devices); LIST_HEAD(pci_devices);
extern struct device_driver pci_device_driver;
/* /*
* Translate the low bits of the PCI base * Translate the low bits of the PCI base
* to the resource type * to the resource type
...@@ -511,7 +509,6 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus) ...@@ -511,7 +509,6 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
dev0.bus = bus; dev0.bus = bus;
dev0.sysdata = bus->sysdata; dev0.sysdata = bus->sysdata;
dev0.dev.parent = bus->dev; dev0.dev.parent = bus->dev;
dev0.dev.driver = &pci_device_driver;
dev0.dev.bus = &pci_bus_type; dev0.dev.bus = &pci_bus_type;
/* Go find them, Rover! */ /* Go find them, Rover! */
......
...@@ -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;
......
...@@ -487,6 +487,8 @@ struct pci_driver { ...@@ -487,6 +487,8 @@ struct pci_driver {
int (*suspend) (struct pci_dev *dev, u32 state); /* Device suspended */ int (*suspend) (struct pci_dev *dev, u32 state); /* Device suspended */
int (*resume) (struct pci_dev *dev); /* Device woken up */ int (*resume) (struct pci_dev *dev); /* Device woken up */
int (*enable_wake) (struct pci_dev *dev, u32 state, int enable); /* Enable wake event */ int (*enable_wake) (struct pci_dev *dev, u32 state, int enable); /* Enable wake event */
struct device_driver driver;
}; };
......
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