Message ID | 20210106125822.31315-3-tony@atomide.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Lost key-up interrupt handling for omap4-keypad | expand |
Hi Tony, I love your patch! Perhaps something to improve: [auto build test WARNING on input/next] [also build test WARNING on hid/for-next linux/master linus/master v5.11-rc2 next-20210104] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Tony-Lindgren/Lost-key-up-interrupt-handling-for-omap4-keypad/20210106-210045 base: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next config: openrisc-randconfig-s031-20210106 (attached as .config) compiler: or1k-linux-gcc (GCC) 9.3.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # apt-get install sparse # sparse version: v0.6.3-208-g46a52ca4-dirty # https://github.com/0day-ci/linux/commit/6a18714b171daeb44c0418e33cc3e78c7daaa44b git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Tony-Lindgren/Lost-key-up-interrupt-handling-for-omap4-keypad/20210106-210045 git checkout 6a18714b171daeb44c0418e33cc3e78c7daaa44b # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=openrisc If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All warnings (new ones prefixed by >>): drivers/input/keyboard/omap4-keypad.c: In function 'omap4_keypad_irq_thread_fn': drivers/input/keyboard/omap4-keypad.c:161:15: warning: variable 'keys_down' set but not used [-Wunused-but-set-variable] 161 | int keys_up, keys_down; | ^~~~~~~~~ >> drivers/input/keyboard/omap4-keypad.c:161:6: warning: variable 'keys_up' set but not used [-Wunused-but-set-variable] 161 | int keys_up, keys_down; | ^~~~~~~ vim +/keys_up +161 drivers/input/keyboard/omap4-keypad.c 156 157 static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id) 158 { 159 struct omap4_keypad *keypad_data = dev_id; 160 struct input_dev *input_dev = keypad_data->input; > 161 int keys_up, keys_down; 162 u32 low, high; 163 u64 keys; 164 165 low = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0); 166 high = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32); 167 keys = low | (u64)high << 32; 168 169 /* Scan for key up events for lost key-up interrupts */ 170 keys_up = omap4_keypad_scan_state(keypad_data, keys, false); 171 172 /* Scan for key down events */ 173 keys_down = omap4_keypad_scan_state(keypad_data, keys, true); 174 175 input_sync(input_dev); 176 177 keypad_data->keys = keys; 178 179 /* clear pending interrupts */ 180 kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, 181 kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); 182 183 return IRQ_HANDLED; 184 } 185 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -78,7 +78,7 @@ struct omap4_keypad { u32 irqreg_offset; unsigned int row_shift; bool no_autorepeat; - unsigned char key_state[8]; + u64 keys; unsigned short *keymap; }; @@ -107,6 +107,41 @@ static void kbd_write_irqreg(struct omap4_keypad *keypad_data, keypad_data->base + keypad_data->irqreg_offset + offset); } +static int omap4_keypad_scan_state(struct omap4_keypad *keypad_data, u64 keys, + bool down) +{ + struct input_dev *input_dev = keypad_data->input; + unsigned int col, row, code; + DECLARE_BITMAP(mask, 64); + unsigned long bit; + int events = 0; + bool key_down; + u64 changed; + + changed = keys ^ keypad_data->keys; + bitmap_from_u64(mask, changed); + + for_each_set_bit(bit, mask, keypad_data->rows * BITS_PER_BYTE) { + row = bit / BITS_PER_BYTE; + col = bit % BITS_PER_BYTE; + code = MATRIX_SCAN_CODE(row, col, keypad_data->row_shift); + + if (BIT_ULL(bit) & keys) + key_down = true; + else + key_down = false; + + if (key_down != down) + continue; + + input_event(input_dev, EV_MSC, MSC_SCAN, code); + input_report_key(input_dev, keypad_data->keymap[code], + key_down); + events++; + } + + return events; +} /* Interrupt handlers */ static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id) @@ -123,34 +158,23 @@ static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id) { struct omap4_keypad *keypad_data = dev_id; struct input_dev *input_dev = keypad_data->input; - unsigned char key_state[ARRAY_SIZE(keypad_data->key_state)]; - unsigned int col, row, code, changed; - u32 *new_state = (u32 *) key_state; + int keys_up, keys_down; + u32 low, high; + u64 keys; - *new_state = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0); - *(new_state + 1) = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32); + low = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0); + high = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32); + keys = low | (u64)high << 32; - for (row = 0; row < keypad_data->rows; row++) { - changed = key_state[row] ^ keypad_data->key_state[row]; - if (!changed) - continue; + /* Scan for key up events for lost key-up interrupts */ + keys_up = omap4_keypad_scan_state(keypad_data, keys, false); - for (col = 0; col < keypad_data->cols; col++) { - if (changed & (1 << col)) { - code = MATRIX_SCAN_CODE(row, col, - keypad_data->row_shift); - input_event(input_dev, EV_MSC, MSC_SCAN, code); - input_report_key(input_dev, - keypad_data->keymap[code], - key_state[row] & (1 << col)); - } - } - } + /* Scan for key down events */ + keys_down = omap4_keypad_scan_state(keypad_data, keys, true); input_sync(input_dev); - memcpy(keypad_data->key_state, key_state, - sizeof(keypad_data->key_state)); + keypad_data->keys = keys; /* clear pending interrupts */ kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
Because of errata i689 the keyboard can idle with state where no key up interrupts are seen until after the next key press. This means we need to first check for any lost key up events before scanning for new down events. For example, rapidly pressing shift-shift-j can sometimes produce a J instead of j. Let's fix the issue by scanning the keyboard in two phases. First we scan for any key up events that we may have missed, and then we scan for key down events. Let's also simplify things with for_each_set_bit() as suggested by Dmitry Torokhov <dmitry.torokhov@gmail.com>. Cc: Arthur Demchenkov <spinal.by@gmail.com> Cc: Carl Philipp Klemm <philipp@uvos.xyz> Cc: Merlijn Wajer <merlijn@wizzup.org> Cc: Pavel Machek <pavel@ucw.cz> Cc: ruleh <ruleh@gmx.de> Cc: Sebastian Reichel <sre@kernel.org> Signed-off-by: Tony Lindgren <tony@atomide.com> --- drivers/input/keyboard/omap4-keypad.c | 70 ++++++++++++++++++--------- 1 file changed, 47 insertions(+), 23 deletions(-)