From f371ab1c59dab04bfe7d239c3d5e85550bf31365 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 28 May 2002 03:59:17 -0700 Subject: 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 --- include/linux/device.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'include') 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; -- cgit v1.2.3 From 4b4a837f2b57467de03001bb9003382d1c9a7f18 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 28 May 2002 04:02:33 -0700 Subject: PCI: start to use common fields of struct device_driver more - add struct device_driver field to struct pci_driver - make sure those fields get set on driver registration (and register with core) - remove internal pci_drivers --- drivers/pci/hotplug.c | 3 +- drivers/pci/pci-driver.c | 124 ++++++++++++++++++++++++++++++----------------- drivers/pci/probe.c | 3 -- include/linux/pci.h | 2 + 4 files changed, 82 insertions(+), 50 deletions(-) (limited to 'include') 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 #include /* 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 a105a7b862a2..01db47dc97bf 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 @@ -512,7 +510,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/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; }; -- cgit v1.2.3