Commit 4ee5a59e authored by Patrick Mochel's avatar Patrick Mochel

Driver model: handle devices registered with ->driver set.

In some cases, especially when dealing with system and platform devices, a 
device's driver is known when the device is registered. We still want to add
the device to the driver's list and add it to the class.

This makes splits driver binding into probe() and attach(). If the device already
has a driver, we simply call attach(). Otherwise, we try to match it on the bus
and still call found_match().

This requires that all drivers that are referenced are registered beforehand.
parent 8b755139
...@@ -23,6 +23,19 @@ spinlock_t device_lock = SPIN_LOCK_UNLOCKED; ...@@ -23,6 +23,19 @@ spinlock_t device_lock = SPIN_LOCK_UNLOCKED;
#define to_dev(node) container_of(node,struct device,driver_list) #define to_dev(node) container_of(node,struct device,driver_list)
static int probe(struct device * dev, struct device_driver * drv)
{
dev->driver = drv;
return drv->probe ? drv->probe(dev) : 0;
}
static void attach(struct device * dev)
{
spin_lock(&device_lock);
list_add_tail(&dev->driver_list,&dev->driver->devices);
spin_unlock(&device_lock);
devclass_add_device(dev);
}
/** /**
* found_match - do actual binding of device to driver * found_match - do actual binding of device to driver
...@@ -43,25 +56,14 @@ static int found_match(struct device * dev, struct device_driver * drv) ...@@ -43,25 +56,14 @@ static int found_match(struct device * dev, struct device_driver * drv)
{ {
int error = 0; int error = 0;
dev->driver = get_driver(drv); if (!(error = probe(dev,get_driver(drv)))) {
if (drv->probe)
if (drv->probe(dev))
goto ProbeFailed;
pr_debug("bound device '%s' to driver '%s'\n", pr_debug("bound device '%s' to driver '%s'\n",
dev->bus_id,drv->name); dev->bus_id,drv->name);
attach(dev);
spin_lock(&device_lock); } else {
list_add_tail(&dev->driver_list,&drv->devices);
spin_unlock(&device_lock);
devclass_add_device(dev);
goto Done;
ProbeFailed:
put_driver(drv); put_driver(drv);
dev->driver = NULL; dev->driver = NULL;
Done: }
return error; return error;
} }
...@@ -80,18 +82,19 @@ static int do_device_attach(struct device_driver * drv, void * data) ...@@ -80,18 +82,19 @@ 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 (drv->bus->match && drv->bus->match(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_attach(struct device * dev) static int device_attach(struct device * dev)
{ {
int error = 0; int error = 0;
if (!dev->driver) {
if (dev->bus) if (dev->bus)
error = bus_for_each_drv(dev->bus,dev,do_device_attach); error = bus_for_each_drv(dev->bus,dev,do_device_attach);
} else
attach(dev);
return error; return error;
} }
...@@ -103,7 +106,6 @@ static void device_detach(struct device * dev) ...@@ -103,7 +106,6 @@ static void device_detach(struct device * dev)
devclass_remove_device(dev); devclass_remove_device(dev);
if (drv && drv->remove) if (drv && drv->remove)
drv->remove(dev); drv->remove(dev);
dev->driver = NULL; dev->driver = NULL;
} }
} }
......
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