X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fbase%2Fpower%2Fresume.c;h=f6cfea496ea0838653b113259071a9dfc7b23e7b;hb=11048dcf333c414f237bb713c422e68f67b115a3;hp=826093ef4c7eb0e83cd0fa5fc8564cf6416144ea;hpb=0a1340c185734a57fbf4775927966ad4a1347b02;p=linux-2.6 diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index 826093ef4c..f6cfea496e 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c @@ -26,7 +26,9 @@ int resume_device(struct device * dev) TRACE_DEVICE(dev); TRACE_RESUME(0); + down(&dev->sem); + if (dev->power.pm_parent && dev->power.pm_parent->power.power_state.event) { dev_err(dev, "PM: resume from %d, parent %s still %d\n", @@ -34,20 +36,51 @@ int resume_device(struct device * dev) dev->power.pm_parent->bus_id, dev->power.pm_parent->power.power_state.event); } + if (dev->bus && dev->bus->resume) { dev_dbg(dev,"resuming\n"); error = dev->bus->resume(dev); } + + if (!error && dev->type && dev->type->resume) { + dev_dbg(dev,"resuming\n"); + error = dev->type->resume(dev); + } + + if (!error && dev->class && dev->class->resume) { + dev_dbg(dev,"class resume\n"); + error = dev->class->resume(dev); + } + up(&dev->sem); + TRACE_RESUME(error); return error; } +static int resume_device_early(struct device * dev) +{ + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + if (dev->bus && dev->bus->resume_early) { + dev_dbg(dev,"EARLY resume\n"); + error = dev->bus->resume_early(dev); + } + TRACE_RESUME(error); + return error; +} +/* + * Resume the devices that have either not gone through + * the late suspend, or that did go through it but also + * went through the early resume + */ void dpm_resume(void) { - down(&dpm_list_sem); + mutex_lock(&dpm_list_mtx); while(!list_empty(&dpm_off)) { struct list_head * entry = dpm_off.next; struct device * dev = to_device(entry); @@ -55,13 +88,13 @@ void dpm_resume(void) get_device(dev); list_move_tail(entry, &dpm_active); - up(&dpm_list_sem); + mutex_unlock(&dpm_list_mtx); if (!dev->power.prev_state.event) resume_device(dev); - down(&dpm_list_sem); + mutex_lock(&dpm_list_mtx); put_device(dev); } - up(&dpm_list_sem); + mutex_unlock(&dpm_list_mtx); } @@ -74,21 +107,22 @@ void dpm_resume(void) void device_resume(void) { - down(&dpm_sem); + might_sleep(); + mutex_lock(&dpm_mtx); dpm_resume(); - up(&dpm_sem); + mutex_unlock(&dpm_mtx); } EXPORT_SYMBOL_GPL(device_resume); /** - * device_power_up_irq - Power on some devices. + * dpm_power_up - Power on some devices. * * Walk the dpm_off_irq list and power each device up. This * is used for devices that required they be powered down with - * interrupts disabled. As devices are powered on, they are moved to - * the dpm_suspended list. + * interrupts disabled. As devices are powered on, they are moved + * to the dpm_active list. * * Interrupts must be disabled when calling this. */ @@ -99,16 +133,14 @@ void dpm_power_up(void) struct list_head * entry = dpm_off_irq.next; struct device * dev = to_device(entry); - get_device(dev); - list_move_tail(entry, &dpm_active); - resume_device(dev); - put_device(dev); + list_move_tail(entry, &dpm_off); + resume_device_early(dev); } } /** - * device_pm_power_up - Turn on all devices that need special attention. + * device_power_up - Turn on all devices that need special attention. * * Power on system devices then devices that required we shut them down * with interrupts disabled.