Re: [RFC PATCH] Input: gpio_keys: Fix suspend/resume press event lost

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 31 Jan 2013 15:25:43 +0200 "ivan.khoronzhuk" <ivan.khoronzhuk@xxxxxx>
wrote:

> On 01/28/2013 08:51 PM, NeilBrown wrote:
> > On Mon, 28 Jan 2013 18:13:14 +0200 "ivan.khoronzhuk" <ivan.khoronzhuk@xxxxxx>
> > wrote:
> >
> >> On 01/22/2013 07:24 AM, NeilBrown wrote:
> >>> On Mon, 21 Jan 2013 15:57:18 -0800 Dmitry Torokhov
> >>> <dmitry.torokhov@xxxxxxxxx> wrote:
> >>>
> >>>> Hi Ivan,
> >>>>
> >>>> On Mon, Jan 21, 2013 at 03:15:14PM +0200, Ivan Khoronzhuk wrote:
> >>>>> Rebased on linux_omap/master.
> >>>>>
> >>>>> During suspend/resume the key press can be lost if time of resume
> >>>>> sequence is significant.
> >>>>>
> >>>>> If press event cannot be remembered then the driver can read the
> >>>>> current button state only in time of interrupt handling. But in some
> >>>>> cases when time between IRQ and IRQ handler is significant we can
> >>>>> read incorrect state. As a particular case, when device is in suspend
> >>>>> we press wakupable key and up it back in a jiffy, the interrupt
> >>>>> handler read the state of up but the interrupt source is press indeed.
> >>>>> As a result, in a OS like android, we resume then suspend right away
> >>>>> because the key state is not changed.
> >>>>>
> >>>>> This patch add to gpio_keys framework opportunity to recover lost of
> >>>>> press key event at resuming. The variable "key_pressed" from
> >>>>> gpio_button_data structure is not used for gpio keys, it is only used
> >>>>> for gpio irq keys, so it is logically used to remember press lost
> >>>>> while resuming.
> >>>> The same could happen if you delay processing of interrupt long enough
> >>>> during normal operation. If key is released by the time you get around
> >>>> to reading it you will not see a key press.
> >>>>
> >>>> To me this sounds like you need to speed up your resume process so that
> >>>> you can start serving interrupts quicker.
> >>>>
> >>> Agreed.  When I was looking at this I found that any genuine button press
> >>> would have at least 70msec between press and release, while the device could
> >>> wake up to the point of being able to handle interrupts in about 14msec.
> >>> That is enough of a gap to make it pointless to try to 'fix' the code.
> >>>
> >>> With enough verbose debugging enabled that 14msec can easily grow to
> >>> hundreds, but then if  you have debugging enabled to can discipline yourself
> >>> to hold the button for longer.
> >>>
> >>> Ivan: What sort of delay are you seeing between the button press and the
> >>> interrupt routine running?  And can you measure how long the button is
> >>> typically down for?
> >>>
> >>> NeilBrown
> >> In my case I have the delay between the button press and the ISR
> >> about 145ms. If the button down for 120ms the IRQ press event is
> >> lost and if 160ms event is captured. I cannot speed up resume
> >> process enough to guarantee correct work, so I wrote this fix.
> >>
> >
> > 145ms does sound like a long time.
> > You should be able to get precise timings by putting a printk in various
> > parts of the code and ensuring the kernel logs are getting precise timestamps.
> >
> > Then you could see if the delay is between resume starting and the ISR
> > running, or between the ISR and the gpio_work_func getting scheduled.
> >
> > I assume that you don't have ->debounce_interval set....
> >
> > If the ISR is running soon enough, it might be possible to read the GPIO from
> > the ISR - I think that would be a cleaner solution.
> >
> > If not, then you will need something that interpolates an extra key press.
> > In that case I would suggest my original patch - it seems simpler than yours
> > and doesn't make a special case out of suspend.  As Dmitry said, any delay
> > could cause a problem.
> > My patch simply ensures that there is at least one button event for each
> > interrupt by generating an extra event for the inverse of the current button
> > position.  If that state had already been noticed, the input subsystem will
> > filter the extra event out so it won't be visible elsewhere.
> >
> > For reference, my original patch is below.
> >
> > NeilBrown
> >
> > [PATCH] Input: gpio_keys - ensure we don't miss key-presses during resume.
> >
> > If the latency of resume means we don't poll the key status until
> > after it has been released, we can lose the keypress which woke the
> > device.
> >
> > So on each interrupt, record that a press is pending, and in that
> > case, report both the up and down event, ordered such that the second
> > event is that one that reflects the current state.
> >
> > One event will normally be swallowed by the input layer if there was
> > no change, but the result will be that every interrupt will produce at
> > least one event.
> >
> > Signed-off-by: NeilBrown <neilb@xxxxxxx>
> >
> > diff --git a/drivers/input/keyboard/gpio_keys.c
> > b/drivers/input/keyboard/gpio_keys.c index 62bfce4..961e5e1 100644
> > --- a/drivers/input/keyboard/gpio_keys.c
> > +++ b/drivers/input/keyboard/gpio_keys.c
> > @@ -40,6 +40,7 @@ struct gpio_button_data {
> >   	spinlock_t lock;
> >   	bool disabled;
> >   	bool key_pressed;
> > +	bool pending;
> >   };
> >   
> >   struct gpio_keys_drvdata {
> > @@ -335,6 +336,14 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) if (state)
> >   			input_event(input, type, button->code, button->value); } else {
> > +		if (type == EV_KEY && bdata->pending) {
> > +			/* Before reporting the observed state, report the
> > +			 * alternate to be sure that a change is seen.
> > +			 */
> > +			bdata->pending = 0;
> > +			input_event(input, type, button->code, !state);
> > +			input_sync(input);
> > +		}
> >   		input_event(input, type, button->code, !!state);
> >   	}Yes it si
> >   	input_sync(input);
> > @@ -361,6 +370,7 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
> >   	BUG_ON(irq != bdata->irq);
> >   
> > +	bdata->pending = true;
> >   	if (bdata->timer_debounce)
> >   		mod_timer(&bdata->timer,
> >   			jiffies + msecs_to_jiffies(bdata->timer_debounce));
> 
> The delay is between resume starting and the ISR running,
> It is measured with oscilloscope between signal on button pin and
> before irq enabling. And I doubly checked it by printk() right in
> the ISR. So I cannot read the button state right in the ISR.

Wow.  That is a big delay then.

> 
> Your patch is simpler but it doesn't take into account one situation.
> It is unlikely but what if the event is lost at 16:00 and reproduced
> at 17:30, in some cases it is better to lose the event than recover it
> out of time.

Is that at all a realistic scenario?  Interrupts disabled for 90 minutes!  If
that happened you would have more to worry about than one stray button press
(which is still a valid button press, but is a bit late).

I think you are over-complicating things.  Just keep it simple:  Generate at
least one button event on every interrupt.

NeilBrown

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux