input: keyboard: fix key scan and support more events
This commit is contained in:
parent
aa21aeb567
commit
83a1f53cfa
|
@ -24,6 +24,16 @@
|
|||
|
||||
#define BK_IS_PRESSED(val) ((~val & 0x40) >> 6)
|
||||
|
||||
#define BK_IS_SWITCH(val) (((val)&0x80) != 0)
|
||||
#define BK_SW_CODE(val) (((val) >> 1) & 0x1F)
|
||||
#define BK_SWITCH_ON(val) (((val)&1) == 0)
|
||||
|
||||
enum { BK_SW_LCD_TRANSFORMING_TO_TABLET = 3,
|
||||
BK_SW_UNKNOWN4,
|
||||
BK_SW_USB_VBUS,
|
||||
BK_SW_LCD_FULLY_TRANSFORMED,
|
||||
BK_SW_LCD_TRANSFORMING_TO_CLOSED };
|
||||
|
||||
struct keymap_def {
|
||||
u8 brain_keycode;
|
||||
unsigned int kernel_keycode;
|
||||
|
@ -39,11 +49,41 @@ struct bk_i2c_data {
|
|||
|
||||
bool symbol;
|
||||
u32 symbol_keycode;
|
||||
bool closing;
|
||||
};
|
||||
|
||||
static bool detect_key(struct bk_i2c_data *kbd, u8 keycode)
|
||||
{
|
||||
int i;
|
||||
if (BK_IS_SWITCH(keycode)) {
|
||||
bool sw_on = BK_SWITCH_ON(keycode);
|
||||
unsigned int sw_code;
|
||||
switch (BK_SW_CODE(keycode)) {
|
||||
case BK_SW_LCD_TRANSFORMING_TO_TABLET:
|
||||
if (!sw_on) {
|
||||
kbd->closing = false;
|
||||
}
|
||||
return true;
|
||||
case BK_SW_LCD_TRANSFORMING_TO_CLOSED:
|
||||
if (sw_on) {
|
||||
kbd->closing = true;
|
||||
}
|
||||
return true;
|
||||
|
||||
case BK_SW_LCD_FULLY_TRANSFORMED:
|
||||
sw_code = (kbd->closing) ? SW_LID : SW_TABLET_MODE;
|
||||
input_report_switch(kbd->idev, sw_code, sw_on);
|
||||
return true;
|
||||
|
||||
case BK_SW_USB_VBUS:
|
||||
input_report_switch(kbd->idev, SW_DOCK, sw_on);
|
||||
return true;
|
||||
default:
|
||||
dev_dbg(&kbd->cli->dev, "Unknown switch event %0x02X",
|
||||
keycode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((keycode & 0x3f) == (u8)(kbd->symbol_keycode)) {
|
||||
if (BK_IS_PRESSED(keycode)) {
|
||||
|
@ -101,20 +141,23 @@ static irqreturn_t bk_i2c_irq_handler(int irq, void *devid)
|
|||
n = raw >> 8;
|
||||
k1 = raw & 0xff;
|
||||
|
||||
dev_dbg(&kbd->cli->dev, "N=%d, Raw key event: %02X\n", n, k1);
|
||||
if (k1 == 0x00) {
|
||||
dev_dbg(&kbd->cli->dev,
|
||||
"interrupted but no key press was found\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (n == 1) {
|
||||
if (detect_key(kbd, k1)) {
|
||||
goto done;
|
||||
} else {
|
||||
dev_dbg(&kbd->cli->dev,
|
||||
"unknown key was pressed: %02x\n", (k1 & 0x3f));
|
||||
goto err;
|
||||
}
|
||||
if (n < 1) {
|
||||
goto done;
|
||||
}
|
||||
if (!detect_key(kbd, k1)) {
|
||||
dev_dbg(&kbd->cli->dev, "unknown key was pressed: %02x\n",
|
||||
(k1 & 0x3f));
|
||||
goto err;
|
||||
}
|
||||
if (n < 2) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
raw = i2c_smbus_read_word_swapped(kbd->cli, BK_CMD_KEYCODE);
|
||||
|
@ -127,12 +170,13 @@ static irqreturn_t bk_i2c_irq_handler(int irq, void *devid)
|
|||
k2 = (raw & 0xff00) >> 8;
|
||||
k3 = raw & 0xff;
|
||||
|
||||
dev_dbg(&kbd->cli->dev, "Raw key event 2 and 3: %02X,%02X\n", k2, k3);
|
||||
detect_key(kbd, k2);
|
||||
|
||||
if (n == 3) {
|
||||
detect_key(kbd, k3);
|
||||
if (n < 3) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
detect_key(kbd, k3);
|
||||
done:
|
||||
input_sync(kbd->idev);
|
||||
err:
|
||||
|
@ -155,8 +199,8 @@ static int bk_i2c_probe(struct i2c_client *cli, const struct i2c_device_id *id)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(cli->dev.of_node,
|
||||
"symbol-keycode", &kbd->symbol_keycode)) {
|
||||
if (of_property_read_u32(cli->dev.of_node, "symbol-keycode",
|
||||
&kbd->symbol_keycode)) {
|
||||
kbd->symbol_keycode = 0x19;
|
||||
}
|
||||
|
||||
|
@ -254,6 +298,10 @@ static int bk_i2c_probe(struct i2c_client *cli, const struct i2c_device_id *id)
|
|||
input_set_capability(kbd->idev, EV_KEY,
|
||||
kbd->km_symbol[i].kernel_keycode);
|
||||
}
|
||||
kbd->closing = false;
|
||||
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_DOCK);
|
||||
|
||||
err = input_register_device(kbd->idev);
|
||||
if (err) {
|
||||
|
|
Loading…
Reference in New Issue