On Thu, 10 Feb 2011 17:16:07 +0000 (GMT) Daniel Drake <dsd@xxxxxxxxxx> wrote: > The OLPC XO laptop is able to use the PS/2 controller as a wakeup > source. When used as a wakeup source, the key press/mouse motion must > not be lost. > > Add infrastructure to allow controllers to be marked as > wakeup-capable, and avoid doing power control/reset on the > i8042/serio devices when running in this mode. > > Signed-off-by: Daniel Drake <dsd@xxxxxxxxxx> > --- > drivers/input/serio/i8042-io.h | 4 +++ > drivers/input/serio/i8042-ip22io.h | 4 +++ > drivers/input/serio/i8042-jazzio.h | 4 +++ > drivers/input/serio/i8042-ppcio.h | 4 +++ > drivers/input/serio/i8042-snirm.h | 4 +++ > drivers/input/serio/i8042-sparcio.h | 4 +++ > drivers/input/serio/i8042-x86ia64io.h | 4 +++ > drivers/input/serio/i8042.c | 37 > +++++++++++++++++++++++++++++--- > drivers/input/serio/serio.c | 28 +++++++++++++++++++++--- > 9 files changed, 85 insertions(+), 8 deletions(-) > > A followup patch will come soon, hooking this into OLPC's embedded > controller: > http://dev.laptop.org/~dsd/20110114/0015-i8042-Enable-OLPC-s-EC-based-i8042-wakeup-control.patch > > diff --git a/drivers/input/serio/i8042-io.h > b/drivers/input/serio/i8042-io.h index 5d48bb6..296633c 100644 > --- a/drivers/input/serio/i8042-io.h > +++ b/drivers/input/serio/i8042-io.h > @@ -92,4 +92,8 @@ static inline void i8042_platform_exit(void) > #endif > } > > +static inline void i8042_platform_suspend(struct device *dev, bool > may_wakeup) +{ > +} > + > #endif /* _I8042_IO_H */ > diff --git a/drivers/input/serio/i8042-ip22io.h > b/drivers/input/serio/i8042-ip22io.h index ee1ad27..c5b76a4 100644 > --- a/drivers/input/serio/i8042-ip22io.h > +++ b/drivers/input/serio/i8042-ip22io.h > @@ -73,4 +73,8 @@ static inline void i8042_platform_exit(void) > #endif > } > > +static inline void i8042_platform_suspend(struct device *dev, bool > may_wakeup) +{ > +} > + > #endif /* _I8042_IP22_H */ > diff --git a/drivers/input/serio/i8042-jazzio.h > b/drivers/input/serio/i8042-jazzio.h index 13fd710..a11913a 100644 > --- a/drivers/input/serio/i8042-jazzio.h > +++ b/drivers/input/serio/i8042-jazzio.h > @@ -66,4 +66,8 @@ static inline void i8042_platform_exit(void) > #endif > } > > +static inline void i8042_platform_suspend(struct device *dev, bool > may_wakeup) +{ > +} > + > #endif /* _I8042_JAZZ_H */ > diff --git a/drivers/input/serio/i8042-ppcio.h > b/drivers/input/serio/i8042-ppcio.h index f708c75..c9f4292 100644 > --- a/drivers/input/serio/i8042-ppcio.h > +++ b/drivers/input/serio/i8042-ppcio.h > @@ -52,6 +52,10 @@ static inline void i8042_platform_exit(void) > { > } > > +static inline void i8042_platform_suspend(struct device *dev, bool > may_wakeup) +{ > +} > + > #else > > #include "i8042-io.h" > diff --git a/drivers/input/serio/i8042-snirm.h > b/drivers/input/serio/i8042-snirm.h index 409a934..96d034f 100644 > --- a/drivers/input/serio/i8042-snirm.h > +++ b/drivers/input/serio/i8042-snirm.h > @@ -72,4 +72,8 @@ static inline void i8042_platform_exit(void) > > } > > +static inline void i8042_platform_suspend(struct device *dev, bool > may_wakeup) +{ > +} > + > #endif /* _I8042_SNIRM_H */ > diff --git a/drivers/input/serio/i8042-sparcio.h > b/drivers/input/serio/i8042-sparcio.h index c5cc450..a6c1f74 100644 > --- a/drivers/input/serio/i8042-sparcio.h > +++ b/drivers/input/serio/i8042-sparcio.h > @@ -154,4 +154,8 @@ static inline void i8042_platform_exit(void) > } > #endif /* !CONFIG_PCI */ > > +static inline void i8042_platform_suspend(struct device *dev, bool > may_wakeup) +{ > +} > + > #endif /* _I8042_SPARCIO_H */ > diff --git a/drivers/input/serio/i8042-x86ia64io.h > b/drivers/input/serio/i8042-x86ia64io.h index bb9f5d3..76b2e58 100644 > --- a/drivers/input/serio/i8042-x86ia64io.h > +++ b/drivers/input/serio/i8042-x86ia64io.h > @@ -875,6 +875,10 @@ static inline int i8042_pnp_init(void) { return > 0; } static inline void i8042_pnp_exit(void) { } > #endif > > +static inline void i8042_platform_suspend(struct device *dev, bool > may_wakeup) +{ > +} > + > static int __init i8042_platform_init(void) > { > int retval; > diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c > index ac4c936..fb9dee6 100644 > --- a/drivers/input/serio/i8042.c > +++ b/drivers/input/serio/i8042.c > @@ -79,6 +79,10 @@ module_param_named(nopnp, i8042_nopnp, bool, 0); > MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller > settings"); #endif > > +static bool i8042_enable_wakeup; > +module_param_named(enable_wakeup, i8042_enable_wakeup, bool, 0); > +MODULE_PARM_DESC(enable_wakeup, "Enable i8042 as wakeup-capable > device"); + If we're going to default to disabling this (which we should), it would be nice to have a quirk for OLPC (probably checking DMI or something) that enables it. > #define DEBUG > #ifdef DEBUG > static bool i8042_debug; > @@ -1081,10 +1085,17 @@ static void i8042_dritek_enable(void) > * before suspending. > */ > > -static int i8042_controller_resume(bool force_reset) > +static int i8042_controller_resume(bool force_reset, bool > soft_resume) { > int error; > > + /* > + * If device is selected as a wakeup source, it was not > powered down > + * or reset during suspend, so we have very little to do. > + */ > + if (soft_resume) > + goto soft; > + > error = i8042_controller_check(); > if (error) > return error; > @@ -1128,6 +1139,7 @@ static int i8042_controller_resume(bool > force_reset) if (i8042_ports[I8042_KBD_PORT_NO].serio) > i8042_enable_kbd_port(); > > +soft: > i8042_interrupt(0, NULL); > > return 0; > @@ -1145,6 +1157,20 @@ static int i8042_pm_reset(struct device *dev) > return 0; > } > > +static int i8042_pm_suspend(struct device *dev) > +{ > + i8042_platform_suspend(dev, device_may_wakeup(dev)); What exactly is the purpose of this? I see this allows various architectures to provide an override here, but it seems like this functionality wasn't previously present (they all just used i8042_pm_reset). Do you have a later patch that makes use of this or something? > + > + /* > + * If device is selected as a wakeup source, don't powerdown > or reset > + * during suspend. > + */ > + if (device_may_wakeup(dev)) > + return 0; > + > + return i8042_pm_reset(dev); > +} > + > static int i8042_pm_resume(struct device *dev) > { > /* > @@ -1152,7 +1178,7 @@ static int i8042_pm_resume(struct device *dev) > * to bring it in a sane state. (In case of S2D we expect > * BIOS to reset the controller for us.) > */ > - return i8042_controller_resume(true); > + return i8042_controller_resume(true, device_may_wakeup(dev)); > } > > static int i8042_pm_thaw(struct device *dev) > @@ -1164,11 +1190,11 @@ static int i8042_pm_thaw(struct device *dev) > > static int i8042_pm_restore(struct device *dev) > { > - return i8042_controller_resume(false); > + return i8042_controller_resume(false, false); > } > > static const struct dev_pm_ops i8042_pm_ops = { > - .suspend = i8042_pm_reset, > + .suspend = i8042_pm_suspend, > .resume = i8042_pm_resume, > .thaw = i8042_pm_thaw, > .poweroff = i8042_pm_reset, > @@ -1402,6 +1428,9 @@ static int __init i8042_probe(struct > platform_device *dev) i8042_dritek_enable(); > #endif > > + if (i8042_enable_wakeup) > + device_set_wakeup_capable(&dev->dev, true); > + > if (!i8042_noaux) { > error = i8042_setup_aux(); > if (error && error != -ENODEV && error != -EBUSY) > diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c > index db5b0bc..7480be5 100644 > --- a/drivers/input/serio/serio.c > +++ b/drivers/input/serio/serio.c > @@ -928,7 +928,7 @@ static int serio_uevent(struct device *dev, > struct kobj_uevent_env *env) #endif /* CONFIG_HOTPLUG */ > > #ifdef CONFIG_PM > -static int serio_suspend(struct device *dev) > +static int serio_poweroff(struct device *dev) > { > struct serio *serio = to_serio_port(dev); > > @@ -937,7 +937,17 @@ static int serio_suspend(struct device *dev) > return 0; > } > > -static int serio_resume(struct device *dev) > +static int serio_suspend(struct device *dev) > +{ > + /* If parent controller is configured as a wakeup source, > don't > + * power off. */ > + if (device_may_wakeup(dev->parent)) > + return 0; > + > + return serio_poweroff(dev); > +} > + > +static int serio_restore(struct device *dev) > { > struct serio *serio = to_serio_port(dev); > > @@ -950,11 +960,21 @@ static int serio_resume(struct device *dev) > return 0; > } > > +static int serio_resume(struct device *dev) > +{ > + /* If parent controller is configured as a wakeup source, we > didn't > + * power off during suspend, and hence have nothing to do. */ > + if (device_may_wakeup(dev->parent)) > + return 0; > + > + return serio_restore(dev); > +} > + > static const struct dev_pm_ops serio_pm_ops = { > .suspend = serio_suspend, > .resume = serio_resume, > - .poweroff = serio_suspend, > - .restore = serio_resume, > + .poweroff = serio_poweroff, > + .restore = serio_restore, > }; > #endif /* CONFIG_PM */ > -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html