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