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 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 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_WSP: /* 3 */ 98 if (buttons & (1 << 5)) { 99 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, z); 100 buttons &= ~(1 << 5); 101 } else { 102 evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z); 103 } 104 break; 105 case EVDEV_SYSMOUSE_T_AXIS_PSM: /* 2 */ 106 switch (z) { 107 case 1: 108 case -1: 109 evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z); 110 break; 111 case 2: 112 case -2: 113 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, z / 2); 114 break; 115 } 116 break; 117 case EVDEV_SYSMOUSE_T_AXIS_UMS: /* 1 */ 118 if (buttons & (1 << 6)) 119 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, 1); 120 else if (buttons & (1 << 5)) 121 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, -1); 122 buttons &= ~((1 << 5)|(1 << 6)); 123 /* PASSTHROUGH */ 124 case EVDEV_SYSMOUSE_T_AXIS_NONE: /* 0 */ 125 default: 126 evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z); 127 } 128 evdev_push_mouse_btn(sysmouse_evdev, buttons); 129 evdev_sync(sysmouse_evdev); 130 } 131 #endif 132 133 static void 134 smdev_close(struct tty *tp) 135 { 136 mouse_level = 0; 137 } 138 139 static int 140 smdev_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) 141 { 142 mousehw_t *hw; 143 mousemode_t *mode; 144 145 switch (cmd) { 146 case MOUSE_GETHWINFO: /* get device information */ 147 hw = (mousehw_t *)data; 148 hw->buttons = 10; /* XXX unknown */ 149 hw->iftype = MOUSE_IF_SYSMOUSE; 150 hw->type = MOUSE_MOUSE; 151 hw->model = MOUSE_MODEL_GENERIC; 152 hw->hwid = 0; 153 return 0; 154 155 case MOUSE_GETMODE: /* get protocol/mode */ 156 mode = (mousemode_t *)data; 157 mode->level = mouse_level; 158 switch (mode->level) { 159 case 0: /* emulate MouseSystems protocol */ 160 mode->protocol = MOUSE_PROTO_MSC; 161 mode->rate = -1; /* unknown */ 162 mode->resolution = -1; /* unknown */ 163 mode->accelfactor = 0; /* disabled */ 164 mode->packetsize = MOUSE_MSC_PACKETSIZE; 165 mode->syncmask[0] = MOUSE_MSC_SYNCMASK; 166 mode->syncmask[1] = MOUSE_MSC_SYNC; 167 break; 168 169 case 1: /* sysmouse protocol */ 170 mode->protocol = MOUSE_PROTO_SYSMOUSE; 171 mode->rate = -1; 172 mode->resolution = -1; 173 mode->accelfactor = 0; 174 mode->packetsize = MOUSE_SYS_PACKETSIZE; 175 mode->syncmask[0] = MOUSE_SYS_SYNCMASK; 176 mode->syncmask[1] = MOUSE_SYS_SYNC; 177 break; 178 } 179 return 0; 180 181 case MOUSE_SETMODE: /* set protocol/mode */ 182 mode = (mousemode_t *)data; 183 if (mode->level == -1) 184 ; /* don't change the current setting */ 185 else if ((mode->level < 0) || (mode->level > 1)) 186 return EINVAL; 187 else 188 mouse_level = mode->level; 189 return 0; 190 191 case MOUSE_GETLEVEL: /* get operation level */ 192 *(int *)data = mouse_level; 193 return 0; 194 195 case MOUSE_SETLEVEL: /* set operation level */ 196 if ((*(int *)data < 0) || (*(int *)data > 1)) 197 return EINVAL; 198 mouse_level = *(int *)data; 199 return 0; 200 201 case MOUSE_GETSTATUS: /* get accumulated mouse events */ 202 *(mousestatus_t *)data = mouse_status; 203 mouse_status.flags = 0; 204 mouse_status.obutton = mouse_status.button; 205 mouse_status.dx = 0; 206 mouse_status.dy = 0; 207 mouse_status.dz = 0; 208 return 0; 209 210 case MOUSE_READSTATE: /* read status from the device */ 211 case MOUSE_READDATA: /* read data from the device */ 212 return ENODEV; 213 } 214 215 return (ENOIOCTL); 216 } 217 218 static int 219 smdev_param(struct tty *tp, struct termios *t) 220 { 221 222 /* 223 * Set the output baud rate to zero. The mouse device supports 224 * no output, so we don't want to waste buffers. 225 */ 226 t->c_ispeed = TTYDEF_SPEED; 227 t->c_ospeed = B0; 228 229 return (0); 230 } 231 232 static struct ttydevsw smdev_ttydevsw = { 233 .tsw_flags = TF_NOPREFIX, 234 .tsw_close = smdev_close, 235 .tsw_ioctl = smdev_ioctl, 236 .tsw_param = smdev_param, 237 }; 238 239 static void 240 sm_attach_mouse(void *unused) 241 { 242 if (!vty_enabled(VTY_SC)) 243 return; 244 sysmouse_tty = tty_alloc(&smdev_ttydevsw, NULL); 245 tty_makedev(sysmouse_tty, NULL, "sysmouse"); 246 #ifdef EVDEV_SUPPORT 247 smdev_evdev_init(); 248 #endif 249 } 250 251 SYSINIT(sysmouse, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sm_attach_mouse, NULL); 252 253 int 254 sysmouse_event(mouse_info_t *info) 255 { 256 /* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */ 257 static int butmap[8] = { 258 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, 259 MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, 260 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP, 261 MOUSE_MSC_BUTTON3UP, 262 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP, 263 MOUSE_MSC_BUTTON2UP, 264 MOUSE_MSC_BUTTON1UP, 265 0, 266 }; 267 u_char buf[8]; 268 int x, y, z; 269 int i, flags = 0; 270 271 tty_lock(sysmouse_tty); 272 273 switch (info->operation) { 274 case MOUSE_ACTION: 275 mouse_status.button = info->u.data.buttons; 276 /* FALL THROUGH */ 277 case MOUSE_MOTION_EVENT: 278 x = info->u.data.x; 279 y = info->u.data.y; 280 z = info->u.data.z; 281 break; 282 case MOUSE_BUTTON_EVENT: 283 x = y = z = 0; 284 if (info->u.event.value > 0) 285 mouse_status.button |= info->u.event.id; 286 else 287 mouse_status.button &= ~info->u.event.id; 288 break; 289 default: 290 goto done; 291 } 292 293 mouse_status.dx += x; 294 mouse_status.dy += y; 295 mouse_status.dz += z; 296 mouse_status.flags |= ((x || y || z) ? MOUSE_POSCHANGED : 0) 297 | (mouse_status.obutton ^ mouse_status.button); 298 flags = mouse_status.flags; 299 if (flags == 0) 300 goto done; 301 302 #ifdef EVDEV_SUPPORT 303 smdev_evdev_write(x, y, z, mouse_status.button); 304 if (evdev_is_grabbed(sysmouse_evdev)) 305 goto done; 306 #endif 307 308 if (!tty_opened(sysmouse_tty)) 309 goto done; 310 311 /* the first five bytes are compatible with MouseSystems' */ 312 buf[0] = MOUSE_MSC_SYNC 313 | butmap[mouse_status.button & MOUSE_STDBUTTONS]; 314 x = imax(imin(x, 255), -256); 315 buf[1] = x >> 1; 316 buf[3] = x - buf[1]; 317 y = -imax(imin(y, 255), -256); 318 buf[2] = y >> 1; 319 buf[4] = y - buf[2]; 320 for (i = 0; i < MOUSE_MSC_PACKETSIZE; ++i) 321 ttydisc_rint(sysmouse_tty, buf[i], 0); 322 if (mouse_level >= 1) { 323 /* extended part */ 324 z = imax(imin(z, 127), -128); 325 buf[5] = (z >> 1) & 0x7f; 326 buf[6] = (z - (z >> 1)) & 0x7f; 327 /* buttons 4-10 */ 328 buf[7] = (~mouse_status.button >> 3) & 0x7f; 329 for (i = MOUSE_MSC_PACKETSIZE; i < MOUSE_SYS_PACKETSIZE; ++i) 330 ttydisc_rint(sysmouse_tty, buf[i], 0); 331 } 332 ttydisc_rint_done(sysmouse_tty); 333 334 done: tty_unlock(sysmouse_tty); 335 return (flags); 336 } 337 338 #endif /* !SC_NO_SYSMOUSE */ 339