]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/ps2mouse.c
Add two missing eventhandler.h headers
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / ps2mouse.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
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/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/types.h>
34
35 #include <assert.h>
36 #include <stdbool.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <strings.h>
40 #include <pthread.h>
41 #include <pthread_np.h>
42
43 #include "atkbdc.h"
44 #include "console.h"
45
46 /* mouse device commands */
47 #define PS2MC_RESET_DEV         0xff
48 #define PS2MC_SET_DEFAULTS      0xf6
49 #define PS2MC_DISABLE           0xf5
50 #define PS2MC_ENABLE            0xf4
51 #define PS2MC_SET_SAMPLING_RATE 0xf3
52 #define PS2MC_SEND_DEV_ID       0xf2
53 #define PS2MC_SET_REMOTE_MODE   0xf0
54 #define PS2MC_SEND_DEV_DATA     0xeb
55 #define PS2MC_SET_STREAM_MODE   0xea
56 #define PS2MC_SEND_DEV_STATUS   0xe9
57 #define PS2MC_SET_RESOLUTION    0xe8
58 #define PS2MC_SET_SCALING1      0xe7
59 #define PS2MC_SET_SCALING2      0xe6
60
61 #define PS2MC_BAT_SUCCESS       0xaa
62 #define PS2MC_ACK               0xfa
63
64 /* mouse device id */
65 #define PS2MOUSE_DEV_ID         0x0
66
67 /* mouse data bits */
68 #define PS2M_DATA_Y_OFLOW       0x80
69 #define PS2M_DATA_X_OFLOW       0x40
70 #define PS2M_DATA_Y_SIGN        0x20
71 #define PS2M_DATA_X_SIGN        0x10
72 #define PS2M_DATA_AONE          0x08
73 #define PS2M_DATA_MID_BUTTON    0x04
74 #define PS2M_DATA_RIGHT_BUTTON  0x02
75 #define PS2M_DATA_LEFT_BUTTON   0x01
76
77 /* mouse status bits */
78 #define PS2M_STS_REMOTE_MODE    0x40
79 #define PS2M_STS_ENABLE_DEV     0x20
80 #define PS2M_STS_SCALING_21     0x10
81 #define PS2M_STS_MID_BUTTON     0x04
82 #define PS2M_STS_RIGHT_BUTTON   0x02
83 #define PS2M_STS_LEFT_BUTTON    0x01
84
85 #define PS2MOUSE_FIFOSZ         16
86
87 struct fifo {
88         uint8_t buf[PS2MOUSE_FIFOSZ];
89         int     rindex;         /* index to read from */
90         int     windex;         /* index to write to */
91         int     num;            /* number of bytes in the fifo */
92         int     size;           /* size of the fifo */
93 };
94
95 struct ps2mouse_softc {
96         struct atkbdc_softc     *atkbdc_sc;
97         pthread_mutex_t         mtx;
98
99         uint8_t         status;
100         uint8_t         resolution;
101         uint8_t         sampling_rate;
102         int             ctrlenable;
103         struct fifo     fifo;
104
105         uint8_t         curcmd; /* current command for next byte */
106
107         int             cur_x, cur_y;
108         int             delta_x, delta_y;
109 };
110
111 static void
112 fifo_init(struct ps2mouse_softc *sc)
113 {
114         struct fifo *fifo;
115
116         fifo = &sc->fifo;
117         fifo->size = sizeof(((struct fifo *)0)->buf);
118 }
119
120 static void
121 fifo_reset(struct ps2mouse_softc *sc)
122 {
123         struct fifo *fifo;
124
125         fifo = &sc->fifo;
126         bzero(fifo, sizeof(struct fifo));
127         fifo->size = sizeof(((struct fifo *)0)->buf);
128 }
129
130 static void
131 fifo_put(struct ps2mouse_softc *sc, uint8_t val)
132 {
133         struct fifo *fifo;
134
135         fifo = &sc->fifo;
136         if (fifo->num < fifo->size) {
137                 fifo->buf[fifo->windex] = val;
138                 fifo->windex = (fifo->windex + 1) % fifo->size;
139                 fifo->num++;
140         }
141 }
142
143 static int
144 fifo_get(struct ps2mouse_softc *sc, uint8_t *val)
145 {
146         struct fifo *fifo;
147
148         fifo = &sc->fifo;
149         if (fifo->num > 0) {
150                 *val = fifo->buf[fifo->rindex];
151                 fifo->rindex = (fifo->rindex + 1) % fifo->size;
152                 fifo->num--;
153                 return (0);
154         }
155
156         return (-1);
157 }
158
159 static void
160 movement_reset(struct ps2mouse_softc *sc)
161 {
162         assert(pthread_mutex_isowned_np(&sc->mtx));
163
164         sc->delta_x = 0;
165         sc->delta_y = 0;
166 }
167
168 static void
169 movement_update(struct ps2mouse_softc *sc, int x, int y)
170 {
171         sc->delta_x += x - sc->cur_x;
172         sc->delta_y += sc->cur_y - y;
173         sc->cur_x = x;
174         sc->cur_y = y;
175 }
176
177 static void
178 movement_get(struct ps2mouse_softc *sc)
179 {
180         uint8_t val0, val1, val2;
181
182         assert(pthread_mutex_isowned_np(&sc->mtx));
183
184         val0 = PS2M_DATA_AONE;
185         val0 |= sc->status & (PS2M_DATA_LEFT_BUTTON |
186             PS2M_DATA_RIGHT_BUTTON | PS2M_DATA_MID_BUTTON);
187
188         if (sc->delta_x >= 0) {
189                 if (sc->delta_x > 255) {
190                         val0 |= PS2M_DATA_X_OFLOW;
191                         val1 = 255;
192                 } else
193                         val1 = sc->delta_x;
194         } else {
195                 val0 |= PS2M_DATA_X_SIGN;
196                 if (sc->delta_x < -255) {
197                         val0 |= PS2M_DATA_X_OFLOW;
198                         val1 = 255;
199                 } else
200                         val1 = sc->delta_x;
201         }
202         sc->delta_x = 0;
203
204         if (sc->delta_y >= 0) {
205                 if (sc->delta_y > 255) {
206                         val0 |= PS2M_DATA_Y_OFLOW;
207                         val2 = 255;
208                 } else
209                         val2 = sc->delta_y;
210         } else {
211                 val0 |= PS2M_DATA_Y_SIGN;
212                 if (sc->delta_y < -255) {
213                         val0 |= PS2M_DATA_Y_OFLOW;
214                         val2 = 255;
215                 } else
216                         val2 = sc->delta_y;
217         }
218         sc->delta_y = 0;
219
220         if (sc->fifo.num < (sc->fifo.size - 3)) {
221                 fifo_put(sc, val0);
222                 fifo_put(sc, val1);
223                 fifo_put(sc, val2);
224         }
225 }
226
227 static void
228 ps2mouse_reset(struct ps2mouse_softc *sc)
229 {
230         assert(pthread_mutex_isowned_np(&sc->mtx));
231         fifo_reset(sc);
232         movement_reset(sc);
233         sc->status = PS2M_STS_ENABLE_DEV;
234         sc->resolution = 4;
235         sc->sampling_rate = 100;
236
237         sc->cur_x = 0;
238         sc->cur_y = 0;
239         sc->delta_x = 0;
240         sc->delta_y = 0;
241 }
242
243 int
244 ps2mouse_read(struct ps2mouse_softc *sc, uint8_t *val)
245 {
246         int retval;
247
248         pthread_mutex_lock(&sc->mtx);
249         retval = fifo_get(sc, val);
250         pthread_mutex_unlock(&sc->mtx);
251
252         return (retval);
253 }
254
255 int
256 ps2mouse_fifocnt(struct ps2mouse_softc *sc)
257 {
258         return (sc->fifo.num);
259 }
260
261 void
262 ps2mouse_toggle(struct ps2mouse_softc *sc, int enable)
263 {
264         pthread_mutex_lock(&sc->mtx);
265         if (enable)
266                 sc->ctrlenable = 1;
267         else {
268                 sc->ctrlenable = 0;
269                 sc->fifo.rindex = 0;
270                 sc->fifo.windex = 0;
271                 sc->fifo.num = 0;
272         }
273         pthread_mutex_unlock(&sc->mtx);
274 }
275
276 void
277 ps2mouse_write(struct ps2mouse_softc *sc, uint8_t val, int insert)
278 {
279         pthread_mutex_lock(&sc->mtx);
280         fifo_reset(sc);
281         if (sc->curcmd) {
282                 switch (sc->curcmd) {
283                 case PS2MC_SET_SAMPLING_RATE:
284                         sc->sampling_rate = val;
285                         fifo_put(sc, PS2MC_ACK);
286                         break;
287                 case PS2MC_SET_RESOLUTION:
288                         sc->resolution = val;
289                         fifo_put(sc, PS2MC_ACK);
290                         break;
291                 default:
292                         fprintf(stderr, "Unhandled ps2 mouse current "
293                             "command byte 0x%02x\n", val);
294                         break;
295                 }
296                 sc->curcmd = 0;
297
298         } else if (insert) {
299                 fifo_put(sc, val);
300         } else {
301                 switch (val) {
302                 case 0x00:
303                         fifo_put(sc, PS2MC_ACK);
304                         break;
305                 case PS2MC_RESET_DEV:
306                         ps2mouse_reset(sc);
307                         fifo_put(sc, PS2MC_ACK);
308                         fifo_put(sc, PS2MC_BAT_SUCCESS);
309                         fifo_put(sc, PS2MOUSE_DEV_ID);
310                         break;
311                 case PS2MC_SET_DEFAULTS:
312                         ps2mouse_reset(sc);
313                         fifo_put(sc, PS2MC_ACK);
314                         break;
315                 case PS2MC_DISABLE:
316                         fifo_reset(sc);
317                         sc->status &= ~PS2M_STS_ENABLE_DEV;
318                         fifo_put(sc, PS2MC_ACK);
319                         break;
320                 case PS2MC_ENABLE:
321                         fifo_reset(sc);
322                         sc->status |= PS2M_STS_ENABLE_DEV;
323                         fifo_put(sc, PS2MC_ACK);
324                         break;
325                 case PS2MC_SET_SAMPLING_RATE:
326                         sc->curcmd = val;
327                         fifo_put(sc, PS2MC_ACK);
328                         break;
329                 case PS2MC_SEND_DEV_ID:
330                         fifo_put(sc, PS2MC_ACK);
331                         fifo_put(sc, PS2MOUSE_DEV_ID);
332                         break;
333                 case PS2MC_SET_REMOTE_MODE:
334                         sc->status |= PS2M_STS_REMOTE_MODE;
335                         fifo_put(sc, PS2MC_ACK);
336                         break;
337                 case PS2MC_SEND_DEV_DATA:
338                         fifo_put(sc, PS2MC_ACK);
339                         movement_get(sc);
340                         break;
341                 case PS2MC_SET_STREAM_MODE:
342                         sc->status &= ~PS2M_STS_REMOTE_MODE;
343                         fifo_put(sc, PS2MC_ACK);
344                         break;
345                 case PS2MC_SEND_DEV_STATUS:
346                         fifo_put(sc, PS2MC_ACK);
347                         fifo_put(sc, sc->status);
348                         fifo_put(sc, sc->resolution);
349                         fifo_put(sc, sc->sampling_rate);
350                         break;
351                 case PS2MC_SET_RESOLUTION:
352                         sc->curcmd = val;
353                         fifo_put(sc, PS2MC_ACK);
354                         break;
355                 case PS2MC_SET_SCALING1:
356                 case PS2MC_SET_SCALING2:
357                         fifo_put(sc, PS2MC_ACK);
358                         break;
359                 default:
360                         fifo_put(sc, PS2MC_ACK);
361                         fprintf(stderr, "Unhandled ps2 mouse command "
362                             "0x%02x\n", val);
363                         break;
364                 }
365         }
366         pthread_mutex_unlock(&sc->mtx);
367 }
368
369 static void
370 ps2mouse_event(uint8_t button, int x, int y, void *arg)
371 {
372         struct ps2mouse_softc *sc = arg;
373
374         pthread_mutex_lock(&sc->mtx);
375         movement_update(sc, x, y);
376
377         sc->status &= ~(PS2M_STS_LEFT_BUTTON |
378             PS2M_STS_RIGHT_BUTTON | PS2M_STS_MID_BUTTON);
379         if (button & (1 << 0))
380                 sc->status |= PS2M_STS_LEFT_BUTTON;
381         if (button & (1 << 1))
382                 sc->status |= PS2M_STS_MID_BUTTON;
383         if (button & (1 << 2))
384                 sc->status |= PS2M_STS_RIGHT_BUTTON;
385
386         if ((sc->status & PS2M_STS_ENABLE_DEV) == 0 || !sc->ctrlenable) {
387                 /* no data reporting */
388                 pthread_mutex_unlock(&sc->mtx);
389                 return;
390         }
391
392         movement_get(sc);
393         pthread_mutex_unlock(&sc->mtx);
394
395         if (sc->fifo.num > 0)
396                 atkbdc_event(sc->atkbdc_sc, 0);
397 }
398
399 struct ps2mouse_softc *
400 ps2mouse_init(struct atkbdc_softc *atkbdc_sc)
401 {
402         struct ps2mouse_softc *sc;
403
404         sc = calloc(1, sizeof (struct ps2mouse_softc));
405         pthread_mutex_init(&sc->mtx, NULL);
406         fifo_init(sc);
407         sc->atkbdc_sc = atkbdc_sc;
408
409         pthread_mutex_lock(&sc->mtx);
410         ps2mouse_reset(sc);
411         pthread_mutex_unlock(&sc->mtx);
412
413         console_ptr_register(ps2mouse_event, sc, 1);
414
415         return (sc);
416 }
417
418