summaryrefslogtreecommitdiff
path: root/src/sun_mouse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sun_mouse.c')
-rw-r--r--src/sun_mouse.c169
1 files changed, 167 insertions, 2 deletions
diff --git a/src/sun_mouse.c b/src/sun_mouse.c
index d7c534e..3539ba7 100644
--- a/src/sun_mouse.c
+++ b/src/sun_mouse.c
@@ -76,6 +76,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)
@@ -111,6 +113,9 @@ typedef struct _VuidMseRec {
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;
@@ -118,6 +123,9 @@ static VuidMsePtr vuidMouseList = NULL;
static int vuidMouseProc(DeviceIntPtr pPointer, int what);
static void vuidReadInput(InputInfoPtr pInfo);
+static int CheckRelToAbs(InputInfoPtr pInfo);
+static int CheckRelToAbsWalker(di_node_t node, void *arg);
+
#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
# include "compat-api.h"
@@ -226,6 +234,11 @@ vuidPreInit(InputInfoPtr pInfo, const char *protocol, int flags)
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;
@@ -247,6 +260,120 @@ vuidPreInit(InputInfoPtr pInfo, const char *protocol, int flags)
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 < (ssize_t) 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)
@@ -289,7 +416,9 @@ vuidReadInput(InputInfoPtr pInfo)
ssize_t n;
unsigned char *pBuf;
int absX = 0, absY = 0;
+ int hdisplay = 0, vdisplay = 0;
Bool absXset = FALSE, absYset = FALSE;
+ int relToAbs;
pMse = pInfo->private;
buttons = pMse->lastButtons;
@@ -299,6 +428,18 @@ vuidReadInput(InputInfoPtr pInfo)
return;
}
pBuf = pVuidMse->buffer;
+ relToAbs = pVuidMse->relToAbs;
+ 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));
@@ -358,10 +499,34 @@ vuidReadInput(InputInfoPtr pInfo)
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) {