Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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