aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/macintosh/mac_hid.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2010-01-30 03:53:29 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-01-30 04:47:49 -0500
commit99b089c3c38a83ebaeb1cc4584ddcde841626467 (patch)
tree484a9ac4871a055873b6427d2f7c3c37554fd0ce /drivers/macintosh/mac_hid.c
parentef7995f4e46b1677f3eaaf547316e1a910b38dcb (diff)
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 <dtor@mail.ru>
Diffstat (limited to 'drivers/macintosh/mac_hid.c')
-rw-r--r--drivers/macintosh/mac_hid.c257
1 files changed, 187 insertions, 70 deletions
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
index 7b4ef5bb556b..0b210a90aef5 100644
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -13,17 +13,195 @@
13#include <linux/sysctl.h> 13#include <linux/sysctl.h>
14#include <linux/input.h> 14#include <linux/input.h>
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/kbd_kern.h>
17 16
18
19static struct input_dev *emumousebtn;
20static int emumousebtn_input_register(void);
21static int mouse_emulate_buttons; 17static int mouse_emulate_buttons;
22static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */ 18static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */
23static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */ 19static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */
24static int mouse_last_keycode;
25 20
26#if defined(CONFIG_SYSCTL) 21static struct input_dev *mac_hid_emumouse_dev;
22
23static 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
59static void mac_hid_destroy_emumouse(void)
60{
61 input_unregister_device(mac_hid_emumouse_dev);
62 mac_hid_emumouse_dev = NULL;
63}
64
65static 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
87static 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
131static 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
138static 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
146MODULE_DEVICE_TABLE(input, mac_hid_emumouse_ids);
147
148static 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
156static 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
173static void mac_hid_stop_emulation(void)
174{
175 input_unregister_handler(&mac_hid_emumouse_handler);
176 mac_hid_destroy_emumouse();
177}
178
179static 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
27/* file(s) in /proc/sys/dev/mac_hid */ 205/* file(s) in /proc/sys/dev/mac_hid */
28static ctl_table mac_hid_files[] = { 206static ctl_table mac_hid_files[] = {
29 { 207 {
@@ -31,7 +209,7 @@ static ctl_table mac_hid_files[] = {
31 .data = &mouse_emulate_buttons, 209 .data = &mouse_emulate_buttons,
32 .maxlen = sizeof(int), 210 .maxlen = sizeof(int),
33 .mode = 0644, 211 .mode = 0644,
34 .proc_handler = proc_dointvec, 212 .proc_handler = mac_hid_toggle_emumouse,
35 }, 213 },
36 { 214 {
37 .procname = "mouse_button2_keycode", 215 .procname = "mouse_button2_keycode",
@@ -74,73 +252,12 @@ static ctl_table mac_hid_root_dir[] = {
74 252
75static struct ctl_table_header *mac_hid_sysctl_header; 253static struct ctl_table_header *mac_hid_sysctl_header;
76 254
77#endif /* endif CONFIG_SYSCTL */
78
79int 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
101static struct lock_class_key emumousebtn_event_class;
102static struct lock_class_key emumousebtn_mutex_class;
103
104static 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}
132 255
133static int __init mac_hid_init(void) 256static int __init mac_hid_init(void)
134{ 257{
135 int err;
136
137 err = emumousebtn_input_register();
138 if (err)
139 return err;
140
141#if defined(CONFIG_SYSCTL)
142 mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir); 258 mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir);
143#endif /* CONFIG_SYSCTL */ 259 if (!mac_hid_sysctl_header)
260 return -ENOMEM;
144 261
145 return 0; 262 return 0;
146} 263}