sun_mouse.c revision fc27e79c
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, 2008-2009 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    pVuidMse->buffer = (unsigned char *)&pVuidMse->event;
208    pVuidMse->strmod = xf86SetStrOption(pInfo->options, "StreamsModule", NULL);
209
210    /* Check if the device can be opened. */
211    pInfo->fd = xf86OpenSerial(pInfo->options);
212    if (pInfo->fd == -1) {
213	if (xf86GetAllowMouseOpenFail()) {
214	    xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name);
215	} else {
216	    xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name);
217	    xfree(pVuidMse->strmod);
218	    xfree(pVuidMse);
219	    xfree(pMse);
220	    return FALSE;
221	}
222    } else {
223	if (pVuidMse->strmod) {
224	    /* Check to see if module is already pushed */
225	    SYSCALL(i = ioctl(pInfo->fd, I_FIND, pVuidMse->strmod));
226
227	    if (i == 0) { /* Not already pushed */
228		SYSCALL(i = ioctl(pInfo->fd, I_PUSH, pVuidMse->strmod));
229		if (i < 0) {
230		    xf86Msg(X_ERROR,
231			"%s: cannot push module '%s' onto mouse device: %s\n",
232			pInfo->name, pVuidMse->strmod, strerror(errno));
233		    xf86CloseSerial(pInfo->fd);
234		    pInfo->fd = -1;
235		    xfree(pVuidMse->strmod);
236		    xfree(pVuidMse);
237		    xfree(pMse);
238		    return FALSE;
239		}
240	    }
241	}
242
243	buttons = xf86SetIntOption(pInfo->options, "Buttons", 0);
244	if (buttons == 0) {
245	    SYSCALL(i = ioctl(pInfo->fd, MSIOBUTTONS, &buttons));
246	    if (i == 0) {
247		pInfo->conf_idev->commonOptions =
248		    xf86ReplaceIntOption(pInfo->conf_idev->commonOptions,
249					 "Buttons", buttons);
250		xf86Msg(X_INFO, "%s: Setting Buttons option to \"%d\"\n",
251			pInfo->name, buttons);
252	    }
253	}
254
255	if (pVuidMse->strmod) {
256	    SYSCALL(i = ioctl(pInfo->fd, I_POP, pVuidMse->strmod));
257	    if (i == -1) {
258		xf86Msg(X_WARNING,
259			"%s: cannot pop module '%s' off mouse device: %s\n",
260			pInfo->name, pVuidMse->strmod, strerror(errno));
261	    }
262	}
263
264	xf86CloseSerial(pInfo->fd);
265	pInfo->fd = -1;
266    }
267
268    /* Process common mouse options (like Emulate3Buttons, etc). */
269    pMse->CommonOptions(pInfo);
270
271    /* Setup the local procs. */
272    pVuidMse->wrapped_device_control = pInfo->device_control;
273    pInfo->device_control = vuidMouseProc;
274    pInfo->read_input = vuidReadInput;
275
276    pMse->xisbscale = sizeof(Firm_event);
277
278#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
279    pVuidMse->absres.height = pVuidMse->absres.width = 0;
280#endif
281    pVuidMse->pInfo = pInfo;
282    pVuidMse->next = vuidMouseList;
283    vuidMouseList = pVuidMse;
284
285    pInfo->flags |= XI86_CONFIGURED;
286    return TRUE;
287}
288
289static void
290vuidFlushAbsEvents(InputInfoPtr pInfo, int absX, int absY,
291		   Bool *absXset, Bool *absYset)
292{
293#ifdef DEBUG
294    ErrorF("vuidFlushAbsEvents: %d,%d (set: %d, %d)\n", absX, absY,
295	   *absXset, *absYset);
296#endif
297    if ((*absXset) && (*absYset)) {
298	xf86PostMotionEvent(pInfo->dev,
299			    /* is_absolute: */    TRUE,
300			    /* first_valuator: */ 0,
301			    /* num_valuators: */  2,
302			    absX, absY);
303    } else if (*absXset) {
304	xf86PostMotionEvent(pInfo->dev,
305			    /* is_absolute: */    TRUE,
306			    /* first_valuator: */ 0,
307			    /* num_valuators: */  1,
308			    absX);
309    } else if (*absYset) {
310	xf86PostMotionEvent(pInfo->dev,
311			    /* is_absolute: */    TRUE,
312			    /* first_valuator: */ 1,
313			    /* num_valuators: */  1,
314			    absY);
315    }
316
317    *absXset = FALSE;
318    *absYset = FALSE;
319}
320
321static void
322vuidReadInput(InputInfoPtr pInfo)
323{
324    MouseDevPtr pMse;
325    VuidMsePtr pVuidMse;
326    int buttons;
327    int dx = 0, dy = 0, dz = 0, dw = 0;
328    unsigned int n;
329    int c;
330    unsigned char *pBuf;
331    int absX = 0, absY = 0;
332    Bool absXset = FALSE, absYset = FALSE;
333
334    pMse = pInfo->private;
335    pVuidMse = getVuidMsePriv(pInfo);
336    buttons = pMse->lastButtons;
337    XisbBlockDuration(pMse->buffer, -1);
338    pBuf = pVuidMse->buffer;
339    n = 0;
340
341    do {
342	while (n < sizeof(Firm_event) && (c = XisbRead(pMse->buffer)) >= 0) {
343	    pBuf[n++] = (unsigned char)c;
344	}
345
346	if (n == 0)
347	    return;
348
349	if (n != sizeof(Firm_event)) {
350	    xf86Msg(X_WARNING, "%s: incomplete packet, size %d\n",
351			pInfo->name, n);
352	}
353
354#ifdef DEBUG
355	ErrorF("vuidReadInput: event type: %3d value: %5d\n",
356	       pVuidMse->event.id, pVuidMse->event.value);
357#endif
358
359	if (pVuidMse->event.id >= BUT_FIRST && pVuidMse->event.id <= BUT_LAST) {
360	    /* button */
361	    int butnum = pVuidMse->event.id - BUT_FIRST;
362
363	    if (butnum < 3)
364		butnum = 2 - butnum;
365	    if (!pVuidMse->event.value)
366		buttons &= ~(1 << butnum);
367	    else
368		buttons |= (1 << butnum);
369	} else if (pVuidMse->event.id >= VLOC_FIRST &&
370		   pVuidMse->event.id <= VLOC_LAST) {
371	    /* axis */
372	    int delta = pVuidMse->event.value;
373	    switch(pVuidMse->event.id) {
374	    case LOC_X_DELTA:
375		dx += delta;
376		break;
377	    case LOC_Y_DELTA:
378		dy -= delta;
379		break;
380	    case LOC_X_ABSOLUTE:
381		if (absXset) {
382		    vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
383		}
384		absX = delta;
385		absXset = TRUE;
386		break;
387	    case LOC_Y_ABSOLUTE:
388		if (absYset) {
389		    vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
390		}
391		absY = delta;
392		absYset = TRUE;
393		break;
394	    }
395	}
396#ifdef HAVE_VUID_WHEEL
397	else if (vuid_in_range(VUID_WHEEL, pVuidMse->event.id)) {
398	    if (vuid_id_offset(pVuidMse->event.id) == 0)
399		dz -= VUID_WHEEL_GETDELTA(pVuidMse->event.value);
400	    else
401		dw -= VUID_WHEEL_GETDELTA(pVuidMse->event.value);
402	}
403#endif
404#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
405	else if (pVuidMse->event.id == MOUSE_TYPE_ABSOLUTE) {
406	    ScreenPtr 	ptrCurScreen;
407
408	    /* force sending absolute resolution scaling ioctl */
409	    pVuidMse->absres.height = pVuidMse->absres.width = 0;
410#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
411	    ptrCurScreen = miPointerCurrentScreen();
412#else
413	    ptrCurScreen = miPointerGetScreen(pInfo->dev);
414#endif
415	    vuidMouseSendScreenSize(ptrCurScreen, pVuidMse);
416	}
417#endif
418
419	n = 0;
420	if ((c = XisbRead(pMse->buffer)) >= 0) {
421	    /* Another packet.  Handle it right away. */
422	    pBuf[n++] = c;
423	}
424    } while (n != 0);
425
426    if (absXset || absYset) {
427	vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
428    }
429
430    pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw);
431    return;
432}
433
434#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
435static void vuidMouseSendScreenSize(ScreenPtr pScreen, VuidMsePtr pVuidMse)
436{
437    InputInfoPtr pInfo = pVuidMse->pInfo;
438    ScrnInfoPtr pScr = XF86SCRNINFO(pScreen);
439    int result;
440
441    if ((pVuidMse->absres.width != pScr->currentMode->HDisplay) ||
442	(pVuidMse->absres.height != pScr->currentMode->VDisplay))
443    {
444	pVuidMse->absres.width = pScr->currentMode->HDisplay;
445	pVuidMse->absres.height = pScr->currentMode->VDisplay;
446
447	do {
448	    result = ioctl(pInfo->fd, MSIOSRESOLUTION, &(pVuidMse->absres));
449	} while ( (result != 0) && (errno == EINTR) );
450
451	if (result != 0) {
452	    xf86Msg(X_WARNING,
453		    "%s: couldn't set absolute mouse scaling resolution: %s\n",
454		    pInfo->name, strerror(errno));
455#ifdef DEBUG
456	} else {
457	    xf86Msg(X_INFO,
458		    "%s: absolute mouse scaling resolution set to %d x %d\n",
459		    pInfo->name,
460		    pVuidMse->absres.width, pVuidMse->absres.height);
461#endif
462	}
463    }
464}
465
466static void vuidMouseAdjustFrame(int index, int x, int y, int flags)
467{
468      ScrnInfoPtr	pScrn = xf86Screens[index];
469      ScreenPtr		pScreen = pScrn->pScreen;
470      xf86AdjustFrameProc *wrappedAdjustFrame
471	  = (xf86AdjustFrameProc *) vuidMouseGetScreenPrivate(pScreen);
472      VuidMsePtr	m;
473      ScreenPtr 	ptrCurScreen;
474
475      if(wrappedAdjustFrame) {
476        pScrn->AdjustFrame = wrappedAdjustFrame;
477        (*pScrn->AdjustFrame)(index, x, y, flags);
478        pScrn->AdjustFrame = vuidMouseAdjustFrame;
479      }
480
481#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
482      ptrCurScreen = miPointerCurrentScreen();
483#endif
484
485      for (m = vuidMouseList; m != NULL ; m = m->next) {
486#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 0
487	  ptrCurScreen = miPointerGetScreen(m->pInfo->dev);
488#endif
489	  if (ptrCurScreen == pScreen)
490	  {
491	      vuidMouseSendScreenSize(pScreen, m);
492	  }
493      }
494}
495#endif /* HAVE_ABSOLUTE_MOUSE_SCALING */
496
497
498static int
499vuidMouseProc(DeviceIntPtr pPointer, int what)
500{
501    InputInfoPtr pInfo;
502    MouseDevPtr pMse;
503    VuidMsePtr pVuidMse;
504    int ret = Success;
505    int i;
506
507    pInfo = pPointer->public.devicePrivate;
508    pMse = pInfo->private;
509    pMse->device = pPointer;
510
511    pVuidMse = getVuidMsePriv(pInfo);
512    if (pVuidMse == NULL) {
513	return BadImplementation;
514    }
515
516    switch (what) {
517
518    case DEVICE_INIT:
519#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
520	if (vuidMouseGeneration != serverGeneration) {
521		for (i = 0; i < screenInfo.numScreens; i++) {
522		    ScreenPtr pScreen = screenInfo.screens[i];
523		    ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen);
524		    vuidMouseSetScreenPrivate(pScreen, pScrn->AdjustFrame);
525		    pScrn->AdjustFrame = vuidMouseAdjustFrame;
526		}
527	    vuidMouseGeneration = serverGeneration;
528	}
529#endif
530	ret = pVuidMse->wrapped_device_control(pPointer, what);
531	break;
532
533    case DEVICE_ON:
534	ret = pVuidMse->wrapped_device_control(pPointer, DEVICE_ON);
535
536	if ((ret == Success) && (pInfo->fd != -1)) {
537	    int fmt = VUID_FIRM_EVENT;
538
539	    if (pVuidMse->strmod) {
540		/* Check to see if module is already pushed */
541		SYSCALL(i = ioctl(pInfo->fd, I_FIND, pVuidMse->strmod));
542
543		if (i == 0) { /* Not already pushed */
544		    SYSCALL(i = ioctl(pInfo->fd, I_PUSH, pVuidMse->strmod));
545		    if (i < 0) {
546			xf86Msg(X_WARNING, "%s: cannot push module '%s' "
547				"onto mouse device: %s\n", pInfo->name,
548				pVuidMse->strmod, strerror(errno));
549			xfree(pVuidMse->strmod);
550			pVuidMse->strmod = NULL;
551		    }
552		}
553	    }
554
555	    SYSCALL(i = ioctl(pInfo->fd, VUIDSFORMAT, &fmt));
556	    if (i < 0) {
557		xf86Msg(X_WARNING,
558			"%s: cannot set mouse device to VUID mode: %s\n",
559			pInfo->name, strerror(errno));
560	    }
561	    vuidMouseWheelInit(pInfo);
562#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
563	    vuidMouseSendScreenSize(screenInfo.screens[0], pVuidMse);
564#endif
565	    xf86FlushInput(pInfo->fd);
566	}
567	break;
568
569    case DEVICE_OFF:
570    case DEVICE_CLOSE:
571	if (pInfo->fd != -1) {
572	    if (pVuidMse->strmod) {
573		SYSCALL(i = ioctl(pInfo->fd, I_POP, pVuidMse->strmod));
574		if (i == -1) {
575		    xf86Msg(X_WARNING,
576		      "%s: cannot pop module '%s' off mouse device: %s\n",
577		      pInfo->name, pVuidMse->strmod, strerror(errno));
578		}
579	    }
580	}
581	ret = pVuidMse->wrapped_device_control(pPointer, what);
582	break;
583
584    default: /* Should never be called, but just in case */
585	ret = pVuidMse->wrapped_device_control(pPointer, what);
586	break;
587    }
588    return ret;
589}
590
591static Bool
592sunMousePreInit(InputInfoPtr pInfo, const char *protocol, int flags)
593{
594    /* The protocol is guaranteed to be one of the internalNames[] */
595    if (xf86NameCmp(protocol, "VUID") == 0) {
596	return vuidPreInit(pInfo, protocol, flags);
597    }
598    return TRUE;
599}
600
601static const char **
602BuiltinNames(void)
603{
604    return internalNames;
605}
606
607static Bool
608CheckProtocol(const char *protocol)
609{
610    int i;
611
612    for (i = 0; internalNames[i]; i++)
613	if (xf86NameCmp(protocol, internalNames[i]) == 0)
614	    return TRUE;
615
616    return FALSE;
617}
618
619static const char *
620DefaultProtocol(void)
621{
622    return "Auto";
623}
624
625static Bool
626solarisMouseAutoProbe(InputInfoPtr pInfo, const char **protocol,
627	const char **device)
628{
629    const char **pdev, **pproto;
630    int fd = -1;
631    Bool found;
632    char *strmod;
633
634    if (*device == NULL) {
635	/* Check to see if xorg.conf or HAL specified a device to use */
636	*device = xf86CheckStrOption(pInfo->options, "Device", NULL);
637	if (*device == NULL) {
638	    *device = xf86CheckStrOption(pInfo->conf_idev->commonOptions,
639					 "Device", NULL);
640	}
641    }
642
643    if (*device != NULL) {
644	strmod = xf86CheckStrOption(pInfo->options, "StreamsModule", NULL);
645	if (strmod == NULL) {
646	    strmod = xf86CheckStrOption(pInfo->conf_idev->commonOptions,
647					"StreamsModule", NULL);
648	}
649	if (strmod) {
650	    /* if a device name is already known, and a StreamsModule is
651	       specified to convert events to VUID, then we don't need to
652	       probe further */
653	    *protocol = "VUID";
654	    return TRUE;
655	}
656    }
657
658
659    for (pdev = solarisMouseDevs; *pdev; pdev += 2) {
660	pproto = pdev + 1;
661	if ((*protocol != NULL) && (strcmp(*protocol, "Auto") != 0) &&
662	  (*pproto != NULL) && (strcmp(*pproto, *protocol) != 0)) {
663	    continue;
664	}
665	if ((*device != NULL) && (strcmp(*device, *pdev) != 0)) {
666	    continue;
667	}
668        SYSCALL (fd = open(*pdev, O_RDWR | O_NONBLOCK));
669	if (fd == -1) {
670#ifdef DEBUG
671	    ErrorF("Cannot open %s (%s)\n", pdev, strerror(errno));
672#endif
673	} else {
674	    found = TRUE;
675	    if ((*pproto != NULL) && (strcmp(*pproto, "VUID") == 0)) {
676		int i, r;
677		SYSCALL(r = ioctl(fd, VUIDGFORMAT, &i));
678    		if (r < 0) {
679		    found = FALSE;
680		}
681	    }
682	    close(fd);
683	    if (found == TRUE) {
684		if (*pproto != NULL) {
685		    *protocol = *pproto;
686		}
687		*device = *pdev;
688		return TRUE;
689	    }
690	}
691    }
692    return FALSE;
693}
694
695static const char *
696SetupAuto(InputInfoPtr pInfo, int *protoPara)
697{
698    const char *pdev = NULL;
699    const char *pproto = NULL;
700    MouseDevPtr pMse = pInfo->private;
701
702    if (pInfo->fd == -1) {
703	/* probe to find device/protocol to use */
704	if (solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) {
705	    /* Set the Device option. */
706	    pInfo->conf_idev->commonOptions =
707	     xf86AddNewOption(pInfo->conf_idev->commonOptions, "Device", pdev);
708	    xf86Msg(X_INFO, "%s: Setting Device option to \"%s\"\n",
709	      pInfo->name, pdev);
710	}
711    } else if (pMse->protocolID == PROT_AUTO) {
712	pdev = xf86CheckStrOption(pInfo->conf_idev->commonOptions,
713		"Device", NULL);
714	solarisMouseAutoProbe(pInfo, &pproto, &pdev);
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->conf_idev->commonOptions =
728	  xf86AddNewOption(pInfo->conf_idev->commonOptions, "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
742_X_EXPORT OSMouseInfoPtr
743xf86OSMouseInit(int flags)
744{
745    OSMouseInfoPtr p;
746
747    p = xcalloc(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