Skip to content

Commit 99b089c

Browse files
committed
Input: Mac button emulation - implement as an input filter
Current implementation of Mac mouse button emulation plugs into legacy keyboard driver, converts certain keys into button events on a separate device, and suppresses the real events from reaching tty. This worked well enough until user space started using evdev which was completely unaware of this arrangement and kept sending original key presses to its users. Change the implementation to use newly added input filter framework so that original key presses are not transmitted to any handlers. As a bonus remove SYSCTL dependencies from the code and use Kconfig instead; also do not create the emulated mouse device until user activates emulation. Signed-off-by: Dmitry Torokhov <[email protected]>
1 parent ef7995f commit 99b089c

File tree

4 files changed

+188
-78
lines changed

4 files changed

+188
-78
lines changed

drivers/char/keyboard.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,11 +1185,6 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
11851185

11861186
rep = (down == 2);
11871187

1188-
#ifdef CONFIG_MAC_EMUMOUSEBTN
1189-
if (mac_hid_mouse_emulate_buttons(1, keycode, down))
1190-
return;
1191-
#endif /* CONFIG_MAC_EMUMOUSEBTN */
1192-
11931188
if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
11941189
if (emulate_raw(vc, keycode, !down << 7))
11951190
if (keycode < BTN_MISC && printk_ratelimit())

drivers/macintosh/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ config INPUT_ADBHID
172172

173173
config MAC_EMUMOUSEBTN
174174
bool "Support for mouse button 2+3 emulation"
175+
depends on SYSCTL
175176
select INPUT
176177
help
177178
This provides generic support for emulating the 2nd and 3rd mouse

drivers/macintosh/mac_hid.c

Lines changed: 187 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,203 @@
1313
#include <linux/sysctl.h>
1414
#include <linux/input.h>
1515
#include <linux/module.h>
16-
#include <linux/kbd_kern.h>
1716

18-
19-
static struct input_dev *emumousebtn;
20-
static int emumousebtn_input_register(void);
2117
static int mouse_emulate_buttons;
2218
static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */
2319
static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */
24-
static int mouse_last_keycode;
2520

