sun_mouse.c revision ebac4eb7
1/*
2 * Copyright (c) 2004, 2022, Oracle and/or its affiliates.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23/*
24 * Copyright 1999-2001 The XFree86 Project, Inc.  All Rights Reserved.
25 *
26 * Permission is hereby granted, free of charge, to any person obtaining a copy
27 * of this software and associated documentation files (the "Software"), to
28 * deal in the Software without restriction, including without limitation the
29 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
30 * sell copies of the Software, and to permit persons to whom the Software is
31 * furnished to do so, subject to the following conditions:
32 *
33 * The above copyright notice and this permission notice shall be included in
34 * all copies or substantial portions of the Software.
35 *
36 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
39 * XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
40 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
41 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 *
43 * Except as contained in this notice, the name of the XFree86 Project shall
44 * not be used in advertising or otherwise to promote the sale, use or other
45 * dealings in this Software without prior written authorization from the
46 * XFree86 Project.
47 */
48
49#ifdef HAVE_CONFIG_H
50#include "config.h"
51#endif
52
53#ifdef HAVE_XORG_CONFIG_H
54#include <xorg-config.h>
55#endif
56
57#include <unistd.h> /* for ioctl(2) */
58#include <sys/stropts.h>
59#include <sys/vuid_event.h>
60#include <sys/msio.h>
61#include <fcntl.h>
62#include <errno.h>
63#include "xorg-server.h"
64#include "xf86.h"
65#include "xf86_OSlib.h"
66#include "mouse.h"
67#include "xisb.h"
68#include "mipointer.h"
69#include "xf86Crtc.h"
70
71/* Wheel mouse support in VUID drivers in Solaris 9 updates & Solaris 10 */
72#ifdef WHEEL_DEVID /* Defined in vuid_event.h if VUID wheel support present */
73# define HAVE_VUID_WHEEL
74#endif
75#ifdef HAVE_VUID_WHEEL
76# include <sys/vuid_wheel.h>
77#endif
78
79#include <libdevinfo.h>
80
81/* Support for scaling absolute coordinates to screen size in
82 * Solaris 10 updates and beyond */
83#if !defined(HAVE_ABSOLUTE_MOUSE_SCALING)
84# ifdef MSIOSRESOLUTION /* Defined in msio.h if scaling support present */
85#  define HAVE_ABSOLUTE_MOUSE_SCALING
86# endif
87#endif
88
89/* Names of protocols that are handled internally here. */
90
91static const char *internalNames[] = {
92        "VUID",
93        NULL
94};
95
96static const char *solarisMouseDevs[] = {
97    /* Device file:     Protocol:                       */
98    "/dev/mouse",       "VUID",         /* USB or SPARC */
99#if defined(__i386) || defined(__x86)
100    "/dev/kdmouse",     "PS/2",         /* PS/2 */
101#endif
102    NULL
103};
104
105typedef struct _VuidMseRec {
106    struct _VuidMseRec *next;
107    InputInfoPtr        pInfo;
108    Firm_event          event;
109    unsigned char *     buffer;
110    char *              strmod;
111    Bool(*wrapped_device_control)(DeviceIntPtr device, int what);
112#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
113    Ms_screen_resolution         absres;
114#endif
115    OsTimerPtr          remove_timer;   /* Callback for removal on ENODEV */
116    int                 relToAbs;
117    int                 absX;
118    int                 absY;
119} VuidMseRec, *VuidMsePtr;
120
121static VuidMsePtr       vuidMouseList = NULL;
122
123static int  vuidMouseProc(DeviceIntPtr pPointer, int what);
124static void vuidReadInput(InputInfoPtr pInfo);
125
126static int CheckRelToAbs(InputInfoPtr pInfo);
127static int CheckRelToAbsWalker(di_node_t node, void *arg);
128
129#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
130# include "compat-api.h"
131
132static void vuidMouseSendScreenSize(ScreenPtr pScreen, VuidMsePtr pVuidMse);
133static void vuidMouseAdjustFrame(ADJUST_FRAME_ARGS_DECL);
134
135static unsigned long vuidMouseGeneration = 0;
136
137#if HAS_DEVPRIVATEKEYREC
138static DevPrivateKeyRec vuidMouseScreenIndex;
139#else
140static int vuidMouseScreenIndex;
141#endif /* HAS_DEVPRIVATEKEYREC */
142
143#define vuidMouseGetScreenPrivate(s) ( \
144    dixLookupPrivate(&(s)->devPrivates, &vuidMouseScreenIndex))
145#define vuidMouseSetScreenPrivate(s,p) \
146    dixSetPrivate(&(s)->devPrivates, &vuidMouseScreenIndex, (void *) p)
147#endif /* HAVE_ABSOLUTE_MOUSE_SCALING */
148
149static inline
150VuidMsePtr getVuidMsePriv(InputInfoPtr pInfo)
151{
152    VuidMsePtr m = vuidMouseList;
153
154    while ((m != NULL) && (m->pInfo != pInfo)) {
155        m = m->next;
156    }
157
158    return m;
159}
160
161/* Called from OsTimer callback, since removing a device from the device
162   list or changing pInfo->fd while xf86Wakeup is looping through the list
163   causes server crashes */
164static CARD32
165vuidRemoveMouse(OsTimerPtr timer, CARD32 now, pointer arg)
166{
167    InputInfoPtr pInfo = (InputInfoPtr) arg;
168
169    xf86DisableDevice(pInfo->dev, TRUE);
170
171    return 0;  /* All done, don't set to run again */
172}
173
174/*
175 * Initialize and enable the mouse wheel, if present.
176 *
177 * Returns 1 if mouse wheel was successfully enabled.
178 * Returns 0 if an error occurred or if there is no mouse wheel.
179 */
180static int
181vuidMouseWheelInit(InputInfoPtr pInfo)
182{
183#ifdef HAVE_VUID_WHEEL
184    wheel_state wstate;
185    int nwheel = -1;
186    int i;
187
188    wstate.vers = VUID_WHEEL_STATE_VERS;
189    wstate.id = 0;
190    wstate.stateflags = (uint32_t) -1;
191
192    SYSCALL(i = ioctl(pInfo->fd, VUIDGWHEELCOUNT, &nwheel));
193    if (i != 0)
194        return (0);
195
196    SYSCALL(i = ioctl(pInfo->fd, VUIDGWHEELSTATE, &wstate));
197    if (i != 0) {
198        xf86Msg(X_WARNING, "%s: couldn't get wheel state\n", pInfo->name);
199        return (0);
200    }
201
202    wstate.stateflags |= VUID_WHEEL_STATE_ENABLED;
203
204    SYSCALL(i = ioctl(pInfo->fd, VUIDSWHEELSTATE, &wstate));
205    if (i != 0) {
206        xf86Msg(X_WARNING, "%s: couldn't enable wheel\n", pInfo->name);
207        return (0);
208    }
209
210    return (1);
211#else
212    return (0);
213#endif
214}
215
216
217/* This function is called when the protocol is "VUID". */
218static Bool
219vuidPreInit(InputInfoPtr pInfo, const char *protocol, int flags)
220{
221    MouseDevPtr pMse = pInfo->private;
222    VuidMsePtr pVuidMse;
223
224    /* Ensure we don't add the same device twice */
225    if (getVuidMsePriv(pInfo) != NULL)
226        return TRUE;
227
228    pVuidMse = calloc(sizeof(VuidMseRec), 1);
229    if (pVuidMse == NULL) {
230        xf86Msg(X_ERROR, "%s: cannot allocate VuidMouseRec\n", pInfo->name);
231        free(pMse);
232        return FALSE;
233    }
234
235    pVuidMse->buffer = (unsigned char *)&pVuidMse->event;
236    pVuidMse->strmod = xf86SetStrOption(pInfo->options, "StreamsModule", NULL);
237    pVuidMse->relToAbs = xf86SetIntOption(pInfo->options, "RelToAbs", -1);
238    if (pVuidMse->relToAbs == -1)
239        pVuidMse->relToAbs = CheckRelToAbs(pInfo);
240    pVuidMse->absX = 0;
241    pVuidMse->absY = 0;
242
243    /* Setup the local procs. */
244    pVuidMse->wrapped_device_control = pInfo->device_control;
245    pInfo->device_control = vuidMouseProc;
246    pInfo->read_input = vuidReadInput;
247
248    pMse->xisbscale = sizeof(Firm_event);
249
250#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
251    pVuidMse->absres.height = pVuidMse->absres.width = 0;
252#endif
253    pVuidMse->pInfo = pInfo;
254    pVuidMse->next = vuidMouseList;
255    vuidMouseList = pVuidMse;
256
257#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
258    pInfo->flags |= XI86_CONFIGURED;
259#endif
260    return TRUE;
261}
262
263/*
264 * It seems that the mouse that is presented by the Emulex ILOM
265 * device (USB 0x430, 0xa101 and USB 0x430, 0xa102) sends relative
266 * mouse movements.  But relative mouse movements are subject to
267 * acceleration.  This causes the position indicated on the ILOM
268 * window to not match what the Xorg server actually has.  This
269 * makes the mouse in this environment rather unusable.  So, for the
270 * Emulex ILOM device, we will change all relative mouse movements
271 * into absolute mouse movements, making it appear more like a
272 * tablet.  This will not be subject to acceleration, and this
273 * should keep the ILOM window and Xorg server with the same values
274 * for the coordinates of the mouse.
275 */
276
277typedef struct reltoabs_match {
278	int matched;
279	char const *matchname;
280	} reltoabs_match_t;
281
282/* Sun Microsystems, keyboard / mouse */
283#define	RELTOABS_MATCH1	"usbif430,a101.config1.1"
284/* Sun Microsystems, keyboard / mouse / storage */
285#define	RELTOABS_MATCH2	"usbif430,a102.config1.1"
286
287static int
288CheckRelToAbsWalker(di_node_t node, void *arg)
289{
290	di_minor_t minor;
291	char *path;
292	int numvalues;
293	int valueon;
294	char const *stringptr;
295	int status;
296	reltoabs_match_t *const matchptr = (reltoabs_match_t *)arg;
297	char *stringvalues;
298
299	for (minor = di_minor_next(node, DI_MINOR_NIL);
300	  minor != DI_MINOR_NIL;
301	  minor = di_minor_next(node, minor)) {
302	    path = di_devfs_minor_path(minor);
303	    status = path != NULL && strcmp(path, matchptr -> matchname) == 0;
304	    di_devfs_path_free(path);
305	    if (status)
306		break;
307	    }
308
309	if (minor == DI_MINOR_NIL)
310	    return (DI_WALK_CONTINUE);
311
312	numvalues = di_prop_lookup_strings(DDI_DEV_T_ANY, node,
313	  "compatible", &stringvalues);
314	if (numvalues <= 0)
315	    return (DI_WALK_CONTINUE);
316
317	for (valueon = 0, stringptr = stringvalues; valueon < numvalues;
318	  valueon++, stringptr += strlen(stringptr) + 1) {
319	    if (strcmp(stringptr, RELTOABS_MATCH1) == 0) {
320		matchptr -> matched = 1;
321		return (DI_WALK_TERMINATE);
322	    }
323	    if (strcmp(stringptr, RELTOABS_MATCH2) == 0) {
324		matchptr -> matched = 2;
325		return (DI_WALK_TERMINATE);
326	    }
327	}
328	return (DI_WALK_CONTINUE);
329}
330
331static int
332CheckRelToAbs(InputInfoPtr pInfo)
333{
334	char const *device;
335	char const *matchname;
336	ssize_t readstatus;
337	di_node_t node;
338	struct stat statbuf;
339	char linkname[512];
340	reltoabs_match_t reltoabs_match;
341
342	device = xf86CheckStrOption(pInfo->options, "Device", NULL);
343	if (device == NULL)
344	    return (0);
345
346	matchname = device;
347
348	if (lstat(device, &statbuf) == 0 &&
349	  (statbuf.st_mode & S_IFMT) == S_IFLNK) {
350	    readstatus = readlink(device, linkname, sizeof(linkname));
351	    if (readstatus > 0 && readstatus < (ssize_t) sizeof(linkname)) {
352		linkname[readstatus] = 0;
353		matchname = linkname;
354		if (strncmp(matchname, "../..", sizeof("../..") - 1) == 0)
355		    matchname += sizeof("../..") - 1;
356	    }
357	}
358
359	if (strncmp(matchname, "/devices", sizeof("/devices") - 1) == 0)
360	    matchname += sizeof("/devices") - 1;
361
362	reltoabs_match.matched = 0;
363	reltoabs_match.matchname = matchname;
364
365	node = di_init("/", DINFOCPYALL);
366	if (node == DI_NODE_NIL)
367	    return (0);
368
369	di_walk_node(node, DI_WALK_CLDFIRST, (void *)&reltoabs_match,
370	  CheckRelToAbsWalker);
371
372	di_fini(node);
373
374	return (reltoabs_match.matched != 0);
375}
376
377static void
378vuidFlushAbsEvents(InputInfoPtr pInfo, int absX, int absY,
379                   Bool *absXset, Bool *absYset)
380{
381#ifdef DEBUG
382    ErrorF("vuidFlushAbsEvents: %d,%d (set: %d, %d)\n", absX, absY,
383           *absXset, *absYset);
384#endif
385    if ((*absXset) && (*absYset)) {
386        xf86PostMotionEvent(pInfo->dev,
387                            /* is_absolute: */    TRUE,
388                            /* first_valuator: */ 0,
389                            /* num_valuators: */  2,
390                            absX, absY);
391    } else if (*absXset) {
392        xf86PostMotionEvent(pInfo->dev,
393                            /* is_absolute: */    TRUE,
394                            /* first_valuator: */ 0,
395                            /* num_valuators: */  1,
396                            absX);
397    } else if (*absYset) {
398        xf86PostMotionEvent(pInfo->dev,
399                            /* is_absolute: */    TRUE,
400                            /* first_valuator: */ 1,
401                            /* num_valuators: */  1,
402                            absY);
403    }
404
405    *absXset = FALSE;
406    *absYset = FALSE;
407}
408
409static void
410vuidReadInput(InputInfoPtr pInfo)
411{
412    MouseDevPtr pMse;
413    VuidMsePtr pVuidMse;
414    int buttons;
415    int dx = 0, dy = 0, dz = 0, dw = 0;
416    ssize_t n;
417    unsigned char *pBuf;
418    int absX = 0, absY = 0;
419    int hdisplay = 0, vdisplay = 0;
420    Bool absXset = FALSE, absYset = FALSE;
421    int relToAbs;
422
423    pMse = pInfo->private;
424    buttons = pMse->lastButtons;
425    pVuidMse = getVuidMsePriv(pInfo);
426    if (pVuidMse == NULL) {
427        xf86Msg(X_ERROR, "%s: cannot locate VuidMsePtr\n", pInfo->name);
428        return;
429    }
430    pBuf = pVuidMse->buffer;
431    relToAbs = pVuidMse->relToAbs;
432    if (relToAbs) {
433	ScreenPtr   pScreen = miPointerGetScreen(pInfo->dev);
434	ScrnInfoPtr pScr = XF86SCRNINFO(pScreen);
435
436	if (pScr->currentMode) {
437	    hdisplay = pScr->currentMode->HDisplay;
438	    vdisplay = pScr->currentMode->VDisplay;
439	}
440	absX = pVuidMse->absX;
441	absY = pVuidMse->absY;
442    }
443
444    do {
445        n = read(pInfo->fd, pBuf, sizeof(Firm_event));
446
447        if (n == 0) {
448            break;
449        } else if (n == -1) {
450            switch (errno) {
451                case EAGAIN: /* Nothing to read now */
452                    n = 0;   /* End loop, go on to flush events & return */
453                    continue;
454                case EINTR:  /* Interrupted, try again */
455                    continue;
456                case ENODEV: /* May happen when USB mouse is unplugged */
457                    /* We use X_NONE here because it didn't alloc since we
458                       may be called from SIGIO handler. No longer true for
459                       sigsafe logging, but matters for older servers  */
460                    LogMessageVerbSigSafe(X_NONE, 0,
461                                          "%s: Device no longer present - removing.\n",
462                                          pInfo->name);
463                    xf86RemoveEnabledDevice(pInfo);
464                    pVuidMse->remove_timer =
465                        TimerSet(pVuidMse->remove_timer, 0, 1,
466                                 vuidRemoveMouse, pInfo);
467                    return;
468                default:     /* All other errors */
469                    /* We use X_NONE here because it didn't alloc since we
470                       may be called from SIGIO handler. No longer true for
471                       sigsafe logging, but matters for older servers  */
472                    LogMessageVerbSigSafe(X_NONE, 0, "%s: Read error: %s\n",
473                                          pInfo->name, strerror(errno));
474                    return;
475            }
476        } else if (n != sizeof(Firm_event)) {
477            xf86Msg(X_WARNING, "%s: incomplete packet, size %zd\n",
478                        pInfo->name, n);
479        }
480
481#ifdef DEBUG
482        LogMessageVerbSigSafe("vuidReadInput: event type: %d value: %d\n",
483                              pVuidMse->event.id, pVuidMse->event.value);
484#endif
485
486        if (pVuidMse->event.id >= BUT_FIRST && pVuidMse->event.id <= BUT_LAST) {
487            /* button */
488            int butnum = pVuidMse->event.id - BUT_FIRST;
489
490            if (butnum < 3)
491                butnum = 2 - butnum;
492            if (!pVuidMse->event.value)
493                buttons &= ~(1 << butnum);
494            else
495                buttons |= (1 << butnum);
496        } else if (pVuidMse->event.id >= VLOC_FIRST &&
497                   pVuidMse->event.id <= VLOC_LAST) {
498            /* axis */
499            int delta = pVuidMse->event.value;
500            switch(pVuidMse->event.id) {
501            case LOC_X_DELTA:
502                if (!relToAbs)
503                    dx += delta;
504                else {
505                    if (absXset)
506                        vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
507                    absX += delta;
508                    if (absX < 0)
509                        absX = 0;
510                    else if (absX >= hdisplay && hdisplay > 0)
511                        absX = hdisplay - 1;
512                    pVuidMse->absX = absX;
513                    absXset = TRUE;
514                }
515                break;
516            case LOC_Y_DELTA:
517                if (!relToAbs)
518                    dy -= delta;
519                else {
520                    if (absYset)
521                        vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
522                    absY -= delta;
523                    if (absY < 0)
524                        absY = 0;
525                    else if (absY >= vdisplay && vdisplay > 0)
526                        absY = vdisplay - 1;
527                    pVuidMse->absY = absY;
528                    absYset = TRUE;
529                }
530                break;
531            case LOC_X_ABSOLUTE:
532                if (absXset) {
533                    vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
534                }
535                absX = delta;
536                absXset = TRUE;
537                break;
538            case LOC_Y_ABSOLUTE:
539                if (absYset) {
540                    vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
541                }
542                absY = delta;
543                absYset = TRUE;
544                break;
545            }
546        }
547#ifdef HAVE_VUID_WHEEL
548        else if (vuid_in_range(VUID_WHEEL, pVuidMse->event.id)) {
549            if (vuid_id_offset(pVuidMse->event.id) == 0)
550                dz -= VUID_WHEEL_GETDELTA(pVuidMse->event.value);
551            else
552                dw -= VUID_WHEEL_GETDELTA(pVuidMse->event.value);
553        }
554#endif
555#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
556        else if (pVuidMse->event.id == MOUSE_TYPE_ABSOLUTE) {
557            ScreenPtr   ptrCurScreen;
558
559            /* force sending absolute resolution scaling ioctl */
560            pVuidMse->absres.height = pVuidMse->absres.width = 0;
561            ptrCurScreen = miPointerGetScreen(pInfo->dev);
562            vuidMouseSendScreenSize(ptrCurScreen, pVuidMse);
563        }
564#endif
565
566    } while (n != 0);
567
568    if (absXset || absYset) {
569        vuidFlushAbsEvents(pInfo, absX, absY, &absXset, &absYset);
570    }
571
572    pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw);
573    return;
574}
575
576#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
577static void vuidMouseSendScreenSize(ScreenPtr pScreen, VuidMsePtr pVuidMse)
578{
579    InputInfoPtr pInfo = pVuidMse->pInfo;
580    ScrnInfoPtr pScr = XF86SCRNINFO(pScreen);
581    int result;
582
583    if ((pVuidMse->absres.width != pScr->virtualX) ||
584        (pVuidMse->absres.height != pScr->virtualY))
585    {
586        pVuidMse->absres.width = pScr->virtualX;
587        pVuidMse->absres.height = pScr->virtualY;
588
589        do {
590            result = ioctl(pInfo->fd, MSIOSRESOLUTION, &(pVuidMse->absres));
591        } while ( (result != 0) && (errno == EINTR) );
592
593        if (result != 0) {
594            LogMessageVerbSigSafe(X_WARNING, -1,
595                                  "%s: couldn't set absolute mouse scaling resolution: %s\n",
596                                  pInfo->name, strerror(errno));
597#ifdef DEBUG
598        } else {
599            LogMessageVerbSigSafe(X_INFO,
600                                  "%s: absolute mouse scaling resolution set to %d x %d\n",
601                                  pInfo->name,
602                                  pVuidMse->absres.width,
603                                  pVuidMse->absres.height);
604#endif
605        }
606    }
607}
608
609static void vuidMouseAdjustFrame(ADJUST_FRAME_ARGS_DECL)
610{
611      SCRN_INFO_PTR(arg);
612      ScreenPtr         pScreen = xf86ScrnToScreen(pScrn);
613      xf86AdjustFrameProc *wrappedAdjustFrame
614          = (xf86AdjustFrameProc *) vuidMouseGetScreenPrivate(pScreen);
615      VuidMsePtr        m;
616      ScreenPtr         ptrCurScreen;
617
618      if (wrappedAdjustFrame) {
619          pScrn->AdjustFrame = wrappedAdjustFrame;
620          (*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, x, y));
621          pScrn->AdjustFrame = vuidMouseAdjustFrame;
622      }
623
624      for (m = vuidMouseList; m != NULL ; m = m->next) {
625          ptrCurScreen = miPointerGetScreen(m->pInfo->dev);
626          if (ptrCurScreen == pScreen)
627          {
628              vuidMouseSendScreenSize(pScreen, m);
629          }
630      }
631}
632
633static void vuidMouseCrtcNotify(ScreenPtr pScreen)
634{
635    xf86_crtc_notify_proc_ptr wrappedCrtcNotify
636        = (xf86_crtc_notify_proc_ptr) vuidMouseGetScreenPrivate(pScreen);
637    VuidMsePtr       m;
638    ScreenPtr        ptrCurScreen;
639
640    if (wrappedCrtcNotify)
641        wrappedCrtcNotify(pScreen);
642
643    for (m = vuidMouseList; m != NULL ; m = m->next) {
644        ptrCurScreen = miPointerGetScreen(m->pInfo->dev);
645        if (ptrCurScreen == pScreen) {
646            vuidMouseSendScreenSize(pScreen, m);
647        }
648    }
649}
650#endif /* HAVE_ABSOLUTE_MOUSE_SCALING */
651
652
653static int
654vuidMouseProc(DeviceIntPtr pPointer, int what)
655{
656    InputInfoPtr pInfo;
657    MouseDevPtr pMse;
658    VuidMsePtr pVuidMse;
659    int ret = Success;
660    int i;
661
662    pInfo = pPointer->public.devicePrivate;
663    pMse = pInfo->private;
664    pMse->device = pPointer;
665
666    pVuidMse = getVuidMsePriv(pInfo);
667    if (pVuidMse == NULL) {
668        return BadImplementation;
669    }
670
671    switch (what) {
672
673    case DEVICE_INIT:
674#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
675
676#if HAS_DEVPRIVATEKEYREC
677        if (!dixRegisterPrivateKey(&vuidMouseScreenIndex, PRIVATE_SCREEN, 0))
678                return BadAlloc;
679#endif  /* HAS_DEVPRIVATEKEYREC */
680
681        if (vuidMouseGeneration != serverGeneration) {
682                for (i = 0; i < screenInfo.numScreens; i++) {
683                    ScreenPtr pScreen = screenInfo.screens[i];
684                    ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen);
685                    if (xf86CrtcConfigPrivateIndex != -1) {
686                        xf86_crtc_notify_proc_ptr pCrtcNotify
687                            = xf86_wrap_crtc_notify(pScreen,
688                                                    vuidMouseCrtcNotify);
689                        vuidMouseSetScreenPrivate(pScreen, pCrtcNotify);
690                    } else {
691                        vuidMouseSetScreenPrivate(pScreen,
692                                                  pScrn->AdjustFrame);
693                        pScrn->AdjustFrame = vuidMouseAdjustFrame;
694                    }
695                }
696            vuidMouseGeneration = serverGeneration;
697        }
698#endif
699        ret = pVuidMse->wrapped_device_control(pPointer, what);
700        break;
701
702    case DEVICE_ON:
703        ret = pVuidMse->wrapped_device_control(pPointer, DEVICE_ON);
704
705        if ((ret == Success) && (pInfo->fd != -1)) {
706            int fmt = VUID_FIRM_EVENT;
707
708            if (pVuidMse->strmod) {
709                /* Check to see if module is already pushed */
710                SYSCALL(i = ioctl(pInfo->fd, I_FIND, pVuidMse->strmod));
711
712                if (i == 0) { /* Not already pushed */
713                    SYSCALL(i = ioctl(pInfo->fd, I_PUSH, pVuidMse->strmod));
714                    if (i < 0) {
715                        xf86Msg(X_WARNING, "%s: cannot push module '%s' "
716                                "onto mouse device: %s\n", pInfo->name,
717                                pVuidMse->strmod, strerror(errno));
718                        free(pVuidMse->strmod);
719                        pVuidMse->strmod = NULL;
720                    }
721                }
722            }
723
724            SYSCALL(i = ioctl(pInfo->fd, VUIDSFORMAT, &fmt));
725            if (i < 0) {
726                xf86Msg(X_WARNING,
727                        "%s: cannot set mouse device to VUID mode: %s\n",
728                        pInfo->name, strerror(errno));
729            }
730            vuidMouseWheelInit(pInfo);
731#ifdef HAVE_ABSOLUTE_MOUSE_SCALING
732            vuidMouseSendScreenSize(screenInfo.screens[0], pVuidMse);
733#endif
734            xf86FlushInput(pInfo->fd);
735
736            /* Allocate here so we don't alloc in ReadInput which may be called
737               from SIGIO handler. */
738            if (pVuidMse->remove_timer == NULL) {
739                pVuidMse->remove_timer = TimerSet(pVuidMse->remove_timer,
740                                                  0, 0, NULL, NULL);
741            }
742        }
743        break;
744
745    case DEVICE_CLOSE:
746        if (vuidMouseList == pVuidMse)
747            vuidMouseList = vuidMouseList->next;
748        else {
749            VuidMsePtr m = vuidMouseList;
750
751            while ((m != NULL) && (m->next != pVuidMse)) {
752                m = m->next;
753            }
754
755            if (m != NULL)
756                m->next = pVuidMse->next;
757        }
758        /* fallthrough */
759    case DEVICE_OFF:
760        if (pInfo->fd != -1) {
761            if (pVuidMse->strmod) {
762                SYSCALL(i = ioctl(pInfo->fd, I_POP, pVuidMse->strmod));
763                if (i == -1) {
764                    xf86Msg(X_WARNING,
765                      "%s: cannot pop module '%s' off mouse device: %s\n",
766                      pInfo->name, pVuidMse->strmod, strerror(errno));
767                }
768            }
769        }
770        if (pVuidMse->remove_timer) {
771            TimerFree(pVuidMse->remove_timer);
772            pVuidMse->remove_timer = NULL;
773        }
774        ret = pVuidMse->wrapped_device_control(pPointer, what);
775        break;
776
777    default: /* Should never be called, but just in case */
778        ret = pVuidMse->wrapped_device_control(pPointer, what);
779        break;
780    }
781    return ret;
782}
783
784static Bool
785sunMousePreInit(InputInfoPtr pInfo, const char *protocol, int flags)
786{
787    /* The protocol is guaranteed to be one of the internalNames[] */
788    if (xf86NameCmp(protocol, "VUID") == 0) {
789        return vuidPreInit(pInfo, protocol, flags);
790    }
791    return TRUE;
792}
793
794static const char **
795BuiltinNames(void)
796{
797    return internalNames;
798}
799
800static Bool
801CheckProtocol(const char *protocol)
802{
803    int i;
804
805    for (i = 0; internalNames[i]; i++)
806        if (xf86NameCmp(protocol, internalNames[i]) == 0)
807            return TRUE;
808
809    return FALSE;
810}
811
812static const char *
813DefaultProtocol(void)
814{
815    return "Auto";
816}
817
818static Bool
819solarisMouseAutoProbe(InputInfoPtr pInfo, const char **protocol,
820        const char **device)
821{
822    const char **pdev, **pproto;
823    int fd = -1;
824    Bool found;
825    char *strmod;
826
827    if (*device == NULL) {
828        /* Check to see if xorg.conf or HAL specified a device to use */
829        *device = xf86CheckStrOption(pInfo->options, "Device", NULL);
830    }
831
832    if (*device != NULL) {
833        strmod = xf86CheckStrOption(pInfo->options, "StreamsModule", NULL);
834        if (strmod) {
835            /* if a device name is already known, and a StreamsModule is
836               specified to convert events to VUID, then we don't need to
837               probe further */
838            *protocol = "VUID";
839            return TRUE;
840        }
841    }
842
843
844    for (pdev = solarisMouseDevs; *pdev; pdev += 2) {
845        pproto = pdev + 1;
846        if ((*protocol != NULL) && (strcmp(*protocol, "Auto") != 0) &&
847          (*pproto != NULL) && (strcmp(*pproto, *protocol) != 0)) {
848            continue;
849        }
850        if ((*device != NULL) && (strcmp(*device, *pdev) != 0)) {
851            continue;
852        }
853        SYSCALL (fd = open(*pdev, O_RDWR | O_NONBLOCK));
854        if (fd == -1) {
855#ifdef DEBUG
856            ErrorF("Cannot open %s (%s)\n", pdev, strerror(errno));
857#endif
858        } else {
859            found = TRUE;
860            if ((*pproto != NULL) && (strcmp(*pproto, "VUID") == 0)) {
861                int i, r;
862                SYSCALL(r = ioctl(fd, VUIDGFORMAT, &i));
863                if (r < 0) {
864                    found = FALSE;
865                }
866            }
867            close(fd);
868            if (found == TRUE) {
869                if (*pproto != NULL) {
870                    *protocol = *pproto;
871                }
872                *device = *pdev;
873                return TRUE;
874            }
875        }
876    }
877    return FALSE;
878}
879
880static const char *
881SetupAuto(InputInfoPtr pInfo, int *protoPara)
882{
883    const char *pdev = NULL;
884    const char *pproto = NULL;
885    MouseDevPtr pMse = pInfo->private;
886
887    if (pInfo->fd == -1) {
888        /* probe to find device/protocol to use */
889        if (solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) {
890            /* Set the Device option. */
891            pInfo->options =
892             xf86AddNewOption(pInfo->options, "Device", pdev);
893            xf86Msg(X_INFO, "%s: Setting Device option to \"%s\"\n",
894              pInfo->name, pdev);
895        }
896    } else if (pMse->protocolID == PROT_AUTO) {
897        pdev = xf86CheckStrOption(pInfo->options,
898                "Device", NULL);
899        if ((solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) &&
900            (pproto != NULL))
901            sunMousePreInit(pInfo, pproto, 0);
902    }
903    return pproto;
904}
905
906static const char *
907FindDevice(InputInfoPtr pInfo, const char *protocol, int flags)
908{
909    const char *pdev = NULL;
910    const char *pproto = protocol;
911
912    if (solarisMouseAutoProbe(pInfo, &pproto, &pdev) != FALSE) {
913        /* Set the Device option. */
914        pInfo->options =
915          xf86AddNewOption(pInfo->options, "Device", pdev);
916        xf86Msg(X_INFO, "%s: Setting Device option to \"%s\"\n",
917          pInfo->name, pdev);
918    }
919    return pdev;
920}
921
922static int
923SupportedInterfaces(void)
924{
925    /* XXX This needs to be checked. */
926    return MSE_SERIAL | MSE_BUS | MSE_PS2 | MSE_AUTO | MSE_XPS2 | MSE_MISC;
927}
928
929OSMouseInfoPtr
930OSMouseInit(int flags)
931{
932    OSMouseInfoPtr p;
933
934    p = calloc(sizeof(OSMouseInfoRec), 1);
935    if (!p)
936        return NULL;
937    p->SupportedInterfaces = SupportedInterfaces;
938    p->BuiltinNames = BuiltinNames;
939    p->CheckProtocol = CheckProtocol;
940    p->PreInit = sunMousePreInit;
941    p->DefaultProtocol = DefaultProtocol;
942    p->SetupAuto = SetupAuto;
943    p->FindDevice = FindDevice;
944
945    return p;
946}
947
948