ws.c revision 293de341
11.86Smartin/*
21.52Sthorpej * Copyright © 2005-2009,2011 Matthieu Herrb
31.52Sthorpej *
41.52Sthorpej * Permission to use, copy, modify, and distribute this software for any
51.52Sthorpej * purpose with or without fee is hereby granted, provided that the above
61.52Sthorpej * copyright notice and this permission notice appear in all copies.
71.52Sthorpej *
81.52Sthorpej * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
91.52Sthorpej * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
101.52Sthorpej * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
111.52Sthorpej * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
121.52Sthorpej * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
131.52Sthorpej * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
141.52Sthorpej * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
151.52Sthorpej */
161.52Sthorpej/* $OpenBSD: ws.c,v 1.33 2011/07/16 17:51:30 matthieu Exp $ */
171.52Sthorpej
181.52Sthorpej#ifdef HAVE_CONFIG_H
191.52Sthorpej#include "config.h"
201.52Sthorpej#endif
211.52Sthorpej
221.52Sthorpej#include <unistd.h>
231.52Sthorpej#include <errno.h>
241.52Sthorpej#include <sys/ioctl.h>
251.52Sthorpej#include <sys/time.h>
261.52Sthorpej#include <dev/wscons/wsconsio.h>
271.52Sthorpej
281.52Sthorpej#include <xorg-server.h>
291.52Sthorpej#include <xf86.h>
301.52Sthorpej#include <xf86_OSproc.h>
311.52Sthorpej#include <X11/extensions/XI.h>
321.52Sthorpej#include <X11/extensions/XIproto.h>
331.52Sthorpej#include <xf86Xinput.h>
341.52Sthorpej#include <exevents.h>
351.52Sthorpej#include <xisb.h>
361.52Sthorpej#include <mipointer.h>
371.52Sthorpej#include <extinit.h>
381.52Sthorpej
391.19Scgd#include "ws.h"
401.19Scgd
411.19Scgd#include <X11/Xatom.h>
421.19Scgd#include "ws-properties.h"
431.19Scgd#include <xserver-properties.h>
441.19Scgd
451.19Scgd
461.19Scgdstatic MODULESETUPPROTO(SetupProc);
471.19Scgdstatic void TearDownProc(pointer);
481.19Scgd
491.19Scgd#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
501.19Scgdstatic InputInfoPtr wsPreInit(InputDriverPtr, IDevPtr, int);
511.19Scgd#endif
521.19Scgdstatic int wsPreInit12(InputDriverPtr, InputInfoPtr, int);
531.19Scgdstatic int wsProc(DeviceIntPtr, int);
541.19Scgdstatic int wsDeviceInit(DeviceIntPtr);
551.19Scgdstatic int wsDeviceOn(DeviceIntPtr);
561.19Scgdstatic void wsDeviceOff(DeviceIntPtr);
571.19Scgdstatic void wsReadInput(InputInfoPtr);
581.19Scgdstatic void wsSendButtons(InputInfoPtr, int);
591.19Scgdstatic int wsChangeControl(InputInfoPtr, xDeviceCtl *);
601.19Scgdstatic int wsSwitchMode(ClientPtr, DeviceIntPtr, int);
611.19Scgdstatic Bool wsOpen(InputInfoPtr);
621.19Scgdstatic void wsClose(InputInfoPtr);
631.19Scgdstatic void wsControlProc(DeviceIntPtr , PtrCtrl *);
641.19Scgd
651.19Scgdstatic void wsInitProperty(DeviceIntPtr);
661.19Scgdstatic int wsSetProperty(DeviceIntPtr, Atom, XIPropertyValuePtr, BOOL);
671.19Scgd
681.19Scgdstatic Atom prop_calibration = 0;
691.19Scgdstatic Atom prop_swap = 0;
701.19Scgd
711.19Scgd#ifdef DEBUG
721.19Scgdint ws_debug_level = 0;
731.19Scgd#endif
741.19Scgd
751.19Scgdstatic XF86ModuleVersionInfo VersionRec = {
761.19Scgd	"ws",
771.19Scgd	MODULEVENDORSTRING,
781.19Scgd	MODINFOSTRING1,
791.78Slukem	MODINFOSTRING2,
801.78Slukem	XORG_VERSION_CURRENT,
811.86Smartin	PACKAGE_VERSION_MAJOR,
821.44Sjonathan	PACKAGE_VERSION_MINOR,
831.44Sjonathan	PACKAGE_VERSION_PATCHLEVEL,
841.86Smartin	ABI_CLASS_XINPUT,
851.80Sbriggs	ABI_XINPUT_VERSION,
861.19Scgd	MOD_CLASS_XINPUT,
871.19Scgd	{0, 0, 0, 0}
881.19Scgd};
891.19Scgd
901.19Scgd#define WS_NOZMAP 0
911.19Scgd
921.19ScgdXF86ModuleData wsModuleData = {&VersionRec,
931.25Schristos			       SetupProc, TearDownProc };
941.26Schristos
951.27Sjonathan
961.45SrossInputDriverRec WS = {
971.82Sthorpej	1,
981.19Scgd	"ws",
991.19Scgd	NULL,
1001.74Sthorpej#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
1011.74Sthorpej	wsPreInit,
1021.74Sthorpej#else
1031.25Schristos	wsPreInit12,
1041.19Scgd#endif
1051.19Scgd	NULL,
1061.19Scgd	NULL,
1071.19Scgd	0
1081.19Scgd};
1091.19Scgd
1101.19Scgdstatic pointer
1111.19ScgdSetupProc(pointer module, pointer options, int *errmaj, int *errmin)
1121.19Scgd{
1131.19Scgd	static Bool Initialised = FALSE;
1141.19Scgd
1151.19Scgd	if (!Initialised) {
1161.19Scgd		xf86AddInputDriver(&WS, module, 0);
1171.19Scgd		Initialised = TRUE;
1181.19Scgd	}
1191.19Scgd	return module;
1201.19Scgd}
1211.19Scgd
1221.19Scgdstatic void
1231.19ScgdTearDownProc(pointer p)
1241.19Scgd{
1251.19Scgd	DBG(1, ErrorF("WS TearDownProc called\n"));
1261.19Scgd}
1271.19Scgd
1281.19Scgd
1291.19Scgdstatic int
1301.19ScgdwsPreInit12(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
1311.19Scgd{
1321.27Sjonathan	WSDevicePtr priv;
1331.27Sjonathan	MessageType buttons_from = X_CONFIG;
1341.27Sjonathan	char *s;
1351.27Sjonathan	const char *cs;
1361.27Sjonathan	int rc;
1371.27Sjonathan
1381.27Sjonathan	priv = (WSDevicePtr)calloc(1, sizeof(WSDeviceRec));
1391.27Sjonathan	if (priv == NULL) {
1401.27Sjonathan		rc = BadAlloc;
1411.27Sjonathan		goto fail;
1421.27Sjonathan	}
1431.27Sjonathan	pInfo->private = priv;
1441.27Sjonathan
1451.27Sjonathan#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
1461.27Sjonathan	xf86CollectInputOptions(pInfo, NULL, NULL);
1471.27Sjonathan	xf86ProcessCommonOptions(pInfo, pInfo->options);
1481.27Sjonathan#else
1491.27Sjonathan	xf86CollectInputOptions(pInfo, NULL);
1501.27Sjonathan#endif
1511.27Sjonathan#ifdef DEBUG
1521.27Sjonathan	ws_debug_level = xf86SetIntOption(pInfo->options, "DebugLevel",
1531.27Sjonathan	    ws_debug_level);
1541.27Sjonathan	xf86Msg(X_INFO, "%s: debuglevel %d\n", pInfo->name,
1551.27Sjonathan	    ws_debug_level);
1561.27Sjonathan#endif
1571.27Sjonathan	priv->devName = xf86FindOptionValue(pInfo->options, "Device");
1581.27Sjonathan	if (priv->devName == NULL) {
1591.27Sjonathan		xf86Msg(X_ERROR, "%s: No Device specified.\n",
1601.27Sjonathan			pInfo->name);
1611.27Sjonathan		rc = BadValue;
1621.27Sjonathan		goto fail;
1631.27Sjonathan	}
1641.27Sjonathan	priv->buttons = xf86SetIntOption(pInfo->options, "Buttons", 0);
1651.27Sjonathan	if (priv->buttons == 0) {
1661.27Sjonathan		priv->buttons = DFLTBUTTONS;
1671.27Sjonathan		buttons_from = X_DEFAULT;
1681.27Sjonathan	}
1691.27Sjonathan	priv->negativeZ =  priv->positiveZ = WS_NOZMAP;
1701.27Sjonathan	s = xf86SetStrOption(pInfo->options, "ZAxisMapping", "4 5 6 7");
1711.27Sjonathan	if (s) {
1721.27Sjonathan		int b1, b2;
1731.27Sjonathan
1741.27Sjonathan		if (sscanf(s, "%d %d", &b1, &b2) == 2 &&
1751.27Sjonathan		    b1 > 0 && b1 <= NBUTTONS &&
1761.27Sjonathan		    b2 > 0 && b2 <= NBUTTONS) {
1771.27Sjonathan			priv->negativeZ = b1;
1781.27Sjonathan			priv->positiveZ = b2;
1791.27Sjonathan			xf86Msg(X_CONFIG,
1801.27Sjonathan			    "%s: ZAxisMapping: buttons %d and %d\n",
1811.27Sjonathan			    pInfo->name, b1, b2);
1821.27Sjonathan		} else {
1831.27Sjonathan			xf86Msg(X_WARNING, "%s: invalid ZAxisMapping value: "
1841.27Sjonathan			    "\"%s\"\n", pInfo->name, s);
1851.27Sjonathan		}
1861.27Sjonathan	}
1871.27Sjonathan	if (priv->negativeZ > priv->buttons) {
1881.27Sjonathan		priv->buttons = priv->negativeZ;
1891.27Sjonathan		buttons_from = X_CONFIG;
1901.27Sjonathan	}
1911.27Sjonathan	if (priv->positiveZ > priv->buttons) {
1921.27Sjonathan		priv->buttons = priv->positiveZ;
1931.27Sjonathan		buttons_from = X_CONFIG;
1941.27Sjonathan	}
1951.27Sjonathan	priv->negativeW =  priv->positiveW = WS_NOZMAP;
1961.27Sjonathan	s = xf86SetStrOption(pInfo->options, "WAxisMapping", NULL);
1971.27Sjonathan	if (s) {
1981.27Sjonathan		int b1, b2;
1991.27Sjonathan
2001.27Sjonathan		if (sscanf(s, "%d %d", &b1, &b2) == 2 &&
2011.27Sjonathan		    b1 > 0 && b1 <= NBUTTONS &&
2021.27Sjonathan		    b2 > 0 && b2 <= NBUTTONS) {
2031.27Sjonathan			priv->negativeW = b1;
2041.27Sjonathan			priv->positiveW = b2;
2051.27Sjonathan			xf86Msg(X_CONFIG,
2061.27Sjonathan			    "%s: WAxisMapping: buttons %d and %d\n",
2071.27Sjonathan			    pInfo->name, b1, b2);
2081.27Sjonathan		} else {
2091.27Sjonathan			xf86Msg(X_WARNING, "%s: invalid WAxisMapping value: "
2101.27Sjonathan			    "\"%s\"\n", pInfo->name, s);
2111.27Sjonathan		}
2121.27Sjonathan	}
2131.27Sjonathan	if (priv->negativeW > priv->buttons) {
2141.27Sjonathan		priv->buttons = priv->negativeW;
2151.27Sjonathan		buttons_from = X_CONFIG;
2161.27Sjonathan	}
2171.27Sjonathan	if (priv->positiveW > priv->buttons) {
2181.27Sjonathan		priv->buttons = priv->positiveW;
2191.27Sjonathan		buttons_from = X_CONFIG;
2201.27Sjonathan	}
2211.27Sjonathan
2221.27Sjonathan	priv->screen_no = xf86SetIntOption(pInfo->options, "ScreenNo", 0);
2231.27Sjonathan	xf86Msg(X_CONFIG, "%s associated screen: %d\n",
2241.27Sjonathan	    pInfo->name, priv->screen_no);
2251.27Sjonathan	if (priv->screen_no >= screenInfo.numScreens ||
2261.27Sjonathan	    priv->screen_no < 0) {
2271.27Sjonathan		priv->screen_no = 0;
2281.27Sjonathan	}
2291.27Sjonathan
2301.27Sjonathan
2311.27Sjonathan	priv->swap_axes = xf86SetBoolOption(pInfo->options, "SwapXY", 0);
2321.27Sjonathan	if (priv->swap_axes) {
2331.27Sjonathan		xf86Msg(X_CONFIG,
2341.27Sjonathan		    "%s device will work with X and Y axes swapped\n",
2351.27Sjonathan		    pInfo->name);
2361.27Sjonathan	}
2371.27Sjonathan	priv->inv_x = 0;
2381.27Sjonathan	priv->inv_y = 0;
2391.27Sjonathan	cs = xf86FindOptionValue(pInfo->options, "Rotate");
2401.27Sjonathan	if (cs) {
2411.27Sjonathan		if (xf86NameCmp(cs, "CW") == 0) {
2421.27Sjonathan			priv->inv_x = 1;
2431.27Sjonathan			priv->inv_y = 0;
2441.27Sjonathan			priv->swap_axes = 1;
2451.27Sjonathan		} else if (xf86NameCmp(cs, "CCW") == 0) {
2461.27Sjonathan			priv->inv_x = 0;
2471.27Sjonathan			priv->inv_y = 1;
2481.27Sjonathan			priv->swap_axes = 1;
2491.27Sjonathan		} else if (xf86NameCmp(cs, "UD") == 0) {
2501.27Sjonathan			priv->inv_x = 1;
2511.27Sjonathan			priv->inv_y = 1;
2521.27Sjonathan		} else {
2531.27Sjonathan			xf86Msg(X_ERROR, "\"%s\" is not a valid value "
2541.27Sjonathan				"for Option \"Rotate\"\n", cs);
2551.27Sjonathan			xf86Msg(X_ERROR, "Valid options are \"CW\", \"CCW\","
2561.27Sjonathan				" or \"UD\"\n");
2571.27Sjonathan		}
2581.27Sjonathan	}
2591.27Sjonathan	if (wsOpen(pInfo) != Success) {
2601.27Sjonathan		rc = BadValue;
2611.27Sjonathan		goto fail;
2621.27Sjonathan	}
2631.27Sjonathan	if (ioctl(pInfo->fd, WSMOUSEIO_GTYPE, &priv->type) != 0) {
2641.27Sjonathan		wsClose(pInfo);
2651.27Sjonathan		rc = BadValue;
2661.27Sjonathan		goto fail;
2671.27Sjonathan	}
2681.27Sjonathan
2691.27Sjonathan	/* assume screen coordinate space until proven wrong */
2701.27Sjonathan	priv->min_x = 0;
2711.27Sjonathan	priv->max_x = screenInfo.screens[priv->screen_no]->width - 1;
2721.27Sjonathan	priv->min_y = 0;
2731.27Sjonathan	priv->max_y = screenInfo.screens[priv->screen_no]->height - 1;
2741.27Sjonathan	priv->raw = 0;
2751.27Sjonathan
2761.27Sjonathan	/* don't rely on the device type - we may be listening to a mux */
2771.27Sjonathan	if (ioctl(pInfo->fd, WSMOUSEIO_GCALIBCOORDS,
2781.27Sjonathan		&priv->coords) != 0) {
2791.27Sjonathan		/* can't get absolute coordinate space - assume mouse */
2801.27Sjonathan		pInfo->type_name = XI_MOUSE;
2811.27Sjonathan	} else if (priv->coords.samplelen == WSMOUSE_CALIBCOORDS_RESET) {
2821.27Sjonathan		/*
2831.27Sjonathan		 * we're getting raw coordinates - update accordingly and hope
2841.27Sjonathan		 * that there is no other absolute positioning device on the
2851.27Sjonathan		 * same mux
2861.27Sjonathan		 */
2871.27Sjonathan		priv->min_x = priv->coords.minx;
2881.27Sjonathan		priv->max_x = priv->coords.maxx;
2891.27Sjonathan		priv->min_y = priv->coords.miny;
2901.27Sjonathan		priv->max_y = priv->coords.maxy;
2911.27Sjonathan		priv->raw = 1;
2921.27Sjonathan		pInfo->type_name = XI_TOUCHSCREEN;
2931.27Sjonathan	} else {
2941.27Sjonathan		/*
2951.27Sjonathan		 * touchscreen not in raw mode, should send us screen
2961.27Sjonathan		 * coordinates
2971.27Sjonathan		 */
2981.27Sjonathan		pInfo->type_name = XI_TOUCHSCREEN;
2991.27Sjonathan	}
3001.27Sjonathan
3011.27Sjonathan	if (priv->raw) {
3021.27Sjonathan		xf86Msg(X_CONFIG,
3031.27Sjonathan		    "%s device will work in raw mode\n",
3041.27Sjonathan		    pInfo->name);
3051.19Scgd	}
3061.19Scgd
3071.19Scgd	/* Allow options to override this */
3081.19Scgd	priv->min_x = xf86SetIntOption(pInfo->options, "MinX", priv->min_x);
3091.55Saugustss	xf86Msg(X_INFO, "%s minimum x position: %d\n",
3101.55Saugustss	    pInfo->name, priv->min_x);
3111.19Scgd	priv->max_x = xf86SetIntOption(pInfo->options, "MaxX", priv->max_x);
3121.19Scgd	xf86Msg(X_INFO, "%s maximum x position: %d\n",
3131.19Scgd	    pInfo->name, priv->max_x);
3141.19Scgd	priv->min_y = xf86SetIntOption(pInfo->options, "MinY", priv->min_y);
3151.19Scgd	xf86Msg(X_INFO, "%s minimum y position: %d\n",
3161.19Scgd	    pInfo->name, priv->min_y);
3171.19Scgd	priv->max_y = xf86SetIntOption(pInfo->options, "MaxY", priv->max_y);
3181.19Scgd	xf86Msg(X_INFO, "%s maximum y position: %d\n",
3191.19Scgd	    pInfo->name, priv->max_y);
3201.19Scgd
3211.80Sbriggs	pInfo->device_control = wsProc;
3221.75Ssimonb	pInfo->read_input = wsReadInput;
3231.19Scgd	pInfo->control_proc = wsChangeControl;
3241.84Sthorpej	pInfo->switch_mode = wsSwitchMode;
3251.70Ssommerfe	pInfo->private = priv;
3261.22Scgd#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
3271.22Scgd	pInfo->conversion_proc = NULL;
3281.34Sbriggs	pInfo->reverse_conversion_proc = NULL;
3291.39Scgd	pInfo->old_x = -1;
3301.34Sbriggs	pInfo->old_y = -1;
3311.27Sjonathan#endif
3321.31Smycroft	xf86Msg(buttons_from, "%s: Buttons: %d\n", pInfo->name, priv->buttons);
3331.31Smycroft
3341.19Scgd	wsClose(pInfo);
3351.48Schristos
3361.48Schristos	wsmbEmuPreInit(pInfo);
3371.48Schristos	return Success;
3381.48Schristos
3391.48Schristosfail:
3401.48Schristos	if (priv != NULL) {
3411.19Scgd		free(priv);
3421.19Scgd		pInfo->private = NULL;
3431.73Sthorpej	}
3441.73Sthorpej	return rc;
3451.66Sthorpej}
3461.19Scgd
3471.19Scgd#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
3481.19Scgdstatic InputInfoPtr
3491.63SthorpejwsPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
3501.19Scgd{
3511.55Saugustss	InputInfoPtr pInfo = NULL;
3521.19Scgd
3531.73Sthorpej	pInfo = xf86AllocateInput(drv, 0);
3541.73Sthorpej	if (pInfo == NULL) {
3551.73Sthorpej		return NULL;
3561.73Sthorpej	}
3571.73Sthorpej	pInfo->name = dev->identifier;
3581.73Sthorpej	pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
3591.19Scgd	pInfo->conf_idev = dev;
3601.19Scgd	pInfo->close_proc = NULL;
3611.19Scgd	pInfo->private_flags = 0;
3621.19Scgd	pInfo->always_core_feedback = NULL;
3631.70Ssommerfe
3641.19Scgd	if (wsPreInit12(drv, pInfo, flags) != Success) {
3651.19Scgd		xf86DeleteInput(pInfo, 0);
3661.19Scgd		return NULL;
3671.70Ssommerfe	}
3681.19Scgd	/* mark the device configured */
3691.19Scgd	pInfo->flags |= XI86_CONFIGURED;
3701.19Scgd	return pInfo;
3711.19Scgd}
3721.19Scgd#endif
3731.70Ssommerfe
3741.31Smycroftstatic int
3751.31SmycroftwsProc(DeviceIntPtr pWS, int what)
3761.31Smycroft{
3771.57Smycroft	InputInfoPtr pInfo = (InputInfoPtr)pWS->public.devicePrivate;
3781.57Smycroft
3791.57Smycroft	switch (what) {
3801.57Smycroft	case DEVICE_INIT:
3811.57Smycroft		return wsDeviceInit(pWS);
3821.57Smycroft
3831.57Smycroft	case DEVICE_ON:
3841.57Smycroft		return wsDeviceOn(pWS);
3851.57Smycroft
3861.57Smycroft	case DEVICE_OFF:
3871.57Smycroft		wsDeviceOff(pWS);
3881.57Smycroft		break;
3891.57Smycroft
3901.57Smycroft	case DEVICE_CLOSE:
3911.57Smycroft		DBG(1, ErrorF("WS DEVICE_CLOSE\n"));
3921.57Smycroft		wsClose(pInfo);
3931.57Smycroft		break;
3941.57Smycroft
3951.31Smycroft	default:
3961.31Smycroft		xf86Msg(X_ERROR, "WS: unknown command %d\n", what);
3971.31Smycroft		return !Success;
3981.31Smycroft	} /* switch */
3991.31Smycroft	return Success;
4001.31Smycroft} /* wsProc */
4011.31Smycroft
4021.31Smycroftstatic int
4031.31SmycroftwsDeviceInit(DeviceIntPtr pWS)
4041.31Smycroft{
4051.31Smycroft	InputInfoPtr pInfo = (InputInfoPtr)pWS->public.devicePrivate;
4061.41Stls	WSDevicePtr priv = (WSDevicePtr)pInfo->private;
4071.41Stls	unsigned char map[NBUTTONS + 1];
4081.41Stls	int i, xmin, xmax, ymin, ymax;
4091.31Smycroft	Atom btn_labels[NBUTTONS] = {0};
4101.43Sross	Atom axes_labels[NAXES] = {0};
4111.31Smycroft
4121.31Smycroft	DBG(1, ErrorF("WS DEVICE_INIT\n"));
4131.31Smycroft
4141.57Smycroft	btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
4151.57Smycroft	btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
4161.57Smycroft	btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
4171.57Smycroft	for (i = 0; i < NBUTTONS; i++)
4181.57Smycroft		map[i + 1] = i + 1;
4191.57Smycroft	if (!InitButtonClassDeviceStruct(pWS,
4201.57Smycroft		min(priv->buttons, NBUTTONS),
4211.57Smycroft		btn_labels,
4221.57Smycroft		map))
4231.57Smycroft		return !Success;
4241.57Smycroft
4251.57Smycroft	if (priv->type == WSMOUSE_TYPE_TPANEL) {
4261.57Smycroft		xmin = priv->min_x;
4271.57Smycroft		xmax = priv->max_x;
4281.57Smycroft		ymin = priv->min_y;
4291.57Smycroft		ymax = priv->max_y;
4301.57Smycroft	} else {
4311.57Smycroft		xmin = -1;
4321.57Smycroft		xmax = -1;
4331.31Smycroft		ymin = -1;
4341.31Smycroft		ymax = -1;
4351.50Ssommerfe	}
4361.50Ssommerfe
4371.52Sthorpej	if (priv->swap_axes) {
4381.52Sthorpej		int tmp;
4391.52Sthorpej		tmp = xmin;
4401.52Sthorpej		xmin = ymin;
4411.50Ssommerfe		ymin = tmp;
4421.31Smycroft		tmp = xmax;
4431.31Smycroft		xmax = ymax;
4441.19Scgd		ymax = tmp;
4451.19Scgd	}
4461.19Scgd	if ((priv->type == WSMOUSE_TYPE_TPANEL)) {
4471.19Scgd		axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X);
4481.19Scgd		axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y);
4491.19Scgd	} else {
4501.63Sthorpej		axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
4511.19Scgd		axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
4521.82Sthorpej	}
4531.55Saugustss	if (!InitValuatorClassDeviceStruct(pWS,
4541.55Saugustss		NAXES,
4551.19Scgd		axes_labels,
4561.19Scgd		GetMotionHistorySize(),
4571.70Ssommerfe		priv->type == WSMOUSE_TYPE_TPANEL ?
4581.82Sthorpej		Absolute : Relative))
4591.30Smycroft		return !Success;
4601.55Saugustss	if (!InitPtrFeedbackClassDeviceStruct(pWS, wsControlProc))
4611.55Saugustss		return !Success;
4621.29Schristos
4631.19Scgd	xf86InitValuatorAxisStruct(pWS, 0,
4641.82Sthorpej	    axes_labels[0],
4651.82Sthorpej	    xmin, xmax, 1, 0, 1
4661.82Sthorpej#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
4671.19Scgd	    , priv->type == WSMOUSE_TYPE_TPANEL  ? Absolute : Relative
4681.19Scgd#endif
4691.19Scgd	);
4701.82Sthorpej	xf86InitValuatorDefaults(pWS, 0);
4711.82Sthorpej
4721.82Sthorpej	xf86InitValuatorAxisStruct(pWS, 1,
4731.82Sthorpej	    axes_labels[1],
4741.82Sthorpej	    ymin, ymax, 1, 0, 1
4751.82Sthorpej#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
4761.82Sthorpej	    , priv->type == WSMOUSE_TYPE_TPANEL ? Absolute : Relative
4771.82Sthorpej#endif
4781.19Scgd	);
4791.19Scgd	xf86InitValuatorDefaults(pWS, 1);
4801.19Scgd
4811.19Scgd#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
4821.19Scgd	xf86MotionHistoryAllocate(pInfo);
4831.19Scgd	AssignTypeAndName(pWS, pInfo->atom, pInfo->name);
4841.19Scgd#endif
4851.70Ssommerfe	pWS->public.on = FALSE;
4861.71Ssommerfe	if (wsOpen(pInfo) != Success) {
4871.70Ssommerfe		return !Success;
4881.60Sthorpej	}
4891.60Sthorpej	wsInitProperty(pWS);
4901.60Sthorpej	XIRegisterPropertyHandler(pWS, wsSetProperty, NULL, NULL);
4911.60Sthorpej	wsmbEmuInitProperty(pWS);
4921.60Sthorpej	return Success;
4931.70Ssommerfe}
4941.60Sthorpej
4951.60Sthorpejstatic int
4961.60SthorpejwsDeviceOn(DeviceIntPtr pWS)
4971.19Scgd{
4981.22Scgd	InputInfoPtr pInfo = (InputInfoPtr)pWS->public.devicePrivate;
4991.22Scgd	WSDevicePtr priv = (WSDevicePtr)pInfo->private;
5001.22Scgd#ifndef __NetBSD__
5011.22Scgd	struct wsmouse_calibcoords coords;
5021.22Scgd#endif
5031.22Scgd
5041.19Scgd	DBG(1, ErrorF("WS DEVICE ON\n"));
5051.84Sthorpej	if ((pInfo->fd < 0) && (wsOpen(pInfo) != Success)) {
5061.22Scgd		xf86Msg(X_ERROR, "wsOpen failed %s\n",
5071.27Sjonathan		    strerror(errno));
5081.27Sjonathan			return !Success;
5091.22Scgd	}
5101.39Scgd
5111.24Scgd#ifndef __NetBSD__
5121.39Scgd	if (priv->type == WSMOUSE_TYPE_TPANEL) {
5131.39Scgd		/* get calibration values */
5141.22Scgd		if (ioctl(pInfo->fd, WSMOUSEIO_GCALIBCOORDS, &coords) != 0) {
5151.22Scgd			xf86Msg(X_ERROR, "GCALIBCOORS failed %s\n",
5161.27Sjonathan			    strerror(errno));
5171.27Sjonathan			return !Success;
5181.22Scgd		}
5191.38Scgd		memcpy(&priv->coords, &coords, sizeof coords);
5201.19Scgd		/* set raw mode */
5211.19Scgd		if (coords.samplelen != priv->raw) {
5221.27Sjonathan			coords.samplelen = priv->raw;
5231.27Sjonathan			if (ioctl(pInfo->fd, WSMOUSEIO_SCALIBCOORDS,
5241.27Sjonathan				&coords) != 0) {
5251.27Sjonathan				xf86Msg(X_ERROR, "SCALIBCOORS failed %s\n",
5261.27Sjonathan				    strerror(errno));
5271.27Sjonathan				return !Success;
5281.27Sjonathan			}
5291.27Sjonathan		}
5301.19Scgd	}
5311.27Sjonathan#endif
5321.31Smycroft	priv->buffer = XisbNew(pInfo->fd,
5331.30Smycroft	    sizeof(struct wscons_event) * NUMEVENTS);
5341.27Sjonathan	if (priv->buffer == NULL) {
5351.27Sjonathan		xf86Msg(X_ERROR, "cannot alloc xisb buffer\n");
5361.27Sjonathan		wsClose(pInfo);
5371.27Sjonathan		return !Success;
5381.27Sjonathan	}
5391.27Sjonathan	xf86AddEnabledDevice(pInfo);
5401.27Sjonathan	wsmbEmuOn(pInfo);
5411.27Sjonathan	pWS->public.on = TRUE;
5421.27Sjonathan	return Success;
5431.27Sjonathan}
5441.27Sjonathan
5451.31Smycroftstatic void
5461.27SjonathanwsDeviceOff(DeviceIntPtr pWS)
5471.27Sjonathan{
5481.27Sjonathan	InputInfoPtr pInfo = (InputInfoPtr)pWS->public.devicePrivate;
5491.27Sjonathan	WSDevicePtr priv = pInfo->private;
5501.27Sjonathan#ifndef __NetBSD__
5511.27Sjonathan	struct wsmouse_calibcoords coords;
5521.27Sjonathan#endif
5531.27Sjonathan
5541.27Sjonathan	DBG(1, ErrorF("WS DEVICE OFF\n"));
5551.27Sjonathan	wsmbEmuFinalize(pInfo);
5561.27Sjonathan#ifndef __NetBSD__
5571.27Sjonathan	if (priv->type == WSMOUSE_TYPE_TPANEL) {
5581.27Sjonathan		/* Restore calibration data */
5591.27Sjonathan		memcpy(&coords, &priv->coords, sizeof coords);
5601.27Sjonathan		if (ioctl(pInfo->fd, WSMOUSEIO_SCALIBCOORDS, &coords) != 0) {
5611.27Sjonathan			xf86Msg(X_ERROR, "SCALIBCOORS failed %s\n",
5621.27Sjonathan			    strerror(errno));
5631.27Sjonathan		}
5641.27Sjonathan	}
5651.27Sjonathan#endif
5661.27Sjonathan	if (pInfo->fd >= 0) {
5671.27Sjonathan		xf86RemoveEnabledDevice(pInfo);
5681.27Sjonathan		wsClose(pInfo);
5691.27Sjonathan	}
5701.27Sjonathan	if (priv->buffer) {
5711.27Sjonathan		XisbFree(priv->buffer);
5721.27Sjonathan		priv->buffer = NULL;
5731.27Sjonathan	}
5741.27Sjonathan	pWS->public.on = FALSE;
5751.27Sjonathan}
5761.27Sjonathan
5771.27Sjonathanstatic void
5781.27SjonathanwsReadInput(InputInfoPtr pInfo)
5791.27Sjonathan{
5801.27Sjonathan	WSDevicePtr priv;
5811.27Sjonathan	static struct wscons_event eventList[NUMEVENTS];
5821.27Sjonathan	int n, c;
5831.27Sjonathan	struct wscons_event *event = eventList;
5841.27Sjonathan	unsigned char *pBuf;
5851.27Sjonathan	int ax, ay;
5861.27Sjonathan
5871.27Sjonathan	priv = pInfo->private;
5881.27Sjonathan
5891.27Sjonathan	XisbBlockDuration(priv->buffer, -1);
5901.27Sjonathan	pBuf = (unsigned char *)eventList;
5911.27Sjonathan	n = 0;
5921.27Sjonathan	while (n < sizeof(eventList) && (c = XisbRead(priv->buffer)) >= 0) {
5931.27Sjonathan		pBuf[n++] = (unsigned char)c;
5941.27Sjonathan	}
5951.27Sjonathan
5961.27Sjonathan	if (n == 0)
5971.27Sjonathan		return;
5981.27Sjonathan
5991.27Sjonathan	n /= sizeof(struct wscons_event);
6001.27Sjonathan	while( n-- ) {
6011.27Sjonathan		int buttons = priv->lastButtons;
6021.27Sjonathan		int dx = 0, dy = 0, dz = 0, dw = 0;
6031.27Sjonathan		int zbutton = 0, wbutton = 0;
6041.27Sjonathan
6051.27Sjonathan		ax = 0; ay = 0;
6061.27Sjonathan		switch (event->type) {
6071.31Smycroft		case WSCONS_EVENT_MOUSE_UP:
6081.27Sjonathan
6091.27Sjonathan			buttons &= ~(1 << event->value);
6101.27Sjonathan			DBG(4, ErrorF("Button %d up %x\n", event->value,
6111.27Sjonathan				buttons));
6121.27Sjonathan		break;
6131.27Sjonathan		case WSCONS_EVENT_MOUSE_DOWN:
6141.31Smycroft			buttons |= (1 << event->value);
6151.27Sjonathan			DBG(4, ErrorF("Button %d down %x\n", event->value,
6161.27Sjonathan				buttons));
6171.27Sjonathan			break;
6181.27Sjonathan		case WSCONS_EVENT_MOUSE_DELTA_X:
6191.27Sjonathan			dx = event->value;
6201.27Sjonathan			DBG(4, ErrorF("Relative X %d\n", event->value));
6211.31Smycroft			break;
6221.27Sjonathan		case WSCONS_EVENT_MOUSE_DELTA_Y:
6231.27Sjonathan			dy = -event->value;
6241.27Sjonathan			DBG(4, ErrorF("Relative Y %d\n", event->value));
6251.27Sjonathan			break;
6261.27Sjonathan		case WSCONS_EVENT_MOUSE_ABSOLUTE_X:
6271.27Sjonathan			DBG(4, ErrorF("Absolute X %d\n", event->value));
6281.31Smycroft			if (event->value == 4095)
6291.27Sjonathan				break;
6301.27Sjonathan			ax = event->value;
6311.27Sjonathan			if (priv->inv_x)
6321.31Smycroft				ax = priv->max_x - ax + priv->min_x;
6331.27Sjonathan			break;
6341.27Sjonathan		case WSCONS_EVENT_MOUSE_ABSOLUTE_Y:
6351.31Smycroft			DBG(4, ErrorF("Absolute Y %d\n", event->value));
6361.27Sjonathan			ay = event->value;
6371.27Sjonathan			if (priv->inv_y)
6381.27Sjonathan				ay = priv->max_y - ay + priv->min_y;
6391.27Sjonathan			break;
6401.27Sjonathan		case WSCONS_EVENT_MOUSE_DELTA_Z:
6411.27Sjonathan			DBG(4, ErrorF("Relative Z %d\n", event->value));
6421.27Sjonathan			dz = event->value;
6431.27Sjonathan			break;
6441.27Sjonathan		case WSCONS_EVENT_MOUSE_ABSOLUTE_Z:
6451.27Sjonathan			/* ignore those */
6461.27Sjonathan			++event;
6471.27Sjonathan			continue;
6481.27Sjonathan			break;
6491.27Sjonathan		case WSCONS_EVENT_MOUSE_DELTA_W:
6501.27Sjonathan			DBG(4, ErrorF("Relative W %d\n", event->value));
6511.27Sjonathan			dw = event->value;
6521.27Sjonathan			break;
6531.27Sjonathan		default:
6541.27Sjonathan			xf86Msg(X_WARNING, "%s: bad wsmouse event type=%d\n",
6551.31Smycroft			    pInfo->name, event->type);
6561.31Smycroft			++event;
6571.27Sjonathan			continue;
6581.27Sjonathan		} /* case */
6591.27Sjonathan
6601.27Sjonathan		if (dx || dy) {
6611.27Sjonathan			/* relative motion event */
6621.27Sjonathan			DBG(3, ErrorF("postMotionEvent dX %d dY %d\n",
6631.27Sjonathan				      dx, dy));
6641.31Smycroft			xf86PostMotionEvent(pInfo->dev, 0, 0, 2,
6651.31Smycroft			    dx, dy);
6661.31Smycroft		}
6671.27Sjonathan		if (dz && priv->negativeZ != WS_NOZMAP
6681.27Sjonathan		    && priv->positiveZ != WS_NOZMAP) {
6691.27Sjonathan			buttons &= ~(priv->negativeZ | priv->positiveZ);
6701.27Sjonathan			if (dz < 0) {
6711.27Sjonathan				DBG(4, ErrorF("Z -> button %d\n",
6721.27Sjonathan					priv->negativeZ));
6731.27Sjonathan				zbutton = 1 << (priv->negativeZ - 1);
6741.27Sjonathan			} else {
6751.27Sjonathan				DBG(4, ErrorF("Z -> button %d\n",
6761.27Sjonathan					priv->positiveZ));
6771.27Sjonathan				zbutton = 1 << (priv->positiveZ - 1);
6781.27Sjonathan			}
6791.27Sjonathan			buttons |= zbutton;
6801.27Sjonathan			dz = 0;
6811.27Sjonathan		}
6821.27Sjonathan		if (dw && priv->negativeW != WS_NOZMAP
6831.27Sjonathan		    && priv->positiveW != WS_NOZMAP) {
6841.27Sjonathan			buttons &= ~(priv->negativeW | priv->positiveW);
6851.27Sjonathan			if (dw < 0) {
6861.27Sjonathan				DBG(4, ErrorF("W -> button %d\n",
6871.27Sjonathan					priv->negativeW));
6881.27Sjonathan				wbutton = 1 << (priv->negativeW - 1);
6891.31Smycroft			} else {
6901.27Sjonathan				DBG(4, ErrorF("W -> button %d\n",
6911.31Smycroft					priv->positiveW));
6921.31Smycroft				wbutton = 1 << (priv->positiveW - 1);
6931.27Sjonathan			}
6941.27Sjonathan			buttons |= wbutton;
6951.27Sjonathan			dw = 0;
6961.31Smycroft		}
6971.31Smycroft		if (priv->lastButtons != buttons) {
6981.46Smycroft			/* button event */
6991.46Smycroft			wsSendButtons(pInfo, buttons);
7001.46Smycroft		}
7011.46Smycroft		if (zbutton != 0) {
7021.46Smycroft			/* generate a button up event */
7031.46Smycroft			buttons &= ~zbutton;
7041.46Smycroft			wsSendButtons(pInfo, buttons);
7051.57Smycroft		}
7061.57Smycroft		if (priv->swap_axes) {
7071.46Smycroft			int tmp;
7081.46Smycroft
7091.46Smycroft			tmp = ax;
7101.46Smycroft			ax = ay;
7111.57Smycroft			ay = tmp;
7121.57Smycroft		}
7131.27Sjonathan		if (ax) {
7141.31Smycroft			/* absolute position event */
7151.58Smycroft			DBG(3, ErrorF("postMotionEvent X %d\n", ax));
7161.58Smycroft			xf86PostMotionEvent(pInfo->dev, 1, 0, 1, ax);
7171.58Smycroft		}
7181.58Smycroft		if (ay) {
7191.58Smycroft			/* absolute position event */
7201.58Smycroft			DBG(3, ErrorF("postMotionEvent y %d\n", ay));
7211.58Smycroft			xf86PostMotionEvent(pInfo->dev, 1, 1, 1, ay);
7221.58Smycroft		}
7231.58Smycroft		++event;
7241.58Smycroft	}
7251.58Smycroft	return;
7261.58Smycroft} /* wsReadInput */
7271.31Smycroft
7281.56Smycroftstatic void
7291.46SmycroftwsSendButtons(InputInfoPtr pInfo, int buttons)
7301.46Smycroft{
7311.46Smycroft	WSDevicePtr priv = (WSDevicePtr)pInfo->private;
7321.46Smycroft	int button, mask;
7331.46Smycroft
7341.46Smycroft	for (button = 1; button < NBUTTONS; button++) {
7351.46Smycroft		mask = 1 << (button - 1);
7361.46Smycroft		if ((mask & priv->lastButtons) != (mask & buttons)) {
7371.46Smycroft			if (!wsmbEmuFilterEvent(pInfo, button,
7381.31Smycroft				(buttons & mask) != 0)) {
7391.56Smycroft				xf86PostButtonEvent(pInfo->dev, TRUE,
7401.56Smycroft				    button, (buttons & mask) != 0,
7411.56Smycroft				    0, 0);
7421.46Smycroft				DBG(3, ErrorF("post button event %d %d\n",
7431.56Smycroft					button, (buttons & mask) != 0))
7441.56Smycroft				    }
7451.46Smycroft		}
7461.56Smycroft	} /* for */
7471.56Smycroft	priv->lastButtons = buttons;
7481.43Sross} /* wsSendButtons */
7491.46Smycroft
7501.43Sross
7511.56Smycroftstatic int
7521.56SmycroftwsChangeControl(InputInfoPtr pInfo, xDeviceCtl *control)
7531.56Smycroft{
7541.56Smycroft	return BadMatch;
7551.56Smycroft}
7561.56Smycroft
7571.56Smycroftstatic int
7581.56SmycroftwsSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode)
7591.56Smycroft{
7601.56Smycroft	return BadMatch;
7611.56Smycroft}
7621.56Smycroft
7631.56Smycroftstatic Bool
7641.56SmycroftwsOpen(InputInfoPtr pInfo)
7651.56Smycroft{
7661.56Smycroft	WSDevicePtr priv = (WSDevicePtr)pInfo->private;
7671.56Smycroft#ifdef __NetBSD__
7681.56Smycroft	int version = WSMOUSE_EVENT_VERSION;
7691.56Smycroft#endif
7701.56Smycroft
7711.56Smycroft	DBG(1, ErrorF("WS open %s\n", priv->devName));
7721.31Smycroft	pInfo->fd = xf86OpenSerial(pInfo->options);
7731.27Sjonathan	if (pInfo->fd == -1) {
7741.27Sjonathan	    xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name);
7751.27Sjonathan	    return !Success;
7761.27Sjonathan	}
7771.27Sjonathan#ifdef __NetBSD__
7781.27Sjonathan	if (ioctl(pInfo->fd, WSMOUSEIO_SETVERSION, &version) == -1) {
7791.27Sjonathan		xf86Msg(X_ERROR, "%s: cannot set wsmouse event version\n",
7801.27Sjonathan		    pInfo->name);
7811.27Sjonathan		return !Success;
7821.27Sjonathan	}
7831.27Sjonathan#endif
7841.27Sjonathan	return Success;
7851.27Sjonathan}
7861.27Sjonathan
7871.27Sjonathanstatic void
7881.27SjonathanwsClose(InputInfoPtr pInfo)
7891.27Sjonathan{
7901.27Sjonathan	xf86CloseSerial(pInfo->fd);
7911.27Sjonathan	pInfo->fd = -1;
7921.27Sjonathan}
7931.27Sjonathan
7941.27Sjonathanstatic void
7951.27SjonathanwsControlProc(DeviceIntPtr device, PtrCtrl *ctrl)
7961.27Sjonathan{
7971.27Sjonathan	InputInfoPtr pInfo = device->public.devicePrivate;
7981.27Sjonathan	WSDevicePtr priv = (WSDevicePtr)pInfo->private;
7991.27Sjonathan
8001.27Sjonathan	DBG(1, ErrorF("wsControlProc\n"));
8011.27Sjonathan	priv->num = ctrl->num;
8021.27Sjonathan	priv->den = ctrl->den;
8031.27Sjonathan	priv->threshold = ctrl->threshold;
8041.27Sjonathan}
8051.27Sjonathan
8061.27Sjonathanstatic void
8071.27SjonathanwsInitProperty(DeviceIntPtr device)
8081.27Sjonathan{
8091.27Sjonathan	InputInfoPtr pInfo = device->public.devicePrivate;
8101.27Sjonathan	WSDevicePtr priv = (WSDevicePtr)pInfo->private;
8111.27Sjonathan	int rc;
8121.27Sjonathan
8131.27Sjonathan	DBG(1, ErrorF("wsInitProperty\n"));
8141.27Sjonathan	if (priv->type != WSMOUSE_TYPE_TPANEL)
8151.27Sjonathan		return;
8161.27Sjonathan
8171.31Smycroft	prop_calibration = MakeAtom(WS_PROP_CALIBRATION,
8181.19Scgd	    strlen(WS_PROP_CALIBRATION), TRUE);
8191.19Scgd	rc = XIChangeDeviceProperty(device, prop_calibration, XA_INTEGER, 32,
8201.84Sthorpej	    PropModeReplace, 4, &priv->min_x, FALSE);
8211.19Scgd	if (rc != Success)
8221.19Scgd		return;
8231.19Scgd
8241.84Sthorpej	XISetDevicePropertyDeletable(device, prop_calibration, FALSE);
8251.19Scgd
8261.19Scgd	prop_swap = MakeAtom(WS_PROP_SWAP_AXES,
8271.19Scgd	    strlen(WS_PROP_SWAP_AXES), TRUE);
8281.52Sthorpej	rc = XIChangeDeviceProperty(device, prop_swap, XA_INTEGER, 8,
8291.52Sthorpej	    PropModeReplace, 1, &priv->swap_axes, FALSE);
8301.19Scgd	if (rc != Success)
8311.65Sthorpej		return;
8321.69Sthorpej	return;
8331.73Sthorpej}
8341.69Sthorpej
8351.73Sthorpejstatic int
8361.73SthorpejwsSetProperty(DeviceIntPtr device, Atom atom, XIPropertyValuePtr val,
8371.73Sthorpej    BOOL checkonly)
8381.73Sthorpej{
8391.19Scgd	InputInfoPtr pInfo = device->public.devicePrivate;
8401.73Sthorpej	WSDevicePtr priv = (WSDevicePtr)pInfo->private;
8411.73Sthorpej	struct wsmouse_calibcoords coords;
8421.52Sthorpej	int need_update = 0;
8431.19Scgd	AxisInfoPtr ax = device->valuator->axes,
8441.19Scgd		    ay = device->valuator->axes + 1;
8451.19Scgd
8461.52Sthorpej	DBG(1, ErrorF("wsSetProperty %s\n", NameForAtom(atom)));
8471.52Sthorpej
8481.19Scgd	/* Ignore non panel devices */
8491.19Scgd	if (priv->type != WSMOUSE_TYPE_TPANEL)
8501.63Sthorpej		return Success;
8511.19Scgd
8521.62Sthorpej	if (atom == prop_calibration) {
8531.62Sthorpej		if (val->format != 32 || val->type != XA_INTEGER)
8541.19Scgd			return BadMatch;
8551.19Scgd		if (val->size != 4 && val->size != 0)
8561.19Scgd			return BadMatch;
8571.62Sthorpej		if (!checkonly) {
8581.62Sthorpej			if (val->size == 0) {
8591.62Sthorpej				DBG(1, ErrorF(" uncalibrate\n"));
8601.62Sthorpej				priv->min_x = 0;
8611.62Sthorpej				priv->max_x = -1;
8621.62Sthorpej				priv->min_y = 0;
8631.19Scgd				priv->max_y = -1;
8641.62Sthorpej			} else {
8651.62Sthorpej				priv->min_x = ((int *)(val->data))[0];
8661.62Sthorpej				priv->max_x = ((int *)(val->data))[1];
8671.62Sthorpej				priv->min_y = ((int *)(val->data))[2];
8681.62Sthorpej				priv->max_y = ((int *)(val->data))[3];
8691.62Sthorpej				DBG(1, ErrorF(" calibrate %d %d %d %d\n",
8701.62Sthorpej					priv->min_x, priv->max_x,
8711.62Sthorpej					priv->min_y, priv->max_y));
8721.62Sthorpej				need_update++;
8731.62Sthorpej			}
8741.62Sthorpej			/* Update axes descriptors */
8751.19Scgd			if (!priv->swap_axes) {
8761.40Smycroft				ax->min_value = priv->min_x;
8771.19Scgd				ax->max_value = priv->max_x;
8781.62Sthorpej				ay->min_value = priv->min_y;
8791.62Sthorpej				ay->max_value = priv->max_y;
8801.62Sthorpej			} else {
8811.62Sthorpej				ax->min_value = priv->min_y;
8821.62Sthorpej				ax->max_value = priv->max_y;
8831.62Sthorpej				ay->min_value = priv->min_x;
8841.62Sthorpej				ay->max_value = priv->max_x;
8851.62Sthorpej			}
8861.62Sthorpej		}
8871.62Sthorpej	} else if (atom == prop_swap) {
8881.62Sthorpej		if (val->format != 8 || val->type != XA_INTEGER ||
8891.62Sthorpej		    val->size != 1)
8901.62Sthorpej			return BadMatch;
8911.62Sthorpej		if (!checkonly) {
8921.62Sthorpej			priv->swap_axes = *((BOOL *)val->data);
8931.62Sthorpej			DBG(1, ErrorF("swap_axes %d\n", priv->swap_axes));
8941.62Sthorpej			need_update++;
8951.62Sthorpej		}
8961.62Sthorpej	}
8971.62Sthorpej	if (need_update) {
8981.62Sthorpej		/* Update the saved values to be restored on device off */
8991.19Scgd		priv->coords.minx = priv->min_x;
9001.62Sthorpej		priv->coords.maxx = priv->max_x;
9011.62Sthorpej		priv->coords.miny = priv->min_y;
9021.62Sthorpej		priv->coords.maxy = priv->max_y;
9031.62Sthorpej#ifndef __NetBSD__
9041.62Sthorpej		priv->coords.swapxy = priv->swap_axes;
9051.62Sthorpej#endif
9061.19Scgd
9071.19Scgd		/* Update the kernel calibration table */
9081.19Scgd		coords.minx = priv->min_x;
9091.19Scgd		coords.maxx = priv->max_x;
9101.19Scgd		coords.miny = priv->min_y;
9111.19Scgd		coords.maxy = priv->max_y;
9121.19Scgd#ifndef __NetBSD__
9131.19Scgd		coords.swapxy = priv->swap_axes;
9141.19Scgd#endif
9151.63Sthorpej		coords.samplelen = priv->raw;
9161.19Scgd#ifndef __NetBSD__
9171.19Scgd		coords.resx = priv->coords.resx;
9181.19Scgd		coords.resy = priv->coords.resy;
9191.19Scgd#endif
9201.80Sbriggs		if (ioctl(pInfo->fd, WSMOUSEIO_SCALIBCOORDS, &coords) != 0) {
9211.80Sbriggs			xf86Msg(X_ERROR, "SCALIBCOORDS failed %s\n",
9221.80Sbriggs			    strerror(errno));
9231.80Sbriggs		}
9241.70Ssommerfe	}
9251.70Ssommerfe	return Success;
9261.19Scgd}
9271.19Scgd