Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 77dc2db6d1d2703ee4e83d4b3dbecf4e06a910e6 365 lines 9.1 kB view raw
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 41MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 42MODULE_DESCRIPTION(DRIVER_DESC); 43MODULE_LICENSE("GPL"); 44 45static 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 49struct 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 64static void sermouse_process_msc(struct sermouse *sermouse, signed char data, struct pt_regs *regs) 65{ 66 struct input_dev *dev = sermouse->dev; 67 signed char *buf = sermouse->buf; 68 69 input_regs(dev, regs); 70 71 switch (sermouse->count) { 72 73 case 0: 74 if ((data & 0xf8) != 0x80) return; 75 input_report_key(dev, BTN_LEFT, !(data & 4)); 76 input_report_key(dev, BTN_RIGHT, !(data & 1)); 77 input_report_key(dev, BTN_MIDDLE, !(data & 2)); 78 break; 79 80 case 1: 81 case 3: 82 input_report_rel(dev, REL_X, data / 2); 83 input_report_rel(dev, REL_Y, -buf[1]); 84 buf[0] = data - data / 2; 85 break; 86 87 case 2: 88 case 4: 89 input_report_rel(dev, REL_X, buf[0]); 90 input_report_rel(dev, REL_Y, buf[1] - data); 91 buf[1] = data / 2; 92 break; 93 } 94 95 input_sync(dev); 96 97 if (++sermouse->count == 5) 98 sermouse->count = 0; 99} 100 101/* 102 * sermouse_process_ms() anlyzes the incoming MS(Z/+/++) bytestream and 103 * generates events. With prediction it gets 80 updates/sec, assuming 104 * standard 3-byte packets and 1200 bps. 105 */ 106 107static void sermouse_process_ms(struct sermouse *sermouse, signed char data, struct pt_regs *regs) 108{ 109 struct input_dev *dev = sermouse->dev; 110 signed char *buf = sermouse->buf; 111 112 if (data & 0x40) sermouse->count = 0; 113 114 input_regs(dev, regs); 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) break; 177 178 switch (buf[1]) { 179 180 case 1: /* Extra mouse info */ 181 182 input_report_key(dev, BTN_SIDE, (data >> 4) & 1); 183 input_report_key(dev, BTN_EXTRA, (data >> 5) & 1); 184 input_report_rel(dev, data & 0x80 ? REL_HWHEEL : REL_WHEEL, (data & 7) - (data & 8)); 185 186 break; 187 188 default: /* We don't decode anything else yet. */ 189 190 printk(KERN_WARNING 191 "sermouse.c: Received MZ++ packet %x, don't know how to handle.\n", buf[1]); 192 break; 193 } 194 195 break; 196 } 197 198 input_sync(dev); 199 200 sermouse->count++; 201} 202 203/* 204 * sermouse_interrupt() handles incoming characters, either gathering them into 205 * packets or passing them to the command routine as command output. 206 */ 207 208static irqreturn_t sermouse_interrupt(struct serio *serio, 209 unsigned char data, unsigned int flags, struct pt_regs *regs) 210{ 211 struct sermouse *sermouse = serio_get_drvdata(serio); 212 213 if (time_after(jiffies, sermouse->last + HZ/10)) sermouse->count = 0; 214 sermouse->last = jiffies; 215 216 if (sermouse->type > SERIO_SUN) 217 sermouse_process_ms(sermouse, data, regs); 218 else 219 sermouse_process_msc(sermouse, data, regs); 220 return IRQ_HANDLED; 221} 222 223/* 224 * sermouse_disconnect() cleans up after we don't want talk 225 * to the mouse anymore. 226 */ 227 228static void sermouse_disconnect(struct serio *serio) 229{ 230 struct sermouse *sermouse = serio_get_drvdata(serio); 231 232 serio_close(serio); 233 serio_set_drvdata(serio, NULL); 234 input_unregister_device(sermouse->dev); 235 kfree(sermouse); 236} 237 238/* 239 * sermouse_connect() is a callback form the serio module when 240 * an unhandled serio port is found. 241 */ 242 243static int sermouse_connect(struct serio *serio, struct serio_driver *drv) 244{ 245 struct sermouse *sermouse; 246 struct input_dev *input_dev; 247 unsigned char c = serio->id.extra; 248 int err = -ENOMEM; 249 250 sermouse = kzalloc(sizeof(struct sermouse), GFP_KERNEL); 251 input_dev = input_allocate_device(); 252 if (!sermouse || !input_dev) 253 goto fail; 254 255 sermouse->dev = input_dev; 256 snprintf(sermouse->phys, sizeof(sermouse->phys), "%s/input0", serio->phys); 257 sermouse->type = serio->id.proto; 258 259 input_dev->name = sermouse_protocols[sermouse->type]; 260 input_dev->phys = sermouse->phys; 261 input_dev->id.bustype = BUS_RS232; 262 input_dev->id.vendor = sermouse->type; 263 input_dev->id.product = c; 264 input_dev->id.version = 0x0100; 265 input_dev->cdev.dev = &serio->dev; 266 267 input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); 268 input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); 269 input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); 270 input_dev->private = sermouse; 271 272 if (c & 0x01) set_bit(BTN_MIDDLE, input_dev->keybit); 273 if (c & 0x02) set_bit(BTN_SIDE, input_dev->keybit); 274 if (c & 0x04) set_bit(BTN_EXTRA, input_dev->keybit); 275 if (c & 0x10) set_bit(REL_WHEEL, input_dev->relbit); 276 if (c & 0x20) set_bit(REL_HWHEEL, input_dev->relbit); 277 278 serio_set_drvdata(serio, sermouse); 279 280 err = serio_open(serio, drv); 281 if (err) 282 goto fail; 283 284 input_register_device(sermouse->dev); 285 286 return 0; 287 288 fail: serio_set_drvdata(serio, NULL); 289 input_free_device(input_dev); 290 kfree(sermouse); 291 return err; 292} 293 294static struct serio_device_id sermouse_serio_ids[] = { 295 { 296 .type = SERIO_RS232, 297 .proto = SERIO_MSC, 298 .id = SERIO_ANY, 299 .extra = SERIO_ANY, 300 }, 301 { 302 .type = SERIO_RS232, 303 .proto = SERIO_SUN, 304 .id = SERIO_ANY, 305 .extra = SERIO_ANY, 306 }, 307 { 308 .type = SERIO_RS232, 309 .proto = SERIO_MS, 310 .id = SERIO_ANY, 311 .extra = SERIO_ANY, 312 }, 313 { 314 .type = SERIO_RS232, 315 .proto = SERIO_MP, 316 .id = SERIO_ANY, 317 .extra = SERIO_ANY, 318 }, 319 { 320 .type = SERIO_RS232, 321 .proto = SERIO_MZ, 322 .id = SERIO_ANY, 323 .extra = SERIO_ANY, 324 }, 325 { 326 .type = SERIO_RS232, 327 .proto = SERIO_MZP, 328 .id = SERIO_ANY, 329 .extra = SERIO_ANY, 330 }, 331 { 332 .type = SERIO_RS232, 333 .proto = SERIO_MZPP, 334 .id = SERIO_ANY, 335 .extra = SERIO_ANY, 336 }, 337 { 0 } 338}; 339 340MODULE_DEVICE_TABLE(serio, sermouse_serio_ids); 341 342static struct serio_driver sermouse_drv = { 343 .driver = { 344 .name = "sermouse", 345 }, 346 .description = DRIVER_DESC, 347 .id_table = sermouse_serio_ids, 348 .interrupt = sermouse_interrupt, 349 .connect = sermouse_connect, 350 .disconnect = sermouse_disconnect, 351}; 352 353static int __init sermouse_init(void) 354{ 355 serio_register_driver(&sermouse_drv); 356 return 0; 357} 358 359static void __exit sermouse_exit(void) 360{ 361 serio_unregister_driver(&sermouse_drv); 362} 363 364module_init(sermouse_init); 365module_exit(sermouse_exit);