sun_mouse.c revision ebac4eb7
1b73be646Smrg/*
2ebac4eb7Smrg * Copyright (c) 2004, 2022, Oracle and/or its affiliates.
3b73be646Smrg *
4b73be646Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b73be646Smrg * copy of this software and associated documentation files (the "Software"),
6b73be646Smrg * to deal in the Software without restriction, including without limitation
7b73be646Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b73be646Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b73be646Smrg * Software is furnished to do so, subject to the following conditions:
10b73be646Smrg *
11b73be646Smrg * The above copyright notice and this permission notice (including the next
12b73be646Smrg * paragraph) shall be included in all copies or substantial portions of the
13b73be646Smrg * Software.
14b73be646Smrg *
15b73be646Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b73be646Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b73be646Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b73be646Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b73be646Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b73be646Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21b73be646Smrg * DEALINGS IN THE SOFTWARE.
22b73be646Smrg */
236aab59a7Smrg/*
246aab59a7Smrg * Copyright 1999-2001 The XFree86 Project, Inc.  All Rights Reserved.
256aab59a7Smrg *
266aab59a7Smrg * Permission is hereby granted, free of charge, to any person obtaining a copy
276aab59a7Smrg * of this software and associated documentation files (the "Software"), to
286aab59a7Smrg * deal in the Software without restriction, including without limitation the
296aab59a7Smrg * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
306aab59a7Smrg * sell copies of the Software, and to permit persons to whom the Software is
316aab59a7Smrg * furnished to do so, subject to the following conditions:
326aab59a7Smrg *
336aab59a7Smrg * The above copyright notice and this permission notice shall be included in
346aab59a7Smrg * all copies or substantial portions of the Software.
356aab59a7Smrg *
366aab59a7Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
376aab59a7Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
386aab59a7Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
396aab59a7Smrg * XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
406aab59a7Smrg * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
416aab59a7Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
426aab59a7Smrg *
436aab59a7Smrg * Except as contained in this notice, the name of the XFree86 Project shall
446aab59a7Smrg * not be used in advertising or otherwise to promote the sale, use or other
456aab59a7Smrg * dealings in this Software without prior written authorization from the
466aab59a7Smrg * XFree86 Project.
476aab59a7Smrg */
486aab59a7Smrg
49370b807fSmrg#ifdef HAVE_CONFIG_H
50370b807fSmrg#include "config.h"
51370b807fSmrg#endif
52370b807fSmrg
536aab59a7Smrg#ifdef HAVE_XORG_CONFIG_H
546aab59a7Smrg#include <xorg-config.h>
556aab59a7Smrg#endif
566aab59a7Smrg
57ebac4eb7Smrg#include <unistd.h> /* for ioctl(2) */
58ebac4eb7Smrg#include <sys/stropts.h>
59ebac4eb7Smrg#include <sys/vuid_event.h>
60ebac4eb7Smrg#include <sys/msio.h>
61ebac4eb7Smrg#include <fcntl.h>
62ebac4eb7Smrg#include <errno.h>
636aab59a7Smrg#include "xorg-server.h"
646aab59a7Smrg#include "xf86.h"
656aab59a7Smrg#include "xf86_OSlib.h"
66bd3a1963Smrg#include "mouse.h"
676aab59a7Smrg#include "xisb.h"
686aab59a7Smrg#include "mipointer.h"
6984bf8334Smrg#include "xf86Crtc.h"
706aab59a7Smrg
716aab59a7Smrg/* Wheel mouse support in VUID drivers in Solaris 9 updates & Solaris 10 */
726aab59a7Smrg#ifdef WHEEL_DEVID /* Defined in vuid_event.h if VUID wheel support present */
736aab59a7Smrg# define HAVE_VUID_WHEEL
746aab59a7Smrg#endif
756aab59a7Smrg#ifdef HAVE_VUID_WHEEL
766aab59a7Smrg# include <sys/vuid_wheel.h>
776aab59a7Smrg#endif
786aab59a7Smrg
79ebac4eb7Smrg#include <libdevinfo.h>
80ebac4eb7Smrg
81a73597f9Smrg/* Support for scaling absolute coordinates to screen size in
826aab59a7Smrg * Solaris 10 updates and beyond */
836aab59a7Smrg#if !defined(HAVE_ABSOLUTE_MOUSE_SCALING)
846aab59a7Smrg# ifdef MSIOSRESOLUTION /* Defined in msio.h if scaling support present */
856aab59a7Smrg#  define HAVE_ABSOLUTE_MOUSE_SCALING
866aab59a7Smrg# endif
876aab59a7Smrg#endif
886aab59a7Smrg
896aab59a7Smrg/* Names of protocols that are handled internally here. */
906aab59a7Smrg
916aab59a7Smrgstatic const char *internalNames[] = {
92a73597f9Smrg        "VUID",
93a73597f9Smrg        NULL
946aab59a7Smrg};
956aab59a7Smrg
966aab59a7Smrgstatic const char *solarisMouseDevs[] = {
97a73597f9Smrg    /* Device file:     Protocol:                       */
98a73597f9Smrg    "/dev/mouse",       "VUID",         /* USB or SPARC */
996aab59a7Smrg#if defined(__i386) || defined(__x86)
100a73597f9Smrg    "/dev/kdmouse",     "PS/2",         /* PS/2 */
1016aab59a7Smrg#endif
1026aab59a7Smrg    NULL
1036aab59a7Smrg};
1046aab59a7Smrg
1056aab59a7Smrgtypedef struct _VuidMseRec {
106a73597f9Smrg    struct _VuidMseRec *next;
107a73597f9Smrg    InputInfoPtr        pInfo;
108a73597f9Smrg    Firm_event          event;
109a73597f9Smrg    unsigned char *     buffer;
110a73597f9Smrg    char *              strmod;
1116aab59a7Smrg    Bool(*wrapped_device_control)(DeviceIntPtr device, int what);
1126aab59a7Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
113a73597f9Smrg    Ms_screen_resolution         absres;
1146aab59a7Smrg#endif
115a73597f9Smrg    OsTimerPtr          remove_timer;   /* Callback for removal on ENODEV */
116ebac4eb7Smrg    int                 relToAbs;
117ebac4eb7Smrg    int                 absX;
118ebac4eb7Smrg    int                 absY;
1196aab59a7Smrg} VuidMseRec, *VuidMsePtr;
1206aab59a7Smrg
121a73597f9Smrgstatic VuidMsePtr       vuidMouseList = NULL;
1226aab59a7Smrg
1236aab59a7Smrgstatic int  vuidMouseProc(DeviceIntPtr pPointer, int what);
1246aab59a7Smrgstatic void vuidReadInput(InputInfoPtr pInfo);
1256aab59a7Smrg
126ebac4eb7Smrgstatic int CheckRelToAbs(InputInfoPtr pInfo);
127ebac4eb7Smrgstatic int CheckRelToAbsWalker(di_node_t node, void *arg);
128ebac4eb7Smrg
1296aab59a7Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
130a73597f9Smrg# include "compat-api.h"
131a73597f9Smrg
1326aab59a7Smrgstatic void vuidMouseSendScreenSize(ScreenPtr pScreen, VuidMsePtr pVuidMse);
133a73597f9Smrgstatic void vuidMouseAdjustFrame(ADJUST_FRAME_ARGS_DECL);
1346aab59a7Smrg
135370b807fSmrgstatic unsigned long vuidMouseGeneration = 0;
136b73be646Smrg
137b73be646Smrg#if HAS_DEVPRIVATEKEYREC
138b73be646Smrgstatic DevPrivateKeyRec vuidMouseScreenIndex;
139b73be646Smrg#else
1406aab59a7Smrgstatic int vuidMouseScreenIndex;
141b73be646Smrg#endif /* HAS_DEVPRIVATEKEYREC */
142b73be646Smrg
1436aab59a7Smrg#define vuidMouseGetScreenPrivate(s) ( \
1446aab59a7Smrg    dixLookupPrivate(&(s)->devPrivates, &vuidMouseScreenIndex))
1456aab59a7Smrg#define vuidMouseSetScreenPrivate(s,p) \
1466aab59a7Smrg    dixSetPrivate(&(s)->devPrivates, &vuidMouseScreenIndex, (void *) p)
1476aab59a7Smrg#endif /* HAVE_ABSOLUTE_MOUSE_SCALING */
1486aab59a7Smrg
1496aab59a7Smrgstatic inline
1506aab59a7SmrgVuidMsePtr getVuidMsePriv(InputInfoPtr pInfo)
1516aab59a7Smrg{
1526aab59a7Smrg    VuidMsePtr m = vuidMouseList;
1536aab59a7Smrg
1546aab59a7Smrg    while ((m != NULL) && (m->pInfo != pInfo)) {
155a73597f9Smrg        m = m->next;
1566aab59a7Smrg    }
1576aab59a7Smrg
1586aab59a7Smrg    return m;
1596aab59a7Smrg}
1606aab59a7Smrg
161b73be646Smrg/* Called from OsTimer callback, since removing a device from the device
162b73be646Smrg   list or changing pInfo->fd while xf86Wakeup is looping through the list
163b73be646Smrg   causes server crashes */
164b73be646Smrgstatic CARD32
165a73597f9SmrgvuidRemoveMouse(OsTimerPtr timer, CARD32 now, pointer arg)
166b73be646Smrg{
167b73be646Smrg    InputInfoPtr pInfo = (InputInfoPtr) arg;
168b73be646Smrg
169b73be646Smrg    xf86DisableDevice(pInfo->dev, TRUE);
170b73be646Smrg
171b73be646Smrg    return 0;  /* All done, don't set to run again */
172b73be646Smrg}
1736aab59a7Smrg
1746aab59a7Smrg/*
1756aab59a7Smrg * Initialize and enable the mouse wheel, if present.
1766aab59a7Smrg *
1776aab59a7Smrg * Returns 1 if mouse wheel was successfully enabled.
1786aab59a7Smrg * Returns 0 if an error occurred or if there is no mouse wheel.
1796aab59a7Smrg */
1806aab59a7Smrgstatic int
1816aab59a7SmrgvuidMouseWheelInit(InputInfoPtr pInfo)
1826aab59a7Smrg{
1836aab59a7Smrg#ifdef HAVE_VUID_WHEEL
1846aab59a7Smrg    wheel_state wstate;
1856aab59a7Smrg    int nwheel = -1;
1866aab59a7Smrg    int i;
1876aab59a7Smrg
1886aab59a7Smrg    wstate.vers = VUID_WHEEL_STATE_VERS;
1896aab59a7Smrg    wstate.id = 0;
1906aab59a7Smrg    wstate.stateflags = (uint32_t) -1;
1916aab59a7Smrg
1926aab59a7Smrg    SYSCALL(i = ioctl(pInfo->fd, VUIDGWHEELCOUNT, &nwheel));
1936aab59a7Smrg    if (i != 0)
194a73597f9Smrg        return (0);
1956aab59a7Smrg
1966aab59a7Smrg    SYSCALL(i = ioctl(pInfo->fd, VUIDGWHEELSTATE, &wstate));
1976aab59a7Smrg    if (i != 0) {
198a73597f9Smrg        xf86Msg(X_WARNING, "%s: couldn't get wheel state\n", pInfo->name);
199a73597f9Smrg        return (0);
2006aab59a7Smrg    }
2016aab59a7Smrg
2026aab59a7Smrg    wstate.stateflags |= VUID_WHEEL_STATE_ENABLED;
2036aab59a7Smrg
2046aab59a7Smrg    SYSCALL(i = ioctl(pInfo->fd, VUIDSWHEELSTATE, &wstate));
2056aab59a7Smrg    if (i != 0) {
206a73597f9Smrg        xf86Msg(X_WARNING, "%s: couldn't enable wheel\n", pInfo->name);
207a73597f9Smrg        return (0);
2086aab59a7Smrg    }
2096aab59a7Smrg
2106aab59a7Smrg    return (1);
2116aab59a7Smrg#else
2126aab59a7Smrg    return (0);
2136aab59a7Smrg#endif
2146aab59a7Smrg}
2156aab59a7Smrg
2166aab59a7Smrg
2176aab59a7Smrg/* This function is called when the protocol is "VUID". */
2186aab59a7Smrgstatic Bool
2196aab59a7SmrgvuidPreInit(InputInfoPtr pInfo, const char *protocol, int flags)
2206aab59a7Smrg{
2216aab59a7Smrg    MouseDevPtr pMse = pInfo->private;
2226aab59a7Smrg    VuidMsePtr pVuidMse;
223a73597f9Smrg
224a73597f9Smrg    /* Ensure we don't add the same device twice */
225a73597f9Smrg    if (getVuidMsePriv(pInfo) != NULL)
226a73597f9Smrg        return TRUE;
2276aab59a7Smrg
228bd3a1963Smrg    pVuidMse = calloc(sizeof(VuidMseRec), 1);
2296aab59a7Smrg    if (pVuidMse == NULL) {
230a73597f9Smrg        xf86Msg(X_ERROR, "%s: cannot allocate VuidMouseRec\n", pInfo->name);
231a73597f9Smrg        free(pMse);
232a73597f9Smrg        return FALSE;
2336aab59a7Smrg    }
2346aab59a7Smrg
235fc27e79cSmrg    pVuidMse->buffer = (unsigned char *)&pVuidMse->event;
236fc27e79cSmrg    pVuidMse->strmod = xf86SetStrOption(pInfo->options, "StreamsModule", NULL);
237ebac4eb7Smrg    pVuidMse->relToAbs = xf86SetIntOption(pInfo->options, "RelToAbs", -1);
238ebac4eb7Smrg    if (pVuidMse->relToAbs == -1)
239ebac4eb7Smrg        pVuidMse->relToAbs = CheckRelToAbs(pInfo);
240ebac4eb7Smrg    pVuidMse->absX = 0;
241ebac4eb7Smrg    pVuidMse->absY = 0;
242fc27e79cSmrg
2436aab59a7Smrg    /* Setup the local procs. */
2446aab59a7Smrg    pVuidMse->wrapped_device_control = pInfo->device_control;
2456aab59a7Smrg    pInfo->device_control = vuidMouseProc;
2466aab59a7Smrg    pInfo->read_input = vuidReadInput;
2476aab59a7Smrg
2486aab59a7Smrg    pMse->xisbscale = sizeof(Firm_event);
2496aab59a7Smrg
250a73597f9Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
2516aab59a7Smrg    pVuidMse->absres.height = pVuidMse->absres.width = 0;
2526aab59a7Smrg#endif
2536aab59a7Smrg    pVuidMse->pInfo = pInfo;
254a73597f9Smrg    pVuidMse->next = vuidMouseList;
2556aab59a7Smrg    vuidMouseList = pVuidMse;
2566aab59a7Smrg
257bd3a1963Smrg#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
2586aab59a7Smrg    pInfo->flags |= XI86_CONFIGURED;
259bd3a1963Smrg#endif
2606aab59a7Smrg    return TRUE;
2616aab59a7Smrg}
2626aab59a7Smrg
263ebac4eb7Smrg/*
264ebac4eb7Smrg * It seems that the mouse that is presented by the Emulex ILOM
265ebac4eb7Smrg * device (USB 0x430, 0xa101 and USB 0x430, 0xa102) sends relative
266ebac4eb7Smrg * mouse movements.  But relative mouse movements are subject to
267ebac4eb7Smrg * acceleration.  This causes the position indicated on the ILOM
268ebac4eb7Smrg * window to not match what the Xorg server actually has.  This
269ebac4eb7Smrg * makes the mouse in this environment rather unusable.  So, for the
270ebac4eb7Smrg * Emulex ILOM device, we will change all relative mouse movements
271ebac4eb7Smrg * into absolute mouse movements, making it appear more like a
272ebac4eb7Smrg * tablet.  This will not be subject to acceleration, and this
273ebac4eb7Smrg * should keep the ILOM window and Xorg server with the same values
274ebac4eb7Smrg * for the coordinates of the mouse.
275ebac4eb7Smrg */
276ebac4eb7Smrg
277ebac4eb7Smrgtypedef struct reltoabs_match {
278ebac4eb7Smrg	int matched;
279ebac4eb7Smrg	char const *matchname;
280ebac4eb7Smrg	} reltoabs_match_t;
281ebac4eb7Smrg
282ebac4eb7Smrg/* Sun Microsystems, keyboard / mouse */
283ebac4eb7Smrg#define	RELTOABS_MATCH1	"usbif430,a101.config1.1"
284ebac4eb7Smrg/* Sun Microsystems, keyboard / mouse / storage */
285ebac4eb7Smrg#define	RELTOABS_MATCH2	"usbif430,a102.config1.1"
286ebac4eb7Smrg
287ebac4eb7Smrgstatic int
288ebac4eb7SmrgCheckRelToAbsWalker(di_node_t node, void *arg)
289ebac4eb7Smrg{
290ebac4eb7Smrg	di_minor_t minor;
291ebac4eb7Smrg	char *path;
292ebac4eb7Smrg	int numvalues;
293ebac4eb7Smrg	int valueon;
294ebac4eb7Smrg	char const *stringptr;
295ebac4eb7Smrg	int status;
296ebac4eb7Smrg	reltoabs_match_t *const matchptr = (reltoabs_match_t *)arg;
297ebac4eb7Smrg	char *stringvalues;
298ebac4eb7Smrg
299ebac4eb7Smrg	for (minor = di_minor_next(node, DI_MINOR_NIL);
300ebac4eb7Smrg	  minor != DI_MINOR_NIL;
301ebac4eb7Smrg	  minor = di_minor_next(node, minor)) {
302ebac4eb7Smrg	    path = di_devfs_minor_path(minor);
303ebac4eb7Smrg	    status = path != NULL && strcmp(path, matchptr -> matchname) == 0;
304ebac4eb7Smrg	    di_devfs_path_free(path);
305ebac4eb7Smrg	    if (status)
306ebac4eb7Smrg		break;
307ebac4eb7Smrg	    }
308ebac4eb7Smrg
309ebac4eb7Smrg	if (minor == DI_MINOR_NIL)
310ebac4eb7Smrg	    return (DI_WALK_CONTINUE);
311ebac4eb7Smrg
312ebac4eb7Smrg	numvalues = di_prop_lookup_strings(DDI_DEV_T_ANY, node,
313ebac4eb7Smrg	  "compatible", &stringvalues);
314ebac4eb7Smrg	if (numvalues <= 0)
315ebac4eb7Smrg	    return (DI_WALK_CONTINUE);
316ebac4eb7Smrg
317ebac4eb7Smrg	for (valueon = 0, stringptr = stringvalues; valueon < numvalues;
318ebac4eb7Smrg	  valueon++, stringptr += strlen(stringptr) + 1) {
319ebac4eb7Smrg	    if (strcmp(stringptr, RELTOABS_MATCH1) == 0) {
320ebac4eb7Smrg		matchptr -> matched = 1;
321ebac4eb7Smrg		return (DI_WALK_TERMINATE);
322ebac4eb7Smrg	    }
323ebac4eb7Smrg	    if (strcmp(stringptr, RELTOABS_MATCH2) == 0) {
324ebac4eb7Smrg		matchptr -> matched = 2;
325ebac4eb7Smrg		return (DI_WALK_TERMINATE);
326ebac4eb7Smrg	    }
327ebac4eb7Smrg	}
328ebac4eb7Smrg	return (DI_WALK_CONTINUE);
329ebac4eb7Smrg}
330ebac4eb7Smrg
331ebac4eb7Smrgstatic int
332ebac4eb7SmrgCheckRelToAbs(InputInfoPtr pInfo)
333ebac4eb7Smrg{
334ebac4eb7Smrg	char const *device;
335ebac4eb7Smrg	char const *matchname;
336ebac4eb7Smrg	ssize_t readstatus;
337ebac4eb7Smrg	di_node_t node;
338ebac4eb7Smrg	struct stat statbuf;
339ebac4eb7Smrg	char linkname[512];
340ebac4eb7Smrg	reltoabs_match_t reltoabs_match;
341ebac4eb7Smrg
342ebac4eb7Smrg	device = xf86CheckStrOption(pInfo->options, "Device", NULL);
343ebac4eb7Smrg	if (device == NULL)
344ebac4eb7Smrg	    return (0);
345ebac4eb7Smrg
346ebac4eb7Smrg	matchname = device;
347ebac4eb7Smrg
348ebac4eb7Smrg	if (lstat(device, &statbuf) == 0 &&
349ebac4eb7Smrg	  (statbuf.st_mode & S_IFMT) == S_IFLNK) {
350ebac4eb7Smrg	    readstatus = readlink(device, linkname, sizeof(linkname));
351ebac4eb7Smrg	    if (readstatus > 0 && readstatus < (ssize_t) sizeof(linkname)) {
352ebac4eb7Smrg		linkname[readstatus] = 0;
353ebac4eb7Smrg		matchname = linkname;
354ebac4eb7Smrg		if (strncmp(matchname, "../..", sizeof("../..") - 1) == 0)
355ebac4eb7Smrg		    matchname += sizeof("../..") - 1;
356ebac4eb7Smrg	    }
357ebac4eb7Smrg	}
358ebac4eb7Smrg
359ebac4eb7Smrg	if (strncmp(matchname, "/devices", sizeof("/devices") - 1) == 0)
360ebac4eb7Smrg	    matchname += sizeof("/devices") - 1;
361ebac4eb7Smrg
362ebac4eb7Smrg	reltoabs_match.matched = 0;
363ebac4eb7Smrg	reltoabs_match.matchname = matchname;
364ebac4eb7Smrg
365ebac4eb7Smrg	node = di_init("/", DINFOCPYALL);
366ebac4eb7Smrg	if (node == DI_NODE_NIL)
367ebac4eb7Smrg	    return (0);
368ebac4eb7Smrg
369ebac4eb7Smrg	di_walk_node(node, DI_WALK_CLDFIRST, (void *)&reltoabs_match,
370ebac4eb7Smrg	  CheckRelToAbsWalker);
371ebac4eb7Smrg
372ebac4eb7Smrg	di_fini(node);
373ebac4eb7Smrg
374ebac4eb7Smrg	return (reltoabs_match.matched != 0);
375ebac4eb7Smrg}
376ebac4eb7Smrg
3776aab59a7Smrgstatic void
378a73597f9SmrgvuidFlushAbsEvents(InputInfoPtr pInfo, int absX, int absY,
379a73597f9Smrg                   Bool *absXset, Bool *absYset)
3806aab59a7Smrg{
3816aab59a7Smrg#ifdef DEBUG
382a73597f9Smrg    ErrorF("vuidFlushAbsEvents: %d,%d (set: %d, %d)\n", absX, absY,
383a73597f9Smrg           *absXset, *absYset);
3846aab59a7Smrg#endif
3856aab59a7Smrg    if ((*absXset) && (*absYset)) {
386a73597f9Smrg        xf86PostMotionEvent(pInfo->dev,
387a73597f9Smrg                            /* is_absolute: */    TRUE,
388a73597f9Smrg                            /* first_valuator: */ 0,
389a73597f9Smrg                            /* num_valuators: */  2,
390a73597f9Smrg                            absX, absY);
3916aab59a7Smrg    } else if (*absXset) {
392a73597f9Smrg        xf86PostMotionEvent(pInfo->dev,
393a73597f9Smrg                            /* is_absolute: */    TRUE,
394a73597f9Smrg                            /* first_valuator: */ 0,
395a73597f9Smrg                            /* num_valuators: */  1,
396a73597f9Smrg                            absX);
3976aab59a7Smrg    } else if (*absYset) {
398a73597f9Smrg        xf86PostMotionEvent(pInfo->dev,
399a73597f9Smrg                            /* is_absolute: */    TRUE,
400a73597f9Smrg                            /* first_valuator: */ 1,
401a73597f9Smrg                            /* num_valuators: */  1,
402a73597f9Smrg                            absY);
4036aab59a7Smrg    }
4046aab59a7Smrg
4056aab59a7Smrg    *absXset = FALSE;
4066aab59a7Smrg    *absYset = FALSE;
4076aab59a7Smrg}
4086aab59a7Smrg
4096aab59a7Smrgstatic void
4106aab59a7SmrgvuidReadInput(InputInfoPtr pInfo)
4116aab59a7Smrg{
4126aab59a7Smrg    MouseDevPtr pMse;
4136aab59a7Smrg    VuidMsePtr pVuidMse;
4146aab59a7Smrg    int buttons;
4156aab59a7Smrg    int dx = 0, dy = 0, dz = 0, dw = 0;
416370b807fSmrg    ssize_t n;
4176aab59a7Smrg    unsigned char *pBuf;
4186aab59a7Smrg    int absX = 0, absY = 0;
419ebac4eb7Smrg    int hdisplay = 0, vdisplay = 0;
4206aab59a7Smrg    Bool absXset = FALSE, absYset = FALSE;
421ebac4eb7Smrg    int relToAbs;
4226aab59a7Smrg
4236aab59a7Smrg    pMse = pInfo->private;
4246aab59a7Smrg    buttons = pMse->lastButtons;
425370b807fSmrg    pVuidMse = getVuidMsePriv(pInfo);
426370b807fSmrg    if (pVuidMse == NULL) {
427370b807fSmrg        xf86Msg(X_ERROR, "%s: cannot locate VuidMsePtr\n", pInfo->name);
428370b807fSmrg        return;
429370b807fSmrg    }
4306aab59a7Smrg    pBuf = pVuidMse->buffer;
431ebac4eb7Smrg    relToAbs = pVuidMse->relToAbs;
432ebac4eb7Smrg    if (relToAbs) {
433ebac4eb7Smrg	ScreenPtr   pScreen = miPointerGetScreen(pInfo->dev);
434ebac4eb7Smrg	ScrnInfoPtr pScr = XF86SCRNINFO(pScreen);
435ebac4eb7Smrg
436ebac4eb7Smrg	if (pScr->currentMode) {
437ebac4eb7Smrg	    hdisplay = pScr->currentMode->HDisplay;
438ebac4eb7Smrg	    vdisplay = pScr->currentMode->VDisplay;
439ebac4eb7Smrg	}
440ebac4eb7Smrg	absX = pVuidMse->absX;
441ebac4eb7Smrg	absY = pVuidMse->absY;
442ebac4eb7Smrg    }
4436aab59a7Smrg
4446aab59a7Smrg    do {
445a73597f9Smrg        n = read(pInfo->fd, pBuf, sizeof(Firm_event));
446a73597f9Smrg
447a73597f9Smrg        if (n == 0) {
448a73597f9Smrg            break;
449a73597f9Smrg        } else if (n == -1) {
450a73597f9Smrg            switch (errno) {
451a73597f9Smrg                case EAGAIN: /* Nothing to read now */
452a73597f9Smrg                    n = 0;   /* End loop, go on to flush events & return */
453a73597f9Smrg                    continue;
454a73597f9Smrg                case EINTR:  /* Interrupted, try again */
455a73597f9Smrg                    continue;
456a73597f9Smrg                case ENODEV: /* May happen when USB mouse is unplugged */
457a73597f9Smrg                    /* We use X_NONE here because it didn't alloc since we
458a73597f9Smrg                       may be called from SIGIO handler. No longer true for
459a73597f9Smrg                       sigsafe logging, but matters for older servers  */
460a73597f9Smrg                    LogMessageVerbSigSafe(X_NONE, 0,
461a73597f9Smrg                                          "%s: Device no longer present - removing.\n",
462a73597f9Smrg                                          pInfo->name);
463a73597f9Smrg                    xf86RemoveEnabledDevice(pInfo);
464a73597f9Smrg                    pVuidMse->remove_timer =
465a73597f9Smrg                        TimerSet(pVuidMse->remove_timer, 0, 1,
466a73597f9Smrg                                 vuidRemoveMouse, pInfo);
467a73597f9Smrg                    return;
468a73597f9Smrg                default:     /* All other errors */
469a73597f9Smrg                    /* We use X_NONE here because it didn't alloc since we
470a73597f9Smrg                       may be called from SIGIO handler. No longer true for
471a73597f9Smrg                       sigsafe logging, but matters for older servers  */
472a73597f9Smrg                    LogMessageVerbSigSafe(X_NONE, 0, "%s: Read error: %s\n",
473a73597f9Smrg                                          pInfo->name, strerror(errno));
474a73597f9Smrg                    return;
475a73597f9Smrg            }
476a73597f9Smrg        } else if (n != sizeof(Firm_event)) {
477370b807fSmrg            xf86Msg(X_WARNING, "%s: incomplete packet, size %zd\n",
478a73597f9Smrg                        pInfo->name, n);
479a73597f9Smrg        }
4806aab59a7Smrg
4816aab59a7Smrg#ifdef DEBUG
482a73597f9Smrg        LogMessageVerbSigSafe("vuidReadInput: event type: %d value: %d\n",
483a73597f9Smrg                              pVuidMse->event.id, pVuidMse->event.value);
4846aab59a7Smrg#endif
4856aab59a7Smrg
486a73597f9Smrg        if (pVuidMse->event.id >= BUT_FIRST && pVuidMse->event.id <= BUT_LAST) {
487a73597f9Smrg            /* button */
488a73597f9Smrg            int butnum = pVuidMse->event.id - BUT_FIRST;
489a73597f9Smrg
490a73597f9Smrg            if (butnum < 3)
491a73597f9Smrg                butnum = 2 - butnum;
492a73597f9Smrg            if (!pVuidMse->event.value)
493a73597f9Smrg                buttons &= ~(1 << butnum);
494a73597f9Smrg            else
495a73597f9Smrg                buttons |= (1 << butnum);
496a73597f9Smrg        } else if (pVuidMse->event.id >= VLOC_FIRST &&
497a73597f9Smrg                   pVuidMse->event.id <= VLOC_LAST) {
498a73597f9Smrg            /* axis */
499a73597f9Smrg            int delta = pVuidMse->event.value;
500a73597f9Smrg            switch(pVuidMse->event.id) {
501a73597f9Smrg            case LOC_X_DELTA:
502ebac4eb7Smrg                if (!relToAbs)
503ebac4eb7Smrg                    dx += delta;
504ebac4eb7Smrg                else {
505ebac4eb7Smrg                    if (absXset)
506ebac4eb7Smrg                        vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
507ebac4eb7Smrg                    absX += delta;
508ebac4eb7Smrg                    if (absX < 0)
509ebac4eb7Smrg                        absX = 0;
510ebac4eb7Smrg                    else if (absX >= hdisplay && hdisplay > 0)
511ebac4eb7Smrg                        absX = hdisplay - 1;
512ebac4eb7Smrg                    pVuidMse->absX = absX;
513ebac4eb7Smrg                    absXset = TRUE;
514ebac4eb7Smrg                }
515a73597f9Smrg                break;
516a73597f9Smrg            case LOC_Y_DELTA:
517ebac4eb7Smrg                if (!relToAbs)
518ebac4eb7Smrg                    dy -= delta;
519ebac4eb7Smrg                else {
520ebac4eb7Smrg                    if (absYset)
521ebac4eb7Smrg                        vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
522ebac4eb7Smrg                    absY -= delta;
523ebac4eb7Smrg                    if (absY < 0)
524ebac4eb7Smrg                        absY = 0;
525ebac4eb7Smrg                    else if (absY >= vdisplay && vdisplay > 0)
526ebac4eb7Smrg                        absY = vdisplay - 1;
527ebac4eb7Smrg                    pVuidMse->absY = absY;
528ebac4eb7Smrg                    absYset = TRUE;
529ebac4eb7Smrg                }
530a73597f9Smrg                break;
531a73597f9Smrg            case LOC_X_ABSOLUTE:
532a73597f9Smrg                if (absXset) {
533a73597f9Smrg                    vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
534a73597f9Smrg                }
535a73597f9Smrg                absX = delta;
536a73597f9Smrg                absXset = TRUE;
537a73597f9Smrg                break;
538a73597f9Smrg            case LOC_Y_ABSOLUTE:
539a73597f9Smrg                if (absYset) {
540a73597f9Smrg                    vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
541a73597f9Smrg                }
542a73597f9Smrg                absY = delta;
543a73597f9Smrg                absYset = TRUE;
544a73597f9Smrg                break;
545a73597f9Smrg            }
546a73597f9Smrg        }
5476aab59a7Smrg#ifdef HAVE_VUID_WHEEL
548a73597f9Smrg        else if (vuid_in_range(VUID_WHEEL, pVuidMse->event.id)) {
549a73597f9Smrg            if (vuid_id_offset(pVuidMse->event.id) == 0)
550a73597f9Smrg                dz -= VUID_WHEEL_GETDELTA(pVuidMse->event.value);
551a73597f9Smrg            else
552a73597f9Smrg                dw -= VUID_WHEEL_GETDELTA(pVuidMse->event.value);
553a73597f9Smrg        }
5546aab59a7Smrg#endif
5556aab59a7Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
556a73597f9Smrg        else if (pVuidMse->event.id == MOUSE_TYPE_ABSOLUTE) {
557a73597f9Smrg            ScreenPtr   ptrCurScreen;
558a73597f9Smrg
559a73597f9Smrg            /* force sending absolute resolution scaling ioctl */
560a73597f9Smrg            pVuidMse->absres.height = pVuidMse->absres.width = 0;
561a73597f9Smrg            ptrCurScreen = miPointerGetScreen(pInfo->dev);
562a73597f9Smrg            vuidMouseSendScreenSize(ptrCurScreen, pVuidMse);
563a73597f9Smrg        }
5646aab59a7Smrg#endif
5656aab59a7Smrg
5666aab59a7Smrg    } while (n != 0);
5676aab59a7Smrg
5686aab59a7Smrg    if (absXset || absYset) {
569a73597f9Smrg        vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
5706aab59a7Smrg    }
5716aab59a7Smrg
5726aab59a7Smrg    pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw);
5736aab59a7Smrg    return;
5746aab59a7Smrg}
5756aab59a7Smrg
5766aab59a7Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
5776aab59a7Smrgstatic void vuidMouseSendScreenSize(ScreenPtr pScreen, VuidMsePtr pVuidMse)
5786aab59a7Smrg{
5796aab59a7Smrg    InputInfoPtr pInfo = pVuidMse->pInfo;
5806aab59a7Smrg    ScrnInfoPtr pScr = XF86SCRNINFO(pScreen);
5816aab59a7Smrg    int result;
5826aab59a7Smrg
58384bf8334Smrg    if ((pVuidMse->absres.width != pScr->virtualX) ||
58484bf8334Smrg        (pVuidMse->absres.height != pScr->virtualY))
5856aab59a7Smrg    {
58684bf8334Smrg        pVuidMse->absres.width = pScr->virtualX;
58784bf8334Smrg        pVuidMse->absres.height = pScr->virtualY;
5886aab59a7Smrg
589a73597f9Smrg        do {
590a73597f9Smrg            result = ioctl(pInfo->fd, MSIOSRESOLUTION, &(pVuidMse->absres));
591a73597f9Smrg        } while ( (result != 0) && (errno == EINTR) );
5926aab59a7Smrg
593a73597f9Smrg        if (result != 0) {
594a73597f9Smrg            LogMessageVerbSigSafe(X_WARNING, -1,
595a73597f9Smrg                                  "%s: couldn't set absolute mouse scaling resolution: %s\n",
596a73597f9Smrg                                  pInfo->name, strerror(errno));
5976aab59a7Smrg#ifdef DEBUG
598a73597f9Smrg        } else {
599a73597f9Smrg            LogMessageVerbSigSafe(X_INFO,
600a73597f9Smrg                                  "%s: absolute mouse scaling resolution set to %d x %d\n",
601a73597f9Smrg                                  pInfo->name,
602a73597f9Smrg                                  pVuidMse->absres.width,
603a73597f9Smrg                                  pVuidMse->absres.height);
6046aab59a7Smrg#endif
605a73597f9Smrg        }
6066aab59a7Smrg    }
6076aab59a7Smrg}
6086aab59a7Smrg
609a73597f9Smrgstatic void vuidMouseAdjustFrame(ADJUST_FRAME_ARGS_DECL)
6106aab59a7Smrg{
611a73597f9Smrg      SCRN_INFO_PTR(arg);
612a73597f9Smrg      ScreenPtr         pScreen = xf86ScrnToScreen(pScrn);
613a73597f9Smrg      xf86AdjustFrameProc *wrappedAdjustFrame
614a73597f9Smrg          = (xf86AdjustFrameProc *) vuidMouseGetScreenPrivate(pScreen);
615a73597f9Smrg      VuidMsePtr        m;
616a73597f9Smrg      ScreenPtr         ptrCurScreen;
617a73597f9Smrg
618a73597f9Smrg      if (wrappedAdjustFrame) {
619a73597f9Smrg          pScrn->AdjustFrame = wrappedAdjustFrame;
620a73597f9Smrg          (*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, x, y));
621a73597f9Smrg          pScrn->AdjustFrame = vuidMouseAdjustFrame;
6226aab59a7Smrg      }
6236aab59a7Smrg
6246aab59a7Smrg      for (m = vuidMouseList; m != NULL ; m = m->next) {
625a73597f9Smrg          ptrCurScreen = miPointerGetScreen(m->pInfo->dev);
626a73597f9Smrg          if (ptrCurScreen == pScreen)
627a73597f9Smrg          {
628a73597f9Smrg              vuidMouseSendScreenSize(pScreen, m);
629a73597f9Smrg          }
6306aab59a7Smrg      }
6316aab59a7Smrg}
63284bf8334Smrg
63384bf8334Smrgstatic void vuidMouseCrtcNotify(ScreenPtr pScreen)
63484bf8334Smrg{
63584bf8334Smrg    xf86_crtc_notify_proc_ptr wrappedCrtcNotify
63684bf8334Smrg        = (xf86_crtc_notify_proc_ptr) vuidMouseGetScreenPrivate(pScreen);
63784bf8334Smrg    VuidMsePtr       m;
63884bf8334Smrg    ScreenPtr        ptrCurScreen;
63984bf8334Smrg
64084bf8334Smrg    if (wrappedCrtcNotify)
64184bf8334Smrg        wrappedCrtcNotify(pScreen);
64284bf8334Smrg
64384bf8334Smrg    for (m = vuidMouseList; m != NULL ; m = m->next) {
64484bf8334Smrg        ptrCurScreen = miPointerGetScreen(m->pInfo->dev);
64584bf8334Smrg        if (ptrCurScreen == pScreen) {
64684bf8334Smrg            vuidMouseSendScreenSize(pScreen, m);
64784bf8334Smrg        }
64884bf8334Smrg    }
64984bf8334Smrg}
6506aab59a7Smrg#endif /* HAVE_ABSOLUTE_MOUSE_SCALING */
6516aab59a7Smrg
6526aab59a7Smrg
6536aab59a7Smrgstatic int
6546aab59a7SmrgvuidMouseProc(DeviceIntPtr pPointer, int what)
6556aab59a7Smrg{
6566aab59a7Smrg    InputInfoPtr pInfo;
6576aab59a7Smrg    MouseDevPtr pMse;
6586aab59a7Smrg    VuidMsePtr pVuidMse;
6596aab59a7Smrg    int ret = Success;
6606aab59a7Smrg    int i;
6616aab59a7Smrg
6626aab59a7Smrg    pInfo = pPointer->public.devicePrivate;
6636aab59a7Smrg    pMse = pInfo->private;
6646aab59a7Smrg    pMse->device = pPointer;
6656aab59a7Smrg
6666aab59a7Smrg    pVuidMse = getVuidMsePriv(pInfo);
6676aab59a7Smrg    if (pVuidMse == NULL) {
668a73597f9Smrg        return BadImplementation;
6696aab59a7Smrg    }
670a73597f9Smrg
6716aab59a7Smrg    switch (what) {
6726aab59a7Smrg
6736aab59a7Smrg    case DEVICE_INIT:
6746aab59a7Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
675b73be646Smrg
676b73be646Smrg#if HAS_DEVPRIVATEKEYREC
677a73597f9Smrg        if (!dixRegisterPrivateKey(&vuidMouseScreenIndex, PRIVATE_SCREEN, 0))
678a73597f9Smrg                return BadAlloc;
679b73be646Smrg#endif  /* HAS_DEVPRIVATEKEYREC */
680b73be646Smrg
681a73597f9Smrg        if (vuidMouseGeneration != serverGeneration) {
682a73597f9Smrg                for (i = 0; i < screenInfo.numScreens; i++) {
683a73597f9Smrg                    ScreenPtr pScreen = screenInfo.screens[i];
684a73597f9Smrg                    ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen);
68584bf8334Smrg                    if (xf86CrtcConfigPrivateIndex != -1) {
68684bf8334Smrg                        xf86_crtc_notify_proc_ptr pCrtcNotify
68784bf8334Smrg                            = xf86_wrap_crtc_notify(pScreen,
68884bf8334Smrg                                                    vuidMouseCrtcNotify);
68984bf8334Smrg                        vuidMouseSetScreenPrivate(pScreen, pCrtcNotify);
69084bf8334Smrg                    } else {
69184bf8334Smrg                        vuidMouseSetScreenPrivate(pScreen,
69284bf8334Smrg                                                  pScrn->AdjustFrame);
69384bf8334Smrg                        pScrn->AdjustFrame = vuidMouseAdjustFrame;
69484bf8334Smrg                    }
695a73597f9Smrg                }
696a73597f9Smrg            vuidMouseGeneration = serverGeneration;
697a73597f9Smrg        }
698a73597f9Smrg#endif
699a73597f9Smrg        ret = pVuidMse->wrapped_device_control(pPointer, what);
700a73597f9Smrg        break;
701a73597f9Smrg
7026aab59a7Smrg    case DEVICE_ON:
703a73597f9Smrg        ret = pVuidMse->wrapped_device_control(pPointer, DEVICE_ON);
704a73597f9Smrg
705a73597f9Smrg        if ((ret == Success) && (pInfo->fd != -1)) {
706a73597f9Smrg            int fmt = VUID_FIRM_EVENT;
707a73597f9Smrg
708a73597f9Smrg            if (pVuidMse->strmod) {
709a73597f9Smrg                /* Check to see if module is already pushed */
710a73597f9Smrg                SYSCALL(i = ioctl(pInfo->fd, I_FIND, pVuidMse->strmod));
711a73597f9Smrg
712a73597f9Smrg                if (i == 0) { /* Not already pushed */
713a73597f9Smrg                    SYSCALL(i = ioctl(pInfo->fd, I_PUSH, pVuidMse->strmod));
714a73597f9Smrg                    if (i < 0) {
715a73597f9Smrg                        xf86Msg(X_WARNING, "%s: cannot push module '%s' "
716a73597f9Smrg                                "onto mouse device: %s\n", pInfo->name,
717a73597f9Smrg                                pVuidMse->strmod, strerror(errno));
718a73597f9Smrg                        free(pVuidMse->strmod);
719a73597f9Smrg                        pVuidMse->strmod = NULL;
720a73597f9Smrg                    }
721a73597f9Smrg                }
722a73597f9Smrg            }
723a73597f9Smrg
724a73597f9Smrg            SYSCALL(i = ioctl(pInfo->fd, VUIDSFORMAT, &fmt));
725a73597f9Smrg            if (i < 0) {
726a73597f9Smrg                xf86Msg(X_WARNING,
727a73597f9Smrg                        "%s: cannot set mouse device to VUID mode: %s\n",
728a73597f9Smrg                        pInfo->name, strerror(errno));
729a73597f9Smrg            }
730a73597f9Smrg            vuidMouseWheelInit(pInfo);
731a73597f9Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
732a73597f9Smrg            vuidMouseSendScreenSize(screenInfo.screens[0], pVuidMse);
733a73597f9Smrg#endif
734a73597f9Smrg            xf86FlushInput(pInfo->fd);
735a73597f9Smrg
736a73597f9Smrg            /* Allocate here so we don't alloc in ReadInput which may be called
737a73597f9Smrg               from SIGIO handler. */
738a73597f9Smrg            if (pVuidMse->remove_timer == NULL) {
739a73597f9Smrg                pVuidMse->remove_timer = TimerSet(pVuidMse->remove_timer,
740a73597f9Smrg                                                  0, 0, NULL, NULL);
741a73597f9Smrg            }
742a73597f9Smrg        }
743a73597f9Smrg        break;
7446aab59a7Smrg
7456aab59a7Smrg    case DEVICE_CLOSE:
746ebac4eb7Smrg        if (vuidMouseList == pVuidMse)
747ebac4eb7Smrg            vuidMouseList = vuidMouseList->next;
748ebac4eb7Smrg        else {
749ebac4eb7Smrg            VuidMsePtr m = vuidMouseList;
750ebac4eb7Smrg
751ebac4eb7Smrg            while ((m != NULL) && (m->next != pVuidMse)) {
752ebac4eb7Smrg                m = m->next;
753ebac4eb7Smrg            }
754ebac4eb7Smrg
755ebac4eb7Smrg            if (m != NULL)
756ebac4eb7Smrg                m->next = pVuidMse->next;
757ebac4eb7Smrg        }
758ebac4eb7Smrg        /* fallthrough */
759ebac4eb7Smrg    case DEVICE_OFF:
760a73597f9Smrg        if (pInfo->fd != -1) {
761a73597f9Smrg            if (pVuidMse->strmod) {
762a73597f9Smrg                SYSCALL(i = ioctl(pInfo->fd, I_POP, pVuidMse->strmod));
763a73597f9Smrg                if (i == -1) {
764a73597f9Smrg                    xf86Msg(X_WARNING,
765a73597f9Smrg                      "%s: cannot pop module '%s' off mouse device: %s\n",
766a73597f9Smrg                      pInfo->name, pVuidMse->strmod, strerror(errno));
767a73597f9Smrg                }
768a73597f9Smrg            }
769a73597f9Smrg        }
770a73597f9Smrg        if (pVuidMse->remove_timer) {
771a73597f9Smrg            TimerFree(pVuidMse->remove_timer);
772a73597f9Smrg            pVuidMse->remove_timer = NULL;
773a73597f9Smrg        }
774a73597f9Smrg        ret = pVuidMse->wrapped_device_control(pPointer, what);
775a73597f9Smrg        break;
7766aab59a7Smrg
7776aab59a7Smrg    default: /* Should never be called, but just in case */
778a73597f9Smrg        ret = pVuidMse->wrapped_device_control(pPointer, what);
779a73597f9Smrg        break;
7806aab59a7Smrg    }
7816aab59a7Smrg    return ret;
7826aab59a7Smrg}
7836aab59a7Smrg
7846aab59a7Smrgstatic Bool
7856aab59a7SmrgsunMousePreInit(InputInfoPtr pInfo, const char *protocol, int flags)
7866aab59a7Smrg{
7876aab59a7Smrg    /* The protocol is guaranteed to be one of the internalNames[] */
7886aab59a7Smrg    if (xf86NameCmp(protocol, "VUID") == 0) {
789a73597f9Smrg        return vuidPreInit(pInfo, protocol, flags);
7906aab59a7Smrg    }
7916aab59a7Smrg    return TRUE;
792a73597f9Smrg}
7936aab59a7Smrg
7946aab59a7Smrgstatic const char **
7956aab59a7SmrgBuiltinNames(void)
7966aab59a7Smrg{
7976aab59a7Smrg    return internalNames;
7986aab59a7Smrg}
7996aab59a7Smrg
8006aab59a7Smrgstatic Bool
8016aab59a7SmrgCheckProtocol(const char *protocol)
8026aab59a7Smrg{
8036aab59a7Smrg    int i;
8046aab59a7Smrg
8056aab59a7Smrg    for (i = 0; internalNames[i]; i++)
806a73597f9Smrg        if (xf86NameCmp(protocol, internalNames[i]) == 0)
807a73597f9Smrg            return TRUE;
8086aab59a7Smrg
8096aab59a7Smrg    return FALSE;
8106aab59a7Smrg}
8116aab59a7Smrg
8126aab59a7Smrgstatic const char *
8136aab59a7SmrgDefaultProtocol(void)
8146aab59a7Smrg{
8156aab59a7Smrg    return "Auto";
8166aab59a7Smrg}
8176aab59a7Smrg
8186aab59a7Smrgstatic Bool
819a73597f9SmrgsolarisMouseAutoProbe(InputInfoPtr pInfo, const char **protocol,
820a73597f9Smrg        const char **device)
8216aab59a7Smrg{
8226aab59a7Smrg    const char **pdev, **pproto;
8236aab59a7Smrg    int fd = -1;
8246aab59a7Smrg    Bool found;
8256aab59a7Smrg    char *strmod;
8266aab59a7Smrg
8276aab59a7Smrg    if (*device == NULL) {
828a73597f9Smrg        /* Check to see if xorg.conf or HAL specified a device to use */
829a73597f9Smrg        *device = xf86CheckStrOption(pInfo->options, "Device", NULL);
8306aab59a7Smrg    }
8316aab59a7Smrg
8326aab59a7Smrg    if (*device != NULL) {
833a73597f9Smrg        strmod = xf86CheckStrOption(pInfo->options, "StreamsModule", NULL);
834a73597f9Smrg        if (strmod) {
835a73597f9Smrg            /* if a device name is already known, and a StreamsModule is
836a73597f9Smrg               specified to convert events to VUID, then we don't need to
837a73597f9Smrg               probe further */
838a73597f9Smrg            *protocol = "VUID";
839a73597f9Smrg            return TRUE;
840a73597f9Smrg        }
8416aab59a7Smrg    }
8426aab59a7Smrg
8436aab59a7Smrg
8446aab59a7Smrg    for (pdev = solarisMouseDevs; *pdev; pdev += 2) {
845a73597f9Smrg        pproto = pdev + 1;
846a73597f9Smrg        if ((*protocol != NULL) && (strcmp(*protocol, "Auto") != 0) &&
847a73597f9Smrg          (*pproto != NULL) && (strcmp(*pproto, *protocol) != 0)) {
848a73597f9Smrg            continue;
849a73597f9Smrg        }
850a73597f9Smrg        if ((*device != NULL) && (strcmp(*device, *pdev) != 0)) {
851a73597f9Smrg            continue;
852a73597f9Smrg        }
8536aab59a7Smrg        SYSCALL (fd = open(*pdev, O_RDWR | O_NONBLOCK));
854a73597f9Smrg        if (fd == -1) {
8556aab59a7Smrg#ifdef DEBUG
856a73597f9Smrg            ErrorF("Cannot open %s (%s)\n", pdev, strerror(errno));
8576aab59a7Smrg#endif
858a73597f9Smrg        } else {
859a73597f9Smrg            found = TRUE;
860a73597f9Smrg            if ((*pproto != NULL) && (strcmp(*pproto, "VUID") == 0)) {
861a73597f9Smrg                int i, r;
862a73597f9Smrg                SYSCALL(r = ioctl(fd, VUIDGFORMAT, &i));
863a73597f9Smrg                if (r < 0) {
864a73597f9Smrg                    found = FALSE;
865a73597f9Smrg                }
866a73597f9Smrg            }
867a73597f9Smrg            close(fd);
868a73597f9Smrg            if (found == TRUE) {
869a73597f9Smrg                if (*pproto != NULL) {
870a73597f9Smrg                    *protocol = *pproto;
871a73597f9Smrg                }
872a73597f9Smrg                *device = *pdev;
873a73597f9Smrg                return TRUE;
874a73597f9Smrg            }
875a73597f9Smrg        }
8766aab59a7Smrg    }
8776aab59a7Smrg    return FALSE;
8786aab59a7Smrg}
8796aab59a7Smrg
8806aab59a7Smrgstatic const char *
8816aab59a7SmrgSetupAuto(InputInfoPtr pInfo, int *protoPara)
8826aab59a7Smrg{
8836aab59a7Smrg    const char *pdev = NULL;
8846aab59a7Smrg    const char *pproto = NULL;
8856aab59a7Smrg    MouseDevPtr pMse = pInfo->private;
8866aab59a7Smrg
8876aab59a7Smrg    if (pInfo->fd == -1) {
888a73597f9Smrg        /* probe to find device/protocol to use */
889a73597f9Smrg        if (solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) {
890a73597f9Smrg            /* Set the Device option. */
891a73597f9Smrg            pInfo->options =
892a73597f9Smrg             xf86AddNewOption(pInfo->options, "Device", pdev);
893a73597f9Smrg            xf86Msg(X_INFO, "%s: Setting Device option to \"%s\"\n",
894a73597f9Smrg              pInfo->name, pdev);
895a73597f9Smrg        }
8966aab59a7Smrg    } else if (pMse->protocolID == PROT_AUTO) {
897a73597f9Smrg        pdev = xf86CheckStrOption(pInfo->options,
898a73597f9Smrg                "Device", NULL);
899a73597f9Smrg        if ((solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) &&
900a73597f9Smrg            (pproto != NULL))
901a73597f9Smrg            sunMousePreInit(pInfo, pproto, 0);
9026aab59a7Smrg    }
9036aab59a7Smrg    return pproto;
9046aab59a7Smrg}
9056aab59a7Smrg
9066aab59a7Smrgstatic const char *
9076aab59a7SmrgFindDevice(InputInfoPtr pInfo, const char *protocol, int flags)
9086aab59a7Smrg{
9096aab59a7Smrg    const char *pdev = NULL;
9106aab59a7Smrg    const char *pproto = protocol;
9116aab59a7Smrg
9126aab59a7Smrg    if (solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) {
913a73597f9Smrg        /* Set the Device option. */
914a73597f9Smrg        pInfo->options =
915a73597f9Smrg          xf86AddNewOption(pInfo->options, "Device", pdev);
916a73597f9Smrg        xf86Msg(X_INFO, "%s: Setting Device option to \"%s\"\n",
917a73597f9Smrg          pInfo->name, pdev);
9186aab59a7Smrg    }
9196aab59a7Smrg    return pdev;
9206aab59a7Smrg}
9216aab59a7Smrg
9226aab59a7Smrgstatic int
9236aab59a7SmrgSupportedInterfaces(void)
9246aab59a7Smrg{
9256aab59a7Smrg    /* XXX This needs to be checked. */
9266aab59a7Smrg    return MSE_SERIAL | MSE_BUS | MSE_PS2 | MSE_AUTO | MSE_XPS2 | MSE_MISC;
9276aab59a7Smrg}
9286aab59a7Smrg
929bd3a1963SmrgOSMouseInfoPtr
930bd3a1963SmrgOSMouseInit(int flags)
9316aab59a7Smrg{
9326aab59a7Smrg    OSMouseInfoPtr p;
9336aab59a7Smrg
934bd3a1963Smrg    p = calloc(sizeof(OSMouseInfoRec), 1);
9356aab59a7Smrg    if (!p)
936a73597f9Smrg        return NULL;
9376aab59a7Smrg    p->SupportedInterfaces = SupportedInterfaces;
9386aab59a7Smrg    p->BuiltinNames = BuiltinNames;
9396aab59a7Smrg    p->CheckProtocol = CheckProtocol;
9406aab59a7Smrg    p->PreInit = sunMousePreInit;
9416aab59a7Smrg    p->DefaultProtocol = DefaultProtocol;
9426aab59a7Smrg    p->SetupAuto = SetupAuto;
9436aab59a7Smrg    p->FindDevice = FindDevice;
9446aab59a7Smrg
9456aab59a7Smrg    return p;
9466aab59a7Smrg}
9476aab59a7Smrg
948