1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer as
12 * the first lines of this file unmodified.
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 AUTHORS ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30 #include <sys/cdefs.h>
31 #include "opt_evdev.h"
32 #include "opt_syscons.h"
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/priv.h>
37 #include <sys/serial.h>
38 #include <sys/tty.h>
39 #include <sys/ttydefaults.h>
40 #include <sys/kernel.h>
41 #include <sys/cons.h>
42 #include <sys/consio.h>
43 #include <sys/mouse.h>
44
45 #include <dev/syscons/syscons.h>
46
47 #ifdef EVDEV_SUPPORT
48 #include <dev/evdev/input.h>
49 #include <dev/evdev/evdev.h>
50 #endif
51
52 #ifndef SC_NO_SYSMOUSE
53
54 /* local variables */
55 static struct tty *sysmouse_tty;
56 static int mouse_level; /* sysmouse protocol level */
57 static mousestatus_t mouse_status;
58
59 #ifdef EVDEV_SUPPORT
60 static struct evdev_dev *sysmouse_evdev;
61
62 static void
smdev_evdev_init(void)63 smdev_evdev_init(void)
64 {
65 int i;
66
67 sysmouse_evdev = evdev_alloc();
68 evdev_set_name(sysmouse_evdev, "System mouse");
69 evdev_set_phys(sysmouse_evdev, "sysmouse");
70 evdev_set_id(sysmouse_evdev, BUS_VIRTUAL, 0, 0, 0);
71 evdev_support_prop(sysmouse_evdev, INPUT_PROP_POINTER);
72 evdev_support_event(sysmouse_evdev, EV_SYN);
73 evdev_support_event(sysmouse_evdev, EV_REL);
74 evdev_support_event(sysmouse_evdev, EV_KEY);
75 evdev_support_rel(sysmouse_evdev, REL_X);
76 evdev_support_rel(sysmouse_evdev, REL_Y);
77 evdev_support_rel(sysmouse_evdev, REL_WHEEL);
78 evdev_support_rel(sysmouse_evdev, REL_HWHEEL);
79 for (i = 0; i < 8; i++)
80 evdev_support_key(sysmouse_evdev, BTN_MOUSE + i);
81 if (evdev_register(sysmouse_evdev)) {
82 evdev_free(sysmouse_evdev);
83 sysmouse_evdev = NULL;
84 }
85 }
86
87 static void
smdev_evdev_write(int x,int y,int z,int buttons)88 smdev_evdev_write(int x, int y, int z, int buttons)
89 {
90
91 if (sysmouse_evdev == NULL || !(evdev_rcpt_mask & EVDEV_RCPT_SYSMOUSE))
92 return;
93
94 evdev_push_event(sysmouse_evdev, EV_REL, REL_X, x);
95 evdev_push_event(sysmouse_evdev, EV_REL, REL_Y, y);
96 switch (evdev_sysmouse_t_axis) {
97 case EVDEV_SYSMOUSE_T_AXIS_PSM:
98 switch (z) {
99 case 1:
100 case -1:
101 evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z);
102 break;
103 case 2:
104 case -2:
105 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, z / 2);
106 break;
107 }
108 break;
109 case EVDEV_SYSMOUSE_T_AXIS_UMS:
110 if (buttons & (1 << 6))
111 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, 1);
112 else if (buttons & (1 << 5))
113 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, -1);
114 buttons &= ~((1 << 5)|(1 << 6));
115 /* PASSTHROUGH */
116 case EVDEV_SYSMOUSE_T_AXIS_NONE:
117 default:
118 evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z);
119 }
120 evdev_push_mouse_btn(sysmouse_evdev, buttons);
121 evdev_sync(sysmouse_evdev);
122 }
123 #endif
124
125 static void
smdev_close(struct tty * tp)126 smdev_close(struct tty *tp)
127 {
128 mouse_level = 0;
129 }
130
131 static int
smdev_ioctl(struct tty * tp,u_long cmd,caddr_t data,struct thread * td)132 smdev_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
133 {
134 mousehw_t *hw;
135 mousemode_t *mode;
136
137 switch (cmd) {
138 case MOUSE_GETHWINFO: /* get device information */
139 hw = (mousehw_t *)data;
140 hw->buttons = 10; /* XXX unknown */
141 hw->iftype = MOUSE_IF_SYSMOUSE;
142 hw->type = MOUSE_MOUSE;
143 hw->model = MOUSE_MODEL_GENERIC;
144 hw->hwid = 0;
145 return 0;
146
147 case MOUSE_GETMODE: /* get protocol/mode */
148 mode = (mousemode_t *)data;
149 mode->level = mouse_level;
150 switch (mode->level) {
151 case 0: /* emulate MouseSystems protocol */
152 mode->protocol = MOUSE_PROTO_MSC;
153 mode->rate = -1; /* unknown */
154 mode->resolution = -1; /* unknown */
155 mode->accelfactor = 0; /* disabled */
156 mode->packetsize = MOUSE_MSC_PACKETSIZE;
157 mode->syncmask[0] = MOUSE_MSC_SYNCMASK;
158 mode->syncmask[1] = MOUSE_MSC_SYNC;
159 break;
160
161 case 1: /* sysmouse protocol */
162 mode->protocol = MOUSE_PROTO_SYSMOUSE;
163 mode->rate = -1;
164 mode->resolution = -1;
165 mode->accelfactor = 0;
166 mode->packetsize = MOUSE_SYS_PACKETSIZE;
167 mode->syncmask[0] = MOUSE_SYS_SYNCMASK;
168 mode->syncmask[1] = MOUSE_SYS_SYNC;
169 break;
170 }
171 return 0;
172
173 case MOUSE_SETMODE: /* set protocol/mode */
174 mode = (mousemode_t *)data;
175 if (mode->level == -1)
176 ; /* don't change the current setting */
177 else if ((mode->level < 0) || (mode->level > 1))
178 return EINVAL;
179 else
180 mouse_level = mode->level;
181 return 0;
182
183 case MOUSE_GETLEVEL: /* get operation level */
184 *(int *)data = mouse_level;
185 return 0;
186
187 case MOUSE_SETLEVEL: /* set operation level */
188 if ((*(int *)data < 0) || (*(int *)data > 1))
189 return EINVAL;
190 mouse_level = *(int *)data;
191 return 0;
192
193 case MOUSE_GETSTATUS: /* get accumulated mouse events */
194 *(mousestatus_t *)data = mouse_status;
195 mouse_status.flags = 0;
196 mouse_status.obutton = mouse_status.button;
197 mouse_status.dx = 0;
198 mouse_status.dy = 0;
199 mouse_status.dz = 0;
200 return 0;
201
202 case MOUSE_READSTATE: /* read status from the device */
203 case MOUSE_READDATA: /* read data from the device */
204 return ENODEV;
205 }
206
207 return (ENOIOCTL);
208 }
209
210 static int
smdev_param(struct tty * tp,struct termios * t)211 smdev_param(struct tty *tp, struct termios *t)
212 {
213
214 /*
215 * Set the output baud rate to zero. The mouse device supports
216 * no output, so we don't want to waste buffers.
217 */
218 t->c_ispeed = TTYDEF_SPEED;
219 t->c_ospeed = B0;
220
221 return (0);
222 }
223
224 static struct ttydevsw smdev_ttydevsw = {
225 .tsw_flags = TF_NOPREFIX,
226 .tsw_close = smdev_close,
227 .tsw_ioctl = smdev_ioctl,
228 .tsw_param = smdev_param,
229 };
230
231 static void
sm_attach_mouse(void * unused)232 sm_attach_mouse(void *unused)
233 {
234 if (!vty_enabled(VTY_SC))
235 return;
236 sysmouse_tty = tty_alloc(&smdev_ttydevsw, NULL);
237 tty_makedev(sysmouse_tty, NULL, "sysmouse");
238 #ifdef EVDEV_SUPPORT
239 smdev_evdev_init();
240 #endif
241 }
242
243 SYSINIT(sysmouse, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sm_attach_mouse, NULL);
244
245 int
sysmouse_event(mouse_info_t * info)246 sysmouse_event(mouse_info_t *info)
247 {
248 /* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */
249 static int butmap[8] = {
250 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
251 MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
252 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
253 MOUSE_MSC_BUTTON3UP,
254 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
255 MOUSE_MSC_BUTTON2UP,
256 MOUSE_MSC_BUTTON1UP,
257 0,
258 };
259 u_char buf[8];
260 int x, y, z;
261 int i, flags = 0;
262
263 tty_lock(sysmouse_tty);
264
265 switch (info->operation) {
266 case MOUSE_ACTION:
267 mouse_status.button = info->u.data.buttons;
268 /* FALL THROUGH */
269 case MOUSE_MOTION_EVENT:
270 x = info->u.data.x;
271 y = info->u.data.y;
272 z = info->u.data.z;
273 break;
274 case MOUSE_BUTTON_EVENT:
275 x = y = z = 0;
276 if (info->u.event.value > 0)
277 mouse_status.button |= info->u.event.id;
278 else
279 mouse_status.button &= ~info->u.event.id;
280 break;
281 default:
282 goto done;
283 }
284
285 mouse_status.dx += x;
286 mouse_status.dy += y;
287 mouse_status.dz += z;
288 mouse_status.flags |= ((x || y || z) ? MOUSE_POSCHANGED : 0)
289 | (mouse_status.obutton ^ mouse_status.button);
290 flags = mouse_status.flags;
291 if (flags == 0)
292 goto done;
293
294 #ifdef EVDEV_SUPPORT
295 smdev_evdev_write(x, y, z, mouse_status.button);
296 if (evdev_is_grabbed(sysmouse_evdev))
297 goto done;
298 #endif
299
300 if (!tty_opened(sysmouse_tty))
301 goto done;
302
303 /* the first five bytes are compatible with MouseSystems' */
304 buf[0] = MOUSE_MSC_SYNC
305 | butmap[mouse_status.button & MOUSE_STDBUTTONS];
306 x = imax(imin(x, 255), -256);
307 buf[1] = x >> 1;
308 buf[3] = x - buf[1];
309 y = -imax(imin(y, 255), -256);
310 buf[2] = y >> 1;
311 buf[4] = y - buf[2];
312 for (i = 0; i < MOUSE_MSC_PACKETSIZE; ++i)
313 ttydisc_rint(sysmouse_tty, buf[i], 0);
314 if (mouse_level >= 1) {
315 /* extended part */
316 z = imax(imin(z, 127), -128);
317 buf[5] = (z >> 1) & 0x7f;
318 buf[6] = (z - (z >> 1)) & 0x7f;
319 /* buttons 4-10 */
320 buf[7] = (~mouse_status.button >> 3) & 0x7f;
321 for (i = MOUSE_MSC_PACKETSIZE; i < MOUSE_SYS_PACKETSIZE; ++i)
322 ttydisc_rint(sysmouse_tty, buf[i], 0);
323 }
324 ttydisc_rint_done(sysmouse_tty);
325
326 done: tty_unlock(sysmouse_tty);
327 return (flags);
328 }
329
330 #endif /* !SC_NO_SYSMOUSE */
331