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