sun_mouse.c revision a73597f9
1/*
2 * Copyright (c) 2004-2005, 2008-2010, Oracle and/or its affiliates.
3 * All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24/*
25 * Copyright 1999-2001 The XFree86 Project, Inc.  All Rights Reserved.
26 *
27 * Permission is hereby granted, free of charge, to any person obtaining a copy
28 * of this software and associated documentation files (the "Software"), to
29 * deal in the Software without restriction, including without limitation the
30 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
31 * sell copies of the Software, and to permit persons to whom the Software is
32 * furnished to do so, subject to the following conditions:
33 *
34 * The above copyright notice and this permission notice shall be included in
35 * all copies or substantial portions of the Software.
36 *
37 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
40 * XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
41 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
42 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43 *
44 * Except as contained in this notice, the name of the XFree86 Project shall
45 * not be used in advertising or otherwise to promote the sale, use or other
46 * dealings in this Software without prior written authorization from the
47 * XFree86 Project.
48 */
49
50#ifdef HAVE_XORG_CONFIG_H
51#include <xorg-config.h>
52#endif
53
54#include "xorg-server.h"
55#include "xf86.h"
56#include "xf86_OSlib.h"
57#include "mouse.h"
58#include "xisb.h"
59#include "mipointer.h"
60#include <sys/stropts.h>
61#include <sys/vuid_event.h>
62#include <sys/msio.h>
63
64/* Wheel mouse support in VUID drivers in Solaris 9 updates & Solaris 10 */
65#ifdef WHEEL_DEVID /* Defined in vuid_event.h if VUID wheel support present */
66# define HAVE_VUID_WHEEL
67#endif
68#ifdef HAVE_VUID_WHEEL
69# include <sys/vuid_wheel.h>
70#endif
71
72/* Support for scaling absolute coordinates to screen size in
73 * Solaris 10 updates and beyond */
74#if !defined(HAVE_ABSOLUTE_MOUSE_SCALING)
75# ifdef MSIOSRESOLUTION /* Defined in msio.h if scaling support present */
76#  define HAVE_ABSOLUTE_MOUSE_SCALING
77# endif
78#endif
79
80/* Names of protocols that are handled internally here. */
81
82static const char *internalNames[] = {
83        "VUID",
84        NULL
85};
86
87static const char *solarisMouseDevs[] = {
88    /* Device file:     Protocol:                       */
89    "/dev/mouse",       "VUID",         /* USB or SPARC */
90#if defined(__i386) || defined(__x86)
91    "/dev/kdmouse",     "PS/2",         /* PS/2 */
92#endif
93    NULL
94};
95
96typedef struct _VuidMseRec {
97    struct _VuidMseRec *next;
98    InputInfoPtr        pInfo;
99    Firm_event          event;
100    unsigned char *     buffer;
101    char *              strmod;
102    Bool(*wrapped_device_control)(DeviceIntPtr device, int what);
103#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
104    Ms_screen_resolution         absres;
105#endif
106    OsTimerPtr          remove_timer;   /* Callback for removal on ENODEV */
107} VuidMseRec, *VuidMsePtr;
108
109static VuidMsePtr       vuidMouseList = NULL;
110
111static int  vuidMouseProc(DeviceIntPtr pPointer, int what);
112static void vuidReadInput(InputInfoPtr pInfo);
113
114#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
115# include "compat-api.h"
116
117static void vuidMouseSendScreenSize(ScreenPtr pScreen, VuidMsePtr pVuidMse);
118static void vuidMouseAdjustFrame(ADJUST_FRAME_ARGS_DECL);
119
120static int vuidMouseGeneration = 0;
121
122#if HAS_DEVPRIVATEKEYREC
123static DevPrivateKeyRec vuidMouseScreenIndex;
124#else
125static int vuidMouseScreenIndex;
126#endif /* HAS_DEVPRIVATEKEYREC */
127
128#define vuidMouseGetScreenPrivate(s) ( \
129    dixLookupPrivate(&(s)->devPrivates, &vuidMouseScreenIndex))
130#define vuidMouseSetScreenPrivate(s,p) \
131    dixSetPrivate(&(s)->devPrivates, &vuidMouseScreenIndex, (void *) p)
132#endif /* HAVE_ABSOLUTE_MOUSE_SCALING */
133
134static inline
135VuidMsePtr getVuidMsePriv(InputInfoPtr pInfo)
136{
137    VuidMsePtr m = vuidMouseList;
138
139    while ((m != NULL) && (m->pInfo != pInfo)) {
140        m = m->next;
141    }
142
143    return m;
144}
145
146/* Called from OsTimer callback, since removing a device from the device
147   list or changing pInfo->fd while xf86Wakeup is looping through the list
148   causes server crashes */
149static CARD32
150vuidRemoveMouse(OsTimerPtr timer, CARD32 now, pointer arg)
151{
152    InputInfoPtr pInfo = (InputInfoPtr) arg;
153
154    xf86DisableDevice(pInfo->dev, TRUE);
155
156    return 0;  /* All done, don't set to run again */
157}
158
159/*
160 * Initialize and enable the mouse wheel, if present.
161 *
162 * Returns 1 if mouse wheel was successfully enabled.
163 * Returns 0 if an error occurred or if there is no mouse wheel.
164 */
165static int
166vuidMouseWheelInit(InputInfoPtr pInfo)
167{
168#ifdef HAVE_VUID_WHEEL
169    wheel_state wstate;
170    int nwheel = -1;
171    int i;
172
173    wstate.vers = VUID_WHEEL_STATE_VERS;
174    wstate.id = 0;
175    wstate.stateflags = (uint32_t) -1;
176
177    SYSCALL(i = ioctl(pInfo->fd, VUIDGWHEELCOUNT, &nwheel));
178    if (i != 0)
179        return (0);
180
181    SYSCALL(i = ioctl(pInfo->fd, VUIDGWHEELSTATE, &wstate));
182    if (i != 0) {
183        xf86Msg(X_WARNING, "%s: couldn't get wheel state\n", pInfo->name);
184        return (0);
185    }
186
187    wstate.stateflags |= VUID_WHEEL_STATE_ENABLED;
188
189    SYSCALL(i = ioctl(pInfo->fd, VUIDSWHEELSTATE, &wstate));
190    if (i != 0) {
191        xf86Msg(X_WARNING, "%s: couldn't enable wheel\n", pInfo->name);
192        return (0);
193    }
194
195    return (1);
196#else
197    return (0);
198#endif
199}
200
201
202/* This function is called when the protocol is "VUID". */
203static Bool
204vuidPreInit(InputInfoPtr pInfo, const char *protocol, int flags)
205{
206    MouseDevPtr pMse = pInfo->private;
207    VuidMsePtr pVuidMse;
208
209    /* Ensure we don't add the same device twice */
210    if (getVuidMsePriv(pInfo) != NULL)
211        return TRUE;
212
213    pVuidMse = calloc(sizeof(VuidMseRec), 1);
214    if (pVuidMse == NULL) {
215        xf86Msg(X_ERROR, "%s: cannot allocate VuidMouseRec\n", pInfo->name);
216        free(pMse);
217        return FALSE;
218    }
219
220    pVuidMse->buffer = (unsigned char *)&pVuidMse->event;
221    pVuidMse->strmod = xf86SetStrOption(pInfo->options, "StreamsModule", NULL);
222
223    /* Setup the local procs. */
224    pVuidMse->wrapped_device_control = pInfo->device_control;
225    pInfo->device_control = vuidMouseProc;
226    pInfo->read_input = vuidReadInput;
227
228    pMse->xisbscale = sizeof(Firm_event);
229
230#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
231    pVuidMse->absres.height = pVuidMse->absres.width = 0;
232#endif
233    pVuidMse->pInfo = pInfo;
234    pVuidMse->next = vuidMouseList;
235    vuidMouseList = pVuidMse;
236
237#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
238    pInfo->flags |= XI86_CONFIGURED;
239#endif
240    return TRUE;
241}
242
243static void
244vuidFlushAbsEvents(InputInfoPtr pInfo, int absX, int absY,
245                   Bool *absXset, Bool *absYset)
246{
247#ifdef DEBUG
248    ErrorF("vuidFlushAbsEvents: %d,%d (set: %d, %d)\n", absX, absY,
249           *absXset, *absYset);
250#endif
251    if ((*absXset) && (*absYset)) {
252        xf86PostMotionEvent(pInfo->dev,
253                            /* is_absolute: */    TRUE,
254                            /* first_valuator: */ 0,
255                            /* num_valuators: */  2,
256                            absX, absY);
257    } else if (*absXset) {
258        xf86PostMotionEvent(pInfo->dev,
259                            /* is_absolute: */    TRUE,
260                            /* first_valuator: */ 0,
261                            /* num_valuators: */  1,
262                            absX);
263    } else if (*absYset) {
264        xf86PostMotionEvent(pInfo->dev,
265                            /* is_absolute: */    TRUE,
266                            /* first_valuator: */ 1,
267                            /* num_valuators: */  1,
268                            absY);
269    }
270
271    *absXset = FALSE;
272    *absYset = FALSE;
273}
274
275static void
276vuidReadInput(InputInfoPtr pInfo)
277{
278    MouseDevPtr pMse;
279    VuidMsePtr pVuidMse;
280    int buttons;
281    int dx = 0, dy = 0, dz = 0, dw = 0;
282    unsigned int n;
283    unsigned char *pBuf;
284    int absX = 0, absY = 0;
285    Bool absXset = FALSE, absYset = FALSE;
286
287    pMse = pInfo->private;
288    pVuidMse = getVuidMsePriv(pInfo);
289    buttons = pMse->lastButtons;
290    pBuf = pVuidMse->buffer;
291    n = 0;
292
293    do {
294        n = read(pInfo->fd, pBuf, sizeof(Firm_event));
295
296        if (n == 0) {
297            break;
298        } else if (n == -1) {
299            switch (errno) {
300                case EAGAIN: /* Nothing to read now */
301                    n = 0;   /* End loop, go on to flush events & return */
302                    continue;
303                case EINTR:  /* Interrupted, try again */
304                    continue;
305                case ENODEV: /* May happen when USB mouse is unplugged */
306                    /* We use X_NONE here because it didn't alloc since we
307                       may be called from SIGIO handler. No longer true for
308                       sigsafe logging, but matters for older servers  */
309                    LogMessageVerbSigSafe(X_NONE, 0,
310                                          "%s: Device no longer present - removing.\n",
311                                          pInfo->name);
312                    xf86RemoveEnabledDevice(pInfo);
313                    pVuidMse->remove_timer =
314                        TimerSet(pVuidMse->remove_timer, 0, 1,
315                                 vuidRemoveMouse, pInfo);
316                    return;
317                default:     /* All other errors */
318                    /* We use X_NONE here because it didn't alloc since we
319                       may be called from SIGIO handler. No longer true for
320                       sigsafe logging, but matters for older servers  */
321                    LogMessageVerbSigSafe(X_NONE, 0, "%s: Read error: %s\n",
322                                          pInfo->name, strerror(errno));
323                    return;
324            }
325        } else if (n != sizeof(Firm_event)) {
326            xf86Msg(X_WARNING, "%s: incomplete packet, size %d\n",
327                        pInfo->name, n);
328        }
329
330#ifdef DEBUG
331        LogMessageVerbSigSafe("vuidReadInput: event type: %d value: %d\n",
332                              pVuidMse->event.id, pVuidMse->event.value);
333#endif
334
335        if (pVuidMse->event.id >= BUT_FIRST && pVuidMse->event.id <= BUT_LAST) {
336            /* button */
337            int butnum = pVuidMse->event.id - BUT_FIRST;
338
339            if (butnum < 3)
340                butnum = 2 - butnum;
341            if (!pVuidMse->event.value)
342                buttons &= ~(1 << butnum);
343            else
344                buttons |= (1 << butnum);
345        } else if (pVuidMse->event.id >= VLOC_FIRST &&
346                   pVuidMse->event.id <= VLOC_LAST) {
347            /* axis */
348            int delta = pVuidMse->event.value;
349            switch(pVuidMse->event.id) {
350            case LOC_X_DELTA:
351                dx += delta;
352                break;
353            case LOC_Y_DELTA:
354                dy -= delta;
355                break;
356            case LOC_X_ABSOLUTE:
357                if (absXset) {
358                    vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
359                }
360                absX = delta;
361                absXset = TRUE;
362                break;
363            case LOC_Y_ABSOLUTE:
364                if (absYset) {
365                    vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
366                }
367                absY = delta;
368                absYset = TRUE;
369                break;
370            }
371        }
372#ifdef HAVE_VUID_WHEEL
373        else if (vuid_in_range(VUID_WHEEL, pVuidMse->event.id)) {
374            if (vuid_id_offset(pVuidMse->event.id) == 0)
375                dz -= VUID_WHEEL_GETDELTA(pVuidMse->event.value);
376            else
377                dw -= VUID_WHEEL_GETDELTA(pVuidMse->event.value);
378        }
379#endif
380#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
381        else if (pVuidMse->event.id == MOUSE_TYPE_ABSOLUTE) {
382            ScreenPtr   ptrCurScreen;
383
384            /* force sending absolute resolution scaling ioctl */
385            pVuidMse->absres.height = pVuidMse->absres.width = 0;
386            ptrCurScreen = miPointerGetScreen(pInfo->dev);
387            vuidMouseSendScreenSize(ptrCurScreen, pVuidMse);
388        }
389#endif
390
391    } while (n != 0);
392
393    if (absXset || absYset) {
394        vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
395    }
396
397    pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw);
398    return;
399}
400
401#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
402static void vuidMouseSendScreenSize(ScreenPtr pScreen, VuidMsePtr pVuidMse)
403{
404    InputInfoPtr pInfo = pVuidMse->pInfo;
405    ScrnInfoPtr pScr = XF86SCRNINFO(pScreen);
406    int result;
407
408    if (!pScr->currentMode)
409        return;
410
411    if ((pVuidMse->absres.width != pScr->currentMode->HDisplay) ||
412        (pVuidMse->absres.height != pScr->currentMode->VDisplay))
413    {
414        pVuidMse->absres.width = pScr->currentMode->HDisplay;
415        pVuidMse->absres.height = pScr->currentMode->VDisplay;
416
417        do {
418            result = ioctl(pInfo->fd, MSIOSRESOLUTION, &(pVuidMse->absres));
419        } while ( (result != 0) && (errno == EINTR) );
420
421        if (result != 0) {
422            LogMessageVerbSigSafe(X_WARNING, -1,
423                                  "%s: couldn't set absolute mouse scaling resolution: %s\n",
424                                  pInfo->name, strerror(errno));
425#ifdef DEBUG
426        } else {
427            LogMessageVerbSigSafe(X_INFO,
428                                  "%s: absolute mouse scaling resolution set to %d x %d\n",
429                                  pInfo->name,
430                                  pVuidMse->absres.width,
431                                  pVuidMse->absres.height);
432#endif
433        }
434    }
435}
436
437static void vuidMouseAdjustFrame(ADJUST_FRAME_ARGS_DECL)
438{
439      SCRN_INFO_PTR(arg);
440      ScreenPtr         pScreen = xf86ScrnToScreen(pScrn);
441      xf86AdjustFrameProc *wrappedAdjustFrame
442          = (xf86AdjustFrameProc *) vuidMouseGetScreenPrivate(pScreen);
443      VuidMsePtr        m;
444      ScreenPtr         ptrCurScreen;
445
446      if (wrappedAdjustFrame) {
447          pScrn->AdjustFrame = wrappedAdjustFrame;
448          (*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, x, y));
449          pScrn->AdjustFrame = vuidMouseAdjustFrame;
450      }
451
452      for (m = vuidMouseList; m != NULL ; m = m->next) {
453          ptrCurScreen = miPointerGetScreen(m->pInfo->dev);
454          if (ptrCurScreen == pScreen)
455          {
456              vuidMouseSendScreenSize(pScreen, m);
457          }
458      }
459}
460#endif /* HAVE_ABSOLUTE_MOUSE_SCALING */
461
462
463static int
464vuidMouseProc(DeviceIntPtr pPointer, int what)
465{
466    InputInfoPtr pInfo;
467    MouseDevPtr pMse;
468    VuidMsePtr pVuidMse;
469    int ret = Success;
470    int i;
471
472    pInfo = pPointer->public.devicePrivate;
473    pMse = pInfo->private;
474    pMse->device = pPointer;
475
476    pVuidMse = getVuidMsePriv(pInfo);
477    if (pVuidMse == NULL) {
478        return BadImplementation;
479    }
480
481    switch (what) {
482
483    case DEVICE_INIT:
484#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
485
486#if HAS_DEVPRIVATEKEYREC
487        if (!dixRegisterPrivateKey(&vuidMouseScreenIndex, PRIVATE_SCREEN, 0))
488                return BadAlloc;
489#endif  /* HAS_DEVPRIVATEKEYREC */
490
491        if (vuidMouseGeneration != serverGeneration) {
492                for (i = 0; i < screenInfo.numScreens; i++) {
493                    ScreenPtr pScreen = screenInfo.screens[i];
494                    ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen);
495                    vuidMouseSetScreenPrivate(pScreen, pScrn->AdjustFrame);
496                    pScrn->AdjustFrame = vuidMouseAdjustFrame;
497                }
498            vuidMouseGeneration = serverGeneration;
499        }
500#endif
501        ret = pVuidMse->wrapped_device_control(pPointer, what);
502        break;
503
504    case DEVICE_ON:
505        ret = pVuidMse->wrapped_device_control(pPointer, DEVICE_ON);
506
507        if ((ret == Success) && (pInfo->fd != -1)) {
508            int fmt = VUID_FIRM_EVENT;
509
510            if (pVuidMse->strmod) {
511                /* Check to see if module is already pushed */
512                SYSCALL(i = ioctl(pInfo->fd, I_FIND, pVuidMse->strmod));
513
514                if (i == 0) { /* Not already pushed */
515                    SYSCALL(i = ioctl(pInfo->fd, I_PUSH, pVuidMse->strmod));
516                    if (i < 0) {
517                        xf86Msg(X_WARNING, "%s: cannot push module '%s' "
518                                "onto mouse device: %s\n", pInfo->name,
519                                pVuidMse->strmod, strerror(errno));
520                        free(pVuidMse->strmod);
521                        pVuidMse->strmod = NULL;
522                    }
523                }
524            }
525
526            SYSCALL(i = ioctl(pInfo->fd, VUIDSFORMAT, &fmt));
527            if (i < 0) {
528                xf86Msg(X_WARNING,
529                        "%s: cannot set mouse device to VUID mode: %s\n",
530                        pInfo->name, strerror(errno));
531            }
532            vuidMouseWheelInit(pInfo);
533#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
534            vuidMouseSendScreenSize(screenInfo.screens[0], pVuidMse);
535#endif
536            xf86FlushInput(pInfo->fd);
537
538            /* Allocate here so we don't alloc in ReadInput which may be called
539               from SIGIO handler. */
540            if (pVuidMse->remove_timer == NULL) {
541                pVuidMse->remove_timer = TimerSet(pVuidMse->remove_timer,
542                                                  0, 0, NULL, NULL);
543            }
544        }
545        break;
546
547    case DEVICE_OFF:
548    case DEVICE_CLOSE:
549        if (pInfo->fd != -1) {
550            if (pVuidMse->strmod) {
551                SYSCALL(i = ioctl(pInfo->fd, I_POP, pVuidMse->strmod));
552                if (i == -1) {
553                    xf86Msg(X_WARNING,
554                      "%s: cannot pop module '%s' off mouse device: %s\n",
555                      pInfo->name, pVuidMse->strmod, strerror(errno));
556                }
557            }
558        }
559        if (pVuidMse->remove_timer) {
560            TimerFree(pVuidMse->remove_timer);
561            pVuidMse->remove_timer = NULL;
562        }
563        ret = pVuidMse->wrapped_device_control(pPointer, what);
564        break;
565
566    default: /* Should never be called, but just in case */
567        ret = pVuidMse->wrapped_device_control(pPointer, what);
568        break;
569    }
570    return ret;
571}
572
573static Bool
574sunMousePreInit(InputInfoPtr pInfo, const char *protocol, int flags)
575{
576    /* The protocol is guaranteed to be one of the internalNames[] */
577    if (xf86NameCmp(protocol, "VUID") == 0) {
578        return vuidPreInit(pInfo, protocol, flags);
579    }
580    return TRUE;
581}
582
583static const char **
584BuiltinNames(void)
585{
586    return internalNames;
587}
588
589static Bool
590CheckProtocol(const char *protocol)
591{
592    int i;
593
594    for (i = 0; internalNames[i]; i++)
595        if (xf86NameCmp(protocol, internalNames[i]) == 0)
596            return TRUE;
597
598    return FALSE;
599}
600
601static const char *
602DefaultProtocol(void)
603{
604    return "Auto";
605}
606
607static Bool
608solarisMouseAutoProbe(InputInfoPtr pInfo, const char **protocol,
609        const char **device)
610{
611    const char **pdev, **pproto;
612    int fd = -1;
613    Bool found;
614    char *strmod;
615
616    if (*device == NULL) {
617        /* Check to see if xorg.conf or HAL specified a device to use */
618        *device = xf86CheckStrOption(pInfo->options, "Device", NULL);
619    }
620
621    if (*device != NULL) {
622        strmod = xf86CheckStrOption(pInfo->options, "StreamsModule", NULL);
623        if (strmod) {
624            /* if a device name is already known, and a StreamsModule is
625               specified to convert events to VUID, then we don't need to
626               probe further */
627            *protocol = "VUID";
628            return TRUE;
629        }
630    }
631
632
633    for (pdev = solarisMouseDevs; *pdev; pdev += 2) {
634        pproto = pdev + 1;
635        if ((*protocol != NULL) && (strcmp(*protocol, "Auto") != 0) &&
636          (*pproto != NULL) && (strcmp(*pproto, *protocol) != 0)) {
637            continue;
638        }
639        if ((*device != NULL) && (strcmp(*device, *pdev) != 0)) {
640            continue;
641        }
642        SYSCALL (fd = open(*pdev, O_RDWR | O_NONBLOCK));
643        if (fd == -1) {
644#ifdef DEBUG
645            ErrorF("Cannot open %s (%s)\n", pdev, strerror(errno));
646#endif
647        } else {
648            found = TRUE;
649            if ((*pproto != NULL) && (strcmp(*pproto, "VUID") == 0)) {
650                int i, r;
651                SYSCALL(r = ioctl(fd, VUIDGFORMAT, &i));
652                if (r < 0) {
653                    found = FALSE;
654                }
655            }
656            close(fd);
657            if (found == TRUE) {
658                if (*pproto != NULL) {
659                    *protocol = *pproto;
660                }
661                *device = *pdev;
662                return TRUE;
663            }
664        }
665    }
666    return FALSE;
667}
668
669static const char *
670SetupAuto(InputInfoPtr pInfo, int *protoPara)
671{
672    const char *pdev = NULL;
673    const char *pproto = NULL;
674    MouseDevPtr pMse = pInfo->private;
675
676    if (pInfo->fd == -1) {
677        /* probe to find device/protocol to use */
678        if (solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) {
679            /* Set the Device option. */
680            pInfo->options =
681             xf86AddNewOption(pInfo->options, "Device", pdev);
682            xf86Msg(X_INFO, "%s: Setting Device option to \"%s\"\n",
683              pInfo->name, pdev);
684        }
685    } else if (pMse->protocolID == PROT_AUTO) {
686        pdev = xf86CheckStrOption(pInfo->options,
687                "Device", NULL);
688        if ((solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) &&
689            (pproto != NULL))
690            sunMousePreInit(pInfo, pproto, 0);
691    }
692    return pproto;
693}
694
695static const char *
696FindDevice(InputInfoPtr pInfo, const char *protocol, int flags)
697{
698    const char *pdev = NULL;
699    const char *pproto = protocol;
700
701    if (solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) {
702        /* Set the Device option. */
703        pInfo->options =
704          xf86AddNewOption(pInfo->options, "Device", pdev);
705        xf86Msg(X_INFO, "%s: Setting Device option to \"%s\"\n",
706          pInfo->name, pdev);
707    }
708    return pdev;
709}
710
711static int
712SupportedInterfaces(void)
713{
714    /* XXX This needs to be checked. */
715    return MSE_SERIAL | MSE_BUS | MSE_PS2 | MSE_AUTO | MSE_XPS2 | MSE_MISC;
716}
717
718OSMouseInfoPtr
719OSMouseInit(int flags)
720{
721    OSMouseInfoPtr p;
722
723    p = calloc(sizeof(OSMouseInfoRec), 1);
724    if (!p)
725        return NULL;
726    p->SupportedInterfaces = SupportedInterfaces;
727    p->BuiltinNames = BuiltinNames;
728    p->CheckProtocol = CheckProtocol;
729    p->PreInit = sunMousePreInit;
730    p->DefaultProtocol = DefaultProtocol;
731    p->SetupAuto = SetupAuto;
732    p->FindDevice = FindDevice;
733
734    return p;
735}
736
737