diff --git a/drivers/input/keyboard/brain-kbd-gpio.c b/drivers/input/keyboard/brain-kbd-gpio.c index 4b050a996..298583f24 100644 --- a/drivers/input/keyboard/brain-kbd-gpio.c +++ b/drivers/input/keyboard/brain-kbd-gpio.c @@ -37,6 +37,8 @@ struct bk_gpio_data { bool symbol; ulong last_in[7]; bool pressed[7][7]; + /* key code reported when the key went down, so the same code is released */ + unsigned int code[7][7]; }; static void bk_gpio_read_keys(struct input_dev *inputdev, ulong* result) @@ -85,6 +87,17 @@ static void bk_gpio_read_keys(struct input_dev *inputdev, ulong* result) } } +static void bk_gpio_release(struct bk_gpio_data *kbd, struct input_dev *inputdev, + int i, int j) +{ + if (i == kbd->sym_key_bank && j == kbd->sym_key_num) { + kbd->symbol = false; + return; + } + if (kbd->code[i][j] != UINT_MAX) + input_report_key(inputdev, kbd->code[i][j], 0); +} + static void bk_gpio_poll(struct input_dev *inputdev) { struct bk_gpio_data *kbd = input_get_drvdata(inputdev); @@ -124,16 +137,23 @@ static void bk_gpio_poll(struct input_dev *inputdev) dev_dbg(dev, "symbol\n"); kbd->symbol = true; } else { - dev_dbg(dev, "P: %04x\n", kbd->km[i][j]); - input_report_key( - inputdev, - kbd->symbol ? kbd->km_symbol[i][j] : kbd->km[i][j], - 1 - ); + kbd->code[i][j] = kbd->symbol ? + kbd->km_symbol[i][j] : kbd->km[i][j]; + dev_dbg(dev, "P: %04x\n", kbd->code[i][j]); + if (kbd->code[i][j] != UINT_MAX) + input_report_key(inputdev, kbd->code[i][j], 1); } } kbd->pressed[i][j] = true; } else { + /* + * Released while another key of this bank is still + * down (e.g. Symbol held, M released): this used to be + * forgotten without a release event, which left the key + * stuck and auto-repeating. + */ + if (kbd->pressed[i][j]) + bk_gpio_release(kbd, inputdev, i, j); kbd->pressed[i][j] = false; } } @@ -144,14 +164,7 @@ static void bk_gpio_poll(struct input_dev *inputdev) continue; } kbd->pressed[i][j] = false; - - if (i == kbd->sym_key_bank && j == kbd->sym_key_num) { - kbd->symbol = false; - } else { - dev_dbg(dev, "R: %04x\n", kbd->km[i][j]); - input_report_key(inputdev, kbd->km[i][j], 0); - input_report_key(inputdev, kbd->km_symbol[i][j], 0); - } + bk_gpio_release(kbd, inputdev, i, j); } } }