root/drivers/input/mouse/sermouse.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sermouse_process_msc
  2. sermouse_process_ms
  3. sermouse_interrupt
  4. sermouse_disconnect
  5. sermouse_connect

   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 
  22 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  23 MODULE_DESCRIPTION(DRIVER_DESC);
  24 MODULE_LICENSE("GPL");
  25 
  26 static 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 
  30 struct 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 
  45 static 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 
  87 static 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                                         /* fall through */
 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                                         /* fall through */
 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 
 192 static 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 
 215 static 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 
 230 static 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 
 284 static 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 
 330 MODULE_DEVICE_TABLE(serio, sermouse_serio_ids);
 331 
 332 static 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 
 343 module_serio_driver(sermouse_drv);

/* [<][>][^][v][top][bottom][index][help] */