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 * Copyright (c) 2009 The FreeBSD Foundation 8 * All rights reserved. 9 * 10 * This software was developed by Ed Schouten under sponsorship from the 11 * FreeBSD Foundation. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "opt_evdev.h" 36 37 #include <sys/param.h> 38 #include <sys/condvar.h> 39 #include <sys/consio.h> 40 #include <sys/fcntl.h> 41 #include <sys/filio.h> 42 #include <sys/lock.h> 43 #include <sys/kernel.h> 44 #include <sys/malloc.h> 45 #include <sys/mutex.h> 46 #include <sys/poll.h> 47 #include <sys/random.h> 48 #include <sys/selinfo.h> 49 #include <sys/sigio.h> 50 #include <sys/signalvar.h> 51 #include <sys/systm.h> 52 #include <sys/uio.h> 53 54 #include <dev/vt/vt.h> 55 56 #ifdef EVDEV_SUPPORT 57 #include <dev/evdev/input.h> 58 #include <dev/evdev/evdev.h> 59 #endif 60 61 static d_open_t sysmouse_open; 62 static d_close_t sysmouse_close; 63 static d_read_t sysmouse_read; 64 static d_ioctl_t sysmouse_ioctl; 65 static d_poll_t sysmouse_poll; 66 67 static struct cdevsw sysmouse_cdevsw = { 68 .d_version = D_VERSION, 69 .d_open = sysmouse_open, 70 .d_close = sysmouse_close, 71 .d_read = sysmouse_read, 72 .d_ioctl = sysmouse_ioctl, 73 .d_poll = sysmouse_poll, 74 .d_name = "sysmouse", 75 }; 76 77 static struct mtx sysmouse_lock; 78 static struct cv sysmouse_sleep; 79 static struct selinfo sysmouse_bufpoll; 80 81 static int sysmouse_level; 82 static mousestatus_t sysmouse_status; 83 static int sysmouse_flags; 84 #define SM_ASYNC 0x1 85 static struct sigio *sysmouse_sigio; 86 87 #define SYSMOUSE_MAXFRAMES 250 /* 2 KB */ 88 static MALLOC_DEFINE(M_SYSMOUSE, "sysmouse", "sysmouse device"); 89 static unsigned char *sysmouse_buffer; 90 static unsigned int sysmouse_start, sysmouse_length; 91 92 #ifdef EVDEV_SUPPORT 93 static struct evdev_dev *sysmouse_evdev; 94 95 static void 96 sysmouse_evdev_init(void) 97 { 98 int i; 99 100 sysmouse_evdev = evdev_alloc(); 101 evdev_set_name(sysmouse_evdev, "System mouse"); 102 evdev_set_phys(sysmouse_evdev, "sysmouse"); 103 evdev_set_id(sysmouse_evdev, BUS_VIRTUAL, 0, 0, 0); 104 evdev_support_prop(sysmouse_evdev, INPUT_PROP_POINTER); 105 evdev_support_event(sysmouse_evdev, EV_SYN); 106 evdev_support_event(sysmouse_evdev, EV_REL); 107 evdev_support_event(sysmouse_evdev, EV_KEY); 108 evdev_support_rel(sysmouse_evdev, REL_X); 109 evdev_support_rel(sysmouse_evdev, REL_Y); 110 evdev_support_rel(sysmouse_evdev, REL_WHEEL); 111 evdev_support_rel(sysmouse_evdev, REL_HWHEEL); 112 for (i = 0; i < 8; i++) 113 evdev_support_key(sysmouse_evdev, BTN_MOUSE + i); 114 if (evdev_register(sysmouse_evdev)) { 115 evdev_free(sysmouse_evdev); 116 sysmouse_evdev = NULL; 117 } 118 } 119 120 static void 121 sysmouse_evdev_store(int x, int y, int z, int buttons) 122 { 123 124 if (sysmouse_evdev == NULL || !(evdev_rcpt_mask & EVDEV_RCPT_SYSMOUSE)) 125 return; 126 127 evdev_push_event(sysmouse_evdev, EV_REL, REL_X, x); 128 evdev_push_event(sysmouse_evdev, EV_REL, REL_Y, y); 129 switch (evdev_sysmouse_t_axis) { 130 case EVDEV_SYSMOUSE_T_AXIS_WSP: /* 3 */ 131 if (buttons & (1 << 5)) { 132 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, z); 133 buttons &= ~(1 << 5); 134 } else { 135 evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z); 136 } 137 break; 138 case EVDEV_SYSMOUSE_T_AXIS_PSM: /* 2 */ 139 switch (z) { 140 case 1: 141 case -1: 142 evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z); 143 break; 144 case 2: 145 case -2: 146 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, z / 2); 147 break; 148 } 149 break; 150 case EVDEV_SYSMOUSE_T_AXIS_UMS: /* 1 */ 151 if (buttons & (1 << 6)) 152 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, 1); 153 else if (buttons & (1 << 5)) 154 evdev_push_rel(sysmouse_evdev, REL_HWHEEL, -1); 155 buttons &= ~((1 << 5)|(1 << 6)); 156 /* PASSTHROUGH */ 157 case EVDEV_SYSMOUSE_T_AXIS_NONE: /* 0 */ 158 default: 159 evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z); 160 } 161 evdev_push_mouse_btn(sysmouse_evdev, buttons); 162 evdev_sync(sysmouse_evdev); 163 } 164 #endif 165 166 static int 167 sysmouse_buf_read(struct uio *uio, unsigned int length) 168 { 169 unsigned char buf[MOUSE_SYS_PACKETSIZE]; 170 int error; 171 172 if (sysmouse_buffer == NULL) 173 return (ENXIO); 174 else if (sysmouse_length == 0) 175 return (EWOULDBLOCK); 176 177 memcpy(buf, sysmouse_buffer + 178 sysmouse_start * MOUSE_SYS_PACKETSIZE, MOUSE_SYS_PACKETSIZE); 179 sysmouse_start = (sysmouse_start + 1) % SYSMOUSE_MAXFRAMES; 180 sysmouse_length--; 181 182 mtx_unlock(&sysmouse_lock); 183 error = uiomove(buf, length, uio); 184 mtx_lock(&sysmouse_lock); 185 186 return (error); 187 } 188 189 static void 190 sysmouse_buf_store(const unsigned char buf[MOUSE_SYS_PACKETSIZE]) 191 { 192 unsigned int idx; 193 194 if (sysmouse_buffer == NULL || sysmouse_length == SYSMOUSE_MAXFRAMES) 195 return; 196 197 idx = (sysmouse_start + sysmouse_length) % SYSMOUSE_MAXFRAMES; 198 memcpy(sysmouse_buffer + idx * MOUSE_SYS_PACKETSIZE, buf, 199 MOUSE_SYS_PACKETSIZE); 200 sysmouse_length++; 201 cv_broadcast(&sysmouse_sleep); 202 selwakeup(&sysmouse_bufpoll); 203 if (sysmouse_flags & SM_ASYNC && sysmouse_sigio != NULL) 204 pgsigio(&sysmouse_sigio, SIGIO, 0); 205 } 206 207 void 208 sysmouse_process_event(mouse_info_t *mi) 209 { 210 /* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */ 211 static const int buttonmap[8] = { 212 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, 213 MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, 214 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP, 215 MOUSE_MSC_BUTTON3UP, 216 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP, 217 MOUSE_MSC_BUTTON2UP, 218 MOUSE_MSC_BUTTON1UP, 219 0, 220 }; 221 unsigned char buf[MOUSE_SYS_PACKETSIZE]; 222 int x, y, iy, z; 223 224 #ifdef RANDOM_ENABLE_MOUSE 225 random_harvest_queue(mi, sizeof *mi, RANDOM_MOUSE); 226 #endif 227 228 mtx_lock(&sysmouse_lock); 229 switch (mi->operation) { 230 case MOUSE_ACTION: 231 sysmouse_status.button = mi->u.data.buttons; 232 /* FALLTHROUGH */ 233 case MOUSE_MOTION_EVENT: 234 x = mi->u.data.x; 235 y = mi->u.data.y; 236 z = mi->u.data.z; 237 break; 238 case MOUSE_BUTTON_EVENT: 239 x = y = z = 0; 240 if (mi->u.event.value > 0) 241 sysmouse_status.button |= mi->u.event.id; 242 else 243 sysmouse_status.button &= ~mi->u.event.id; 244 break; 245 default: 246 goto done; 247 } 248 249 sysmouse_status.dx += x; 250 sysmouse_status.dy += y; 251 sysmouse_status.dz += z; 252 sysmouse_status.flags |= ((x || y || z) ? MOUSE_POSCHANGED : 0) | 253 (sysmouse_status.obutton ^ sysmouse_status.button); 254 if (sysmouse_status.flags == 0) 255 goto done; 256 257 #ifdef EVDEV_SUPPORT 258 sysmouse_evdev_store(x, y, z, sysmouse_status.button); 259 if (evdev_is_grabbed(sysmouse_evdev)) 260 goto done; 261 #endif 262 263 /* The first five bytes are compatible with MouseSystems. */ 264 buf[0] = MOUSE_MSC_SYNC | 265 buttonmap[sysmouse_status.button & MOUSE_STDBUTTONS]; 266 x = imax(imin(x, 255), -256); 267 buf[1] = x >> 1; 268 buf[3] = x - buf[1]; 269 iy = -imax(imin(y, 255), -256); 270 buf[2] = iy >> 1; 271 buf[4] = iy - buf[2]; 272 /* Extended part. */ 273 z = imax(imin(z, 127), -128); 274 buf[5] = (z >> 1) & 0x7f; 275 buf[6] = (z - (z >> 1)) & 0x7f; 276 /* Buttons 4-10. */ 277 buf[7] = (~sysmouse_status.button >> 3) & 0x7f; 278 279 sysmouse_buf_store(buf); 280 281 #ifndef SC_NO_CUTPASTE 282 mtx_unlock(&sysmouse_lock); 283 vt_mouse_event(mi->operation, x, y, mi->u.event.id, mi->u.event.value, 284 sysmouse_level); 285 return; 286 #endif 287 288 done: mtx_unlock(&sysmouse_lock); 289 } 290 291 static int 292 sysmouse_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 293 { 294 void *buf; 295 296 buf = malloc(MOUSE_SYS_PACKETSIZE * SYSMOUSE_MAXFRAMES, 297 M_SYSMOUSE, M_WAITOK); 298 mtx_lock(&sysmouse_lock); 299 if (sysmouse_buffer == NULL) { 300 sysmouse_buffer = buf; 301 sysmouse_start = sysmouse_length = 0; 302 sysmouse_level = 0; 303 } else { 304 free(buf, M_SYSMOUSE); 305 } 306 mtx_unlock(&sysmouse_lock); 307 308 return (0); 309 } 310 311 static int 312 sysmouse_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 313 { 314 315 mtx_lock(&sysmouse_lock); 316 free(sysmouse_buffer, M_SYSMOUSE); 317 sysmouse_buffer = NULL; 318 sysmouse_level = 0; 319 mtx_unlock(&sysmouse_lock); 320 321 return (0); 322 } 323 324 static int 325 sysmouse_read(struct cdev *dev, struct uio *uio, int ioflag) 326 { 327 unsigned int length; 328 ssize_t oresid; 329 int error = 0; 330 331 oresid = uio->uio_resid; 332 333 mtx_lock(&sysmouse_lock); 334 length = sysmouse_level >= 1 ? MOUSE_SYS_PACKETSIZE : 335 MOUSE_MSC_PACKETSIZE; 336 337 while (uio->uio_resid >= length) { 338 error = sysmouse_buf_read(uio, length); 339 if (error == 0) { 340 /* Process the next frame. */ 341 continue; 342 } else if (error != EWOULDBLOCK) { 343 /* Error (e.g. EFAULT). */ 344 break; 345 } else { 346 /* Block. */ 347 if (oresid != uio->uio_resid || ioflag & O_NONBLOCK) 348 break; 349 error = cv_wait_sig(&sysmouse_sleep, &sysmouse_lock); 350 if (error != 0) 351 break; 352 } 353 } 354 mtx_unlock(&sysmouse_lock); 355 356 return (error); 357 } 358 359 static int 360 sysmouse_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, 361 struct thread *td) 362 { 363 364 switch (cmd) { 365 case FIOASYNC: 366 mtx_lock(&sysmouse_lock); 367 if (*(int *)data) 368 sysmouse_flags |= SM_ASYNC; 369 else 370 sysmouse_flags &= ~SM_ASYNC; 371 mtx_unlock(&sysmouse_lock); 372 return (0); 373 case FIONBIO: 374 return (0); 375 case FIOGETOWN: 376 *(int *)data = fgetown(&sysmouse_sigio); 377 return (0); 378 case FIOSETOWN: 379 return (fsetown(*(int *)data, &sysmouse_sigio)); 380 case MOUSE_GETHWINFO: { 381 mousehw_t *hw = (mousehw_t *)data; 382 383 hw->buttons = 10; 384 hw->iftype = MOUSE_IF_SYSMOUSE; 385 hw->type = MOUSE_MOUSE; 386 hw->model = MOUSE_MODEL_GENERIC; 387 hw->hwid = 0; 388 389 return (0); 390 } 391 case MOUSE_GETLEVEL: 392 *(int *)data = sysmouse_level; 393 return (0); 394 case MOUSE_GETMODE: { 395 mousemode_t *mode = (mousemode_t *)data; 396 397 mode->rate = -1; 398 mode->resolution = -1; 399 mode->accelfactor = 0; 400 mode->level = sysmouse_level; 401 402 switch (mode->level) { 403 case 0: 404 mode->protocol = MOUSE_PROTO_MSC; 405 mode->packetsize = MOUSE_MSC_PACKETSIZE; 406 mode->syncmask[0] = MOUSE_MSC_SYNCMASK; 407 mode->syncmask[1] = MOUSE_MSC_SYNC; 408 break; 409 case 1: 410 mode->protocol = MOUSE_PROTO_SYSMOUSE; 411 mode->packetsize = MOUSE_SYS_PACKETSIZE; 412 mode->syncmask[0] = MOUSE_SYS_SYNCMASK; 413 mode->syncmask[1] = MOUSE_SYS_SYNC; 414 break; 415 } 416 417 return (0); 418 } 419 case MOUSE_GETSTATUS: 420 mtx_lock(&sysmouse_lock); 421 *(mousestatus_t *)data = sysmouse_status; 422 423 sysmouse_status.flags = 0; 424 sysmouse_status.obutton = sysmouse_status.button; 425 sysmouse_status.dx = 0; 426 sysmouse_status.dy = 0; 427 sysmouse_status.dz = 0; 428 mtx_unlock(&sysmouse_lock); 429 430 return (0); 431 case MOUSE_SETLEVEL: { 432 int level; 433 434 level = *(int *)data; 435 if (level != 0 && level != 1) 436 return (EINVAL); 437 438 sysmouse_level = level; 439 return (0); 440 } 441 case MOUSE_SETMODE: { 442 mousemode_t *mode = (mousemode_t *)data; 443 444 switch (mode->level) { 445 case -1: 446 /* Do nothing. */ 447 break; 448 case 0: 449 case 1: 450 sysmouse_level = mode->level; 451 break; 452 default: 453 return (EINVAL); 454 } 455 456 return (0); 457 } 458 case MOUSE_MOUSECHAR: 459 return (0); 460 default: 461 #ifdef VT_SYSMOUSE_DEBUG 462 printf("sysmouse: unknown ioctl: %c:%lx\n", 463 (char)IOCGROUP(cmd), IOCBASECMD(cmd)); 464 #endif 465 return (ENOIOCTL); 466 } 467 } 468 469 static int 470 sysmouse_poll(struct cdev *dev, int events, struct thread *td) 471 { 472 int revents = 0; 473 474 mtx_lock(&sysmouse_lock); 475 if (events & (POLLIN|POLLRDNORM)) { 476 if (sysmouse_length > 0) 477 revents = events & (POLLIN|POLLRDNORM); 478 else 479 selrecord(td, &sysmouse_bufpoll); 480 } 481 mtx_unlock(&sysmouse_lock); 482 483 return (revents); 484 } 485 486 static void 487 sysmouse_drvinit(void *unused) 488 { 489 490 if (!vty_enabled(VTY_VT)) 491 return; 492 mtx_init(&sysmouse_lock, "sysmouse", NULL, MTX_DEF); 493 cv_init(&sysmouse_sleep, "sysmrd"); 494 make_dev(&sysmouse_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 495 "sysmouse"); 496 #ifdef EVDEV_SUPPORT 497 sysmouse_evdev_init(); 498 #endif 499 } 500 501 SYSINIT(sysmouse, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sysmouse_drvinit, NULL); 502