vt_sysmouse.c revision 268366
1199458Sjilles/*- 2199458Sjilles * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 3199458Sjilles * All rights reserved. 4199458Sjilles * 5199458Sjilles * Copyright (c) 2009 The FreeBSD Foundation 6199458Sjilles * All rights reserved. 7199458Sjilles * 8199458Sjilles * This software was developed by Ed Schouten under sponsorship from the 9199458Sjilles * FreeBSD Foundation. 10199458Sjilles * 11199458Sjilles * Redistribution and use in source and binary forms, with or without 12199458Sjilles * modification, are permitted provided that the following conditions 13199458Sjilles * are met: 14199458Sjilles * 1. Redistributions of source code must retain the above copyright 15199458Sjilles * notice, this list of conditions and the following disclaimer. 16199458Sjilles * 2. Redistributions in binary form must reproduce the above copyright 17199458Sjilles * notice, this list of conditions and the following disclaimer in the 18199458Sjilles * documentation and/or other materials provided with the distribution. 19199458Sjilles * 20199458Sjilles * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21199458Sjilles * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22199458Sjilles * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23199458Sjilles * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24199458Sjilles * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25199458Sjilles * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26199458Sjilles * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27199458Sjilles * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28199458Sjilles * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29199458Sjilles * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30199458Sjilles * SUCH DAMAGE. 31199458Sjilles */ 32199458Sjilles 33199458Sjilles#include <sys/cdefs.h> 34199458Sjilles__FBSDID("$FreeBSD: stable/10/sys/dev/vt/vt_sysmouse.c 268366 2014-07-07 14:16:05Z ray $"); 35199458Sjilles 36199458Sjilles#include <sys/param.h> 37199458Sjilles#include <sys/condvar.h> 38199458Sjilles#include <sys/consio.h> 39199458Sjilles#include <sys/fcntl.h> 40199458Sjilles#include <sys/filio.h> 41199458Sjilles#include <sys/kernel.h> 42199458Sjilles#include <sys/malloc.h> 43199458Sjilles#include <sys/poll.h> 44199458Sjilles#include <sys/random.h> 45199458Sjilles#include <sys/selinfo.h> 46199458Sjilles#include <sys/sigio.h> 47199458Sjilles#include <sys/signalvar.h> 48199458Sjilles#include <sys/systm.h> 49199458Sjilles#include <sys/uio.h> 50199458Sjilles 51199458Sjilles#include <dev/vt/vt.h> 52199458Sjilles 53199458Sjillesstatic d_open_t sysmouse_open; 54199458Sjillesstatic d_close_t sysmouse_close; 55199458Sjillesstatic d_read_t sysmouse_read; 56199458Sjillesstatic d_ioctl_t sysmouse_ioctl; 57199458Sjillesstatic d_poll_t sysmouse_poll; 58199458Sjilles 59199458Sjillesstatic struct cdevsw sysmouse_cdevsw = { 60199458Sjilles .d_version = D_VERSION, 61199458Sjilles .d_open = sysmouse_open, 62199458Sjilles .d_close = sysmouse_close, 63199458Sjilles .d_read = sysmouse_read, 64199458Sjilles .d_ioctl = sysmouse_ioctl, 65199458Sjilles .d_poll = sysmouse_poll, 66199458Sjilles .d_name = "sysmouse", 67199458Sjilles}; 68199458Sjilles 69199458Sjillesstatic struct mtx sysmouse_lock; 70199458Sjillesstatic struct cv sysmouse_sleep; 71199458Sjillesstatic struct selinfo sysmouse_bufpoll; 72199458Sjilles 73199458Sjillesstatic int sysmouse_level; 74199458Sjillesstatic mousestatus_t sysmouse_status; 75199458Sjillesstatic int sysmouse_flags; 76199458Sjilles#define SM_ASYNC 0x1 77199458Sjillesstatic struct sigio *sysmouse_sigio; 78199458Sjilles 79199458Sjilles#define SYSMOUSE_MAXFRAMES 250 /* 2 KB */ 80199458Sjillesstatic MALLOC_DEFINE(M_SYSMOUSE, "sysmouse", "sysmouse device"); 81199458Sjillesstatic unsigned char *sysmouse_buffer; 82199458Sjillesstatic unsigned int sysmouse_start, sysmouse_length; 83199458Sjilles 84199458Sjillesstatic int 85199458Sjillessysmouse_buf_read(struct uio *uio, unsigned int length) 86199458Sjilles{ 87199458Sjilles unsigned char buf[MOUSE_SYS_PACKETSIZE]; 88199458Sjilles int error; 89199458Sjilles 90199458Sjilles if (sysmouse_buffer == NULL) 91199458Sjilles return (ENXIO); 92199458Sjilles else if (sysmouse_length == 0) 93199458Sjilles return (EWOULDBLOCK); 94199458Sjilles 95199458Sjilles memcpy(buf, sysmouse_buffer + 96199458Sjilles sysmouse_start * MOUSE_SYS_PACKETSIZE, MOUSE_SYS_PACKETSIZE); 97199458Sjilles sysmouse_start = (sysmouse_start + 1) % SYSMOUSE_MAXFRAMES; 98199458Sjilles sysmouse_length--; 99199458Sjilles 100199458Sjilles mtx_unlock(&sysmouse_lock); 101199458Sjilles error = uiomove(buf, length, uio); 102199458Sjilles mtx_lock(&sysmouse_lock); 103199458Sjilles 104199458Sjilles return (error); 105199458Sjilles} 106199458Sjilles 107199458Sjillesstatic void 108199458Sjillessysmouse_buf_store(const unsigned char buf[MOUSE_SYS_PACKETSIZE]) 109199458Sjilles{ 110199458Sjilles unsigned int idx; 111199458Sjilles 112199458Sjilles if (sysmouse_buffer == NULL || sysmouse_length == SYSMOUSE_MAXFRAMES) 113199458Sjilles return; 114199458Sjilles 115199458Sjilles idx = (sysmouse_start + sysmouse_length) % SYSMOUSE_MAXFRAMES; 116199458Sjilles memcpy(sysmouse_buffer + idx * MOUSE_SYS_PACKETSIZE, buf, 117199458Sjilles MOUSE_SYS_PACKETSIZE); 118199458Sjilles sysmouse_length++; 119199458Sjilles cv_broadcast(&sysmouse_sleep); 120199458Sjilles selwakeup(&sysmouse_bufpoll); 121199458Sjilles if (sysmouse_flags & SM_ASYNC && sysmouse_sigio != NULL) 122199458Sjilles pgsigio(&sysmouse_sigio, SIGIO, 0); 123199458Sjilles} 124199458Sjilles 125199458Sjillesvoid 126199458Sjillessysmouse_process_event(mouse_info_t *mi) 127199458Sjilles{ 128199458Sjilles /* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */ 129199458Sjilles static const int buttonmap[8] = { 130199458Sjilles MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, 131199458Sjilles MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, 132199458Sjilles MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP, 133199458Sjilles MOUSE_MSC_BUTTON3UP, 134199458Sjilles MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP, 135199458Sjilles MOUSE_MSC_BUTTON2UP, 136199458Sjilles MOUSE_MSC_BUTTON1UP, 137199458Sjilles 0, 138199458Sjilles }; 139199458Sjilles unsigned char buf[MOUSE_SYS_PACKETSIZE]; 140199458Sjilles int x, y, iy, z; 141199458Sjilles 142199458Sjilles random_harvest(mi, sizeof *mi, 2, RANDOM_MOUSE); 143199458Sjilles 144245506Sdelphij mtx_lock(&sysmouse_lock); 145199458Sjilles switch (mi->operation) { 146 case MOUSE_ACTION: 147 sysmouse_status.button = mi->u.data.buttons; 148 /* FALLTHROUGH */ 149 case MOUSE_MOTION_EVENT: 150 x = mi->u.data.x; 151 y = mi->u.data.y; 152 z = mi->u.data.z; 153 break; 154 case MOUSE_BUTTON_EVENT: 155 x = y = z = 0; 156 if (mi->u.event.value > 0) 157 sysmouse_status.button |= mi->u.event.id; 158 else 159 sysmouse_status.button &= ~mi->u.event.id; 160 break; 161 default: 162 goto done; 163 } 164 165 sysmouse_status.dx += x; 166 sysmouse_status.dy += y; 167 sysmouse_status.dz += z; 168 sysmouse_status.flags |= ((x || y || z) ? MOUSE_POSCHANGED : 0) | 169 (sysmouse_status.obutton ^ sysmouse_status.button); 170 if (sysmouse_status.flags == 0) 171 goto done; 172 173 174 /* The first five bytes are compatible with MouseSystems. */ 175 buf[0] = MOUSE_MSC_SYNC | 176 buttonmap[sysmouse_status.button & MOUSE_STDBUTTONS]; 177 x = imax(imin(x, 255), -256); 178 buf[1] = x >> 1; 179 buf[3] = x - buf[1]; 180 iy = -imax(imin(y, 255), -256); 181 buf[2] = iy >> 1; 182 buf[4] = iy - buf[2]; 183 /* Extended part. */ 184 z = imax(imin(z, 127), -128); 185 buf[5] = (z >> 1) & 0x7f; 186 buf[6] = (z - (z >> 1)) & 0x7f; 187 /* Buttons 4-10. */ 188 buf[7] = (~sysmouse_status.button >> 3) & 0x7f; 189 190 sysmouse_buf_store(buf); 191 192#ifndef SC_NO_CUTPASTE 193 mtx_unlock(&sysmouse_lock); 194 vt_mouse_event(mi->operation, x, y, mi->u.event.id, mi->u.event.value, 195 sysmouse_level); 196 return; 197#endif 198 199done: mtx_unlock(&sysmouse_lock); 200} 201 202static int 203sysmouse_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 204{ 205 void *buf; 206 207 buf = malloc(MOUSE_SYS_PACKETSIZE * SYSMOUSE_MAXFRAMES, 208 M_SYSMOUSE, M_WAITOK); 209 mtx_lock(&sysmouse_lock); 210 if (sysmouse_buffer == NULL) { 211 sysmouse_buffer = buf; 212 sysmouse_start = sysmouse_length = 0; 213 sysmouse_level = 0; 214 } else { 215 free(buf, M_SYSMOUSE); 216 } 217 mtx_unlock(&sysmouse_lock); 218 219 return (0); 220} 221 222static int 223sysmouse_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 224{ 225 226 mtx_lock(&sysmouse_lock); 227 free(sysmouse_buffer, M_SYSMOUSE); 228 sysmouse_buffer = NULL; 229 sysmouse_level = 0; 230 mtx_unlock(&sysmouse_lock); 231 232 return (0); 233} 234 235static int 236sysmouse_read(struct cdev *dev, struct uio *uio, int ioflag) 237{ 238 unsigned int length; 239 ssize_t oresid; 240 int error = 0; 241 242 oresid = uio->uio_resid; 243 244 mtx_lock(&sysmouse_lock); 245 length = sysmouse_level >= 1 ? MOUSE_SYS_PACKETSIZE : 246 MOUSE_MSC_PACKETSIZE; 247 248 while (uio->uio_resid >= length) { 249 error = sysmouse_buf_read(uio, length); 250 if (error == 0) { 251 /* Process the next frame. */ 252 continue; 253 } else if (error != EWOULDBLOCK) { 254 /* Error (e.g. EFAULT). */ 255 break; 256 } else { 257 /* Block. */ 258 if (oresid != uio->uio_resid || ioflag & O_NONBLOCK) 259 break; 260 error = cv_wait_sig(&sysmouse_sleep, &sysmouse_lock); 261 if (error != 0) 262 break; 263 } 264 } 265 mtx_unlock(&sysmouse_lock); 266 267 return (error); 268} 269 270static int 271sysmouse_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, 272 struct thread *td) 273{ 274 275 switch (cmd) { 276 case FIOASYNC: 277 mtx_lock(&sysmouse_lock); 278 if (*(int *)data) 279 sysmouse_flags |= SM_ASYNC; 280 else 281 sysmouse_flags &= ~SM_ASYNC; 282 mtx_unlock(&sysmouse_lock); 283 return (0); 284 case FIONBIO: 285 return (0); 286 case FIOGETOWN: 287 *(int *)data = fgetown(&sysmouse_sigio); 288 return (0); 289 case FIOSETOWN: 290 return (fsetown(*(int *)data, &sysmouse_sigio)); 291 case MOUSE_GETHWINFO: { 292 mousehw_t *hw = (mousehw_t *)data; 293 294 hw->buttons = 10; 295 hw->iftype = MOUSE_IF_SYSMOUSE; 296 hw->type = MOUSE_MOUSE; 297 hw->model = MOUSE_MODEL_GENERIC; 298 hw->hwid = 0; 299 300 return (0); 301 } 302 case MOUSE_GETLEVEL: 303 *(int *)data = sysmouse_level; 304 return (0); 305 case MOUSE_GETMODE: { 306 mousemode_t *mode = (mousemode_t *)data; 307 308 mode->rate = -1; 309 mode->resolution = -1; 310 mode->accelfactor = 0; 311 mode->level = sysmouse_level; 312 313 switch (mode->level) { 314 case 0: 315 mode->protocol = MOUSE_PROTO_MSC; 316 mode->packetsize = MOUSE_MSC_PACKETSIZE; 317 mode->syncmask[0] = MOUSE_MSC_SYNCMASK; 318 mode->syncmask[1] = MOUSE_MSC_SYNC; 319 break; 320 case 1: 321 mode->protocol = MOUSE_PROTO_SYSMOUSE; 322 mode->packetsize = MOUSE_SYS_PACKETSIZE; 323 mode->syncmask[0] = MOUSE_SYS_SYNCMASK; 324 mode->syncmask[1] = MOUSE_SYS_SYNC; 325 break; 326 } 327 328 return (0); 329 } 330 case MOUSE_GETSTATUS: 331 mtx_lock(&sysmouse_lock); 332 *(mousestatus_t *)data = sysmouse_status; 333 334 sysmouse_status.flags = 0; 335 sysmouse_status.obutton = sysmouse_status.button; 336 sysmouse_status.dx = 0; 337 sysmouse_status.dy = 0; 338 sysmouse_status.dz = 0; 339 mtx_unlock(&sysmouse_lock); 340 341 return (0); 342 case MOUSE_SETLEVEL: { 343 int level; 344 345 level = *(int *)data; 346 if (level != 0 && level != 1) 347 return (EINVAL); 348 349 sysmouse_level = level; 350#ifndef SC_NO_CUTPASTE 351 vt_mouse_state((level == 0)?VT_MOUSE_SHOW:VT_MOUSE_HIDE); 352#endif 353 return (0); 354 } 355 case MOUSE_SETMODE: { 356 mousemode_t *mode = (mousemode_t *)data; 357 358 switch (mode->level) { 359 case -1: 360 /* Do nothing. */ 361 break; 362 case 0: 363 case 1: 364 sysmouse_level = mode->level; 365#ifndef SC_NO_CUTPASTE 366 vt_mouse_state((mode->level == 0)?VT_MOUSE_SHOW: 367 VT_MOUSE_HIDE); 368#endif 369 break; 370 default: 371 return (EINVAL); 372 } 373 374 return (0); 375 } 376 case MOUSE_MOUSECHAR: 377 return (0); 378 default: 379#ifdef VT_SYSMOUSE_DEBUG 380 printf("sysmouse: unknown ioctl: %c:%lx\n", 381 (char)IOCGROUP(cmd), IOCBASECMD(cmd)); 382#endif 383 return (ENOIOCTL); 384 } 385} 386 387static int 388sysmouse_poll(struct cdev *dev, int events, struct thread *td) 389{ 390 int revents = 0; 391 392 mtx_lock(&sysmouse_lock); 393 if (events & (POLLIN|POLLRDNORM)) { 394 if (sysmouse_length > 0) 395 revents = events & (POLLIN|POLLRDNORM); 396 else 397 selrecord(td, &sysmouse_bufpoll); 398 } 399 mtx_unlock(&sysmouse_lock); 400 401 return (revents); 402} 403 404static void 405sysmouse_drvinit(void *unused) 406{ 407 408 if (!vty_enabled(VTY_VT)) 409 return; 410 mtx_init(&sysmouse_lock, "sysmouse", NULL, MTX_DEF); 411 cv_init(&sysmouse_sleep, "sysmrd"); 412 make_dev(&sysmouse_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 413 "sysmouse"); 414} 415 416SYSINIT(sysmouse, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sysmouse_drvinit, NULL); 417