Commit 8ca307c6 authored by Vojtech Pavlik's avatar Vojtech Pavlik Committed by Vojtech Pavlik

input: Add support for scroll wheel on MS Office and similar keyboards.

parent 6967ded8
...@@ -33,18 +33,18 @@ MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); ...@@ -33,18 +33,18 @@ MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
MODULE_PARM(atkbd_set, "1i"); MODULE_PARM(atkbd_set, "1i");
MODULE_PARM(atkbd_reset, "1i"); MODULE_PARM(atkbd_reset, "1i");
MODULE_PARM(atkbd_softrepeat, "1i"); MODULE_PARM(atkbd_softrepeat, "1i");
MODULE_PARM(atkbd_scroll, "1i");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static int atkbd_set = 2; static int atkbd_set = 2;
module_param_named(set, atkbd_set, int, 0); module_param_named(set, atkbd_set, int, 0);
MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3, 4)"); MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3, 4)");
#if defined(__i386__) || defined(__x86_64__) || defined(__hppa__) #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
static int atkbd_reset; static int atkbd_reset;
#else #else
static int atkbd_reset = 1; static int atkbd_reset = 1;
#endif #endif
static int atkbd_softrepeat;
module_param_named(reset, atkbd_reset, bool, 0); module_param_named(reset, atkbd_reset, bool, 0);
MODULE_PARM_DESC(reset, "Reset keyboard during initialization"); MODULE_PARM_DESC(reset, "Reset keyboard during initialization");
...@@ -52,6 +52,10 @@ static int atkbd_softrepeat; ...@@ -52,6 +52,10 @@ static int atkbd_softrepeat;
module_param_named(softrepeat, atkbd_softrepeat, bool, 0); module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat"); MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
static int atkbd_scroll;
module_parm_named(scroll, atkbd_scroll, bool, 0);
MODULE_PARM_DESC_(scroll, "Enable scroll-wheel on office keyboards");
/* /*
* Scancode to keycode tables. These are just the default setting, and * Scancode to keycode tables. These are just the default setting, and
* are loadable via an userland utility. * are loadable via an userland utility.
...@@ -127,11 +131,11 @@ static unsigned char atkbd_unxlate_table[128] = { ...@@ -127,11 +131,11 @@ static unsigned char atkbd_unxlate_table[128] = {
#define ATKBD_CMD_EX_SETLEDS 0x20eb #define ATKBD_CMD_EX_SETLEDS 0x20eb
#define ATKBD_CMD_OK_GETID 0x02e8 #define ATKBD_CMD_OK_GETID 0x02e8
#define ATKBD_RET_ACK 0xfa #define ATKBD_RET_ACK 0xfa
#define ATKBD_RET_NAK 0xfe #define ATKBD_RET_NAK 0xfe
#define ATKBD_RET_BAT 0xaa #define ATKBD_RET_BAT 0xaa
#define ATKBD_RET_EMUL0 0xe0 #define ATKBD_RET_EMUL0 0xe0
#define ATKBD_RET_EMULX 0x80
#define ATKBD_RET_EMUL1 0xe1 #define ATKBD_RET_EMUL1 0xe1
#define ATKBD_RET_RELEASE 0xf0 #define ATKBD_RET_RELEASE 0xf0
#define ATKBD_RET_HANGUEL 0xf1 #define ATKBD_RET_HANGUEL 0xf1
...@@ -141,6 +145,22 @@ static unsigned char atkbd_unxlate_table[128] = { ...@@ -141,6 +145,22 @@ static unsigned char atkbd_unxlate_table[128] = {
#define ATKBD_KEY_UNKNOWN 0 #define ATKBD_KEY_UNKNOWN 0
#define ATKBD_KEY_NULL 255 #define ATKBD_KEY_NULL 255
#define ATKBD_SCR_1 254
#define ATKBD_SCR_2 253
#define ATKBD_SCR_4 252
#define ATKBD_SCR_8 251
#define ATKBD_SCR_CLICK 250
#define ATKBD_SPECIAL 250
static unsigned char atkbd_scroll_keys[5][2] = {
{ ATKBD_SCR_1, 0x45 },
{ ATKBD_SCR_2, 0x29 },
{ ATKBD_SCR_4, 0x36 },
{ ATKBD_SCR_8, 0x27 },
{ ATKBD_SCR_CLICK, 0x60 },
};
/* /*
* The atkbd control structure * The atkbd control structure
*/ */
...@@ -189,6 +209,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -189,6 +209,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
{ {
struct atkbd *atkbd = serio->private; struct atkbd *atkbd = serio->private;
unsigned int code = data; unsigned int code = data;
int scroll = 0, click = -1;
int value; int value;
#ifdef ATKBD_DEBUG #ifdef ATKBD_DEBUG
...@@ -284,6 +305,21 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -284,6 +305,21 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
else else
printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n", code & 0x80 ? "e0" : "", code & 0x7f); printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n", code & 0x80 ? "e0" : "", code & 0x7f);
break; break;
case ATKBD_SCR_1:
scroll = 1 - atkbd->release * 2;
break;
case ATKBD_SCR_2:
scroll = 2 - atkbd->release * 4;
break;
case ATKBD_SCR_4:
scroll = 4 - atkbd->release * 8;
break;
case ATKBD_SCR_8:
scroll = 8 - atkbd->release * 16;
break;
case ATKBD_SCR_CLICK:
click = !atkbd->release;
break;
default: default:
value = atkbd->release ? 0 : value = atkbd->release ? 0 :
(1 + (!atkbd_softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key))); (1 + (!atkbd_softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
...@@ -305,6 +341,13 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -305,6 +341,13 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value); atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value);
} }
if (scroll || click != -1) {
input_regs(&atkbd->dev, regs);
input_report_key(&atkbd->dev, BTN_MIDDLE, click);
input_report_rel(&atkbd->dev, REL_WHEEL, scroll);
input_sync(&atkbd->dev);
}
atkbd->release = 0; atkbd->release = 0;
out: out:
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -705,15 +748,23 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -705,15 +748,23 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
sprintf(atkbd->phys, "%s/input0", serio->phys); sprintf(atkbd->phys, "%s/input0", serio->phys);
if (atkbd_scroll) {
for (i = 0; i < 5; i++)
atkbd_set2_keycode[atkbd_scroll_keys[i][1]] = atkbd_scroll_keys[i][0];
atkbd->dev.evbit[0] |= BIT(EV_REL);
atkbd->dev.relbit[0] = BIT(REL_WHEEL);
set_bit(BTN_MIDDLE, atkbd->dev.keybit);
}
if (atkbd->translated) { if (atkbd->translated) {
for (i = 0; i < 128; i++) { for (i = 0; i < 128; i++) {
atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
} }
} else if (atkbd->set == 2) { } else if (atkbd->set == 3) {
memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
} else {
memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
} else {
memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
} }
atkbd->dev.name = atkbd->name; atkbd->dev.name = atkbd->name;
...@@ -724,7 +775,7 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -724,7 +775,7 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd->dev.id.version = atkbd->id; atkbd->dev.id.version = atkbd->id;
for (i = 0; i < 512; i++) for (i = 0; i < 512; i++)
if (atkbd->keycode[i] && atkbd->keycode[i] < 255) if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
set_bit(atkbd->keycode[i], atkbd->dev.keybit); set_bit(atkbd->keycode[i], atkbd->dev.keybit);
input_register_device(&atkbd->dev); input_register_device(&atkbd->dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment