sun_mouse.c revision 370b807f
1b73be646Smrg/*
2b73be646Smrg * Copyright (c) 2004-2005, 2008-2010, Oracle and/or its affiliates.
3b73be646Smrg * All rights reserved.
4b73be646Smrg *
5b73be646Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6b73be646Smrg * copy of this software and associated documentation files (the "Software"),
7b73be646Smrg * to deal in the Software without restriction, including without limitation
8b73be646Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9b73be646Smrg * and/or sell copies of the Software, and to permit persons to whom the
10b73be646Smrg * Software is furnished to do so, subject to the following conditions:
11b73be646Smrg *
12b73be646Smrg * The above copyright notice and this permission notice (including the next
13b73be646Smrg * paragraph) shall be included in all copies or substantial portions of the
14b73be646Smrg * Software.
15b73be646Smrg *
16b73be646Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17b73be646Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18b73be646Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19b73be646Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20b73be646Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21b73be646Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22b73be646Smrg * DEALINGS IN THE SOFTWARE.
23b73be646Smrg */
246aab59a7Smrg/*
256aab59a7Smrg * Copyright 1999-2001 The XFree86 Project, Inc.  All Rights Reserved.
266aab59a7Smrg *
276aab59a7Smrg * Permission is hereby granted, free of charge, to any person obtaining a copy
286aab59a7Smrg * of this software and associated documentation files (the "Software"), to
296aab59a7Smrg * deal in the Software without restriction, including without limitation the
306aab59a7Smrg * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
316aab59a7Smrg * sell copies of the Software, and to permit persons to whom the Software is
326aab59a7Smrg * furnished to do so, subject to the following conditions:
336aab59a7Smrg *
346aab59a7Smrg * The above copyright notice and this permission notice shall be included in
356aab59a7Smrg * all copies or substantial portions of the Software.
366aab59a7Smrg *
376aab59a7Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
386aab59a7Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
396aab59a7Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
406aab59a7Smrg * XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
416aab59a7Smrg * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
426aab59a7Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
436aab59a7Smrg *
446aab59a7Smrg * Except as contained in this notice, the name of the XFree86 Project shall
456aab59a7Smrg * not be used in advertising or otherwise to promote the sale, use or other
466aab59a7Smrg * dealings in this Software without prior written authorization from the
476aab59a7Smrg * XFree86 Project.
486aab59a7Smrg */
496aab59a7Smrg
50370b807fSmrg#ifdef HAVE_CONFIG_H
51370b807fSmrg#include "config.h"
52370b807fSmrg#endif
53370b807fSmrg
546aab59a7Smrg#ifdef HAVE_XORG_CONFIG_H
556aab59a7Smrg#include <xorg-config.h>
566aab59a7Smrg#endif
576aab59a7Smrg
586aab59a7Smrg#include "xorg-server.h"
596aab59a7Smrg#include "xf86.h"
606aab59a7Smrg#include "xf86_OSlib.h"
61bd3a1963Smrg#include "mouse.h"
626aab59a7Smrg#include "xisb.h"
636aab59a7Smrg#include "mipointer.h"
6484bf8334Smrg#include "xf86Crtc.h"
656aab59a7Smrg#include <sys/stropts.h>
666aab59a7Smrg#include <sys/vuid_event.h>
676aab59a7Smrg#include <sys/msio.h>
686aab59a7Smrg
696aab59a7Smrg/* Wheel mouse support in VUID drivers in Solaris 9 updates & Solaris 10 */
706aab59a7Smrg#ifdef WHEEL_DEVID /* Defined in vuid_event.h if VUID wheel support present */
716aab59a7Smrg# define HAVE_VUID_WHEEL
726aab59a7Smrg#endif
736aab59a7Smrg#ifdef HAVE_VUID_WHEEL
746aab59a7Smrg# include <sys/vuid_wheel.h>
756aab59a7Smrg#endif
766aab59a7Smrg
77a73597f9Smrg/* Support for scaling absolute coordinates to screen size in
786aab59a7Smrg * Solaris 10 updates and beyond */
796aab59a7Smrg#if !defined(HAVE_ABSOLUTE_MOUSE_SCALING)
806aab59a7Smrg# ifdef MSIOSRESOLUTION /* Defined in msio.h if scaling support present */
816aab59a7Smrg#  define HAVE_ABSOLUTE_MOUSE_SCALING
826aab59a7Smrg# endif
836aab59a7Smrg#endif
846aab59a7Smrg
856aab59a7Smrg/* Names of protocols that are handled internally here. */
866aab59a7Smrg
876aab59a7Smrgstatic const char *internalNames[] = {
88a73597f9Smrg        "VUID",
89a73597f9Smrg        NULL
906aab59a7Smrg};
916aab59a7Smrg
926aab59a7Smrgstatic const char *solarisMouseDevs[] = {
93a73597f9Smrg    /* Device file:     Protocol:                       */
94a73597f9Smrg    "/dev/mouse",       "VUID",         /* USB or SPARC */
956aab59a7Smrg#if defined(__i386) || defined(__x86)
96a73597f9Smrg    "/dev/kdmouse",     "PS/2",         /* PS/2 */
976aab59a7Smrg#endif
986aab59a7Smrg    NULL
996aab59a7Smrg};
1006aab59a7Smrg
1016aab59a7Smrgtypedef struct _VuidMseRec {
102a73597f9Smrg    struct _VuidMseRec *next;
103a73597f9Smrg    InputInfoPtr        pInfo;
104a73597f9Smrg    Firm_event          event;
105a73597f9Smrg    unsigned char *     buffer;
106a73597f9Smrg    char *              strmod;
1076aab59a7Smrg    Bool(*wrapped_device_control)(DeviceIntPtr device, int what);
1086aab59a7Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
109a73597f9Smrg    Ms_screen_resolution         absres;
1106aab59a7Smrg#endif
111a73597f9Smrg    OsTimerPtr          remove_timer;   /* Callback for removal on ENODEV */
1126aab59a7Smrg} VuidMseRec, *VuidMsePtr;
1136aab59a7Smrg
114a73597f9Smrgstatic VuidMsePtr       vuidMouseList = NULL;
1156aab59a7Smrg
1166aab59a7Smrgstatic int  vuidMouseProc(DeviceIntPtr pPointer, int what);
1176aab59a7Smrgstatic void vuidReadInput(InputInfoPtr pInfo);
1186aab59a7Smrg
1196aab59a7Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
120a73597f9Smrg# include "compat-api.h"
121a73597f9Smrg
1226aab59a7Smrgstatic void vuidMouseSendScreenSize(ScreenPtr pScreen, VuidMsePtr pVuidMse);
123a73597f9Smrgstatic void vuidMouseAdjustFrame(ADJUST_FRAME_ARGS_DECL);
1246aab59a7Smrg
125370b807fSmrgstatic unsigned long vuidMouseGeneration = 0;
126b73be646Smrg
127b73be646Smrg#if HAS_DEVPRIVATEKEYREC
128b73be646Smrgstatic DevPrivateKeyRec vuidMouseScreenIndex;
129b73be646Smrg#else
1306aab59a7Smrgstatic int vuidMouseScreenIndex;
131b73be646Smrg#endif /* HAS_DEVPRIVATEKEYREC */
132b73be646Smrg
1336aab59a7Smrg#define vuidMouseGetScreenPrivate(s) ( \
1346aab59a7Smrg    dixLookupPrivate(&(s)->devPrivates, &vuidMouseScreenIndex))
1356aab59a7Smrg#define vuidMouseSetScreenPrivate(s,p) \
1366aab59a7Smrg    dixSetPrivate(&(s)->devPrivates, &vuidMouseScreenIndex, (void *) p)
1376aab59a7Smrg#endif /* HAVE_ABSOLUTE_MOUSE_SCALING */
1386aab59a7Smrg
1396aab59a7Smrgstatic inline
1406aab59a7SmrgVuidMsePtr getVuidMsePriv(InputInfoPtr pInfo)
1416aab59a7Smrg{
1426aab59a7Smrg    VuidMsePtr m = vuidMouseList;
1436aab59a7Smrg
1446aab59a7Smrg    while ((m != NULL) && (m->pInfo != pInfo)) {
145a73597f9Smrg        m = m->next;
1466aab59a7Smrg    }
1476aab59a7Smrg
1486aab59a7Smrg    return m;
1496aab59a7Smrg}
1506aab59a7Smrg
151b73be646Smrg/* Called from OsTimer callback, since removing a device from the device
152b73be646Smrg   list or changing pInfo->fd while xf86Wakeup is looping through the list
153b73be646Smrg   causes server crashes */
154b73be646Smrgstatic CARD32
155a73597f9SmrgvuidRemoveMouse(OsTimerPtr timer, CARD32 now, pointer arg)
156b73be646Smrg{
157b73be646Smrg    InputInfoPtr pInfo = (InputInfoPtr) arg;
158b73be646Smrg
159b73be646Smrg    xf86DisableDevice(pInfo->dev, TRUE);
160b73be646Smrg
161b73be646Smrg    return 0;  /* All done, don't set to run again */
162b73be646Smrg}
1636aab59a7Smrg
1646aab59a7Smrg/*
1656aab59a7Smrg * Initialize and enable the mouse wheel, if present.
1666aab59a7Smrg *
1676aab59a7Smrg * Returns 1 if mouse wheel was successfully enabled.
1686aab59a7Smrg * Returns 0 if an error occurred or if there is no mouse wheel.
1696aab59a7Smrg */
1706aab59a7Smrgstatic int
1716aab59a7SmrgvuidMouseWheelInit(InputInfoPtr pInfo)
1726aab59a7Smrg{
1736aab59a7Smrg#ifdef HAVE_VUID_WHEEL
1746aab59a7Smrg    wheel_state wstate;
1756aab59a7Smrg    int nwheel = -1;
1766aab59a7Smrg    int i;
1776aab59a7Smrg
1786aab59a7Smrg    wstate.vers = VUID_WHEEL_STATE_VERS;
1796aab59a7Smrg    wstate.id = 0;
1806aab59a7Smrg    wstate.stateflags = (uint32_t) -1;
1816aab59a7Smrg
1826aab59a7Smrg    SYSCALL(i = ioctl(pInfo->fd, VUIDGWHEELCOUNT, &nwheel));
1836aab59a7Smrg    if (i != 0)
184a73597f9Smrg        return (0);
1856aab59a7Smrg
1866aab59a7Smrg    SYSCALL(i = ioctl(pInfo->fd, VUIDGWHEELSTATE, &wstate));
1876aab59a7Smrg    if (i != 0) {
188a73597f9Smrg        xf86Msg(X_WARNING, "%s: couldn't get wheel state\n", pInfo->name);
189a73597f9Smrg        return (0);
1906aab59a7Smrg    }
1916aab59a7Smrg
1926aab59a7Smrg    wstate.stateflags |= VUID_WHEEL_STATE_ENABLED;
1936aab59a7Smrg
1946aab59a7Smrg    SYSCALL(i = ioctl(pInfo->fd, VUIDSWHEELSTATE, &wstate));
1956aab59a7Smrg    if (i != 0) {
196a73597f9Smrg        xf86Msg(X_WARNING, "%s: couldn't enable wheel\n", pInfo->name);
197a73597f9Smrg        return (0);
1986aab59a7Smrg    }
1996aab59a7Smrg
2006aab59a7Smrg    return (1);
2016aab59a7Smrg#else
2026aab59a7Smrg    return (0);
2036aab59a7Smrg#endif
2046aab59a7Smrg}
2056aab59a7Smrg
2066aab59a7Smrg
2076aab59a7Smrg/* This function is called when the protocol is "VUID". */
2086aab59a7Smrgstatic Bool
2096aab59a7SmrgvuidPreInit(InputInfoPtr pInfo, const char *protocol, int flags)
2106aab59a7Smrg{
2116aab59a7Smrg    MouseDevPtr pMse = pInfo->private;
2126aab59a7Smrg    VuidMsePtr pVuidMse;
213a73597f9Smrg
214a73597f9Smrg    /* Ensure we don't add the same device twice */
215a73597f9Smrg    if (getVuidMsePriv(pInfo) != NULL)
216a73597f9Smrg        return TRUE;
2176aab59a7Smrg
218bd3a1963Smrg    pVuidMse = calloc(sizeof(VuidMseRec), 1);
2196aab59a7Smrg    if (pVuidMse == NULL) {
220a73597f9Smrg        xf86Msg(X_ERROR, "%s: cannot allocate VuidMouseRec\n", pInfo->name);
221a73597f9Smrg        free(pMse);
222a73597f9Smrg        return FALSE;
2236aab59a7Smrg    }
2246aab59a7Smrg
225fc27e79cSmrg    pVuidMse->buffer = (unsigned char *)&pVuidMse->event;
226fc27e79cSmrg    pVuidMse->strmod = xf86SetStrOption(pInfo->options, "StreamsModule", NULL);
227fc27e79cSmrg
2286aab59a7Smrg    /* Setup the local procs. */
2296aab59a7Smrg    pVuidMse->wrapped_device_control = pInfo->device_control;
2306aab59a7Smrg    pInfo->device_control = vuidMouseProc;
2316aab59a7Smrg    pInfo->read_input = vuidReadInput;
2326aab59a7Smrg
2336aab59a7Smrg    pMse->xisbscale = sizeof(Firm_event);
2346aab59a7Smrg
235a73597f9Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
2366aab59a7Smrg    pVuidMse->absres.height = pVuidMse->absres.width = 0;
2376aab59a7Smrg#endif
2386aab59a7Smrg    pVuidMse->pInfo = pInfo;
239a73597f9Smrg    pVuidMse->next = vuidMouseList;
2406aab59a7Smrg    vuidMouseList = pVuidMse;
2416aab59a7Smrg
242bd3a1963Smrg#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
2436aab59a7Smrg    pInfo->flags |= XI86_CONFIGURED;
244bd3a1963Smrg#endif
2456aab59a7Smrg    return TRUE;
2466aab59a7Smrg}
2476aab59a7Smrg
2486aab59a7Smrgstatic void
249a73597f9SmrgvuidFlushAbsEvents(InputInfoPtr pInfo, int absX, int absY,
250a73597f9Smrg                   Bool *absXset, Bool *absYset)
2516aab59a7Smrg{
2526aab59a7Smrg#ifdef DEBUG
253a73597f9Smrg    ErrorF("vuidFlushAbsEvents: %d,%d (set: %d, %d)\n", absX, absY,
254a73597f9Smrg           *absXset, *absYset);
2556aab59a7Smrg#endif
2566aab59a7Smrg    if ((*absXset) && (*absYset)) {
257a73597f9Smrg        xf86PostMotionEvent(pInfo->dev,
258a73597f9Smrg                            /* is_absolute: */    TRUE,
259a73597f9Smrg                            /* first_valuator: */ 0,
260a73597f9Smrg                            /* num_valuators: */  2,
261a73597f9Smrg                            absX, absY);
2626aab59a7Smrg    } else if (*absXset) {
263a73597f9Smrg        xf86PostMotionEvent(pInfo->dev,
264a73597f9Smrg                            /* is_absolute: */    TRUE,
265a73597f9Smrg                            /* first_valuator: */ 0,
266a73597f9Smrg                            /* num_valuators: */  1,
267a73597f9Smrg                            absX);
2686aab59a7Smrg    } else if (*absYset) {
269a73597f9Smrg        xf86PostMotionEvent(pInfo->dev,
270a73597f9Smrg                            /* is_absolute: */    TRUE,
271a73597f9Smrg                            /* first_valuator: */ 1,
272a73597f9Smrg                            /* num_valuators: */  1,
273a73597f9Smrg                            absY);
2746aab59a7Smrg    }
2756aab59a7Smrg
2766aab59a7Smrg    *absXset = FALSE;
2776aab59a7Smrg    *absYset = FALSE;
2786aab59a7Smrg}
2796aab59a7Smrg
2806aab59a7Smrgstatic void
2816aab59a7SmrgvuidReadInput(InputInfoPtr pInfo)
2826aab59a7Smrg{
2836aab59a7Smrg    MouseDevPtr pMse;
2846aab59a7Smrg    VuidMsePtr pVuidMse;
2856aab59a7Smrg    int buttons;
2866aab59a7Smrg    int dx = 0, dy = 0, dz = 0, dw = 0;
287370b807fSmrg    ssize_t n;
2886aab59a7Smrg    unsigned char *pBuf;
2896aab59a7Smrg    int absX = 0, absY = 0;
2906aab59a7Smrg    Bool absXset = FALSE, absYset = FALSE;
2916aab59a7Smrg
2926aab59a7Smrg    pMse = pInfo->private;
2936aab59a7Smrg    buttons = pMse->lastButtons;
294370b807fSmrg    pVuidMse = getVuidMsePriv(pInfo);
295370b807fSmrg    if (pVuidMse == NULL) {
296370b807fSmrg        xf86Msg(X_ERROR, "%s: cannot locate VuidMsePtr\n", pInfo->name);
297370b807fSmrg        return;
298370b807fSmrg    }
2996aab59a7Smrg    pBuf = pVuidMse->buffer;
3006aab59a7Smrg
3016aab59a7Smrg    do {
302a73597f9Smrg        n = read(pInfo->fd, pBuf, sizeof(Firm_event));
303a73597f9Smrg
304a73597f9Smrg        if (n == 0) {
305a73597f9Smrg            break;
306a73597f9Smrg        } else if (n == -1) {
307a73597f9Smrg            switch (errno) {
308a73597f9Smrg                case EAGAIN: /* Nothing to read now */
309a73597f9Smrg                    n = 0;   /* End loop, go on to flush events & return */
310a73597f9Smrg                    continue;
311a73597f9Smrg                case EINTR:  /* Interrupted, try again */
312a73597f9Smrg                    continue;
313a73597f9Smrg                case ENODEV: /* May happen when USB mouse is unplugged */
314a73597f9Smrg                    /* We use X_NONE here because it didn't alloc since we
315a73597f9Smrg                       may be called from SIGIO handler. No longer true for
316a73597f9Smrg                       sigsafe logging, but matters for older servers  */
317a73597f9Smrg                    LogMessageVerbSigSafe(X_NONE, 0,
318a73597f9Smrg                                          "%s: Device no longer present - removing.\n",
319a73597f9Smrg                                          pInfo->name);
320a73597f9Smrg                    xf86RemoveEnabledDevice(pInfo);
321a73597f9Smrg                    pVuidMse->remove_timer =
322a73597f9Smrg                        TimerSet(pVuidMse->remove_timer, 0, 1,
323a73597f9Smrg                                 vuidRemoveMouse, pInfo);
324a73597f9Smrg                    return;
325a73597f9Smrg                default:     /* All other errors */
326a73597f9Smrg                    /* We use X_NONE here because it didn't alloc since we
327a73597f9Smrg                       may be called from SIGIO handler. No longer true for
328a73597f9Smrg                       sigsafe logging, but matters for older servers  */
329a73597f9Smrg                    LogMessageVerbSigSafe(X_NONE, 0, "%s: Read error: %s\n",
330a73597f9Smrg                                          pInfo->name, strerror(errno));
331a73597f9Smrg                    return;
332a73597f9Smrg            }
333a73597f9Smrg        } else if (n != sizeof(Firm_event)) {
334370b807fSmrg            xf86Msg(X_WARNING, "%s: incomplete packet, size %zd\n",
335a73597f9Smrg                        pInfo->name, n);
336a73597f9Smrg        }
3376aab59a7Smrg
3386aab59a7Smrg#ifdef DEBUG
339a73597f9Smrg        LogMessageVerbSigSafe("vuidReadInput: event type: %d value: %d\n",
340a73597f9Smrg                              pVuidMse->event.id, pVuidMse->event.value);
3416aab59a7Smrg#endif
3426aab59a7Smrg
343a73597f9Smrg        if (pVuidMse->event.id >= BUT_FIRST && pVuidMse->event.id <= BUT_LAST) {
344a73597f9Smrg            /* button */
345a73597f9Smrg            int butnum = pVuidMse->event.id - BUT_FIRST;
346a73597f9Smrg
347a73597f9Smrg            if (butnum < 3)
348a73597f9Smrg                butnum = 2 - butnum;
349a73597f9Smrg            if (!pVuidMse->event.value)
350a73597f9Smrg                buttons &= ~(1 << butnum);
351a73597f9Smrg            else
352a73597f9Smrg                buttons |= (1 << butnum);
353a73597f9Smrg        } else if (pVuidMse->event.id >= VLOC_FIRST &&
354a73597f9Smrg                   pVuidMse->event.id <= VLOC_LAST) {
355a73597f9Smrg            /* axis */
356a73597f9Smrg            int delta = pVuidMse->event.value;
357a73597f9Smrg            switch(pVuidMse->event.id) {
358a73597f9Smrg            case LOC_X_DELTA:
359a73597f9Smrg                dx += delta;
360a73597f9Smrg                break;
361a73597f9Smrg            case LOC_Y_DELTA:
362a73597f9Smrg                dy -= delta;
363a73597f9Smrg                break;
364a73597f9Smrg            case LOC_X_ABSOLUTE:
365a73597f9Smrg                if (absXset) {
366a73597f9Smrg                    vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
367a73597f9Smrg                }
368a73597f9Smrg                absX = delta;
369a73597f9Smrg                absXset = TRUE;
370a73597f9Smrg                break;
371a73597f9Smrg            case LOC_Y_ABSOLUTE:
372a73597f9Smrg                if (absYset) {
373a73597f9Smrg                    vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
374a73597f9Smrg                }
375a73597f9Smrg                absY = delta;
376a73597f9Smrg                absYset = TRUE;
377a73597f9Smrg                break;
378a73597f9Smrg            }
379a73597f9Smrg        }
3806aab59a7Smrg#ifdef HAVE_VUID_WHEEL
381a73597f9Smrg        else if (vuid_in_range(VUID_WHEEL, pVuidMse->event.id)) {
382a73597f9Smrg            if (vuid_id_offset(pVuidMse->event.id) == 0)
383a73597f9Smrg                dz -= VUID_WHEEL_GETDELTA(pVuidMse->event.value);
384a73597f9Smrg            else
385a73597f9Smrg                dw -= VUID_WHEEL_GETDELTA(pVuidMse->event.value);
386a73597f9Smrg        }
3876aab59a7Smrg#endif
3886aab59a7Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
389a73597f9Smrg        else if (pVuidMse->event.id == MOUSE_TYPE_ABSOLUTE) {
390a73597f9Smrg            ScreenPtr   ptrCurScreen;
391a73597f9Smrg
392a73597f9Smrg            /* force sending absolute resolution scaling ioctl */
393a73597f9Smrg            pVuidMse->absres.height = pVuidMse->absres.width = 0;
394a73597f9Smrg            ptrCurScreen = miPointerGetScreen(pInfo->dev);
395a73597f9Smrg            vuidMouseSendScreenSize(ptrCurScreen, pVuidMse);
396a73597f9Smrg        }
3976aab59a7Smrg#endif
3986aab59a7Smrg
3996aab59a7Smrg    } while (n != 0);
4006aab59a7Smrg
4016aab59a7Smrg    if (absXset || absYset) {
402a73597f9Smrg        vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
4036aab59a7Smrg    }
4046aab59a7Smrg
4056aab59a7Smrg    pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw);
4066aab59a7Smrg    return;
4076aab59a7Smrg}
4086aab59a7Smrg
4096aab59a7Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
4106aab59a7Smrgstatic void vuidMouseSendScreenSize(ScreenPtr pScreen, VuidMsePtr pVuidMse)
4116aab59a7Smrg{
4126aab59a7Smrg    InputInfoPtr pInfo = pVuidMse->pInfo;
4136aab59a7Smrg    ScrnInfoPtr pScr = XF86SCRNINFO(pScreen);
4146aab59a7Smrg    int result;
4156aab59a7Smrg
41684bf8334Smrg    if ((pVuidMse->absres.width != pScr->virtualX) ||
41784bf8334Smrg        (pVuidMse->absres.height != pScr->virtualY))
4186aab59a7Smrg    {
41984bf8334Smrg        pVuidMse->absres.width = pScr->virtualX;
42084bf8334Smrg        pVuidMse->absres.height = pScr->virtualY;
4216aab59a7Smrg
422a73597f9Smrg        do {
423a73597f9Smrg            result = ioctl(pInfo->fd, MSIOSRESOLUTION, &(pVuidMse->absres));
424a73597f9Smrg        } while ( (result != 0) && (errno == EINTR) );
4256aab59a7Smrg
426a73597f9Smrg        if (result != 0) {
427a73597f9Smrg            LogMessageVerbSigSafe(X_WARNING, -1,
428a73597f9Smrg                                  "%s: couldn't set absolute mouse scaling resolution: %s\n",
429a73597f9Smrg                                  pInfo->name, strerror(errno));
4306aab59a7Smrg#ifdef DEBUG
431a73597f9Smrg        } else {
432a73597f9Smrg            LogMessageVerbSigSafe(X_INFO,
433a73597f9Smrg                                  "%s: absolute mouse scaling resolution set to %d x %d\n",
434a73597f9Smrg                                  pInfo->name,
435a73597f9Smrg                                  pVuidMse->absres.width,
436a73597f9Smrg                                  pVuidMse->absres.height);
4376aab59a7Smrg#endif
438a73597f9Smrg        }
4396aab59a7Smrg    }
4406aab59a7Smrg}
4416aab59a7Smrg
442a73597f9Smrgstatic void vuidMouseAdjustFrame(ADJUST_FRAME_ARGS_DECL)
4436aab59a7Smrg{
444a73597f9Smrg      SCRN_INFO_PTR(arg);
445a73597f9Smrg      ScreenPtr         pScreen = xf86ScrnToScreen(pScrn);
446a73597f9Smrg      xf86AdjustFrameProc *wrappedAdjustFrame
447a73597f9Smrg          = (xf86AdjustFrameProc *) vuidMouseGetScreenPrivate(pScreen);
448a73597f9Smrg      VuidMsePtr        m;
449a73597f9Smrg      ScreenPtr         ptrCurScreen;
450a73597f9Smrg
451a73597f9Smrg      if (wrappedAdjustFrame) {
452a73597f9Smrg          pScrn->AdjustFrame = wrappedAdjustFrame;
453a73597f9Smrg          (*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, x, y));
454a73597f9Smrg          pScrn->AdjustFrame = vuidMouseAdjustFrame;
4556aab59a7Smrg      }
4566aab59a7Smrg
4576aab59a7Smrg      for (m = vuidMouseList; m != NULL ; m = m->next) {
458a73597f9Smrg          ptrCurScreen = miPointerGetScreen(m->pInfo->dev);
459a73597f9Smrg          if (ptrCurScreen == pScreen)
460a73597f9Smrg          {
461a73597f9Smrg              vuidMouseSendScreenSize(pScreen, m);
462a73597f9Smrg          }
4636aab59a7Smrg      }
4646aab59a7Smrg}
46584bf8334Smrg
46684bf8334Smrgstatic void vuidMouseCrtcNotify(ScreenPtr pScreen)
46784bf8334Smrg{
46884bf8334Smrg    xf86_crtc_notify_proc_ptr wrappedCrtcNotify
46984bf8334Smrg        = (xf86_crtc_notify_proc_ptr) vuidMouseGetScreenPrivate(pScreen);
47084bf8334Smrg    VuidMsePtr       m;
47184bf8334Smrg    ScreenPtr        ptrCurScreen;
47284bf8334Smrg
47384bf8334Smrg    if (wrappedCrtcNotify)
47484bf8334Smrg        wrappedCrtcNotify(pScreen);
47584bf8334Smrg
47684bf8334Smrg    for (m = vuidMouseList; m != NULL ; m = m->next) {
47784bf8334Smrg        ptrCurScreen = miPointerGetScreen(m->pInfo->dev);
47884bf8334Smrg        if (ptrCurScreen == pScreen) {
47984bf8334Smrg            vuidMouseSendScreenSize(pScreen, m);
48084bf8334Smrg        }
48184bf8334Smrg    }
48284bf8334Smrg}
4836aab59a7Smrg#endif /* HAVE_ABSOLUTE_MOUSE_SCALING */
4846aab59a7Smrg
4856aab59a7Smrg
4866aab59a7Smrgstatic int
4876aab59a7SmrgvuidMouseProc(DeviceIntPtr pPointer, int what)
4886aab59a7Smrg{
4896aab59a7Smrg    InputInfoPtr pInfo;
4906aab59a7Smrg    MouseDevPtr pMse;
4916aab59a7Smrg    VuidMsePtr pVuidMse;
4926aab59a7Smrg    int ret = Success;
4936aab59a7Smrg    int i;
4946aab59a7Smrg
4956aab59a7Smrg    pInfo = pPointer->public.devicePrivate;
4966aab59a7Smrg    pMse = pInfo->private;
4976aab59a7Smrg    pMse->device = pPointer;
4986aab59a7Smrg
4996aab59a7Smrg    pVuidMse = getVuidMsePriv(pInfo);
5006aab59a7Smrg    if (pVuidMse == NULL) {
501a73597f9Smrg        return BadImplementation;
5026aab59a7Smrg    }
503a73597f9Smrg
5046aab59a7Smrg    switch (what) {
5056aab59a7Smrg
5066aab59a7Smrg    case DEVICE_INIT:
5076aab59a7Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
508b73be646Smrg
509b73be646Smrg#if HAS_DEVPRIVATEKEYREC
510a73597f9Smrg        if (!dixRegisterPrivateKey(&vuidMouseScreenIndex, PRIVATE_SCREEN, 0))
511a73597f9Smrg                return BadAlloc;
512b73be646Smrg#endif  /* HAS_DEVPRIVATEKEYREC */
513b73be646Smrg
514a73597f9Smrg        if (vuidMouseGeneration != serverGeneration) {
515a73597f9Smrg                for (i = 0; i < screenInfo.numScreens; i++) {
516a73597f9Smrg                    ScreenPtr pScreen = screenInfo.screens[i];
517a73597f9Smrg                    ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen);
51884bf8334Smrg                    if (xf86CrtcConfigPrivateIndex != -1) {
51984bf8334Smrg                        xf86_crtc_notify_proc_ptr pCrtcNotify
52084bf8334Smrg                            = xf86_wrap_crtc_notify(pScreen,
52184bf8334Smrg                                                    vuidMouseCrtcNotify);
52284bf8334Smrg                        vuidMouseSetScreenPrivate(pScreen, pCrtcNotify);
52384bf8334Smrg                    } else {
52484bf8334Smrg                        vuidMouseSetScreenPrivate(pScreen,
52584bf8334Smrg                                                  pScrn->AdjustFrame);
52684bf8334Smrg                        pScrn->AdjustFrame = vuidMouseAdjustFrame;
52784bf8334Smrg                    }
528a73597f9Smrg                }
529a73597f9Smrg            vuidMouseGeneration = serverGeneration;
530a73597f9Smrg        }
531a73597f9Smrg#endif
532a73597f9Smrg        ret = pVuidMse->wrapped_device_control(pPointer, what);
533a73597f9Smrg        break;
534a73597f9Smrg
5356aab59a7Smrg    case DEVICE_ON:
536a73597f9Smrg        ret = pVuidMse->wrapped_device_control(pPointer, DEVICE_ON);
537a73597f9Smrg
538a73597f9Smrg        if ((ret == Success) && (pInfo->fd != -1)) {
539a73597f9Smrg            int fmt = VUID_FIRM_EVENT;
540a73597f9Smrg
541a73597f9Smrg            if (pVuidMse->strmod) {
542a73597f9Smrg                /* Check to see if module is already pushed */
543a73597f9Smrg                SYSCALL(i = ioctl(pInfo->fd, I_FIND, pVuidMse->strmod));
544a73597f9Smrg
545a73597f9Smrg                if (i == 0) { /* Not already pushed */
546a73597f9Smrg                    SYSCALL(i = ioctl(pInfo->fd, I_PUSH, pVuidMse->strmod));
547a73597f9Smrg                    if (i < 0) {
548a73597f9Smrg                        xf86Msg(X_WARNING, "%s: cannot push module '%s' "
549a73597f9Smrg                                "onto mouse device: %s\n", pInfo->name,
550a73597f9Smrg                                pVuidMse->strmod, strerror(errno));
551a73597f9Smrg                        free(pVuidMse->strmod);
552a73597f9Smrg                        pVuidMse->strmod = NULL;
553a73597f9Smrg                    }
554a73597f9Smrg                }
555a73597f9Smrg            }
556a73597f9Smrg
557a73597f9Smrg            SYSCALL(i = ioctl(pInfo->fd, VUIDSFORMAT, &fmt));
558a73597f9Smrg            if (i < 0) {
559a73597f9Smrg                xf86Msg(X_WARNING,
560a73597f9Smrg                        "%s: cannot set mouse device to VUID mode: %s\n",
561a73597f9Smrg                        pInfo->name, strerror(errno));
562a73597f9Smrg            }
563a73597f9Smrg            vuidMouseWheelInit(pInfo);
564a73597f9Smrg#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
565a73597f9Smrg            vuidMouseSendScreenSize(screenInfo.screens[0], pVuidMse);
566a73597f9Smrg#endif
567a73597f9Smrg            xf86FlushInput(pInfo->fd);
568a73597f9Smrg
569a73597f9Smrg            /* Allocate here so we don't alloc in ReadInput which may be called
570a73597f9Smrg               from SIGIO handler. */
571a73597f9Smrg            if (pVuidMse->remove_timer == NULL) {
572a73597f9Smrg                pVuidMse->remove_timer = TimerSet(pVuidMse->remove_timer,
573a73597f9Smrg                                                  0, 0, NULL, NULL);
574a73597f9Smrg            }
575a73597f9Smrg        }
576a73597f9Smrg        break;
5776aab59a7Smrg
5786aab59a7Smrg    case DEVICE_OFF:
5796aab59a7Smrg    case DEVICE_CLOSE:
580a73597f9Smrg        if (pInfo->fd != -1) {
581a73597f9Smrg            if (pVuidMse->strmod) {
582a73597f9Smrg                SYSCALL(i = ioctl(pInfo->fd, I_POP, pVuidMse->strmod));
583a73597f9Smrg                if (i == -1) {
584a73597f9Smrg                    xf86Msg(X_WARNING,
585a73597f9Smrg                      "%s: cannot pop module '%s' off mouse device: %s\n",
586a73597f9Smrg                      pInfo->name, pVuidMse->strmod, strerror(errno));
587a73597f9Smrg                }
588a73597f9Smrg            }
589a73597f9Smrg        }
590a73597f9Smrg        if (pVuidMse->remove_timer) {
591a73597f9Smrg            TimerFree(pVuidMse->remove_timer);
592a73597f9Smrg            pVuidMse->remove_timer = NULL;
593a73597f9Smrg        }
594a73597f9Smrg        ret = pVuidMse->wrapped_device_control(pPointer, what);
595a73597f9Smrg        break;
5966aab59a7Smrg
5976aab59a7Smrg    default: /* Should never be called, but just in case */
598a73597f9Smrg        ret = pVuidMse->wrapped_device_control(pPointer, what);
599a73597f9Smrg        break;
6006aab59a7Smrg    }
6016aab59a7Smrg    return ret;
6026aab59a7Smrg}
6036aab59a7Smrg
6046aab59a7Smrgstatic Bool
6056aab59a7SmrgsunMousePreInit(InputInfoPtr pInfo, const char *protocol, int flags)
6066aab59a7Smrg{
6076aab59a7Smrg    /* The protocol is guaranteed to be one of the internalNames[] */
6086aab59a7Smrg    if (xf86NameCmp(protocol, "VUID") == 0) {
609a73597f9Smrg        return vuidPreInit(pInfo, protocol, flags);
6106aab59a7Smrg    }
6116aab59a7Smrg    return TRUE;
612a73597f9Smrg}
6136aab59a7Smrg
6146aab59a7Smrgstatic const char **
6156aab59a7SmrgBuiltinNames(void)
6166aab59a7Smrg{
6176aab59a7Smrg    return internalNames;
6186aab59a7Smrg}
6196aab59a7Smrg
6206aab59a7Smrgstatic Bool
6216aab59a7SmrgCheckProtocol(const char *protocol)
6226aab59a7Smrg{
6236aab59a7Smrg    int i;
6246aab59a7Smrg
6256aab59a7Smrg    for (i = 0; internalNames[i]; i++)
626a73597f9Smrg        if (xf86NameCmp(protocol, internalNames[i]) == 0)
627a73597f9Smrg            return TRUE;
6286aab59a7Smrg
6296aab59a7Smrg    return FALSE;
6306aab59a7Smrg}
6316aab59a7Smrg
6326aab59a7Smrgstatic const char *
6336aab59a7SmrgDefaultProtocol(void)
6346aab59a7Smrg{
6356aab59a7Smrg    return "Auto";
6366aab59a7Smrg}
6376aab59a7Smrg
6386aab59a7Smrgstatic Bool
639a73597f9SmrgsolarisMouseAutoProbe(InputInfoPtr pInfo, const char **protocol,
640a73597f9Smrg        const char **device)
6416aab59a7Smrg{
6426aab59a7Smrg    const char **pdev, **pproto;
6436aab59a7Smrg    int fd = -1;
6446aab59a7Smrg    Bool found;
6456aab59a7Smrg    char *strmod;
6466aab59a7Smrg
6476aab59a7Smrg    if (*device == NULL) {
648a73597f9Smrg        /* Check to see if xorg.conf or HAL specified a device to use */
649a73597f9Smrg        *device = xf86CheckStrOption(pInfo->options, "Device", NULL);
6506aab59a7Smrg    }
6516aab59a7Smrg
6526aab59a7Smrg    if (*device != NULL) {
653a73597f9Smrg        strmod = xf86CheckStrOption(pInfo->options, "StreamsModule", NULL);
654a73597f9Smrg        if (strmod) {
655a73597f9Smrg            /* if a device name is already known, and a StreamsModule is
656a73597f9Smrg               specified to convert events to VUID, then we don't need to
657a73597f9Smrg               probe further */
658a73597f9Smrg            *protocol = "VUID";
659a73597f9Smrg            return TRUE;
660a73597f9Smrg        }
6616aab59a7Smrg    }
6626aab59a7Smrg
6636aab59a7Smrg
6646aab59a7Smrg    for (pdev = solarisMouseDevs; *pdev; pdev += 2) {
665a73597f9Smrg        pproto = pdev + 1;
666a73597f9Smrg        if ((*protocol != NULL) && (strcmp(*protocol, "Auto") != 0) &&
667a73597f9Smrg          (*pproto != NULL) && (strcmp(*pproto, *protocol) != 0)) {
668a73597f9Smrg            continue;
669a73597f9Smrg        }
670a73597f9Smrg        if ((*device != NULL) && (strcmp(*device, *pdev) != 0)) {
671a73597f9Smrg            continue;
672a73597f9Smrg        }
6736aab59a7Smrg        SYSCALL (fd = open(*pdev, O_RDWR | O_NONBLOCK));
674a73597f9Smrg        if (fd == -1) {
6756aab59a7Smrg#ifdef DEBUG
676a73597f9Smrg            ErrorF("Cannot open %s (%s)\n", pdev, strerror(errno));
6776aab59a7Smrg#endif
678a73597f9Smrg        } else {
679a73597f9Smrg            found = TRUE;
680a73597f9Smrg            if ((*pproto != NULL) && (strcmp(*pproto, "VUID") == 0)) {
681a73597f9Smrg                int i, r;
682a73597f9Smrg                SYSCALL(r = ioctl(fd, VUIDGFORMAT, &i));
683a73597f9Smrg                if (r < 0) {
684a73597f9Smrg                    found = FALSE;
685a73597f9Smrg                }
686a73597f9Smrg            }
687a73597f9Smrg            close(fd);
688a73597f9Smrg            if (found == TRUE) {
689a73597f9Smrg                if (*pproto != NULL) {
690a73597f9Smrg                    *protocol = *pproto;
691a73597f9Smrg                }
692a73597f9Smrg                *device = *pdev;
693a73597f9Smrg                return TRUE;
694a73597f9Smrg            }
695a73597f9Smrg        }
6966aab59a7Smrg    }
6976aab59a7Smrg    return FALSE;
6986aab59a7Smrg}
6996aab59a7Smrg
7006aab59a7Smrgstatic const char *
7016aab59a7SmrgSetupAuto(InputInfoPtr pInfo, int *protoPara)
7026aab59a7Smrg{
7036aab59a7Smrg    const char *pdev = NULL;
7046aab59a7Smrg    const char *pproto = NULL;
7056aab59a7Smrg    MouseDevPtr pMse = pInfo->private;
7066aab59a7Smrg
7076aab59a7Smrg    if (pInfo->fd == -1) {
708a73597f9Smrg        /* probe to find device/protocol to use */
709a73597f9Smrg        if (solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) {
710a73597f9Smrg            /* Set the Device option. */
711a73597f9Smrg            pInfo->options =
712a73597f9Smrg             xf86AddNewOption(pInfo->options, "Device", pdev);
713a73597f9Smrg            xf86Msg(X_INFO, "%s: Setting Device option to \"%s\"\n",
714a73597f9Smrg              pInfo->name, pdev);
715a73597f9Smrg        }
7166aab59a7Smrg    } else if (pMse->protocolID == PROT_AUTO) {
717a73597f9Smrg        pdev = xf86CheckStrOption(pInfo->options,
718a73597f9Smrg                "Device", NULL);
719a73597f9Smrg        if ((solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) &&
720a73597f9Smrg            (pproto != NULL))
721a73597f9Smrg            sunMousePreInit(pInfo, pproto, 0);
7226aab59a7Smrg    }
7236aab59a7Smrg    return pproto;
7246aab59a7Smrg}
7256aab59a7Smrg
7266aab59a7Smrgstatic const char *
7276aab59a7SmrgFindDevice(InputInfoPtr pInfo, const char *protocol, int flags)
7286aab59a7Smrg{
7296aab59a7Smrg    const char *pdev = NULL;
7306aab59a7Smrg    const char *pproto = protocol;
7316aab59a7Smrg
7326aab59a7Smrg    if (solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) {
733a73597f9Smrg        /* Set the Device option. */
734a73597f9Smrg        pInfo->options =
735a73597f9Smrg          xf86AddNewOption(pInfo->options, "Device", pdev);
736a73597f9Smrg        xf86Msg(X_INFO, "%s: Setting Device option to \"%s\"\n",
737a73597f9Smrg          pInfo->name, pdev);
7386aab59a7Smrg    }
7396aab59a7Smrg    return pdev;
7406aab59a7Smrg}
7416aab59a7Smrg
7426aab59a7Smrgstatic int
7436aab59a7SmrgSupportedInterfaces(void)
7446aab59a7Smrg{
7456aab59a7Smrg    /* XXX This needs to be checked. */
7466aab59a7Smrg    return MSE_SERIAL | MSE_BUS | MSE_PS2 | MSE_AUTO | MSE_XPS2 | MSE_MISC;
7476aab59a7Smrg}
7486aab59a7Smrg
749bd3a1963SmrgOSMouseInfoPtr
750bd3a1963SmrgOSMouseInit(int flags)
7516aab59a7Smrg{
7526aab59a7Smrg    OSMouseInfoPtr p;
7536aab59a7Smrg
754bd3a1963Smrg    p = calloc(sizeof(OSMouseInfoRec), 1);
7556aab59a7Smrg    if (!p)
756a73597f9Smrg        return NULL;
7576aab59a7Smrg    p->SupportedInterfaces = SupportedInterfaces;
7586aab59a7Smrg    p->BuiltinNames = BuiltinNames;
7596aab59a7Smrg    p->CheckProtocol = CheckProtocol;
7606aab59a7Smrg    p->PreInit = sunMousePreInit;
7616aab59a7Smrg    p->DefaultProtocol = DefaultProtocol;
7626aab59a7Smrg    p->SetupAuto = SetupAuto;
7636aab59a7Smrg    p->FindDevice = FindDevice;
7646aab59a7Smrg
7656aab59a7Smrg    return p;
7666aab59a7Smrg}
7676aab59a7Smrg
768