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/config.h> 37 #include <linux/serio.h> 38 #include <linux/init.h> 39 40 #define DRIVER_DESC "Serial mouse driver" 41 42 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 43 MODULE_DESCRIPTION(DRIVER_DESC); 44 MODULE_LICENSE("GPL"); 45 46 static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", 47 "Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse", 48 "Logitech MZ++ Mouse"}; 49 50 struct sermouse { 51 struct input_dev dev; 52 signed char buf[8]; 53 unsigned char count; 54 unsigned char type; 55 unsigned long last; 56 char phys[32]; 57 }; 58 59 /* 60 * sermouse_process_msc() analyzes the incoming MSC/Sun bytestream and 61 * applies some prediction to the data, resulting in 96 updates per 62 * second, which is as good as a PS/2 or USB mouse. 63 */ 64 65 static void sermouse_process_msc(struct sermouse *sermouse, signed char data, struct pt_regs *regs) 66 { 67 struct input_dev *dev = &sermouse->dev; 68 signed char *buf = sermouse->buf; 69 70 input_regs(dev, regs); 71 72 switch (sermouse->count) { 73 74 case 0: 75 if ((data & 0xf8) != 0x80) return; 76 input_report_key(dev, BTN_LEFT, !(data & 4)); 77 input_report_key(dev, BTN_RIGHT, !(data & 1)); 78 input_report_key(dev, BTN_MIDDLE, !(data & 2)); 79 break; 80 81 case 1: 82 case 3: 83 input_report_rel(dev, REL_X, data / 2); 84 input_report_rel(dev, REL_Y, -buf[1]); 85 buf[0] = data - data / 2; 86 break; 87 88 case 2: 89 case 4: 90 input_report_rel(dev, REL_X, buf[0]); 91 input_report_rel(dev, REL_Y, buf[1] - data); 92 buf[1] = data / 2; 93 break; 94 } 95 96 input_sync(dev); 97 98 if (++sermouse->count == (5 - ((sermouse->type == SERIO_SUN) << 1))) 99 sermouse->count = 0; 100 } 101 102 /* 103 * sermouse_process_ms() anlyzes the incoming MS(Z/+/++) bytestream and 104 * generates events. With prediction it gets 80 updates/sec, assuming 105 * standard 3-byte packets and 1200 bps. 106 */ 107 108 static void sermouse_process_ms(struct sermouse *sermouse, signed char data, struct pt_regs *regs) 109 { 110 struct input_dev *dev = &sermouse->dev; 111 signed char *buf = sermouse->buf; 112 113 if (data & 0x40) sermouse->count = 0; 114 115 input_regs(dev, regs); 116 117 switch (sermouse->count) { 118 119 case 0: 120 buf[1] = data; 121 input_report_key(dev, BTN_LEFT, (data >> 5) & 1); 122 input_report_key(dev, BTN_RIGHT, (data >> 4) & 1); 123 break; 124 125 case 1: 126 buf[2] = data; 127 data = (signed char) (((buf[1] << 6) & 0xc0) | (data & 0x3f)); 128 input_report_rel(dev, REL_X, data / 2); 129 input_report_rel(dev, REL_Y, buf[4]); 130 buf[3] = data - data / 2; 131 break; 132 133 case 2: 134 /* Guessing the state of the middle button on 3-button MS-protocol mice - ugly. */ 135 if ((sermouse->type == SERIO_MS) && !data && !buf[2] && !((buf[0] & 0xf0) ^ buf[1])) 136 input_report_key(dev, BTN_MIDDLE, !test_bit(BTN_MIDDLE, dev->key)); 137 buf[0] = buf[1]; 138 139 data = (signed char) (((buf[1] << 4) & 0xc0) | (data & 0x3f)); 140 input_report_rel(dev, REL_X, buf[3]); 141 input_report_rel(dev, REL_Y, data - buf[4]); 142 buf[4] = data / 2; 143 break; 144 145 case 3: 146 147 switch (sermouse->type) { 148 149 case SERIO_MS: 150 sermouse->type = SERIO_MP; 151 152 case SERIO_MP: 153 if ((data >> 2) & 3) break; /* M++ Wireless Extension packet. */ 154 input_report_key(dev, BTN_MIDDLE, (data >> 5) & 1); 155 input_report_key(dev, BTN_SIDE, (data >> 4) & 1); 156 break; 157 158 case SERIO_MZP: 159 case SERIO_MZPP: 160 input_report_key(dev, BTN_SIDE, (data >> 5) & 1); 161 162 case SERIO_MZ: 163 input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1); 164 input_report_rel(dev, REL_WHEEL, (data & 8) - (data & 7)); 165 break; 166 } 167 168 break; 169 170 case 4: 171 case 6: /* MZ++ packet type. We can get these bytes for M++ too but we ignore them later. */ 172 buf[1] = (data >> 2) & 0x0f; 173 break; 174 175 case 5: 176 case 7: /* Ignore anything besides MZ++ */ 177 if (sermouse->type != SERIO_MZPP) 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, struct pt_regs *regs) 211 { 212 struct sermouse *sermouse = serio_get_drvdata(serio); 213 214 if (time_after(jiffies, sermouse->last + HZ/10)) sermouse->count = 0; 215 sermouse->last = jiffies; 216 217 if (sermouse->type > SERIO_SUN) 218 sermouse_process_ms(sermouse, data, regs); 219 else 220 sermouse_process_msc(sermouse, data, regs); 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 input_unregister_device(&sermouse->dev); 234 serio_close(serio); 235 serio_set_drvdata(serio, NULL); 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 unsigned char c; 248 int err; 249 250 if (!serio->id.proto || serio->id.proto > SERIO_MZPP) 251 return -ENODEV; 252 253 if (!(sermouse = kmalloc(sizeof(struct sermouse), GFP_KERNEL))) 254 return -ENOMEM; 255 256 memset(sermouse, 0, sizeof(struct sermouse)); 257 258 init_input_dev(&sermouse->dev); 259 sermouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); 260 sermouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); 261 sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); 262 sermouse->dev.private = sermouse; 263 264 sermouse->type = serio->id.proto; 265 c = serio->id.extra; 266 267 if (c & 0x01) set_bit(BTN_MIDDLE, sermouse->dev.keybit); 268 if (c & 0x02) set_bit(BTN_SIDE, sermouse->dev.keybit); 269 if (c & 0x04) set_bit(BTN_EXTRA, sermouse->dev.keybit); 270 if (c & 0x10) set_bit(REL_WHEEL, sermouse->dev.relbit); 271 if (c & 0x20) set_bit(REL_HWHEEL, sermouse->dev.relbit); 272 273 sprintf(sermouse->phys, "%s/input0", serio->phys); 274 275 sermouse->dev.name = sermouse_protocols[sermouse->type]; 276 sermouse->dev.phys = sermouse->phys; 277 sermouse->dev.id.bustype = BUS_RS232; 278 sermouse->dev.id.vendor = sermouse->type; 279 sermouse->dev.id.product = c; 280 sermouse->dev.id.version = 0x0100; 281 sermouse->dev.dev = &serio->dev; 282 283 serio_set_drvdata(serio, sermouse); 284 285 err = serio_open(serio, drv); 286 if (err) { 287 serio_set_drvdata(serio, NULL); 288 kfree(sermouse); 289 return err; 290 } 291 292 input_register_device(&sermouse->dev); 293 294 printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys); 295 296 return 0; 297 } 298 299 static struct serio_device_id sermouse_serio_ids[] = { 300 { 301 .type = SERIO_RS232, 302 .proto = SERIO_MSC, 303 .id = SERIO_ANY, 304 .extra = SERIO_ANY, 305 }, 306 { 307 .type = SERIO_RS232, 308 .proto = SERIO_SUN, 309 .id = SERIO_ANY, 310 .extra = SERIO_ANY, 311 }, 312 { 313 .type = SERIO_RS232, 314 .proto = SERIO_MS, 315 .id = SERIO_ANY, 316 .extra = SERIO_ANY, 317 }, 318 { 319 .type = SERIO_RS232, 320 .proto = SERIO_MP, 321 .id = SERIO_ANY, 322 .extra = SERIO_ANY, 323 }, 324 { 325 .type = SERIO_RS232, 326 .proto = SERIO_MZ, 327 .id = SERIO_ANY, 328 .extra = SERIO_ANY, 329 }, 330 { 331 .type = SERIO_RS232, 332 .proto = SERIO_MZP, 333 .id = SERIO_ANY, 334 .extra = SERIO_ANY, 335 }, 336 { 337 .type = SERIO_RS232, 338 .proto = SERIO_MZPP, 339 .id = SERIO_ANY, 340 .extra = SERIO_ANY, 341 }, 342 { 0 } 343 }; 344 345 MODULE_DEVICE_TABLE(serio, sermouse_serio_ids); 346 347 static struct serio_driver sermouse_drv = { 348 .driver = { 349 .name = "sermouse", 350 }, 351 .description = DRIVER_DESC, 352 .id_table = sermouse_serio_ids, 353 .interrupt = sermouse_interrupt, 354 .connect = sermouse_connect, 355 .disconnect = sermouse_disconnect, 356 }; 357 358 static int __init sermouse_init(void) 359 { 360 serio_register_driver(&sermouse_drv); 361 return 0; 362 } 363 364 static void __exit sermouse_exit(void) 365 { 366 serio_unregister_driver(&sermouse_drv); 367 } 368 369 module_init(sermouse_init); 370 module_exit(sermouse_exit); 371