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