Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us