With a sophisticated driver that would never happen, because after
blocking new child registrations, the driver would check that the
power.sleeping flag is set in all the children before powering down the
device. But like I said, I'm not sure if this would be a good
strategy.
(This partly has to do with the requirements for runtime PM. During a
runtime suspend the driver does have to check the children's status; it
can't rely on the PM core. So if the check has to be done anyway, why
not also check during a system sleep?)
With non-sophisticated drivers, it definitely could happen that a new
child is registered concurrently with begin_sleep. Then the core would
go back and suspend the child first, as you say. Eventually the core
would return to the parent device, at which time it would call the
parent's begin_sleep method again -- unless we add another flag to
indicate that it had already been called.
Right. That would be simpler.
I had a change like that in my version of the patch. It's excerpted
below.
AFAICS there needs to be only one begin_sleep method. It should apply
equally well to suspend, freeze, quiesce, and hibernate. (But not to
suspend_late.)
There's no need for that. If it isn't implemented, treat it as though
it was successful.
But if a driver implements suspend() and leaves begin_sleep() as just a
stub (which many drivers might reasonably do, if they never register
any children), then the core shouldn't require suspend() to succeed
merely because begin_sleep() did.
And especially not if begin_sleep() is called in a separate pass.
They wouldn't have to be marked at all. They would never get on any of
the PM lists, because they would never be passed to device_pm_add().
The status of such devices is a little peculiar. For example, consider
the MMC subsystem. There's an MMC controller, generally a platform
device. Its child is an mmc_host device, but the mmc_host methods are
called by the platform device's methods -- there is no driver
associated with an mmc_host. At one time the mmc_host was a
class_device; that's may explain in part why it works this way.
Alan Stern
Index: usb-2.6/drivers/base/core.c
===================================================================
--- usb-2.6.orig/drivers/base/core.c
+++ usb-2.6/drivers/base/core.c
@@ -815,10 +815,12 @@ int device_add(struct device *dev)
error = dpm_sysfs_add(dev);
if (error)
goto PMError;
- device_pm_add(dev);
error = bus_add_device(dev);
if (error)
goto BusError;
+ error = device_pm_add(dev);
+ if (error)
+ goto PMAddError;
kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_attach_device(dev);
if (parent)
@@ -838,8 +840,9 @@ int device_add(struct device *dev)
Done:
put_device(dev);
return error;
+ PMAddError:
+ bus_remove_device(dev);
BusError:
- device_pm_remove(dev);
dpm_sysfs_remove(dev);
PMError:
if (dev->bus)
--