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