]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/macintosh/mac_hid.c
Input: Mac button emulation - implement as an input filter
[mv-sheeva.git] / drivers / macintosh / mac_hid.c
1 /*
2  * drivers/macintosh/mac_hid.c
3  *
4  * HID support stuff for Macintosh computers.
5  *
6  * Copyright (C) 2000 Franz Sirl.
7  *
8  * This file will soon be removed in favor of an uinput userspace tool.
9  */
10
11 #include <linux/init.h>
12 #include <linux/proc_fs.h>
13 #include <linux/sysctl.h>
14 #include <linux/input.h>
15 #include <linux/module.h>
16
17 static int mouse_emulate_buttons;
18 static int mouse_button2_keycode = KEY_RIGHTCTRL;       /* right control key */
19 static int mouse_button3_keycode = KEY_RIGHTALT;        /* right option key */
20
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
205 /* file(s) in /proc/sys/dev/mac_hid */
206 static ctl_table mac_hid_files[] = {
207         {
208                 .procname       = "mouse_button_emulation",
209                 .data           = &mouse_emulate_buttons,
210                 .maxlen         = sizeof(int),
211                 .mode           = 0644,
212                 .proc_handler   = mac_hid_toggle_emumouse,
213         },
214         {
215                 .procname       = "mouse_button2_keycode",
216                 .data           = &mouse_button2_keycode,
217                 .maxlen         = sizeof(int),
218                 .mode           = 0644,
219                 .proc_handler   = proc_dointvec,
220         },
221         {
222                 .procname       = "mouse_button3_keycode",
223                 .data           = &mouse_button3_keycode,
224                 .maxlen         = sizeof(int),
225                 .mode           = 0644,
226                 .proc_handler   = proc_dointvec,
227         },
228         { }
229 };
230
231 /* dir in /proc/sys/dev */
232 static ctl_table mac_hid_dir[] = {
233         {
234                 .procname       = "mac_hid",
235                 .maxlen         = 0,
236                 .mode           = 0555,
237                 .child          = mac_hid_files,
238         },
239         { }
240 };
241
242 /* /proc/sys/dev itself, in case that is not there yet */
243 static ctl_table mac_hid_root_dir[] = {
244         {
245                 .procname       = "dev",
246                 .maxlen         = 0,
247                 .mode           = 0555,
248                 .child          = mac_hid_dir,
249         },
250         { }
251 };
252
253 static struct ctl_table_header *mac_hid_sysctl_header;
254
255
256 static int __init mac_hid_init(void)
257 {
258         mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir);
259         if (!mac_hid_sysctl_header)
260                 return -ENOMEM;
261
262         return 0;
263 }
264
265 device_initcall(mac_hid_init);