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