|
|
|
@ -22,108 +22,145 @@
|
|
|
|
|
|
|
|
|
|
#define BK_CMD_KEYCODE 0x04
|
|
|
|
|
|
|
|
|
|
#define BK_KEY(val) ((val) & 0x3f)
|
|
|
|
|
#define BK_IS_PRESSED(val) ((~val & 0x40) >> 6)
|
|
|
|
|
|
|
|
|
|
#define BK_IS_SWITCH(val) (((val)&0x80) != 0)
|
|
|
|
|
#define BK_IS_SWITCH(val) (((val) & 0x80) != 0)
|
|
|
|
|
#define BK_SW_CODE(val) (((val) >> 1) & 0x1F)
|
|
|
|
|
#define BK_SWITCH_ON(val) (((val)&1) == 0)
|
|
|
|
|
#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 };
|
|
|
|
|
#define BK_KEYCODE_MAX (64)
|
|
|
|
|
#define BK_N_ROLL_MAX (3)
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
unsigned int normal_event_code;
|
|
|
|
|
unsigned int symbol_event_code;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct bk_i2c_data {
|
|
|
|
|
struct i2c_client *cli;
|
|
|
|
|
struct input_dev *idev;
|
|
|
|
|
struct keymap_def *km;
|
|
|
|
|
struct keymap_def *km_symbol;
|
|
|
|
|
int kmlen;
|
|
|
|
|
int kmlen_symbol;
|
|
|
|
|
struct keymap_def keymaps[BK_KEYCODE_MAX];
|
|
|
|
|
|
|
|
|
|
bool symbol;
|
|
|
|
|
bool symbol_states[BK_KEYCODE_MAX];
|
|
|
|
|
bool symbol_mode;
|
|
|
|
|
u32 symbol_keycode;
|
|
|
|
|
bool closing;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static bool detect_key(struct bk_i2c_data *kbd, u8 keycode)
|
|
|
|
|
static bool handle_switch(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;
|
|
|
|
|
bool sw_on = BK_SWITCH_ON(keycode);
|
|
|
|
|
unsigned int sw_code;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
switch (BK_SW_CODE(keycode)) {
|
|
|
|
|
case BK_SW_LCD_TRANSFORMING_TO_TABLET:
|
|
|
|
|
if (!sw_on)
|
|
|
|
|
kbd->closing = false;
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool handle_symbol_key(struct bk_i2c_data *kbd, u8 keycode)
|
|
|
|
|
{
|
|
|
|
|
struct keymap_def *keymap = &kbd->keymaps[BK_KEY(keycode)];
|
|
|
|
|
|
|
|
|
|
if (keymap->symbol_event_code == KEY_RESERVED)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (kbd->symbol_states[BK_KEY(keycode)] == false) {
|
|
|
|
|
input_report_key(kbd->idev, keymap->normal_event_code, 0);
|
|
|
|
|
|
|
|
|
|
dev_dbg(&kbd->cli->dev,
|
|
|
|
|
"mode changed, normal key %02x(%02x) released\n",
|
|
|
|
|
BK_KEY(keycode), keymap->normal_event_code);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((keycode & 0x3f) == (u8)(kbd->symbol_keycode)) {
|
|
|
|
|
input_report_key(kbd->idev, keymap->symbol_event_code,
|
|
|
|
|
BK_IS_PRESSED(keycode));
|
|
|
|
|
|
|
|
|
|
kbd->symbol_states[BK_KEY(keycode)] = BK_IS_PRESSED(keycode);
|
|
|
|
|
|
|
|
|
|
dev_dbg(&kbd->cli->dev, "symbol key %02x(%02x) %s\n", BK_KEY(keycode),
|
|
|
|
|
keymap->symbol_event_code,
|
|
|
|
|
BK_IS_PRESSED(keycode) ? "pressed" : "released");
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool handle_normal_key(struct bk_i2c_data *kbd, u8 keycode)
|
|
|
|
|
{
|
|
|
|
|
struct keymap_def *keymap = &kbd->keymaps[BK_KEY(keycode)];
|
|
|
|
|
|
|
|
|
|
if (keymap->normal_event_code == KEY_RESERVED)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (kbd->symbol_states[BK_KEY(keycode)] == true) {
|
|
|
|
|
input_report_key(kbd->idev, keymap->symbol_event_code, 0);
|
|
|
|
|
|
|
|
|
|
dev_dbg(&kbd->cli->dev,
|
|
|
|
|
"mode changed, symbol key %02x(%02x) released\n",
|
|
|
|
|
BK_KEY(keycode), keymap->symbol_event_code);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
input_report_key(kbd->idev, keymap->normal_event_code,
|
|
|
|
|
BK_IS_PRESSED(keycode));
|
|
|
|
|
|
|
|
|
|
kbd->symbol_states[BK_KEY(keycode)] = false;
|
|
|
|
|
|
|
|
|
|
dev_dbg(&kbd->cli->dev, "normal key %02x(%02x) %s\n", BK_KEY(keycode),
|
|
|
|
|
keymap->normal_event_code,
|
|
|
|
|
BK_IS_PRESSED(keycode) ? "pressed" : "released");
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool detect_key(struct bk_i2c_data *kbd, u8 keycode)
|
|
|
|
|
{
|
|
|
|
|
if (BK_IS_SWITCH(keycode))
|
|
|
|
|
return handle_switch(kbd, keycode);
|
|
|
|
|
|
|
|
|
|
if (BK_KEY(keycode) == (u8)kbd->symbol_keycode) {
|
|
|
|
|
if (BK_IS_PRESSED(keycode)) {
|
|
|
|
|
dev_dbg(&kbd->cli->dev, "symbol pressed!\n");
|
|
|
|
|
kbd->symbol = true;
|
|
|
|
|
kbd->symbol_mode = true;
|
|
|
|
|
} else {
|
|
|
|
|
dev_dbg(&kbd->cli->dev, "symbol released!\n");
|
|
|
|
|
kbd->symbol = false;
|
|
|
|
|
kbd->symbol_mode = false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (kbd->symbol) {
|
|
|
|
|
for (i = 0; i < kbd->kmlen_symbol; i++) {
|
|
|
|
|
if ((keycode & 0x3f) ==
|
|
|
|
|
kbd->km_symbol[i].brain_keycode) {
|
|
|
|
|
dev_dbg(&kbd->cli->dev,
|
|
|
|
|
"symbol: pressed %02x\n",
|
|
|
|
|
kbd->km_symbol[i].brain_keycode);
|
|
|
|
|
input_report_key(
|
|
|
|
|
kbd->idev,
|
|
|
|
|
kbd->km_symbol[i].kernel_keycode,
|
|
|
|
|
BK_IS_PRESSED(keycode));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for (i = 0; i < kbd->kmlen; i++) {
|
|
|
|
|
if ((keycode & 0x3f) == kbd->km[i].brain_keycode) {
|
|
|
|
|
dev_dbg(&kbd->cli->dev,
|
|
|
|
|
"normal: pressed %02x\n",
|
|
|
|
|
kbd->km[i].brain_keycode);
|
|
|
|
|
input_report_key(kbd->idev,
|
|
|
|
|
kbd->km[i].kernel_keycode,
|
|
|
|
|
BK_IS_PRESSED(keycode));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
if (kbd->symbol_mode)
|
|
|
|
|
return handle_symbol_key(kbd, keycode);
|
|
|
|
|
else
|
|
|
|
|
return handle_normal_key(kbd, keycode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static irqreturn_t bk_i2c_irq_handler(int irq, void *devid)
|
|
|
|
@ -141,7 +178,7 @@ 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);
|
|
|
|
|
dev_dbg(&kbd->cli->dev, "N=%d, k1=%02X\n", n, k1);
|
|
|
|
|
if (k1 == 0x00) {
|
|
|
|
|
dev_dbg(&kbd->cli->dev,
|
|
|
|
|
"interrupted but no key press was found\n");
|
|
|
|
@ -150,11 +187,13 @@ static irqreturn_t bk_i2c_irq_handler(int irq, void *devid)
|
|
|
|
|
|
|
|
|
|
if (n < 1) {
|
|
|
|
|
goto done;
|
|
|
|
|
} else if (n > BK_N_ROLL_MAX) {
|
|
|
|
|
dev_dbg(&kbd->cli->dev, "invalid sequence\n");
|
|
|
|
|
n = BK_N_ROLL_MAX;
|
|
|
|
|
}
|
|
|
|
|
if (!detect_key(kbd, k1)) {
|
|
|
|
|
dev_dbg(&kbd->cli->dev, "unknown key was pressed: %02x\n",
|
|
|
|
|
(k1 & 0x3f));
|
|
|
|
|
goto err;
|
|
|
|
|
dev_dbg(&kbd->cli->dev, "unknown key was pressed: k1=%02x\n",
|
|
|
|
|
BK_KEY(k1));
|
|
|
|
|
}
|
|
|
|
|
if (n < 2) {
|
|
|
|
|
goto done;
|
|
|
|
@ -162,21 +201,26 @@ static irqreturn_t bk_i2c_irq_handler(int irq, void *devid)
|
|
|
|
|
|
|
|
|
|
raw = i2c_smbus_read_word_swapped(kbd->cli, BK_CMD_KEYCODE);
|
|
|
|
|
if (raw < 0) {
|
|
|
|
|
dev_err(&kbd->cli->dev, "failed to read 2nd/3rd keycode: %d\n",
|
|
|
|
|
raw);
|
|
|
|
|
dev_err(&kbd->cli->dev, "failed to read 2nd/3rd:%x\n", raw);
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
dev_dbg(&kbd->cli->dev, "k2=%02x, k3=%02x\n", k2, k3);
|
|
|
|
|
if (!detect_key(kbd, k2)) {
|
|
|
|
|
dev_dbg(&kbd->cli->dev, "unknown key was pressed: k2=%02x\n",
|
|
|
|
|
BK_KEY(k2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n < 3) {
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
detect_key(kbd, k3);
|
|
|
|
|
if (!detect_key(kbd, k3)) {
|
|
|
|
|
dev_dbg(&kbd->cli->dev, "unknown key was pressed: k3=%02x\n",
|
|
|
|
|
BK_KEY(k3));
|
|
|
|
|
}
|
|
|
|
|
done:
|
|
|
|
|
input_sync(kbd->idev);
|
|
|
|
|
err:
|
|
|
|
@ -210,15 +254,13 @@ static int bk_i2c_probe(struct i2c_client *cli, const struct i2c_device_id *id)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len /= sizeof(u32) * cells;
|
|
|
|
|
kbd->kmlen = len;
|
|
|
|
|
|
|
|
|
|
kbd->km = devm_kzalloc(&cli->dev, sizeof(struct keymap_def) * len,
|
|
|
|
|
GFP_KERNEL);
|
|
|
|
|
if (!kbd->km) {
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
for (i = 0; i < BK_KEYCODE_MAX; i++) {
|
|
|
|
|
kbd->keymaps[i].normal_event_code = KEY_RESERVED;
|
|
|
|
|
kbd->keymaps[i].symbol_event_code = KEY_RESERVED;
|
|
|
|
|
kbd->symbol_states[i] = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len /= sizeof(u32) * cells;
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
offset = i * cells;
|
|
|
|
|
if (of_property_read_u32_index(cli->dev.of_node, "keymap",
|
|
|
|
@ -233,10 +275,17 @@ static int bk_i2c_probe(struct i2c_client *cli, const struct i2c_device_id *id)
|
|
|
|
|
"could not read DT property (kernel keycode)\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
kbd->km[i].brain_keycode = brain_keycode;
|
|
|
|
|
kbd->km[i].kernel_keycode = kernel_keycode;
|
|
|
|
|
dev_dbg(&cli->dev, "normal: brain: %02x, kernel: %02x",
|
|
|
|
|
brain_keycode, kernel_keycode);
|
|
|
|
|
|
|
|
|
|
if (brain_keycode <= BK_KEYCODE_MAX) {
|
|
|
|
|
kbd->keymaps[brain_keycode].normal_event_code =
|
|
|
|
|
kernel_keycode;
|
|
|
|
|
|
|
|
|
|
dev_dbg(&cli->dev, "normal: brain: %02x, kernel: %02x",
|
|
|
|
|
brain_keycode, kernel_keycode);
|
|
|
|
|
} else {
|
|
|
|
|
dev_err(&cli->dev, "invalid keycode: %02x\n",
|
|
|
|
|
brain_keycode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!of_get_property(cli->dev.of_node, "keymap-symbol", &len)) {
|
|
|
|
@ -245,14 +294,6 @@ static int bk_i2c_probe(struct i2c_client *cli, const struct i2c_device_id *id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len /= sizeof(u32) * cells;
|
|
|
|
|
kbd->kmlen_symbol = len;
|
|
|
|
|
|
|
|
|
|
kbd->km_symbol = devm_kzalloc(
|
|
|
|
|
&cli->dev, sizeof(struct keymap_def) * len, GFP_KERNEL);
|
|
|
|
|
if (!kbd->km_symbol) {
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
offset = i * cells;
|
|
|
|
|
if (of_property_read_u32_index(cli->dev.of_node,
|
|
|
|
@ -269,10 +310,16 @@ static int bk_i2c_probe(struct i2c_client *cli, const struct i2c_device_id *id)
|
|
|
|
|
"could not read DT property (kernel keycode)\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
kbd->km_symbol[i].brain_keycode = brain_keycode;
|
|
|
|
|
kbd->km_symbol[i].kernel_keycode = kernel_keycode;
|
|
|
|
|
dev_dbg(&cli->dev, "symbol: brain: %02x, kernel: %02x",
|
|
|
|
|
brain_keycode, kernel_keycode);
|
|
|
|
|
if (brain_keycode <= BK_KEYCODE_MAX) {
|
|
|
|
|
kbd->keymaps[brain_keycode].symbol_event_code =
|
|
|
|
|
kernel_keycode;
|
|
|
|
|
|
|
|
|
|
dev_dbg(&cli->dev, "symbol: brain: %02x, kernel: %02x",
|
|
|
|
|
brain_keycode, kernel_keycode);
|
|
|
|
|
} else {
|
|
|
|
|
dev_err(&cli->dev, "invalid keycode: %02x\n",
|
|
|
|
|
brain_keycode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kbd->cli = cli;
|
|
|
|
@ -289,14 +336,14 @@ static int bk_i2c_probe(struct i2c_client *cli, const struct i2c_device_id *id)
|
|
|
|
|
|
|
|
|
|
__set_bit(EV_REP, kbd->idev->evbit); /* autorepeat */
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < kbd->kmlen; i++) {
|
|
|
|
|
input_set_capability(kbd->idev, EV_KEY,
|
|
|
|
|
kbd->km[i].kernel_keycode);
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < BK_KEYCODE_MAX; i++) {
|
|
|
|
|
if (kbd->keymaps[i].normal_event_code != KEY_RESERVED)
|
|
|
|
|
input_set_capability(kbd->idev, EV_KEY,
|
|
|
|
|
kbd->keymaps[i].normal_event_code);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < kbd->kmlen_symbol; i++) {
|
|
|
|
|
input_set_capability(kbd->idev, EV_KEY,
|
|
|
|
|
kbd->km_symbol[i].kernel_keycode);
|
|
|
|
|
if (kbd->keymaps[i].symbol_event_code != KEY_RESERVED)
|
|
|
|
|
input_set_capability(kbd->idev, EV_KEY,
|
|
|
|
|
kbd->keymaps[i].symbol_event_code);
|
|
|
|
|
}
|
|
|
|
|
kbd->closing = false;
|
|
|
|
|
input_set_capability(kbd->idev, EV_SW, SW_LID);
|
|
|
|
|