26-
#if defined(CONFIG_SYSCTL)
21+
static struct input_dev *mac_hid_emumouse_dev;
22+
23+
static int mac_hid_create_emumouse(void)
24+
{
25+
static struct lock_class_key mac_hid_emumouse_dev_event_class;
26+
static struct lock_class_key mac_hid_emumouse_dev_mutex_class;
27+
int err;
28+
29+
mac_hid_emumouse_dev = input_allocate_device();
30+
if (!mac_hid_emumouse_dev)
31+
return -ENOMEM;
32+
33+
lockdep_set_class(&mac_hid_emumouse_dev->event_lock,
34+
&mac_hid_emumouse_dev_event_class);
35+
lockdep_set_class(&mac_hid_emumouse_dev->mutex,
36+
&mac_hid_emumouse_dev_mutex_class);
37+
38+
mac_hid_emumouse_dev->name = "Macintosh mouse button emulation";
39+
mac_hid_emumouse_dev->id.bustype = BUS_ADB;
40+
mac_hid_emumouse_dev->id.vendor = 0x0001;
41+
mac_hid_emumouse_dev->id.product = 0x0001;
42+
mac_hid_emumouse_dev->id.version = 0x0100;
43+
44+
mac_hid_emumouse_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
45+
mac_hid_emumouse_dev->keybit[BIT_WORD(BTN_MOUSE)] =
46+
BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
47+
mac_hid_emumouse_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
48+
49+
err = input_register_device(mac_hid_emumouse_dev);
50+
if (err) {
51+
input_free_device(mac_hid_emumouse_dev);
52+
mac_hid_emumouse_dev = NULL;
53+
return err;
54+
}
55+
56+
return 0;
57+
}
58+
59+
static void mac_hid_destroy_emumouse(void)
60+
{
61+
input_unregister_device(mac_hid_emumouse_dev);
62+
mac_hid_emumouse_dev = NULL;
63+
}
64+
65+
static bool mac_hid_emumouse_filter(struct input_handle *handle,
66+
unsigned int type, unsigned int code,
67+
int value)
68+
{
69+
unsigned int btn;
70+
71+
if (type != EV_KEY)
72+
return false;
73+
74+
if (code == mouse_button2_keycode)
75+
btn = BTN_MIDDLE;
76+
else if (code == mouse_button3_keycode)
77+
btn = BTN_RIGHT;
78+
else
79+
return false;
80+
81+
input_report_key(mac_hid_emumouse_dev, btn, value);
82+
input_sync(mac_hid_emumouse_dev);
83+
84+
return true;
85+
}
86+
87+
static int mac_hid_emumouse_connect(struct input_handler *handler,
88+
struct input_dev *dev,
89+
const struct input_device_id *id)
90+
{
91+
struct input_handle *handle;
92+
int error;
93+
94+
/* Don't bind to ourselves */
95+
if (dev == mac_hid_emumouse_dev)
96+
return -ENODEV;
97+
98+
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
99+
if (!handle)
100+
return -ENOMEM;
101+
102+
handle->dev = dev;
103+
handle->handler = handler;
104+
handle->name = "mac-button-emul";
105+
106+
error = input_register_handle(handle);
107+
if (error) {
108+
printk(KERN_ERR
109+
"mac_hid: Failed to register button emulation handle, "
110+
"error %d\n", error);
111+
goto err_free;
112+
}
113+
114+
error = input_open_device(handle);
115+
if (error) {
116+
printk(KERN_ERR
117+
"mac_hid: Failed to open input device, error %d\n",
118+
error);
119+
goto err_unregister;
120+
}
121+
122+
return 0;
123+
124+
err_unregister:
125+
input_unregister_handle(handle);
126+
err_free:
127+
kfree(handle);
128+
return error;
129+
}
130+
131+
static void mac_hid_emumouse_disconnect(struct input_handle *handle)
132+
{
133+
input_close_device(handle);
134+
input_unregister_handle(handle);
135+
kfree(handle);
136+
}
137+
138+
static const struct input_device_id mac_hid_emumouse_ids[] = {
139+
{
140+
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
141+
.evbit = { BIT_MASK(EV_KEY) },
142+
},
143+
{ },
144+
};
145+
146+
MODULE_DEVICE_TABLE(input, mac_hid_emumouse_ids);
147+
148+
static struct input_handler mac_hid_emumouse_handler = {
149+
.filter = mac_hid_emumouse_filter,
150+
.connect = mac_hid_emumouse_connect,
151+
.disconnect = mac_hid_emumouse_disconnect,
152+
.name = "mac-button-emul",
153+
.id_table = mac_hid_emumouse_ids,
154+
};
155+
156+
static int mac_hid_start_emulation(void)
157+
{
158+
int err;
159+
160+
err = mac_hid_create_emumouse();
161+
if (err)
162+
return err;
163+
164+
err = input_register_handler(&mac_hid_emumouse_handler);
165+
if (err) {
166+
mac_hid_destroy_emumouse();
167+
return err;
168+
}
169+
170+
return 0;
171+
}
172+
173+
static void mac_hid_stop_emulation(void)
174+
{
175+
input_unregister_handler(&mac_hid_emumouse_handler);
176+
mac_hid_destroy_emumouse();
177+
}
178+
179+
static int mac_hid_toggle_emumouse(ctl_table *table, int write,
180+
void __user *buffer, size_t *lenp,
181+
loff_t *ppos)
182+
{
183+
int *valp = table->data;
184+
int old_val = *valp;
185+
int rc;
186+
187+
rc = proc_dointvec(table, write, buffer, lenp, ppos);
188+
189+
if (rc == 0 && write && *valp != old_val) {
190+
if (*valp == 1)
191+
rc = mac_hid_start_emulation();
192+
else if (*valp == 0)
193+
mac_hid_stop_emulation();
194+
else
195+
rc = -EINVAL;
196+
}
197+
198+
/* Restore the old value in case of error */
199+
if (rc)
200+
*valp = old_val;
201+
202+
return rc;
203+
}
204+
27205
/* file(s) in /proc/sys/dev/mac_hid */
28206
static ctl_table mac_hid_files[] = {
29207
{
30208
.procname = "mouse_button_emulation",
31209
.data = &mouse_emulate_buttons,
32210
.maxlen = sizeof(int),
33211
.mode = 0644,
34-
.proc_handler = proc_dointvec,
212+
.proc_handler = mac_hid_toggle_emumouse,
35213
},
36214
{
37215
.procname = "mouse_button2_keycode",
@@ -74,73 +252,12 @@ static ctl_table mac_hid_root_dir[] = {
74252

75253
static struct ctl_table_header *mac_hid_sysctl_header;
76254

77-
#endif /* endif CONFIG_SYSCTL */
78-
79-
int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
80-
{
81-
switch (caller) {
82-
case 1:
83-
/* Called from keyboard.c */
84-
if (mouse_emulate_buttons
85-
&& (keycode == mouse_button2_keycode
86-
|| keycode == mouse_button3_keycode)) {
87-
if (mouse_emulate_buttons == 1) {
88-
input_report_key(emumousebtn,
89-
keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT,
90-
down);
91-
input_sync(emumousebtn);
92-
return 1;
93-
}
94-
mouse_last_keycode = down ? keycode : 0;
95-
}
96-
break;
97-
}
98-
return 0;
99-
}
100-
101-
static struct lock_class_key emumousebtn_event_class;
102-
static struct lock_class_key emumousebtn_mutex_class;
103-
104-
static int emumousebtn_input_register(void)
105-
{
106-
int ret;
107-
108-
emumousebtn = input_allocate_device();
109-
if (!emumousebtn)
110-
return -ENOMEM;
111-
112-
lockdep_set_class(&emumousebtn->event_lock, &emumousebtn_event_class);
113-
lockdep_set_class(&emumousebtn->mutex, &emumousebtn_mutex_class);
114-
115-
emumousebtn->name = "Macintosh mouse button emulation";
116-
emumousebtn->id.bustype = BUS_ADB;
117-
emumousebtn->id.vendor = 0x0001;
118-
emumousebtn->id.product = 0x0001;
119-
emumousebtn->id.version = 0x0100;
120-
121-
emumousebtn->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
122-
emumousebtn->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
123-
BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
124-
emumousebtn->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
125-
126-
ret = input_register_device(emumousebtn);
127-
if (ret)
128-
input_free_device(emumousebtn);
129-
130-
return ret;
131-
}
132255

133256
static int __init mac_hid_init(void)
134257
{
135-
int err;
136-
137-
err = emumousebtn_input_register();
138-
if (err)
139-
return err;
140-
141-
#if defined(CONFIG_SYSCTL)
142258
mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir);
143-
#endif /* CONFIG_SYSCTL */
259+
if (!mac_hid_sysctl_header)
260+
return -ENOMEM;
144261

145262
return 0;
146263
}

include/linux/kbd_kern.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,4 @@ static inline void con_schedule_flip(struct tty_struct *t)
161161
schedule_delayed_work(&t->buf.work, 0);
162162
}
163163

164-
/* mac_hid.c */
165-
extern int mac_hid_mouse_emulate_buttons(int, unsigned int, int);
166-
167164
#endif

0 commit comments

Comments
 (0)