sun_mouse.c revision ebac4eb7
1/* 2 * Copyright (c) 2004, 2022, Oracle and/or its affiliates. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23/* 24 * Copyright 1999-2001 The XFree86 Project, Inc. All Rights Reserved. 25 * 26 * Permission is hereby granted, free of charge, to any person obtaining a copy 27 * of this software and associated documentation files (the "Software"), to 28 * deal in the Software without restriction, including without limitation the 29 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 30 * sell copies of the Software, and to permit persons to whom the Software is 31 * furnished to do so, subject to the following conditions: 32 * 33 * The above copyright notice and this permission notice shall be included in 34 * all copies or substantial portions of the Software. 35 * 36 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 37 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 38 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 39 * XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 40 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 41 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 42 * 43 * Except as contained in this notice, the name of the XFree86 Project shall 44 * not be used in advertising or otherwise to promote the sale, use or other 45 * dealings in this Software without prior written authorization from the 46 * XFree86 Project. 47 */ 48 49#ifdef HAVE_CONFIG_H 50#include "config.h" 51#endif 52 53#ifdef HAVE_XORG_CONFIG_H 54#include <xorg-config.h> 55#endif 56 57#include <unistd.h> /* for ioctl(2) */ 58#include <sys/stropts.h> 59#include <sys/vuid_event.h> 60#include <sys/msio.h> 61#include <fcntl.h> 62#include <errno.h> 63#include "xorg-server.h" 64#include "xf86.h" 65#include "xf86_OSlib.h" 66#include "mouse.h" 67#include "xisb.h" 68#include "mipointer.h" 69#include "xf86Crtc.h" 70 71/* Wheel mouse support in VUID drivers in Solaris 9 updates & Solaris 10 */ 72#ifdef WHEEL_DEVID /* Defined in vuid_event.h if VUID wheel support present */ 73# define HAVE_VUID_WHEEL 74#endif 75#ifdef HAVE_VUID_WHEEL 76# include <sys/vuid_wheel.h> 77#endif 78 79#include <libdevinfo.h> 80 81/* Support for scaling absolute coordinates to screen size in 82 * Solaris 10 updates and beyond */ 83#if !defined(HAVE_ABSOLUTE_MOUSE_SCALING) 84# ifdef MSIOSRESOLUTION /* Defined in msio.h if scaling support present */ 85# define HAVE_ABSOLUTE_MOUSE_SCALING 86# endif 87#endif 88 89/* Names of protocols that are handled internally here. */ 90 91static const char *internalNames[] = { 92 "VUID", 93 NULL 94}; 95 96static const char *solarisMouseDevs[] = { 97 /* Device file: Protocol: */ 98 "/dev/mouse", "VUID", /* USB or SPARC */ 99#if defined(__i386) || defined(__x86) 100 "/dev/kdmouse", "PS/2", /* PS/2 */ 101#endif 102 NULL 103}; 104 105typedef struct _VuidMseRec { 106 struct _VuidMseRec *next; 107 InputInfoPtr pInfo; 108 Firm_event event; 109 unsigned char * buffer; 110 char * strmod; 111 Bool(*wrapped_device_control)(DeviceIntPtr device, int what); 112#ifdef HAVE_ABSOLUTE_MOUSE_SCALING 113 Ms_screen_resolution absres; 114#endif 115 OsTimerPtr remove_timer; /* Callback for removal on ENODEV */ 116 int relToAbs; 117 int absX; 118 int absY; 119} VuidMseRec, *VuidMsePtr; 120 121static VuidMsePtr vuidMouseList = NULL; 122 123static int vuidMouseProc(DeviceIntPtr pPointer, int what); 124static void vuidReadInput(InputInfoPtr pInfo); 125 126static int CheckRelToAbs(InputInfoPtr pInfo); 127static int CheckRelToAbsWalker(di_node_t node, void *arg); 128 129#ifdef HAVE_ABSOLUTE_MOUSE_SCALING 130# include "compat-api.h" 131 132static void vuidMouseSendScreenSize(ScreenPtr pScreen, VuidMsePtr pVuidMse); 133static void vuidMouseAdjustFrame(ADJUST_FRAME_ARGS_DECL); 134 135static unsigned long vuidMouseGeneration = 0; 136 137#if HAS_DEVPRIVATEKEYREC 138static DevPrivateKeyRec vuidMouseScreenIndex; 139#else 140static int vuidMouseScreenIndex; 141#endif /* HAS_DEVPRIVATEKEYREC */ 142 143#define vuidMouseGetScreenPrivate(s) ( \ 144 dixLookupPrivate(&(s)->devPrivates, &vuidMouseScreenIndex)) 145#define vuidMouseSetScreenPrivate(s,p) \ 146 dixSetPrivate(&(s)->devPrivates, &vuidMouseScreenIndex, (void *) p) 147#endif /* HAVE_ABSOLUTE_MOUSE_SCALING */ 148 149static inline 150VuidMsePtr getVuidMsePriv(InputInfoPtr pInfo) 151{ 152 VuidMsePtr m = vuidMouseList; 153 154 while ((m != NULL) && (m->pInfo != pInfo)) { 155 m = m->next; 156 } 157 158 return m; 159} 160 161/* Called from OsTimer callback, since removing a device from the device 162 list or changing pInfo->fd while xf86Wakeup is looping through the list 163 causes server crashes */ 164static CARD32 165vuidRemoveMouse(OsTimerPtr timer, CARD32 now, pointer arg) 166{ 167 InputInfoPtr pInfo = (InputInfoPtr) arg; 168 169 xf86DisableDevice(pInfo->dev, TRUE); 170 171 return 0; /* All done, don't set to run again */ 172} 173 174/* 175 * Initialize and enable the mouse wheel, if present. 176 * 177 * Returns 1 if mouse wheel was successfully enabled. 178 * Returns 0 if an error occurred or if there is no mouse wheel. 179 */ 180static int 181vuidMouseWheelInit(InputInfoPtr pInfo) 182{ 183#ifdef HAVE_VUID_WHEEL 184 wheel_state wstate; 185 int nwheel = -1; 186 int i; 187 188 wstate.vers = VUID_WHEEL_STATE_VERS; 189 wstate.id = 0; 190 wstate.stateflags = (uint32_t) -1; 191 192 SYSCALL(i = ioctl(pInfo->fd, VUIDGWHEELCOUNT, &nwheel)); 193 if (i != 0) 194 return (0); 195 196 SYSCALL(i = ioctl(pInfo->fd, VUIDGWHEELSTATE, &wstate)); 197 if (i != 0) { 198 xf86Msg(X_WARNING, "%s: couldn't get wheel state\n", pInfo->name); 199 return (0); 200 } 201 202 wstate.stateflags |= VUID_WHEEL_STATE_ENABLED; 203 204 SYSCALL(i = ioctl(pInfo->fd, VUIDSWHEELSTATE, &wstate)); 205 if (i != 0) { 206 xf86Msg(X_WARNING, "%s: couldn't enable wheel\n", pInfo->name); 207 return (0); 208 } 209 210 return (1); 211#else 212 return (0); 213#endif 214} 215 216 217/* This function is called when the protocol is "VUID". */ 218static Bool 219vuidPreInit(InputInfoPtr pInfo, const char *protocol, int flags) 220{ 221 MouseDevPtr pMse = pInfo->private; 222 VuidMsePtr pVuidMse; 223 224 /* Ensure we don't add the same device twice */ 225 if (getVuidMsePriv(pInfo) != NULL) 226 return TRUE; 227 228 pVuidMse = calloc(sizeof(VuidMseRec), 1); 229 if (pVuidMse == NULL) { 230 xf86Msg(X_ERROR, "%s: cannot allocate VuidMouseRec\n", pInfo->name); 231 free(pMse); 232 return FALSE; 233 } 234 235 pVuidMse->buffer = (unsigned char *)&pVuidMse->event; 236 pVuidMse->strmod = xf86SetStrOption(pInfo->options, "StreamsModule", NULL); 237 pVuidMse->relToAbs = xf86SetIntOption(pInfo->options, "RelToAbs", -1); 238 if (pVuidMse->relToAbs == -1) 239 pVuidMse->relToAbs = CheckRelToAbs(pInfo); 240 pVuidMse->absX = 0; 241 pVuidMse->absY = 0; 242 243 /* Setup the local procs. */ 244 pVuidMse->wrapped_device_control = pInfo->device_control; 245 pInfo->device_control = vuidMouseProc; 246 pInfo->read_input = vuidReadInput; 247 248 pMse->xisbscale = sizeof(Firm_event); 249 250#ifdef HAVE_ABSOLUTE_MOUSE_SCALING 251 pVuidMse->absres.height = pVuidMse->absres.width = 0; 252#endif 253 pVuidMse->pInfo = pInfo; 254 pVuidMse->next = vuidMouseList; 255 vuidMouseList = pVuidMse; 256 257#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12 258 pInfo->flags |= XI86_CONFIGURED; 259#endif 260 return TRUE; 261} 262 263/* 264 * It seems that the mouse that is presented by the Emulex ILOM 265 * device (USB 0x430, 0xa101 and USB 0x430, 0xa102) sends relative 266 * mouse movements. But relative mouse movements are subject to 267 * acceleration. This causes the position indicated on the ILOM 268 * window to not match what the Xorg server actually has. This 269 * makes the mouse in this environment rather unusable. So, for the 270 * Emulex ILOM device, we will change all relative mouse movements 271 * into absolute mouse movements, making it appear more like a 272 * tablet. This will not be subject to acceleration, and this 273 * should keep the ILOM window and Xorg server with the same values 274 * for the coordinates of the mouse. 275 */ 276 277typedef struct reltoabs_match { 278 int matched; 279 char const *matchname; 280 } reltoabs_match_t; 281 282/* Sun Microsystems, keyboard / mouse */ 283#define RELTOABS_MATCH1 "usbif430,a101.config1.1" 284/* Sun Microsystems, keyboard / mouse / storage */ 285#define RELTOABS_MATCH2 "usbif430,a102.config1.1" 286 287static int 288CheckRelToAbsWalker(di_node_t node, void *arg) 289{ 290 di_minor_t minor; 291 char *path; 292 int numvalues; 293 int valueon; 294 char const *stringptr; 295 int status; 296 reltoabs_match_t *const matchptr = (reltoabs_match_t *)arg; 297 char *stringvalues; 298 299 for (minor = di_minor_next(node, DI_MINOR_NIL); 300 minor != DI_MINOR_NIL; 301 minor = di_minor_next(node, minor)) { 302 path = di_devfs_minor_path(minor); 303 status = path != NULL && strcmp(path, matchptr -> matchname) == 0; 304 di_devfs_path_free(path); 305 if (status) 306 break; 307 } 308 309 if (minor == DI_MINOR_NIL) 310 return (DI_WALK_CONTINUE); 311 312 numvalues = di_prop_lookup_strings(DDI_DEV_T_ANY, node, 313 "compatible", &stringvalues); 314 if (numvalues <= 0) 315 return (DI_WALK_CONTINUE); 316 317 for (valueon = 0, stringptr = stringvalues; valueon < numvalues; 318 valueon++, stringptr += strlen(stringptr) + 1) { 319 if (strcmp(stringptr, RELTOABS_MATCH1) == 0) { 320 matchptr -> matched = 1; 321 return (DI_WALK_TERMINATE); 322 } 323 if (strcmp(stringptr, RELTOABS_MATCH2) == 0) { 324 matchptr -> matched = 2; 325 return (DI_WALK_TERMINATE); 326 } 327 } 328 return (DI_WALK_CONTINUE); 329} 330 331static int 332CheckRelToAbs(InputInfoPtr pInfo) 333{ 334 char const *device; 335 char const *matchname; 336 ssize_t readstatus; 337 di_node_t node; 338 struct stat statbuf; 339 char linkname[512]; 340 reltoabs_match_t reltoabs_match; 341 342 device = xf86CheckStrOption(pInfo->options, "Device", NULL); 343 if (device == NULL) 344 return (0); 345 346 matchname = device; 347 348 if (lstat(device, &statbuf) == 0 && 349 (statbuf.st_mode & S_IFMT) == S_IFLNK) { 350 readstatus = readlink(device, linkname, sizeof(linkname)); 351 if (readstatus > 0 && readstatus < (ssize_t) sizeof(linkname)) { 352 linkname[readstatus] = 0; 353 matchname = linkname; 354 if (strncmp(matchname, "../..", sizeof("../..") - 1) == 0) 355 matchname += sizeof("../..") - 1; 356 } 357 } 358 359 if (strncmp(matchname, "/devices", sizeof("/devices") - 1) == 0) 360 matchname += sizeof("/devices") - 1; 361 362 reltoabs_match.matched = 0; 363 reltoabs_match.matchname = matchname; 364 365 node = di_init("/", DINFOCPYALL); 366 if (node == DI_NODE_NIL) 367 return (0); 368 369 di_walk_node(node, DI_WALK_CLDFIRST, (void *)&reltoabs_match, 370 CheckRelToAbsWalker); 371 372 di_fini(node); 373 374 return (reltoabs_match.matched != 0); 375} 376 377static void 378vuidFlushAbsEvents(InputInfoPtr pInfo, int absX, int absY, 379 Bool *absXset, Bool *absYset) 380{ 381#ifdef DEBUG 382 ErrorF("vuidFlushAbsEvents: %d,%d (set: %d, %d)\n", absX, absY, 383 *absXset, *absYset); 384#endif 385 if ((*absXset) && (*absYset)) { 386 xf86PostMotionEvent(pInfo->dev, 387 /* is_absolute: */ TRUE, 388 /* first_valuator: */ 0, 389 /* num_valuators: */ 2, 390 absX, absY); 391 } else if (*absXset) { 392 xf86PostMotionEvent(pInfo->dev, 393 /* is_absolute: */ TRUE, 394 /* first_valuator: */ 0, 395 /* num_valuators: */ 1, 396 absX); 397 } else if (*absYset) { 398 xf86PostMotionEvent(pInfo->dev, 399 /* is_absolute: */ TRUE, 400 /* first_valuator: */ 1, 401 /* num_valuators: */ 1, 402 absY); 403 } 404 405 *absXset = FALSE; 406 *absYset = FALSE; 407} 408 409static void 410vuidReadInput(InputInfoPtr pInfo) 411{ 412 MouseDevPtr pMse; 413 VuidMsePtr pVuidMse; 414 int buttons; 415 int dx = 0, dy = 0, dz = 0, dw = 0; 416 ssize_t n; 417 unsigned char *pBuf; 418 int absX = 0, absY = 0; 419 int hdisplay = 0, vdisplay = 0; 420 Bool absXset = FALSE, absYset = FALSE; 421 int relToAbs; 422 423 pMse = pInfo->private; 424 buttons = pMse->lastButtons; 425 pVuidMse = getVuidMsePriv(pInfo); 426 if (pVuidMse == NULL) { 427 xf86Msg(X_ERROR, "%s: cannot locate VuidMsePtr\n", pInfo->name); 428 return; 429 } 430 pBuf = pVuidMse->buffer; 431 relToAbs = pVuidMse->relToAbs; 432 if (relToAbs) { 433 ScreenPtr pScreen = miPointerGetScreen(pInfo->dev); 434 ScrnInfoPtr pScr = XF86SCRNINFO(pScreen); 435 436 if (pScr->currentMode) { 437 hdisplay = pScr->currentMode->HDisplay; 438 vdisplay = pScr->currentMode->VDisplay; 439 } 440 absX = pVuidMse->absX; 441 absY = pVuidMse->absY; 442 } 443 444 do { 445 n = read(pInfo->fd, pBuf, sizeof(Firm_event)); 446 447 if (n == 0) { 448 break; 449 } else if (n == -1) { 450 switch (errno) { 451 case EAGAIN: /* Nothing to read now */ 452 n = 0; /* End loop, go on to flush events & return */ 453 continue; 454 case EINTR: /* Interrupted, try again */ 455 continue; 456 case ENODEV: /* May happen when USB mouse is unplugged */ 457 /* We use X_NONE here because it didn't alloc since we 458 may be called from SIGIO handler. No longer true for 459 sigsafe logging, but matters for older servers */ 460 LogMessageVerbSigSafe(X_NONE, 0, 461 "%s: Device no longer present - removing.\n", 462 pInfo->name); 463 xf86RemoveEnabledDevice(pInfo); 464 pVuidMse->remove_timer = 465 TimerSet(pVuidMse->remove_timer, 0, 1, 466 vuidRemoveMouse, pInfo); 467 return; 468 default: /* All other errors */ 469 /* We use X_NONE here because it didn't alloc since we 470 may be called from SIGIO handler. No longer true for 471 sigsafe logging, but matters for older servers */ 472 LogMessageVerbSigSafe(X_NONE, 0, "%s: Read error: %s\n", 473 pInfo->name, strerror(errno)); 474 return; 475 } 476 } else if (n != sizeof(Firm_event)) { 477 xf86Msg(X_WARNING, "%s: incomplete packet, size %zd\n", 478 pInfo->name, n); 479 } 480 481#ifdef DEBUG 482 LogMessageVerbSigSafe("vuidReadInput: event type: %d value: %d\n", 483 pVuidMse->event.id, pVuidMse->event.value); 484#endif 485 486 if (pVuidMse->event.id >= BUT_FIRST && pVuidMse->event.id <= BUT_LAST) { 487 /* button */ 488 int butnum = pVuidMse->event.id - BUT_FIRST; 489 490 if (butnum < 3) 491 butnum = 2 - butnum; 492 if (!pVuidMse->event.value) 493 buttons &= ~(1 << butnum); 494 else 495 buttons |= (1 << butnum); 496 } else if (pVuidMse->event.id >= VLOC_FIRST && 497 pVuidMse->event.id <= VLOC_LAST) { 498 /* axis */ 499 int delta = pVuidMse->event.value; 500 switch(pVuidMse->event.id) { 501 case LOC_X_DELTA: 502 if (!relToAbs) 503 dx += delta; 504 else { 505 if (absXset) 506 vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset); 507 absX += delta; 508 if (absX < 0) 509 absX = 0; 510 else if (absX >= hdisplay && hdisplay > 0) 511 absX = hdisplay - 1; 512 pVuidMse->absX = absX; 513 absXset = TRUE; 514 } 515 break; 516 case LOC_Y_DELTA: 517 if (!relToAbs) 518 dy -= delta; 519 else { 520 if (absYset) 521 vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset); 522 absY -= delta; 523 if (absY < 0) 524 absY = 0; 525 else if (absY >= vdisplay && vdisplay > 0) 526 absY = vdisplay - 1; 527 pVuidMse->absY = absY; 528 absYset = TRUE; 529 } 530 break; 531 case LOC_X_ABSOLUTE: 532 if (absXset) { 533 vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset); 534 } 535 absX = delta; 536 absXset = TRUE; 537 break; 538 case LOC_Y_ABSOLUTE: 539 if (absYset) { 540 vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset); 541 } 542 absY = delta; 543 absYset = TRUE; 544 break; 545 } 546 } 547#ifdef HAVE_VUID_WHEEL 548 else if (vuid_in_range(VUID_WHEEL, pVuidMse->event.id)) { 549 if (vuid_id_offset(pVuidMse->event.id) == 0) 550 dz -= VUID_WHEEL_GETDELTA(pVuidMse->event.value); 551 else 552 dw -= VUID_WHEEL_GETDELTA(pVuidMse->event.value); 553 } 554#endif 555#ifdef HAVE_ABSOLUTE_MOUSE_SCALING 556 else if (pVuidMse->event.id == MOUSE_TYPE_ABSOLUTE) { 557 ScreenPtr ptrCurScreen; 558 559 /* force sending absolute resolution scaling ioctl */ 560 pVuidMse->absres.height = pVuidMse->absres.width = 0; 561 ptrCurScreen = miPointerGetScreen(pInfo->dev); 562 vuidMouseSendScreenSize(ptrCurScreen, pVuidMse); 563 } 564#endif 565 566 } while (n != 0); 567 568 if (absXset || absYset) { 569 vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset); 570 } 571 572 pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw); 573 return; 574} 575 576#ifdef HAVE_ABSOLUTE_MOUSE_SCALING 577static void vuidMouseSendScreenSize(ScreenPtr pScreen, VuidMsePtr pVuidMse) 578{ 579 InputInfoPtr pInfo = pVuidMse->pInfo; 580 ScrnInfoPtr pScr = XF86SCRNINFO(pScreen); 581 int result; 582 583 if ((pVuidMse->absres.width != pScr->virtualX) || 584 (pVuidMse->absres.height != pScr->virtualY)) 585 { 586 pVuidMse->absres.width = pScr->virtualX; 587 pVuidMse->absres.height = pScr->virtualY; 588 589 do { 590 result = ioctl(pInfo->fd, MSIOSRESOLUTION, &(pVuidMse->absres)); 591 } while ( (result != 0) && (errno == EINTR) ); 592 593 if (result != 0) { 594 LogMessageVerbSigSafe(X_WARNING, -1, 595 "%s: couldn't set absolute mouse scaling resolution: %s\n", 596 pInfo->name, strerror(errno)); 597#ifdef DEBUG 598 } else { 599 LogMessageVerbSigSafe(X_INFO, 600 "%s: absolute mouse scaling resolution set to %d x %d\n", 601 pInfo->name, 602 pVuidMse->absres.width, 603 pVuidMse->absres.height); 604#endif 605 } 606 } 607} 608 609static void vuidMouseAdjustFrame(ADJUST_FRAME_ARGS_DECL) 610{ 611 SCRN_INFO_PTR(arg); 612 ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 613 xf86AdjustFrameProc *wrappedAdjustFrame 614 = (xf86AdjustFrameProc *) vuidMouseGetScreenPrivate(pScreen); 615 VuidMsePtr m; 616 ScreenPtr ptrCurScreen; 617 618 if (wrappedAdjustFrame) { 619 pScrn->AdjustFrame = wrappedAdjustFrame; 620 (*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, x, y)); 621 pScrn->AdjustFrame = vuidMouseAdjustFrame; 622 } 623 624 for (m = vuidMouseList; m != NULL ; m = m->next) { 625 ptrCurScreen = miPointerGetScreen(m->pInfo->dev); 626 if (ptrCurScreen == pScreen) 627 { 628 vuidMouseSendScreenSize(pScreen, m); 629 } 630 } 631} 632 633static void vuidMouseCrtcNotify(ScreenPtr pScreen) 634{ 635 xf86_crtc_notify_proc_ptr wrappedCrtcNotify 636 = (xf86_crtc_notify_proc_ptr) vuidMouseGetScreenPrivate(pScreen); 637 VuidMsePtr m; 638 ScreenPtr ptrCurScreen; 639 640 if (wrappedCrtcNotify) 641 wrappedCrtcNotify(pScreen); 642 643 for (m = vuidMouseList; m != NULL ; m = m->next) { 644 ptrCurScreen = miPointerGetScreen(m->pInfo->dev); 645 if (ptrCurScreen == pScreen) { 646 vuidMouseSendScreenSize(pScreen, m); 647 } 648 } 649} 650#endif /* HAVE_ABSOLUTE_MOUSE_SCALING */ 651 652 653static int 654vuidMouseProc(DeviceIntPtr pPointer, int what) 655{ 656 InputInfoPtr pInfo; 657 MouseDevPtr pMse; 658 VuidMsePtr pVuidMse; 659 int ret = Success; 660 int i; 661 662 pInfo = pPointer->public.devicePrivate; 663 pMse = pInfo->private; 664 pMse->device = pPointer; 665 666 pVuidMse = getVuidMsePriv(pInfo); 667 if (pVuidMse == NULL) { 668 return BadImplementation; 669 } 670 671 switch (what) { 672 673 case DEVICE_INIT: 674#ifdef HAVE_ABSOLUTE_MOUSE_SCALING 675 676#if HAS_DEVPRIVATEKEYREC 677 if (!dixRegisterPrivateKey(&vuidMouseScreenIndex, PRIVATE_SCREEN, 0)) 678 return BadAlloc; 679#endif /* HAS_DEVPRIVATEKEYREC */ 680 681 if (vuidMouseGeneration != serverGeneration) { 682 for (i = 0; i < screenInfo.numScreens; i++) { 683 ScreenPtr pScreen = screenInfo.screens[i]; 684 ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); 685 if (xf86CrtcConfigPrivateIndex != -1) { 686 xf86_crtc_notify_proc_ptr pCrtcNotify 687 = xf86_wrap_crtc_notify(pScreen, 688 vuidMouseCrtcNotify); 689 vuidMouseSetScreenPrivate(pScreen, pCrtcNotify); 690 } else { 691 vuidMouseSetScreenPrivate(pScreen, 692 pScrn->AdjustFrame); 693 pScrn->AdjustFrame = vuidMouseAdjustFrame; 694 } 695 } 696 vuidMouseGeneration = serverGeneration; 697 } 698#endif 699 ret = pVuidMse->wrapped_device_control(pPointer, what); 700 break; 701 702 case DEVICE_ON: 703 ret = pVuidMse->wrapped_device_control(pPointer, DEVICE_ON); 704 705 if ((ret == Success) && (pInfo->fd != -1)) { 706 int fmt = VUID_FIRM_EVENT; 707 708 if (pVuidMse->strmod) { 709 /* Check to see if module is already pushed */ 710 SYSCALL(i = ioctl(pInfo->fd, I_FIND, pVuidMse->strmod)); 711 712 if (i == 0) { /* Not already pushed */ 713 SYSCALL(i = ioctl(pInfo->fd, I_PUSH, pVuidMse->strmod)); 714 if (i < 0) { 715 xf86Msg(X_WARNING, "%s: cannot push module '%s' " 716 "onto mouse device: %s\n", pInfo->name, 717 pVuidMse->strmod, strerror(errno)); 718 free(pVuidMse->strmod); 719 pVuidMse->strmod = NULL; 720 } 721 } 722 } 723 724 SYSCALL(i = ioctl(pInfo->fd, VUIDSFORMAT, &fmt)); 725 if (i < 0) { 726 xf86Msg(X_WARNING, 727 "%s: cannot set mouse device to VUID mode: %s\n", 728 pInfo->name, strerror(errno)); 729 } 730 vuidMouseWheelInit(pInfo); 731#ifdef HAVE_ABSOLUTE_MOUSE_SCALING 732 vuidMouseSendScreenSize(screenInfo.screens[0], pVuidMse); 733#endif 734 xf86FlushInput(pInfo->fd); 735 736 /* Allocate here so we don't alloc in ReadInput which may be called 737 from SIGIO handler. */ 738 if (pVuidMse->remove_timer == NULL) { 739 pVuidMse->remove_timer = TimerSet(pVuidMse->remove_timer, 740 0, 0, NULL, NULL); 741 } 742 } 743 break; 744 745 case DEVICE_CLOSE: 746 if (vuidMouseList == pVuidMse) 747 vuidMouseList = vuidMouseList->next; 748 else { 749 VuidMsePtr m = vuidMouseList; 750 751 while ((m != NULL) && (m->next != pVuidMse)) { 752 m = m->next; 753 } 754 755 if (m != NULL) 756 m->next = pVuidMse->next; 757 } 758 /* fallthrough */ 759 case DEVICE_OFF: 760 if (pInfo->fd != -1) { 761 if (pVuidMse->strmod) { 762 SYSCALL(i = ioctl(pInfo->fd, I_POP, pVuidMse->strmod)); 763 if (i == -1) { 764 xf86Msg(X_WARNING, 765 "%s: cannot pop module '%s' off mouse device: %s\n", 766 pInfo->name, pVuidMse->strmod, strerror(errno)); 767 } 768 } 769 } 770 if (pVuidMse->remove_timer) { 771 TimerFree(pVuidMse->remove_timer); 772 pVuidMse->remove_timer = NULL; 773 } 774 ret = pVuidMse->wrapped_device_control(pPointer, what); 775 break; 776 777 default: /* Should never be called, but just in case */ 778 ret = pVuidMse->wrapped_device_control(pPointer, what); 779 break; 780 } 781 return ret; 782} 783 784static Bool 785sunMousePreInit(InputInfoPtr pInfo, const char *protocol, int flags) 786{ 787 /* The protocol is guaranteed to be one of the internalNames[] */ 788 if (xf86NameCmp(protocol, "VUID") == 0) { 789 return vuidPreInit(pInfo, protocol, flags); 790 } 791 return TRUE; 792} 793 794static const char ** 795BuiltinNames(void) 796{ 797 return internalNames; 798} 799 800static Bool 801CheckProtocol(const char *protocol) 802{ 803 int i; 804 805 for (i = 0; internalNames[i]; i++) 806 if (xf86NameCmp(protocol, internalNames[i]) == 0) 807 return TRUE; 808 809 return FALSE; 810} 811 812static const char * 813DefaultProtocol(void) 814{ 815 return "Auto"; 816} 817 818static Bool 819solarisMouseAutoProbe(InputInfoPtr pInfo, const char **protocol, 820 const char **device) 821{ 822 const char **pdev, **pproto; 823 int fd = -1; 824 Bool found; 825 char *strmod; 826 827 if (*device == NULL) { 828 /* Check to see if xorg.conf or HAL specified a device to use */ 829 *device = xf86CheckStrOption(pInfo->options, "Device", NULL); 830 } 831 832 if (*device != NULL) { 833 strmod = xf86CheckStrOption(pInfo->options, "StreamsModule", NULL); 834 if (strmod) { 835 /* if a device name is already known, and a StreamsModule is 836 specified to convert events to VUID, then we don't need to 837 probe further */ 838 *protocol = "VUID"; 839 return TRUE; 840 } 841 } 842 843 844 for (pdev = solarisMouseDevs; *pdev; pdev += 2) { 845 pproto = pdev + 1; 846 if ((*protocol != NULL) && (strcmp(*protocol, "Auto") != 0) && 847 (*pproto != NULL) && (strcmp(*pproto, *protocol) != 0)) { 848 continue; 849 } 850 if ((*device != NULL) && (strcmp(*device, *pdev) != 0)) { 851 continue; 852 } 853 SYSCALL (fd = open(*pdev, O_RDWR | O_NONBLOCK)); 854 if (fd == -1) { 855#ifdef DEBUG 856 ErrorF("Cannot open %s (%s)\n", pdev, strerror(errno)); 857#endif 858 } else { 859 found = TRUE; 860 if ((*pproto != NULL) && (strcmp(*pproto, "VUID") == 0)) { 861 int i, r; 862 SYSCALL(r = ioctl(fd, VUIDGFORMAT, &i)); 863 if (r < 0) { 864 found = FALSE; 865 } 866 } 867 close(fd); 868 if (found == TRUE) { 869 if (*pproto != NULL) { 870 *protocol = *pproto; 871 } 872 *device = *pdev; 873 return TRUE; 874 } 875 } 876 } 877 return FALSE; 878} 879 880static const char * 881SetupAuto(InputInfoPtr pInfo, int *protoPara) 882{ 883 const char *pdev = NULL; 884 const char *pproto = NULL; 885 MouseDevPtr pMse = pInfo->private; 886 887 if (pInfo->fd == -1) { 888 /* probe to find device/protocol to use */ 889 if (solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) { 890 /* Set the Device option. */ 891 pInfo->options = 892 xf86AddNewOption(pInfo->options, "Device", pdev); 893 xf86Msg(X_INFO, "%s: Setting Device option to \"%s\"\n", 894 pInfo->name, pdev); 895 } 896 } else if (pMse->protocolID == PROT_AUTO) { 897 pdev = xf86CheckStrOption(pInfo->options, 898 "Device", NULL); 899 if ((solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) && 900 (pproto != NULL)) 901 sunMousePreInit(pInfo, pproto, 0); 902 } 903 return pproto; 904} 905 906static const char * 907FindDevice(InputInfoPtr pInfo, const char *protocol, int flags) 908{ 909 const char *pdev = NULL; 910 const char *pproto = protocol; 911 912 if (solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) { 913 /* Set the Device option. */ 914 pInfo->options = 915 xf86AddNewOption(pInfo->options, "Device", pdev); 916 xf86Msg(X_INFO, "%s: Setting Device option to \"%s\"\n", 917 pInfo->name, pdev); 918 } 919 return pdev; 920} 921 922static int 923SupportedInterfaces(void) 924{ 925 /* XXX This needs to be checked. */ 926 return MSE_SERIAL | MSE_BUS | MSE_PS2 | MSE_AUTO | MSE_XPS2 | MSE_MISC; 927} 928 929OSMouseInfoPtr 930OSMouseInit(int flags) 931{ 932 OSMouseInfoPtr p; 933 934 p = calloc(sizeof(OSMouseInfoRec), 1); 935 if (!p) 936 return NULL; 937 p->SupportedInterfaces = SupportedInterfaces; 938 p->BuiltinNames = BuiltinNames; 939 p->CheckProtocol = CheckProtocol; 940 p->PreInit = sunMousePreInit; 941 p->DefaultProtocol = DefaultProtocol; 942 p->SetupAuto = SetupAuto; 943 p->FindDevice = FindDevice; 944 945 return p; 946} 947 948