Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bhyve/amd64/ps2mouse.c
105677 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2015 Tycho Nightingale <[email protected]>
5
* Copyright (c) 2015 Nahanni Systems Inc.
6
* All rights reserved.
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
10
* are met:
11
* 1. Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
#include <sys/types.h>
31
32
#include <machine/vmm_snapshot.h>
33
34
#include <assert.h>
35
#include <stdbool.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <strings.h>
40
#include <pthread.h>
41
#include <pthread_np.h>
42
43
#include "atkbdc.h"
44
#include "console.h"
45
#include "debug.h"
46
#include "ps2mouse.h"
47
48
/* mouse device commands */
49
#define PS2MC_RESET_DEV 0xff
50
#define PS2MC_SET_DEFAULTS 0xf6
51
#define PS2MC_DISABLE 0xf5
52
#define PS2MC_ENABLE 0xf4
53
#define PS2MC_SET_SAMPLING_RATE 0xf3
54
#define PS2MC_SEND_DEV_ID 0xf2
55
#define PS2MC_SET_REMOTE_MODE 0xf0
56
#define PS2MC_SEND_DEV_DATA 0xeb
57
#define PS2MC_SET_STREAM_MODE 0xea
58
#define PS2MC_SEND_DEV_STATUS 0xe9
59
#define PS2MC_SET_RESOLUTION 0xe8
60
#define PS2MC_SET_SCALING1 0xe7
61
#define PS2MC_SET_SCALING2 0xe6
62
63
#define PS2MC_BAT_SUCCESS 0xaa
64
#define PS2MC_ACK 0xfa
65
66
/* mouse device id */
67
#define PS2MOUSE_DEV_ID 0x0
68
69
/* mouse data bits */
70
#define PS2M_DATA_Y_OFLOW 0x80
71
#define PS2M_DATA_X_OFLOW 0x40
72
#define PS2M_DATA_Y_SIGN 0x20
73
#define PS2M_DATA_X_SIGN 0x10
74
#define PS2M_DATA_AONE 0x08
75
#define PS2M_DATA_MID_BUTTON 0x04
76
#define PS2M_DATA_RIGHT_BUTTON 0x02
77
#define PS2M_DATA_LEFT_BUTTON 0x01
78
79
/* mouse status bits */
80
#define PS2M_STS_REMOTE_MODE 0x40
81
#define PS2M_STS_ENABLE_DEV 0x20
82
#define PS2M_STS_SCALING_21 0x10
83
#define PS2M_STS_MID_BUTTON 0x04
84
#define PS2M_STS_RIGHT_BUTTON 0x02
85
#define PS2M_STS_LEFT_BUTTON 0x01
86
87
#define PS2MOUSE_FIFOSZ 16
88
89
struct fifo {
90
uint8_t buf[PS2MOUSE_FIFOSZ];
91
int rindex; /* index to read from */
92
int windex; /* index to write to */
93
int num; /* number of bytes in the fifo */
94
int size; /* size of the fifo */
95
};
96
97
struct ps2mouse_softc {
98
struct atkbdc_softc *atkbdc_sc;
99
pthread_mutex_t mtx;
100
101
uint8_t status;
102
uint8_t resolution;
103
uint8_t sampling_rate;
104
int ctrlenable;
105
struct fifo fifo;
106
107
uint8_t curcmd; /* current command for next byte */
108
109
int cur_x, cur_y;
110
int delta_x, delta_y;
111
};
112
113
static void
114
fifo_init(struct ps2mouse_softc *sc)
115
{
116
struct fifo *fifo;
117
118
fifo = &sc->fifo;
119
fifo->size = sizeof(((struct fifo *)0)->buf);
120
}
121
122
static void
123
fifo_reset(struct ps2mouse_softc *sc)
124
{
125
struct fifo *fifo;
126
127
fifo = &sc->fifo;
128
bzero(fifo, sizeof(struct fifo));
129
fifo->size = sizeof(((struct fifo *)0)->buf);
130
}
131
132
static void
133
fifo_put(struct ps2mouse_softc *sc, uint8_t val)
134
{
135
struct fifo *fifo;
136
137
fifo = &sc->fifo;
138
if (fifo->num < fifo->size) {
139
fifo->buf[fifo->windex] = val;
140
fifo->windex = (fifo->windex + 1) % fifo->size;
141
fifo->num++;
142
}
143
}
144
145
static int
146
fifo_get(struct ps2mouse_softc *sc, uint8_t *val)
147
{
148
struct fifo *fifo;
149
150
fifo = &sc->fifo;
151
if (fifo->num > 0) {
152
*val = fifo->buf[fifo->rindex];
153
fifo->rindex = (fifo->rindex + 1) % fifo->size;
154
fifo->num--;
155
return (0);
156
}
157
158
return (-1);
159
}
160
161
static void
162
movement_reset(struct ps2mouse_softc *sc)
163
{
164
assert(pthread_mutex_isowned_np(&sc->mtx));
165
166
sc->delta_x = 0;
167
sc->delta_y = 0;
168
}
169
170
static void
171
movement_update(struct ps2mouse_softc *sc, int x, int y)
172
{
173
sc->delta_x += x - sc->cur_x;
174
sc->delta_y += sc->cur_y - y;
175
sc->cur_x = x;
176
sc->cur_y = y;
177
}
178
179
static void
180
movement_get(struct ps2mouse_softc *sc)
181
{
182
uint8_t val0, val1, val2;
183
184
assert(pthread_mutex_isowned_np(&sc->mtx));
185
186
val0 = PS2M_DATA_AONE;
187
val0 |= sc->status & (PS2M_DATA_LEFT_BUTTON |
188
PS2M_DATA_RIGHT_BUTTON | PS2M_DATA_MID_BUTTON);
189
190
if (sc->delta_x >= 0) {
191
if (sc->delta_x > 255) {
192
val0 |= PS2M_DATA_X_OFLOW;
193
val1 = 255;
194
} else
195
val1 = sc->delta_x;
196
} else {
197
val0 |= PS2M_DATA_X_SIGN;
198
if (sc->delta_x < -255) {
199
val0 |= PS2M_DATA_X_OFLOW;
200
val1 = 255;
201
} else
202
val1 = sc->delta_x;
203
}
204
sc->delta_x = 0;
205
206
if (sc->delta_y >= 0) {
207
if (sc->delta_y > 255) {
208
val0 |= PS2M_DATA_Y_OFLOW;
209
val2 = 255;
210
} else
211
val2 = sc->delta_y;
212
} else {
213
val0 |= PS2M_DATA_Y_SIGN;
214
if (sc->delta_y < -255) {
215
val0 |= PS2M_DATA_Y_OFLOW;
216
val2 = 255;
217
} else
218
val2 = sc->delta_y;
219
}
220
sc->delta_y = 0;
221
222
if (sc->fifo.num < (sc->fifo.size - 3)) {
223
fifo_put(sc, val0);
224
fifo_put(sc, val1);
225
fifo_put(sc, val2);
226
}
227
}
228
229
static void
230
ps2mouse_reset(struct ps2mouse_softc *sc)
231
{
232
assert(pthread_mutex_isowned_np(&sc->mtx));
233
fifo_reset(sc);
234
movement_reset(sc);
235
sc->status = PS2M_STS_ENABLE_DEV;
236
sc->resolution = 4;
237
sc->sampling_rate = 100;
238
239
sc->cur_x = 0;
240
sc->cur_y = 0;
241
sc->delta_x = 0;
242
sc->delta_y = 0;
243
}
244
245
int
246
ps2mouse_read(struct ps2mouse_softc *sc, uint8_t *val)
247
{
248
int retval;
249
250
pthread_mutex_lock(&sc->mtx);
251
retval = fifo_get(sc, val);
252
pthread_mutex_unlock(&sc->mtx);
253
254
return (retval);
255
}
256
257
int
258
ps2mouse_fifocnt(struct ps2mouse_softc *sc)
259
{
260
return (sc->fifo.num);
261
}
262
263
void
264
ps2mouse_toggle(struct ps2mouse_softc *sc, int enable)
265
{
266
pthread_mutex_lock(&sc->mtx);
267
if (enable)
268
sc->ctrlenable = 1;
269
else {
270
sc->ctrlenable = 0;
271
sc->fifo.rindex = 0;
272
sc->fifo.windex = 0;
273
sc->fifo.num = 0;
274
}
275
pthread_mutex_unlock(&sc->mtx);
276
}
277
278
void
279
ps2mouse_write(struct ps2mouse_softc *sc, uint8_t val, int insert)
280
{
281
pthread_mutex_lock(&sc->mtx);
282
fifo_reset(sc);
283
if (sc->curcmd) {
284
switch (sc->curcmd) {
285
case PS2MC_SET_SAMPLING_RATE:
286
sc->sampling_rate = val;
287
fifo_put(sc, PS2MC_ACK);
288
break;
289
case PS2MC_SET_RESOLUTION:
290
sc->resolution = val;
291
fifo_put(sc, PS2MC_ACK);
292
break;
293
default:
294
EPRINTLN("Unhandled ps2 mouse current "
295
"command byte 0x%02x", val);
296
break;
297
}
298
sc->curcmd = 0;
299
300
} else if (insert) {
301
fifo_put(sc, val);
302
} else {
303
switch (val) {
304
case 0x00:
305
fifo_put(sc, PS2MC_ACK);
306
break;
307
case PS2MC_RESET_DEV:
308
ps2mouse_reset(sc);
309
fifo_put(sc, PS2MC_ACK);
310
fifo_put(sc, PS2MC_BAT_SUCCESS);
311
fifo_put(sc, PS2MOUSE_DEV_ID);
312
break;
313
case PS2MC_SET_DEFAULTS:
314
ps2mouse_reset(sc);
315
fifo_put(sc, PS2MC_ACK);
316
break;
317
case PS2MC_DISABLE:
318
fifo_reset(sc);
319
sc->status &= ~PS2M_STS_ENABLE_DEV;
320
fifo_put(sc, PS2MC_ACK);
321
break;
322
case PS2MC_ENABLE:
323
fifo_reset(sc);
324
sc->status |= PS2M_STS_ENABLE_DEV;
325
fifo_put(sc, PS2MC_ACK);
326
break;
327
case PS2MC_SET_SAMPLING_RATE:
328
sc->curcmd = val;
329
fifo_put(sc, PS2MC_ACK);
330
break;
331
case PS2MC_SEND_DEV_ID:
332
fifo_put(sc, PS2MC_ACK);
333
fifo_put(sc, PS2MOUSE_DEV_ID);
334
break;
335
case PS2MC_SET_REMOTE_MODE:
336
sc->status |= PS2M_STS_REMOTE_MODE;
337
fifo_put(sc, PS2MC_ACK);
338
break;
339
case PS2MC_SEND_DEV_DATA:
340
fifo_put(sc, PS2MC_ACK);
341
movement_get(sc);
342
break;
343
case PS2MC_SET_STREAM_MODE:
344
sc->status &= ~PS2M_STS_REMOTE_MODE;
345
fifo_put(sc, PS2MC_ACK);
346
break;
347
case PS2MC_SEND_DEV_STATUS:
348
fifo_put(sc, PS2MC_ACK);
349
fifo_put(sc, sc->status);
350
fifo_put(sc, sc->resolution);
351
fifo_put(sc, sc->sampling_rate);
352
break;
353
case PS2MC_SET_RESOLUTION:
354
sc->curcmd = val;
355
fifo_put(sc, PS2MC_ACK);
356
break;
357
case PS2MC_SET_SCALING1:
358
case PS2MC_SET_SCALING2:
359
fifo_put(sc, PS2MC_ACK);
360
break;
361
default:
362
fifo_put(sc, PS2MC_ACK);
363
EPRINTLN("Unhandled ps2 mouse command "
364
"0x%02x", val);
365
break;
366
}
367
}
368
pthread_mutex_unlock(&sc->mtx);
369
}
370
371
static void
372
ps2mouse_event(uint8_t button, int x, int y, void *arg)
373
{
374
struct ps2mouse_softc *sc = arg;
375
376
pthread_mutex_lock(&sc->mtx);
377
movement_update(sc, x, y);
378
379
sc->status &= ~(PS2M_STS_LEFT_BUTTON |
380
PS2M_STS_RIGHT_BUTTON | PS2M_STS_MID_BUTTON);
381
if (button & (1 << 0))
382
sc->status |= PS2M_STS_LEFT_BUTTON;
383
if (button & (1 << 1))
384
sc->status |= PS2M_STS_MID_BUTTON;
385
if (button & (1 << 2))
386
sc->status |= PS2M_STS_RIGHT_BUTTON;
387
388
if ((sc->status & PS2M_STS_ENABLE_DEV) == 0 || !sc->ctrlenable) {
389
/* no data reporting */
390
pthread_mutex_unlock(&sc->mtx);
391
return;
392
}
393
394
movement_get(sc);
395
pthread_mutex_unlock(&sc->mtx);
396
397
if (sc->fifo.num > 0)
398
atkbdc_event(sc->atkbdc_sc, 0);
399
}
400
401
struct ps2mouse_softc *
402
ps2mouse_init(struct atkbdc_softc *atkbdc_sc)
403
{
404
struct ps2mouse_softc *sc;
405
406
sc = calloc(1, sizeof (struct ps2mouse_softc));
407
pthread_mutex_init(&sc->mtx, NULL);
408
fifo_init(sc);
409
sc->atkbdc_sc = atkbdc_sc;
410
411
pthread_mutex_lock(&sc->mtx);
412
ps2mouse_reset(sc);
413
pthread_mutex_unlock(&sc->mtx);
414
415
console_ptr_register(ps2mouse_event, sc, 1);
416
417
return (sc);
418
}
419
420
#ifdef BHYVE_SNAPSHOT
421
int
422
ps2mouse_snapshot(struct ps2mouse_softc *sc, struct vm_snapshot_meta *meta)
423
{
424
int ret;
425
426
SNAPSHOT_VAR_OR_LEAVE(sc->status, meta, ret, done);
427
SNAPSHOT_VAR_OR_LEAVE(sc->resolution, meta, ret, done);
428
SNAPSHOT_VAR_OR_LEAVE(sc->sampling_rate, meta, ret, done);
429
SNAPSHOT_VAR_OR_LEAVE(sc->ctrlenable, meta, ret, done);
430
SNAPSHOT_VAR_OR_LEAVE(sc->curcmd, meta, ret, done);
431
SNAPSHOT_VAR_OR_LEAVE(sc->cur_x, meta, ret, done);
432
SNAPSHOT_VAR_OR_LEAVE(sc->cur_y, meta, ret, done);
433
SNAPSHOT_VAR_OR_LEAVE(sc->delta_x, meta, ret, done);
434
SNAPSHOT_VAR_OR_LEAVE(sc->delta_y, meta, ret, done);
435
436
done:
437
return (ret);
438
}
439
#endif
440
441