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