Merge branch 'next-smack' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[sfrench/cifs-2.6.git] / drivers / input / mouse / sermouse.c
1 /*
2  *  Copyright (c) 1999-2001 Vojtech Pavlik
3  */
4
5 /*
6  *  Serial mouse driver for Linux
7  */
8
9 /*
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  */
24
25 #include <linux/delay.h>
26 #include <linux/module.h>
27 #include <linux/slab.h>
28 #include <linux/interrupt.h>
29 #include <linux/input.h>
30 #include <linux/serio.h>
31
32 #define DRIVER_DESC     "Serial mouse driver"
33
34 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
35 MODULE_DESCRIPTION(DRIVER_DESC);
36 MODULE_LICENSE("GPL");
37
38 static const char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse",
39                                         "Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse",
40                                         "Logitech MZ++ Mouse"};
41
42 struct sermouse {
43         struct input_dev *dev;
44         signed char buf[8];
45         unsigned char count;
46         unsigned char type;
47         unsigned long last;
48         char phys[32];
49 };
50
51 /*
52  * sermouse_process_msc() analyzes the incoming MSC/Sun bytestream and
53  * applies some prediction to the data, resulting in 96 updates per
54  * second, which is as good as a PS/2 or USB mouse.
55  */
56
57 static void sermouse_process_msc(struct sermouse *sermouse, signed char data)
58 {
59         struct input_dev *dev = sermouse->dev;
60         signed char *buf = sermouse->buf;
61
62         switch (sermouse->count) {
63
64                 case 0:
65                         if ((data & 0xf8) != 0x80)
66                                 return;
67                         input_report_key(dev, BTN_LEFT,   !(data & 4));
68                         input_report_key(dev, BTN_RIGHT,  !(data & 1));
69                         input_report_key(dev, BTN_MIDDLE, !(data & 2));
70                         break;
71
72                 case 1:
73                 case 3:
74                         input_report_rel(dev, REL_X, data / 2);
75                         input_report_rel(dev, REL_Y, -buf[1]);
76                         buf[0] = data - data / 2;
77                         break;
78
79                 case 2:
80                 case 4:
81                         input_report_rel(dev, REL_X, buf[0]);
82                         input_report_rel(dev, REL_Y, buf[1] - data);
83                         buf[1] = data / 2;
84                         break;
85         }
86
87         input_sync(dev);
88
89         if (++sermouse->count == 5)
90                 sermouse->count = 0;
91 }
92
93 /*
94  * sermouse_process_ms() anlyzes the incoming MS(Z/+/++) bytestream and
95  * generates events. With prediction it gets 80 updates/sec, assuming
96  * standard 3-byte packets and 1200 bps.
97  */
98
99 static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
100 {
101         struct input_dev *dev = sermouse->dev;
102         signed char *buf = sermouse->buf;
103
104         if (data & 0x40)
105                 sermouse->count = 0;
106         else if (sermouse->count == 0)
107                 return;
108
109         switch (sermouse->count) {
110
111                 case 0:
112                         buf[1] = data;
113                         input_report_key(dev, BTN_LEFT,   (data >> 5) & 1);
114                         input_report_key(dev, BTN_RIGHT,  (data >> 4) & 1);
115                         break;
116
117                 case 1:
118                         buf[2] = data;
119                         data = (signed char) (((buf[1] << 6) & 0xc0) | (data & 0x3f));
120                         input_report_rel(dev, REL_X, data / 2);
121                         input_report_rel(dev, REL_Y, buf[4]);
122                         buf[3] = data - data / 2;
123                         break;
124
125                 case 2:
126                         /* Guessing the state of the middle button on 3-button MS-protocol mice - ugly. */
127                         if ((sermouse->type == SERIO_MS) && !data && !buf[2] && !((buf[0] & 0xf0) ^ buf[1]))
128                                 input_report_key(dev, BTN_MIDDLE, !test_bit(BTN_MIDDLE, dev->key));
129                         buf[0] = buf[1];
130
131                         data = (signed char) (((buf[1] << 4) & 0xc0) | (data & 0x3f));
132                         input_report_rel(dev, REL_X, buf[3]);
133                         input_report_rel(dev, REL_Y, data - buf[4]);
134                         buf[4] = data / 2;
135                         break;
136
137                 case 3:
138
139                         switch (sermouse->type) {
140
141                                 case SERIO_MS:
142                                         sermouse->type = SERIO_MP;
143                                         /* fall through */
144
145                                 case SERIO_MP:
146                                         if ((data >> 2) & 3) break;     /* M++ Wireless Extension packet. */
147                                         input_report_key(dev, BTN_MIDDLE, (data >> 5) & 1);
148                                         input_report_key(dev, BTN_SIDE,   (data >> 4) & 1);
149                                         break;
150
151                                 case SERIO_MZP:
152                                 case SERIO_MZPP:
153                                         input_report_key(dev, BTN_SIDE,   (data >> 5) & 1);
154                                         /* fall through */
155
156                                 case SERIO_MZ:
157                                         input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1);
158                                         input_report_rel(dev, REL_WHEEL,  (data & 8) - (data & 7));
159                                         break;
160                         }
161
162                         break;
163
164                 case 4:
165                 case 6: /* MZ++ packet type. We can get these bytes for M++ too but we ignore them later. */
166                         buf[1] = (data >> 2) & 0x0f;
167                         break;
168
169                 case 5:
170                 case 7: /* Ignore anything besides MZ++ */
171                         if (sermouse->type != SERIO_MZPP)
172                                 break;
173
174                         switch (buf[1]) {
175
176                                 case 1: /* Extra mouse info */
177
178                                         input_report_key(dev, BTN_SIDE, (data >> 4) & 1);
179                                         input_report_key(dev, BTN_EXTRA, (data >> 5) & 1);
180                                         input_report_rel(dev, data & 0x80 ? REL_HWHEEL : REL_WHEEL, (data & 7) - (data & 8));
181
182                                         break;
183
184                                 default: /* We don't decode anything else yet. */
185
186                                         printk(KERN_WARNING
187                                                 "sermouse.c: Received MZ++ packet %x, don't know how to handle.\n", buf[1]);
188                                         break;
189                         }
190
191                         break;
192         }
193
194         input_sync(dev);
195
196         sermouse->count++;
197 }
198
199 /*
200  * sermouse_interrupt() handles incoming characters, either gathering them into
201  * packets or passing them to the command routine as command output.
202  */
203
204 static irqreturn_t sermouse_interrupt(struct serio *serio,
205                 unsigned char data, unsigned int flags)
206 {
207         struct sermouse *sermouse = serio_get_drvdata(serio);
208
209         if (time_after(jiffies, sermouse->last + HZ/10))
210                 sermouse->count = 0;
211
212         sermouse->last = jiffies;
213
214         if (sermouse->type > SERIO_SUN)
215                 sermouse_process_ms(sermouse, data);
216         else
217                 sermouse_process_msc(sermouse, data);
218
219         return IRQ_HANDLED;
220 }
221
222 /*
223  * sermouse_disconnect() cleans up after we don't want talk
224  * to the mouse anymore.
225  */
226
227 static void sermouse_disconnect(struct serio *serio)
228 {
229         struct sermouse *sermouse = serio_get_drvdata(serio);
230
231         serio_close(serio);
232         serio_set_drvdata(serio, NULL);
233         input_unregister_device(sermouse->dev);
234         kfree(sermouse);
235 }
236
237 /*
238  * sermouse_connect() is a callback form the serio module when
239  * an unhandled serio port is found.
240  */
241
242 static int sermouse_connect(struct serio *serio, struct serio_driver *drv)
243 {
244         struct sermouse *sermouse;
245         struct input_dev *input_dev;
246         unsigned char c = serio->id.extra;
247         int err = -ENOMEM;
248
249         sermouse = kzalloc(sizeof(struct sermouse), GFP_KERNEL);
250         input_dev = input_allocate_device();
251         if (!sermouse || !input_dev)
252                 goto fail1;
253
254         sermouse->dev = input_dev;
255         snprintf(sermouse->phys, sizeof(sermouse->phys), "%s/input0", serio->phys);
256         sermouse->type = serio->id.proto;
257
258         input_dev->name = sermouse_protocols[sermouse->type];
259         input_dev->phys = sermouse->phys;
260         input_dev->id.bustype = BUS_RS232;
261         input_dev->id.vendor  = sermouse->type;
262         input_dev->id.product = c;
263         input_dev->id.version = 0x0100;
264         input_dev->dev.parent = &serio->dev;
265
266         input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
267         input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
268                 BIT_MASK(BTN_RIGHT);
269         input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
270
271         if (c & 0x01) set_bit(BTN_MIDDLE, input_dev->keybit);
272         if (c & 0x02) set_bit(BTN_SIDE, input_dev->keybit);
273         if (c & 0x04) set_bit(BTN_EXTRA, input_dev->keybit);
274         if (c & 0x10) set_bit(REL_WHEEL, input_dev->relbit);
275         if (c & 0x20) set_bit(REL_HWHEEL, input_dev->relbit);
276
277         serio_set_drvdata(serio, sermouse);
278
279         err = serio_open(serio, drv);
280         if (err)
281                 goto fail2;
282
283         err = input_register_device(sermouse->dev);
284         if (err)
285                 goto fail3;
286
287         return 0;
288
289  fail3: serio_close(serio);
290  fail2: serio_set_drvdata(serio, NULL);
291  fail1: input_free_device(input_dev);
292         kfree(sermouse);
293         return err;
294 }
295
296 static struct serio_device_id sermouse_serio_ids[] = {
297         {
298                 .type   = SERIO_RS232,
299                 .proto  = SERIO_MSC,
300                 .id     = SERIO_ANY,
301                 .extra  = SERIO_ANY,
302         },
303         {
304                 .type   = SERIO_RS232,
305                 .proto  = SERIO_SUN,
306                 .id     = SERIO_ANY,
307                 .extra  = SERIO_ANY,
308         },
309         {
310                 .type   = SERIO_RS232,
311                 .proto  = SERIO_MS,
312                 .id     = SERIO_ANY,
313                 .extra  = SERIO_ANY,
314         },
315         {
316                 .type   = SERIO_RS232,
317                 .proto  = SERIO_MP,
318                 .id     = SERIO_ANY,
319                 .extra  = SERIO_ANY,
320         },
321         {
322                 .type   = SERIO_RS232,
323                 .proto  = SERIO_MZ,
324                 .id     = SERIO_ANY,
325                 .extra  = SERIO_ANY,
326         },
327         {
328                 .type   = SERIO_RS232,
329                 .proto  = SERIO_MZP,
330                 .id     = SERIO_ANY,
331                 .extra  = SERIO_ANY,
332         },
333         {
334                 .type   = SERIO_RS232,
335                 .proto  = SERIO_MZPP,
336                 .id     = SERIO_ANY,
337                 .extra  = SERIO_ANY,
338         },
339         { 0 }
340 };
341
342 MODULE_DEVICE_TABLE(serio, sermouse_serio_ids);
343
344 static struct serio_driver sermouse_drv = {
345         .driver         = {
346                 .name   = "sermouse",
347         },
348         .description    = DRIVER_DESC,
349         .id_table       = sermouse_serio_ids,
350         .interrupt      = sermouse_interrupt,
351         .connect        = sermouse_connect,
352         .disconnect     = sermouse_disconnect,
353 };
354
355 module_serio_driver(sermouse_drv);