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