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