# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
--- a/src/sun_mouse.c Mon Jul 30 16:37:55 2012
+++ b/src/sun_mouse.c Mon Mar 18 17:34:23 2013
@@ -1,6 +1,5 @@
/*
- * Copyright (c) 2004-2005, 2008-2010, Oracle and/or its affiliates.
- * All rights reserved.
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -69,6 +68,8 @@
# include <sys/vuid_wheel.h>
#endif
+#include <libdevinfo.h>
+
/* Support for scaling absolute coordinates to screen size in
* Solaris 10 updates and beyond */
#if !defined(HAVE_ABSOLUTE_MOUSE_SCALING)
@@ -104,6 +105,9 @@
Ms_screen_resolution absres;
#endif
OsTimerPtr remove_timer; /* Callback for removal on ENODEV */
+ int relToAbs;
+ int absX;
+ int absY;
} VuidMseRec, *VuidMsePtr;
static VuidMsePtr vuidMouseList = NULL;
@@ -117,6 +121,9 @@
static void vuidMouseSendScreenSize(ScreenPtr pScreen, VuidMsePtr pVuidMse);
static void vuidMouseAdjustFrame(ADJUST_FRAME_ARGS_DECL);
+static int CheckRelToAbs(InputInfoPtr pInfo);
+static int CheckRelToAbsWalker(di_node_t node, void *arg);
+
static int vuidMouseGeneration = 0;
#if HAS_DEVPRIVATEKEYREC
@@ -219,6 +226,11 @@
pVuidMse->buffer = (unsigned char *)&pVuidMse->event;
pVuidMse->strmod = xf86SetStrOption(pInfo->options, "StreamsModule", NULL);
+ pVuidMse->relToAbs = xf86SetIntOption(pInfo->options, "RelToAbs", -1);
+ if (pVuidMse->relToAbs == -1)
+ pVuidMse->relToAbs = CheckRelToAbs(pInfo);
+ pVuidMse->absX = 0;
+ pVuidMse->absY = 0;
/* Setup the local procs. */
pVuidMse->wrapped_device_control = pInfo->device_control;
@@ -240,6 +252,120 @@
return TRUE;
}
+/*
+ * It seems that the mouse that is presented by the Emulex ILOM
+ * device (USB 0x430, 0xa101 and USB 0x430, 0xa102) sends relative
+ * mouse movements. But relative mouse movements are subject to
+ * acceleration. This causes the position indicated on the ILOM
+ * window to not match what the Xorg server actually has. This
+ * makes the mouse in this environment rather unusable. So, for the
+ * Emulex ILOM device, we will change all relative mouse movements
+ * into absolute mouse movements, making it appear more like a
+ * tablet. This will not be subject to acceleration, and this
+ * should keep the ILOM window and Xorg server with the same values
+ * for the coordinates of the mouse.
+ */
+
+typedef struct reltoabs_match {
+ int matched;
+ char const *matchname;
+ } reltoabs_match_t;
+
+/* Sun Microsystems, keyboard / mouse */
+#define RELTOABS_MATCH1 "usbif430,a101.config1.1"
+/* Sun Microsystems, keyboard / mouse / storage */
+#define RELTOABS_MATCH2 "usbif430,a102.config1.1"
+
+static int
+CheckRelToAbsWalker(di_node_t node, void *arg)
+{
+ di_minor_t minor;
+ char *path;
+ int numvalues;
+ int valueon;
+ char const *stringptr;
+ int status;
+ reltoabs_match_t *const matchptr = (reltoabs_match_t *)arg;
+ char *stringvalues;
+
+ for (minor = di_minor_next(node, DI_MINOR_NIL);
+ minor != DI_MINOR_NIL;
+ minor = di_minor_next(node, minor)) {
+ path = di_devfs_minor_path(minor);
+ status = path != NULL && strcmp(path, matchptr -> matchname) == 0;
+ di_devfs_path_free(path);
+ if (status)
+ break;
+ }
+
+ if (minor == DI_MINOR_NIL)
+ return (DI_WALK_CONTINUE);
+
+ numvalues = di_prop_lookup_strings(DDI_DEV_T_ANY, node,
+ "compatible", &stringvalues);
+ if (numvalues <= 0)
+ return (DI_WALK_CONTINUE);
+
+ for (valueon = 0, stringptr = stringvalues; valueon < numvalues;
+ valueon++, stringptr += strlen(stringptr) + 1) {
+ if (strcmp(stringptr, RELTOABS_MATCH1) == 0) {
+ matchptr -> matched = 1;
+ return (DI_WALK_TERMINATE);
+ }
+ if (strcmp(stringptr, RELTOABS_MATCH2) == 0) {
+ matchptr -> matched = 2;
+ return (DI_WALK_TERMINATE);
+ }
+ }
+ return (DI_WALK_CONTINUE);
+}
+
+static int
+CheckRelToAbs(InputInfoPtr pInfo)
+{
+ char const *device;
+ char const *matchname;
+ ssize_t readstatus;
+ di_node_t node;
+ struct stat statbuf;
+ char linkname[512];
+ reltoabs_match_t reltoabs_match;
+
+ device = xf86CheckStrOption(pInfo->options, "Device", NULL);
+ if (device == NULL)
+ return (0);
+
+ matchname = device;
+
+ if (lstat(device, &statbuf) == 0 &&
+ (statbuf.st_mode & S_IFMT) == S_IFLNK) {
+ readstatus = readlink(device, linkname, sizeof(linkname));
+ if (readstatus > 0 && readstatus < sizeof(linkname)) {
+ linkname[readstatus] = 0;
+ matchname = linkname;
+ if (strncmp(matchname, "../..", sizeof("../..") - 1) == 0)
+ matchname += sizeof("../..") - 1;
+ }
+ }
+
+ if (strncmp(matchname, "/devices", sizeof("/devices") - 1) == 0)
+ matchname += sizeof("/devices") - 1;
+
+ reltoabs_match.matched = 0;
+ reltoabs_match.matchname = matchname;
+
+ node = di_init("/", DINFOCPYALL);
+ if (node == DI_NODE_NIL)
+ return (0);
+
+ di_walk_node(node, DI_WALK_CLDFIRST, (void *)&reltoabs_match,
+ CheckRelToAbsWalker);
+
+ di_fini(node);
+
+ return (reltoabs_match.matched != 0);
+}
+
static void
vuidFlushAbsEvents(InputInfoPtr pInfo, int absX, int absY,
Bool *absXset, Bool *absYset)
@@ -275,21 +401,29 @@
static void
vuidReadInput(InputInfoPtr pInfo)
{
- MouseDevPtr pMse;
- VuidMsePtr pVuidMse;
- int buttons;
+ MouseDevPtr pMse = pInfo->private;
+ VuidMsePtr pVuidMse = getVuidMsePriv(pInfo);
+ int buttons = pMse->lastButtons;
int dx = 0, dy = 0, dz = 0, dw = 0;
- unsigned int n;
- unsigned char *pBuf;
+ unsigned int n = 0;
+ unsigned char *pBuf = pVuidMse->buffer;
int absX = 0, absY = 0;
+ int hdisplay = 0, vdisplay = 0;
Bool absXset = FALSE, absYset = FALSE;
+ int relToAbs = pVuidMse->relToAbs;
- pMse = pInfo->private;
- pVuidMse = getVuidMsePriv(pInfo);
- buttons = pMse->lastButtons;
- pBuf = pVuidMse->buffer;
- n = 0;
+ if (relToAbs) {
+ ScreenPtr pScreen = miPointerGetScreen(pInfo->dev);
+ ScrnInfoPtr pScr = XF86SCRNINFO(pScreen);
+ if (pScr->currentMode) {
+ hdisplay = pScr->currentMode->HDisplay;
+ vdisplay = pScr->currentMode->VDisplay;
+ }
+ absX = pVuidMse->absX;
+ absY = pVuidMse->absY;
+ }
+
do {
n = read(pInfo->fd, pBuf, sizeof(Firm_event));
@@ -348,10 +482,34 @@
int delta = pVuidMse->event.value;
switch(pVuidMse->event.id) {
case LOC_X_DELTA:
- dx += delta;
+ if (!relToAbs)
+ dx += delta;
+ else {
+ if (absXset)
+ vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
+ absX += delta;
+ if (absX < 0)
+ absX = 0;
+ else if (absX >= hdisplay && hdisplay > 0)
+ absX = hdisplay - 1;
+ pVuidMse->absX = absX;
+ absXset = TRUE;
+ }
break;
case LOC_Y_DELTA:
- dy -= delta;
+ if (!relToAbs)
+ dy -= delta;
+ else {
+ if (absYset)
+ vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
+ absY -= delta;
+ if (absY < 0)
+ absY = 0;
+ else if (absY >= vdisplay && vdisplay > 0)
+ absY = vdisplay - 1;
+ pVuidMse->absY = absY;
+ absYset = TRUE;
+ }
break;
case LOC_X_ABSOLUTE:
if (absXset) {