input: keyboard: fix key repeat bug and unexpected shutdown issue

This commit is contained in:
Suguru Saito 2023-09-17 20:07:52 +09:00
parent b99fc905e5
commit 443e7a22ec
1 changed files with 56 additions and 9 deletions

View File

@ -50,6 +50,7 @@ struct bk_i2c_data {
bool symbol; bool symbol;
u32 symbol_keycode; u32 symbol_keycode;
bool closing; bool closing;
bool symbol_flag[256];
}; };
static bool detect_key(struct bk_i2c_data *kbd, u8 keycode) static bool detect_key(struct bk_i2c_data *kbd, u8 keycode)
@ -97,28 +98,62 @@ static bool detect_key(struct bk_i2c_data *kbd, u8 keycode)
} }
if (kbd->symbol) { if (kbd->symbol) {
if ((0 == BK_IS_PRESSED(keycode)) &&
(false == kbd->symbol_flag[keycode & 0x3f])) {
for (i = 0; i < kbd->kmlen; i++) {
if ((keycode & 0x3f) == kbd->km[i].brain_keycode) {
dev_dbg(&kbd->cli->dev,
"release normal key %02x\n", keycode & 0x3f);
input_report_key(
kbd->idev,
kbd->km[i].kernel_keycode,
BK_IS_PRESSED(keycode));
return true;
}
}
}
for (i = 0; i < kbd->kmlen_symbol; i++) { for (i = 0; i < kbd->kmlen_symbol; i++) {
if ((keycode & 0x3f) == if ((keycode & 0x3f) ==
kbd->km_symbol[i].brain_keycode) { kbd->km_symbol[i].brain_keycode) {
dev_dbg(&kbd->cli->dev, dev_dbg(&kbd->cli->dev,
"symbol: pressed %02x\n", "symbol: %s %02x\n",
BK_IS_PRESSED(keycode) ? "pressed" : "released",
kbd->km_symbol[i].brain_keycode); kbd->km_symbol[i].brain_keycode);
input_report_key( input_report_key(
kbd->idev, kbd->idev,
kbd->km_symbol[i].kernel_keycode, kbd->km_symbol[i].kernel_keycode,
BK_IS_PRESSED(keycode)); BK_IS_PRESSED(keycode));
kbd->symbol_flag[keycode & 0x3f] = BK_IS_PRESSED(keycode);
return true; return true;
} }
} }
} else { } else {
if ((0 == BK_IS_PRESSED(keycode)) &&
(true == kbd->symbol_flag[keycode & 0x3f])) {
for (i = 0; i < kbd->kmlen_symbol; i++) {
if ((keycode & 0x3f) == kbd->km_symbol[i].brain_keycode) {
dev_dbg(&kbd->cli->dev,
"release symbol key %02x\n", keycode & 0x3f);
input_report_key(
kbd->idev,
kbd->km_symbol[i].kernel_keycode,
BK_IS_PRESSED(keycode));
return true;
}
}
}
for (i = 0; i < kbd->kmlen; i++) { for (i = 0; i < kbd->kmlen; i++) {
if ((keycode & 0x3f) == kbd->km[i].brain_keycode) { if ((keycode & 0x3f) == kbd->km[i].brain_keycode) {
dev_dbg(&kbd->cli->dev, dev_dbg(&kbd->cli->dev,
"normal: pressed %02x\n", "normal: %s %02x\n",
BK_IS_PRESSED(keycode) ? "pressed" : "released",
kbd->km[i].brain_keycode); kbd->km[i].brain_keycode);
input_report_key(kbd->idev, input_report_key(kbd->idev,
kbd->km[i].kernel_keycode, kbd->km[i].kernel_keycode,
BK_IS_PRESSED(keycode)); BK_IS_PRESSED(keycode));
kbd->symbol_flag[keycode & 0x3f] = false;
return true; return true;
} }
} }
@ -141,7 +176,7 @@ static irqreturn_t bk_i2c_irq_handler(int irq, void *devid)
n = raw >> 8; n = raw >> 8;
k1 = raw & 0xff; k1 = raw & 0xff;
dev_dbg(&kbd->cli->dev, "N=%d, Raw key event: %02X\n", n, k1); dev_dbg(&kbd->cli->dev, "N=%d, k1=%02X\n", n, k1);
if (k1 == 0x00) { if (k1 == 0x00) {
dev_dbg(&kbd->cli->dev, dev_dbg(&kbd->cli->dev,
"interrupted but no key press was found\n"); "interrupted but no key press was found\n");
@ -150,11 +185,14 @@ static irqreturn_t bk_i2c_irq_handler(int irq, void *devid)
if (n < 1) { if (n < 1) {
goto done; goto done;
} else if (n > 3) {
dev_dbg(&kbd->cli->dev,
"invalid sequence\n");
n = 3;
} }
if (!detect_key(kbd, k1)) { if (!detect_key(kbd, k1)) {
dev_dbg(&kbd->cli->dev, "unknown key was pressed: %02x\n", dev_dbg(&kbd->cli->dev, "unknown key was pressed: k1=%02x\n",
(k1 & 0x3f)); (k1 & 0x3f));
goto err;
} }
if (n < 2) { if (n < 2) {
goto done; goto done;
@ -162,7 +200,7 @@ static irqreturn_t bk_i2c_irq_handler(int irq, void *devid)
raw = i2c_smbus_read_word_swapped(kbd->cli, BK_CMD_KEYCODE); raw = i2c_smbus_read_word_swapped(kbd->cli, BK_CMD_KEYCODE);
if (raw < 0) { if (raw < 0) {
dev_err(&kbd->cli->dev, "failed to read 2nd/3rd keycode: %d\n", dev_err(&kbd->cli->dev, "failed to read 2nd/3rd:%x\n",
raw); raw);
goto err; goto err;
} }
@ -170,13 +208,19 @@ static irqreturn_t bk_i2c_irq_handler(int irq, void *devid)
k2 = (raw & 0xff00) >> 8; k2 = (raw & 0xff00) >> 8;
k3 = raw & 0xff; k3 = raw & 0xff;
dev_dbg(&kbd->cli->dev, "Raw key event 2 and 3: %02X,%02X\n", k2, k3); dev_dbg(&kbd->cli->dev, "k2=%02x, k3=%02x\n", k2, k3);
detect_key(kbd, k2); if (!detect_key(kbd, k2)) {
dev_dbg(&kbd->cli->dev, "unknown key was pressed: k2=%02x\n",
k2 & 0x3f);
}
if (n < 3) { if (n < 3) {
goto done; goto done;
} }
detect_key(kbd, k3); if (!detect_key(kbd, k3)) {
dev_dbg(&kbd->cli->dev, "unknown key was pressed: k3=%02x\n",
k3 & 0x3f);
}
done: done:
input_sync(kbd->idev); input_sync(kbd->idev);
err: err:
@ -299,6 +343,9 @@ static int bk_i2c_probe(struct i2c_client *cli, const struct i2c_device_id *id)
kbd->km_symbol[i].kernel_keycode); kbd->km_symbol[i].kernel_keycode);
} }
kbd->closing = false; kbd->closing = false;
for (i = 0; i < ARRAY_SIZE(kbd->symbol_flag); i++) {
kbd->symbol_flag[i] = false;
}
input_set_capability(kbd->idev, EV_SW, SW_LID); input_set_capability(kbd->idev, EV_SW, SW_LID);
input_set_capability(kbd->idev, EV_SW, SW_TABLET_MODE); input_set_capability(kbd->idev, EV_SW, SW_TABLET_MODE);
input_set_capability(kbd->idev, EV_SW, SW_DOCK); input_set_capability(kbd->idev, EV_SW, SW_DOCK);