Commit 07900f7a authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://ldm.bkbits.net/linux-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 6bd20e27 59fb29c6
...@@ -18,5 +18,5 @@ extern void device_remove_dir(struct device * dev); ...@@ -18,5 +18,5 @@ extern void device_remove_dir(struct device * dev);
extern int device_bus_link(struct device * dev); extern int device_bus_link(struct device * dev);
extern int driver_bind(struct device_driver * drv); extern int driver_attach(struct device_driver * drv);
extern void driver_unbind(struct device_driver * drv); extern void driver_detach(struct device_driver * drv);
...@@ -167,12 +167,13 @@ static int bus_make_dir(struct bus_type * bus) ...@@ -167,12 +167,13 @@ static int bus_make_dir(struct bus_type * bus)
int bus_register(struct bus_type * bus) int bus_register(struct bus_type * bus)
{ {
spin_lock(&device_lock);
rwlock_init(&bus->lock); rwlock_init(&bus->lock);
INIT_LIST_HEAD(&bus->devices); INIT_LIST_HEAD(&bus->devices);
INIT_LIST_HEAD(&bus->drivers); INIT_LIST_HEAD(&bus->drivers);
list_add_tail(&bus->node,&bus_driver_list);
atomic_set(&bus->refcount,2); atomic_set(&bus->refcount,2);
spin_lock(&device_lock);
list_add_tail(&bus->node,&bus_driver_list);
spin_unlock(&device_lock); spin_unlock(&device_lock);
pr_debug("bus type '%s' registered\n",bus->name); pr_debug("bus type '%s' registered\n",bus->name);
......
...@@ -31,7 +31,7 @@ spinlock_t device_lock = SPIN_LOCK_UNLOCKED; ...@@ -31,7 +31,7 @@ spinlock_t device_lock = SPIN_LOCK_UNLOCKED;
* @dev: device * @dev: device
* @drv: driver * @drv: driver
* *
* We're here because the bus's bind callback returned success for this * We're here because the bus's match callback returned success for this
* pair. We call the driver's probe callback to verify they're really a * pair. We call the driver's probe callback to verify they're really a
* match made in heaven. * match made in heaven.
* *
...@@ -67,60 +67,74 @@ static int found_match(struct device * dev, struct device_driver * drv) ...@@ -67,60 +67,74 @@ static int found_match(struct device * dev, struct device_driver * drv)
} }
/** /**
* bind_device - try to associated device with a driver * device_attach - try to associated device with a driver
* @drv: current driver to try * @drv: current driver to try
* @data: device in disguise * @data: device in disguise
* *
* This function is used as a callback to bus_for_each_drv. * This function is used as a callback to bus_for_each_drv.
* It calls the bus's ::bind callback to check if the driver supports * It calls the bus's match callback to check if the driver supports
* the device. If so, it calls the found_match() function above to * the device. If so, it calls the found_match() function above to
* take care of all the details. * take care of all the details.
*/ */
static int do_device_bind(struct device_driver * drv, void * data) static int do_device_attach(struct device_driver * drv, void * data)
{ {
struct device * dev = (struct device *)data; struct device * dev = (struct device *)data;
int error = 0; int error = 0;
if (!dev->driver) { if (!dev->driver) {
if (drv->bus->bind && drv->bus->bind(dev,drv)) if (drv->bus->match && drv->bus->match(dev,drv))
error = found_match(dev,drv); error = found_match(dev,drv);
} }
return error; return error;
} }
static int device_bind(struct device * dev) static int device_attach(struct device * dev)
{ {
int error = 0; int error = 0;
if (dev->bus) if (dev->bus)
error = bus_for_each_drv(dev->bus,dev,do_device_bind); error = bus_for_each_drv(dev->bus,dev,do_device_attach);
return error; return error;
} }
static void device_unbind(struct device * dev) static void device_detach(struct device * dev)
{ {
/* unbind from driver */ struct device_driver * drv;
if (dev->driver && dev->driver->remove)
dev->driver->remove(dev); if (dev->driver) {
lock_device(dev);
drv = dev->driver;
dev->driver = NULL;
unlock_device(dev);
write_lock(&drv->lock);
list_del_init(&dev->driver_list);
write_unlock(&drv->lock);
/* detach from driver */
if (drv->remove)
drv->remove(dev);
put_driver(drv);
}
} }
static int do_driver_bind(struct device * dev, void * data) static int do_driver_attach(struct device * dev, void * data)
{ {
struct device_driver * drv = (struct device_driver *)data; struct device_driver * drv = (struct device_driver *)data;
int error = 0; int error = 0;
if (!dev->driver) { if (!dev->driver) {
if (dev->bus->bind && dev->bus->bind(dev,drv)) if (dev->bus->match && dev->bus->match(dev,drv))
error = found_match(dev,drv); error = found_match(dev,drv);
} }
return error; return error;
} }
int driver_bind(struct device_driver * drv) int driver_attach(struct device_driver * drv)
{ {
return bus_for_each_dev(drv->bus,drv,do_driver_bind); return bus_for_each_dev(drv->bus,drv,do_driver_attach);
} }
static int do_driver_unbind(struct device * dev, struct device_driver * drv) static int do_driver_detach(struct device * dev, struct device_driver * drv)
{ {
lock_device(dev); lock_device(dev);
if (dev->driver == drv) { if (dev->driver == drv) {
...@@ -133,31 +147,32 @@ static int do_driver_unbind(struct device * dev, struct device_driver * drv) ...@@ -133,31 +147,32 @@ static int do_driver_unbind(struct device * dev, struct device_driver * drv)
return 0; return 0;
} }
void driver_unbind(struct device_driver * drv) void driver_detach(struct device_driver * drv)
{ {
struct device * next; struct device * next;
struct device * dev = NULL; struct device * dev = NULL;
struct list_head * node; struct list_head * node;
int error = 0; int error = 0;
read_lock(&drv->lock); write_lock(&drv->lock);
node = drv->devices.next; node = drv->devices.next;
while (node != &drv->devices) { while (node != &drv->devices) {
next = list_entry(node,struct device,driver_list); next = list_entry(node,struct device,driver_list);
get_device(next); get_device(next);
read_unlock(&drv->lock); list_del_init(&next->driver_list);
write_unlock(&drv->lock);
if (dev) if (dev)
put_device(dev); put_device(dev);
dev = next; dev = next;
if ((error = do_driver_unbind(dev,drv))) { if ((error = do_driver_detach(dev,drv))) {
put_device(dev); put_device(dev);
break; break;
} }
read_lock(&drv->lock); write_lock(&drv->lock);
node = dev->driver_list.next; node = drv->devices.next;
} }
read_unlock(&drv->lock); write_unlock(&drv->lock);
if (dev) if (dev)
put_device(dev); put_device(dev);
} }
...@@ -181,13 +196,13 @@ int device_register(struct device *dev) ...@@ -181,13 +196,13 @@ int device_register(struct device *dev)
if (!dev || !strlen(dev->bus_id)) if (!dev || !strlen(dev->bus_id))
return -EINVAL; return -EINVAL;
spin_lock(&device_lock);
INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->node);
INIT_LIST_HEAD(&dev->children); INIT_LIST_HEAD(&dev->children);
INIT_LIST_HEAD(&dev->g_list); INIT_LIST_HEAD(&dev->g_list);
spin_lock_init(&dev->lock); spin_lock_init(&dev->lock);
atomic_set(&dev->refcount,2); atomic_set(&dev->refcount,2);
spin_lock(&device_lock);
if (dev != &device_root) { if (dev != &device_root) {
if (!dev->parent) if (!dev->parent)
dev->parent = &device_root; dev->parent = &device_root;
...@@ -212,7 +227,7 @@ int device_register(struct device *dev) ...@@ -212,7 +227,7 @@ int device_register(struct device *dev)
bus_add_device(dev); bus_add_device(dev);
/* bind to driver */ /* bind to driver */
device_bind(dev); device_attach(dev);
/* notify platform of device entry */ /* notify platform of device entry */
if (platform_notify) if (platform_notify)
...@@ -246,7 +261,7 @@ void put_device(struct device * dev) ...@@ -246,7 +261,7 @@ void put_device(struct device * dev)
if (platform_notify_remove) if (platform_notify_remove)
platform_notify_remove(dev); platform_notify_remove(dev);
device_unbind(dev); device_detach(dev);
bus_remove_device(dev); bus_remove_device(dev);
/* remove the driverfs directory */ /* remove the driverfs directory */
......
...@@ -74,33 +74,27 @@ int driver_register(struct device_driver * drv) ...@@ -74,33 +74,27 @@ int driver_register(struct device_driver * drv)
list_add(&drv->bus_list,&drv->bus->drivers); list_add(&drv->bus_list,&drv->bus->drivers);
write_unlock(&drv->bus->lock); write_unlock(&drv->bus->lock);
driver_make_dir(drv); driver_make_dir(drv);
driver_bind(drv); driver_attach(drv);
put_driver(drv); put_driver(drv);
return 0; return 0;
} }
static void __remove_driver(struct device_driver * drv) static void __remove_driver(struct device_driver * drv)
{ {
if (drv->bus) { pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name);
pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name); driver_detach(drv);
driverfs_remove_dir(&drv->dir);
driver_unbind(drv);
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) if (drv->release)
drv->release(drv); drv->release(drv);
put_bus(drv->bus);
} }
void remove_driver(struct device_driver * drv) void remove_driver(struct device_driver * drv)
{ {
spin_lock(&device_lock); write_lock(&drv->bus->lock);
atomic_set(&drv->refcount,0); atomic_set(&drv->refcount,0);
spin_unlock(&device_lock); list_del_init(&drv->bus_list);
write_unlock(&drv->bus->lock);
__remove_driver(drv); __remove_driver(drv);
} }
...@@ -110,10 +104,13 @@ void remove_driver(struct device_driver * drv) ...@@ -110,10 +104,13 @@ void remove_driver(struct device_driver * drv)
*/ */
void put_driver(struct device_driver * drv) void put_driver(struct device_driver * drv)
{ {
if (!atomic_dec_and_lock(&drv->refcount,&device_lock)) write_lock(&drv->bus->lock);
if (!atomic_dec_and_test(&drv->refcount)) {
write_unlock(&drv->bus->lock);
return; return;
spin_unlock(&device_lock); }
list_del_init(&drv->bus_list);
write_unlock(&drv->bus->lock);
__remove_driver(drv); __remove_driver(drv);
} }
......
...@@ -165,7 +165,7 @@ pci_dev_driver(const struct pci_dev *dev) ...@@ -165,7 +165,7 @@ pci_dev_driver(const struct pci_dev *dev)
} }
/** /**
* pci_bus_bind - Tell if a PCI device structure has a matching PCI device id structure * pci_bus_match - 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
* @dev: the PCI device structure to match against * @dev: the PCI device structure to match against
* *
...@@ -173,7 +173,7 @@ pci_dev_driver(const struct pci_dev *dev) ...@@ -173,7 +173,7 @@ pci_dev_driver(const struct pci_dev *dev)
* system is in its list of supported devices.Returns the matching * system is in its list of supported devices.Returns the matching
* pci_device_id structure or %NULL if there is no match. * pci_device_id structure or %NULL if there is no match.
*/ */
static int pci_bus_bind(struct device * dev, struct device_driver * drv) static int pci_bus_match(struct device * dev, struct device_driver * drv)
{ {
struct pci_dev * pci_dev = list_entry(dev, struct pci_dev, dev); struct pci_dev * pci_dev = list_entry(dev, struct pci_dev, dev);
struct pci_driver * pci_drv = list_entry(drv,struct pci_driver,driver); struct pci_driver * pci_drv = list_entry(drv,struct pci_driver,driver);
...@@ -196,7 +196,7 @@ static int pci_bus_bind(struct device * dev, struct device_driver * drv) ...@@ -196,7 +196,7 @@ static int pci_bus_bind(struct device * dev, struct device_driver * drv)
struct bus_type pci_bus_type = { struct bus_type pci_bus_type = {
name: "pci", name: "pci",
bind: pci_bus_bind, match: pci_bus_match,
}; };
static int __init pci_driver_init(void) static int __init pci_driver_init(void)
......
...@@ -64,7 +64,7 @@ struct bus_type { ...@@ -64,7 +64,7 @@ struct bus_type {
struct driver_dir_entry device_dir; struct driver_dir_entry device_dir;
struct driver_dir_entry driver_dir; struct driver_dir_entry driver_dir;
int (*bind) (struct device * dev, struct device_driver * drv); int (*match) (struct device * dev, struct device_driver * drv);
}; };
......
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