diff options
| author | Patrick Mochel <mochel@osdl.org> | 2002-05-28 18:54:23 -0700 |
|---|---|---|
| committer | Patrick Mochel <mochel@osdl.org> | 2002-05-28 18:54:23 -0700 |
| commit | 21a16f65b95259e28e99eb81977c790e77133ffb (patch) | |
| tree | 8c7bf46d4cf7f13a5dd32aeb899f957df6ad4adc | |
| parent | 83ca4c7e89ffc8fb30dd05754895dc381e0afbc6 (diff) | |
| parent | 4b4a837f2b57467de03001bb9003382d1c9a7f18 (diff) | |
Merge master.kernel.org:/home/mochel/BK/linux-2.5
into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-sync
| -rw-r--r-- | drivers/base/Makefile | 5 | ||||
| -rw-r--r-- | drivers/base/driver.c | 70 | ||||
| -rw-r--r-- | drivers/pci/hotplug.c | 3 | ||||
| -rw-r--r-- | drivers/pci/pci-driver.c | 124 | ||||
| -rw-r--r-- | drivers/pci/probe.c | 3 | ||||
| -rw-r--r-- | include/linux/device.h | 31 | ||||
| -rw-r--r-- | include/linux/pci.h | 2 |
7 files changed, 186 insertions, 52 deletions
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index eae7bc965fcb..a20768fa9630 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -1,7 +1,8 @@ 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 diff --git a/drivers/base/driver.c b/drivers/base/driver.c new file mode 100644 index 000000000000..13a7038c4826 --- /dev/null +++ b/drivers/base/driver.c @@ -0,0 +1,70 @@ +/* + * 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); diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 90eb3d8d426e..96b02d5be4be 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -2,7 +2,6 @@ #include <linux/module.h> #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); #ifndef FALSE @@ -61,7 +60,7 @@ pci_announce_device_to_drivers(struct pci_dev *dev) { 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); if (drv->remove && pci_announce_device(drv, dev)) break; diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 8ff363949d68..228f10eba8b1 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -10,8 +10,6 @@ * 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 * @ids: array of PCI device id structures to search in @@ -61,6 +59,57 @@ out: 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 * @drv: the driver structure to register @@ -73,15 +122,25 @@ out: int pci_register_driver(struct pci_driver *drv) { - struct pci_dev *dev; 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) { 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) void pci_unregister_driver(struct pci_driver *drv) { - struct pci_dev *dev; - - list_del(&drv->node); - pci_for_each_dev(dev) { - if (dev->driver == drv) { - if (drv->remove) - drv->remove(dev); - dev->driver = NULL; - } + list_t * node; + + node = drv->driver.devices.next; + + while (node != &drv->driver.devices) { + struct device * dev = list_entry(node,struct device,driver_list); + struct pci_dev * pci_dev = list_entry(dev,struct pci_dev,dev); + + 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 = { @@ -134,36 +198,6 @@ pci_dev_driver(const struct pci_dev *dev) 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 = { name: "pci", }; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 77e0cb72abfe..75b84219d66b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -18,8 +18,6 @@ LIST_HEAD(pci_root_buses); LIST_HEAD(pci_devices); -extern struct device_driver pci_device_driver; - /* * Translate the low bits of the PCI base * to the resource type @@ -511,7 +509,6 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus) dev0.bus = bus; dev0.sysdata = bus->sysdata; dev0.dev.parent = bus->dev; - dev0.dev.driver = &pci_device_driver; dev0.dev.bus = &pci_bus_type; /* Go find them, Rover! */ diff --git a/include/linux/device.h b/include/linux/device.h index 078c65e02370..2ad1e9ff4f75 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -84,17 +84,48 @@ extern void put_bus(struct bus_type * bus); 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 (*remove) (struct device * dev, u32 flags); int (*suspend) (struct device * dev, u32 state, 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 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 driver_list; struct list_head children; struct device * parent; diff --git a/include/linux/pci.h b/include/linux/pci.h index f6e3a68a2a0d..7cbc68fdb743 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -487,6 +487,8 @@ struct pci_driver { int (*suspend) (struct pci_dev *dev, u32 state); /* Device suspended */ int (*resume) (struct pci_dev *dev); /* Device woken up */ int (*enable_wake) (struct pci_dev *dev, u32 state, int enable); /* Enable wake event */ + + struct device_driver driver; }; |
