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