ws.c revision 53cb6c62
1/* 2 * Copyright © 2005-2009 Matthieu Herrb 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16/* $OpenBSD: ws.c,v 1.26 2009/11/26 18:18:34 matthieu Exp $ */ 17 18#ifdef HAVE_CONFIG_H 19#include "config.h" 20#endif 21 22#include <unistd.h> 23#include <errno.h> 24#include <sys/ioctl.h> 25#include <sys/time.h> 26#include <dev/wscons/wsconsio.h> 27 28#include <xf86.h> 29 30#include <xf86_OSproc.h> 31#include <X11/extensions/XI.h> 32#include <X11/extensions/XIproto.h> 33#include <xf86Xinput.h> 34#include <exevents.h> 35#include <xisb.h> 36#include <mipointer.h> 37#include <extinit.h> 38 39#include "ws.h" 40 41#ifdef HAVE_PROPERTIES 42#include <X11/Xatom.h> 43#include "ws-properties.h" 44#endif 45 46 47#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 48#include <X11/Xatom.h> 49#include <xserver-properties.h> 50#endif 51 52 53static MODULESETUPPROTO(SetupProc); 54static void TearDownProc(pointer); 55 56static InputInfoPtr wsPreInit(InputDriverPtr, IDevPtr, int); 57static int wsProc(DeviceIntPtr, int); 58static int wsDeviceInit(DeviceIntPtr); 59static int wsDeviceOn(DeviceIntPtr); 60static void wsDeviceOff(DeviceIntPtr); 61static void wsReadInput(InputInfoPtr); 62static void wsSendButtons(InputInfoPtr, int); 63static int wsChangeControl(InputInfoPtr, xDeviceCtl *); 64static int wsSwitchMode(ClientPtr, DeviceIntPtr, int); 65static Bool wsOpen(InputInfoPtr); 66static void wsClose(InputInfoPtr); 67static void wsControlProc(DeviceIntPtr , PtrCtrl *); 68 69#ifdef HAVE_PROPERTIES 70static void wsInitProperty(DeviceIntPtr); 71static int wsSetProperty(DeviceIntPtr, Atom, XIPropertyValuePtr, BOOL); 72 73static Atom prop_calibration = 0; 74static Atom prop_swap = 0; 75#endif 76 77#ifdef DEBUG 78int ws_debug_level = 0; 79#endif 80 81static XF86ModuleVersionInfo VersionRec = { 82 "ws", 83 MODULEVENDORSTRING, 84 MODINFOSTRING1, 85 MODINFOSTRING2, 86 XORG_VERSION_CURRENT, 87 PACKAGE_VERSION_MAJOR, 88 PACKAGE_VERSION_MINOR, 89 PACKAGE_VERSION_PATCHLEVEL, 90 ABI_CLASS_XINPUT, 91 ABI_XINPUT_VERSION, 92 MOD_CLASS_XINPUT, 93 {0, 0, 0, 0} 94}; 95 96#define WS_NOZMAP 0 97 98XF86ModuleData wsModuleData = {&VersionRec, 99 SetupProc, TearDownProc }; 100 101 102InputDriverRec WS = { 103 1, 104 "ws", 105 NULL, 106 wsPreInit, 107 NULL, 108 NULL, 109 0 110}; 111 112static pointer 113SetupProc(pointer module, pointer options, int *errmaj, int *errmin) 114{ 115 static Bool Initialised = FALSE; 116 117 if (!Initialised) { 118 xf86AddInputDriver(&WS, module, 0); 119 Initialised = TRUE; 120 } 121 return module; 122} 123 124static void 125TearDownProc(pointer p) 126{ 127 DBG(1, ErrorF("WS TearDownProc called\n")); 128} 129 130static InputInfoPtr 131wsPreInit(InputDriverPtr drv, IDevPtr dev, int flags) 132{ 133 InputInfoPtr pInfo = NULL; 134 WSDevicePtr priv; 135 MessageType buttons_from = X_CONFIG; 136 char *s; 137 138 pInfo = xf86AllocateInput(drv, 0); 139 if (pInfo == NULL) { 140 return NULL; 141 } 142 priv = (WSDevicePtr)xcalloc(1, sizeof(WSDeviceRec)); 143 if (priv == NULL) 144 goto fail; 145 pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS; 146 pInfo->conf_idev = dev; 147 pInfo->name = "ws"; 148 pInfo->private = priv; 149 150 xf86CollectInputOptions(pInfo, NULL, NULL); 151 xf86ProcessCommonOptions(pInfo, pInfo->options); 152#ifdef DEBUG 153 ws_debug_level = xf86SetIntOption(pInfo->options, "DebugLevel", 154 ws_debug_level); 155 xf86Msg(X_INFO, "%s: debuglevel %d\n", dev->identifier, 156 ws_debug_level); 157#endif 158 priv->devName = xf86FindOptionValue(pInfo->options, "Device"); 159 if (priv->devName == NULL) { 160 xf86Msg(X_ERROR, "%s: No Device specified.\n", 161 dev->identifier); 162 goto fail; 163 } 164 priv->buttons = xf86SetIntOption(pInfo->options, "Buttons", 0); 165 if (priv->buttons == 0) { 166 priv->buttons = DFLTBUTTONS; 167 buttons_from = X_DEFAULT; 168 } 169 priv->negativeZ = priv->positiveZ = WS_NOZMAP; 170 s = xf86SetStrOption(pInfo->options, "ZAxisMapping", NULL); 171 if (s) { 172 int b1, b2; 173 174 if (sscanf(s, "%d %d", &b1, &b2) == 2 && 175 b1 > 0 && b1 <= NBUTTONS && 176 b2 > 0 && b2 <= NBUTTONS) { 177 priv->negativeZ = b1; 178 priv->positiveZ = b2; 179 xf86Msg(X_CONFIG, 180 "%s: ZAxisMapping: buttons %d and %d\n", 181 pInfo->name, b1, b2); 182 } else { 183 xf86Msg(X_WARNING, "%s: invalid ZAxisMapping value: " 184 "\"%s\"\n", pInfo->name, s); 185 } 186 } 187 if (priv->negativeZ > priv->buttons) { 188 priv->buttons = priv->negativeZ; 189 buttons_from = X_CONFIG; 190 } 191 if (priv->positiveZ > priv->buttons) { 192 priv->buttons = priv->positiveZ; 193 buttons_from = X_CONFIG; 194 } 195 priv->negativeW = priv->positiveW = WS_NOZMAP; 196 s = xf86SetStrOption(pInfo->options, "WAxisMapping", NULL); 197 if (s) { 198 int b1, b2; 199 200 if (sscanf(s, "%d %d", &b1, &b2) == 2 && 201 b1 > 0 && b1 <= NBUTTONS && 202 b2 > 0 && b2 <= NBUTTONS) { 203 priv->negativeW = b1; 204 priv->positiveW = b2; 205 xf86Msg(X_CONFIG, 206 "%s: WAxisMapping: buttons %d and %d\n", 207 pInfo->name, b1, b2); 208 } else { 209 xf86Msg(X_WARNING, "%s: invalid WAxisMapping value: " 210 "\"%s\"\n", pInfo->name, s); 211 } 212 } 213 if (priv->negativeW > priv->buttons) { 214 priv->buttons = priv->negativeW; 215 buttons_from = X_CONFIG; 216 } 217 if (priv->positiveW > priv->buttons) { 218 priv->buttons = priv->positiveW; 219 buttons_from = X_CONFIG; 220 } 221 222 priv->screen_no = xf86SetIntOption(pInfo->options, "ScreenNo", 0); 223 xf86Msg(X_CONFIG, "%s associated screen: %d\n", 224 dev->identifier, priv->screen_no); 225 if (priv->screen_no >= screenInfo.numScreens || 226 priv->screen_no < 0) { 227 priv->screen_no = 0; 228 } 229 230 231 priv->swap_axes = xf86SetBoolOption(pInfo->options, "SwapXY", 0); 232 if (priv->swap_axes) { 233 xf86Msg(X_CONFIG, 234 "%s device will work with X and Y axes swapped\n", 235 dev->identifier); 236 } 237 priv->inv_x = 0; 238 priv->inv_y = 0; 239 s = xf86FindOptionValue(pInfo->options, "Rotate"); 240 if (s) { 241 if (xf86NameCmp(s, "CW") == 0) { 242 priv->inv_x = 1; 243 priv->inv_y = 0; 244 priv->swap_axes = 1; 245 } else if (xf86NameCmp(s, "CCW") == 0) { 246 priv->inv_x = 0; 247 priv->inv_y = 1; 248 priv->swap_axes = 1; 249 } else if (xf86NameCmp(s, "UD") == 0) { 250 priv->inv_x = 1; 251 priv->inv_y = 1; 252 } else { 253 xf86Msg(X_ERROR, "\"%s\" is not a valid value " 254 "for Option \"Rotate\"\n", s); 255 xf86Msg(X_ERROR, "Valid options are \"CW\", \"CCW\"," 256 " or \"UD\"\n"); 257 } 258 } 259 if (wsOpen(pInfo) != Success) { 260 goto fail; 261 } 262 if (ioctl(pInfo->fd, WSMOUSEIO_GTYPE, &priv->type) != 0) { 263 wsClose(pInfo); 264 goto fail; 265 } 266 if (priv->type == WSMOUSE_TYPE_TPANEL) { 267 pInfo->type_name = XI_TOUCHSCREEN; 268 priv->raw = xf86SetBoolOption(pInfo->options, "Raw", 1); 269 } else { 270 pInfo->type_name = XI_MOUSE; 271 priv->raw = xf86SetBoolOption(pInfo->options, "Raw", 0); 272 if (priv->raw) { 273 xf86Msg(X_WARNING, "Device is not a touch panel," 274 "ignoring 'Option \"Raw\"'\n"); 275 priv->raw = 0; 276 } 277 } 278 if (priv->raw) { 279 xf86Msg(X_CONFIG, 280 "%s device will work in raw mode\n", 281 dev->identifier); 282 } 283 284#ifndef __NetBSD__ 285 if (priv->type == WSMOUSE_TYPE_TPANEL && priv->raw) { 286 if (ioctl(pInfo->fd, WSMOUSEIO_GCALIBCOORDS, 287 &priv->coords) != 0) { 288 xf86Msg(X_ERROR, "GCALIBCOORS failed %s\n", 289 strerror(errno)); 290 wsClose(pInfo); 291 goto fail; 292 } 293 294 /* get default coordinate space from kernel */ 295 priv->min_x = priv->coords.minx; 296 priv->max_x = priv->coords.maxx; 297 priv->min_y = priv->coords.miny; 298 priv->max_y = priv->coords.maxy; 299 } else { 300#endif 301 /* in calibrated mode, coordinate space, is screen coords */ 302 priv->min_x = 0; 303 priv->max_x = screenInfo.screens[priv->screen_no]->width - 1; 304 priv->min_y = 0; 305 priv->max_y = screenInfo.screens[priv->screen_no]->height - 1; 306#ifndef __NetBSD__ 307 } 308#endif 309 /* Allow options to override this */ 310 priv->min_x = xf86SetIntOption(pInfo->options, "MinX", priv->min_x); 311 xf86Msg(X_INFO, "%s minimum x position: %d\n", 312 dev->identifier, priv->min_x); 313 priv->max_x = xf86SetIntOption(pInfo->options, "MaxX", priv->max_x); 314 xf86Msg(X_INFO, "%s maximum x position: %d\n", 315 dev->identifier, priv->max_x); 316 priv->min_y = xf86SetIntOption(pInfo->options, "MinY", priv->min_y); 317 xf86Msg(X_INFO, "%s minimum y position: %d\n", 318 dev->identifier, priv->min_y); 319 priv->max_y = xf86SetIntOption(pInfo->options, "MaxY", priv->max_y); 320 xf86Msg(X_INFO, "%s maximum y position: %d\n", 321 dev->identifier, priv->max_y); 322 323 pInfo->name = dev->identifier; 324 pInfo->device_control = wsProc; 325 pInfo->read_input = wsReadInput; 326 pInfo->control_proc = wsChangeControl; 327 pInfo->switch_mode = wsSwitchMode; 328 pInfo->conversion_proc = NULL; 329 pInfo->reverse_conversion_proc = NULL; 330 pInfo->private = priv; 331 pInfo->old_x = -1; 332 pInfo->old_y = -1; 333 xf86Msg(buttons_from, "%s: Buttons: %d\n", pInfo->name, priv->buttons); 334 335 wsClose(pInfo); 336 337 wsmbEmuPreInit(pInfo); 338 339 /* mark the device configured */ 340 pInfo->flags |= XI86_CONFIGURED; 341 return pInfo; 342fail: 343 if (priv != NULL) { 344 xfree(priv); 345 pInfo->private = NULL; 346 } 347 if (pInfo != NULL) { 348 xf86DeleteInput(pInfo, 0); 349 } 350 return NULL; 351} 352 353static int 354wsProc(DeviceIntPtr pWS, int what) 355{ 356 InputInfoPtr pInfo = (InputInfoPtr)pWS->public.devicePrivate; 357 358 switch (what) { 359 case DEVICE_INIT: 360 return wsDeviceInit(pWS); 361 362 case DEVICE_ON: 363 return wsDeviceOn(pWS); 364 365 case DEVICE_OFF: 366 wsDeviceOff(pWS); 367 break; 368 369 case DEVICE_CLOSE: 370 DBG(1, ErrorF("WS DEVICE_CLOSE\n")); 371 wsClose(pInfo); 372 break; 373 374 default: 375 xf86Msg(X_ERROR, "WS: unknown command %d\n", what); 376 return !Success; 377 } /* switch */ 378 return Success; 379} /* wsProc */ 380 381static int 382wsDeviceInit(DeviceIntPtr pWS) 383{ 384 InputInfoPtr pInfo = (InputInfoPtr)pWS->public.devicePrivate; 385 WSDevicePtr priv = (WSDevicePtr)XI_PRIVATE(pWS); 386 unsigned char map[NBUTTONS + 1]; 387 int i, xmin, xmax, ymin, ymax; 388#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 389 Atom btn_labels[NBUTTONS] = {0}; 390 Atom axes_labels[NAXES] = {0}; 391#endif 392 393 DBG(1, ErrorF("WS DEVICE_INIT\n")); 394 395#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 396 btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); 397 btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); 398 btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); 399#endif 400 priv->screen_width = screenInfo.screens[priv->screen_no]->width; 401 priv->screen_height = screenInfo.screens[priv->screen_no]->height; 402 403 for (i = 0; i < NBUTTONS; i++) 404 map[i + 1] = i + 1; 405 if (!InitButtonClassDeviceStruct(pWS, 406 min(priv->buttons, NBUTTONS), 407#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 408 btn_labels, 409#endif 410 map)) 411 return !Success; 412 413 if (priv->type == WSMOUSE_TYPE_TPANEL) { 414 xmin = priv->min_x; 415 xmax = priv->max_x; 416 ymin = priv->min_y; 417 ymax = priv->max_y; 418 } else { 419 xmin = -1; 420 xmax = -1; 421 ymin = -1; 422 ymax = -1; 423 } 424 425#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 426 if ((priv->type == WSMOUSE_TYPE_TPANEL)) { 427 axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X); 428 axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y); 429 } else { 430 axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); 431 axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); 432 } 433#endif 434 if (!InitValuatorClassDeviceStruct(pWS, 435 NAXES, 436#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 437 axes_labels, 438#endif 439#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3 440 xf86GetMotionEvents, 441#endif 442 GetMotionHistorySize(), 443 priv->type == WSMOUSE_TYPE_TPANEL ? 444 Absolute : Relative)) 445 return !Success; 446 if (!InitPtrFeedbackClassDeviceStruct(pWS, wsControlProc)) 447 return !Success; 448 449 xf86InitValuatorAxisStruct(pWS, 0, 450#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 451 axes_labels[0], 452#endif 453 xmin, xmax, 1, 0, 1); 454 xf86InitValuatorDefaults(pWS, 0); 455 456 xf86InitValuatorAxisStruct(pWS, 1, 457#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 458 axes_labels[1], 459#endif 460 ymin, ymax, 1, 0, 1); 461 xf86InitValuatorDefaults(pWS, 1); 462 xf86MotionHistoryAllocate(pInfo); 463 AssignTypeAndName(pWS, pInfo->atom, pInfo->name); 464 pWS->public.on = FALSE; 465 if (wsOpen(pInfo) != Success) { 466 return !Success; 467 } 468#ifdef HAVE_PROPERTIES 469 wsInitProperty(pWS); 470 XIRegisterPropertyHandler(pWS, wsSetProperty, NULL, NULL); 471 wsmbEmuInitProperty(pWS); 472#endif 473 return Success; 474} 475 476static int 477wsDeviceOn(DeviceIntPtr pWS) 478{ 479 InputInfoPtr pInfo = (InputInfoPtr)pWS->public.devicePrivate; 480 WSDevicePtr priv = (WSDevicePtr)XI_PRIVATE(pWS); 481 struct wsmouse_calibcoords coords; 482 483 DBG(1, ErrorF("WS DEVICE ON\n")); 484 if ((pInfo->fd < 0) && (wsOpen(pInfo) != Success)) { 485 xf86Msg(X_ERROR, "wsOpen failed %s\n", 486 strerror(errno)); 487 return !Success; 488 } 489 490#ifndef __NetBSD__ 491 if (priv->type == WSMOUSE_TYPE_TPANEL) { 492 /* save calibration values */ 493 if (ioctl(pInfo->fd, WSMOUSEIO_GCALIBCOORDS, &coords) != 0) { 494 xf86Msg(X_ERROR, "GCALIBCOORS failed %s\n", 495 strerror(errno)); 496 return !Success; 497 } 498 memcpy(&priv->coords, &coords, sizeof coords); 499 /* set raw mode */ 500 if (coords.samplelen != priv->raw) { 501 coords.samplelen = priv->raw; 502 if (ioctl(pInfo->fd, WSMOUSEIO_SCALIBCOORDS, 503 &coords) != 0) { 504 xf86Msg(X_ERROR, "GCALIBCOORS failed %s\n", 505 strerror(errno)); 506 return !Success; 507 } 508 } 509 } 510#endif 511 priv->buffer = XisbNew(pInfo->fd, 512 sizeof(struct wscons_event) * NUMEVENTS); 513 if (priv->buffer == NULL) { 514 xf86Msg(X_ERROR, "cannot alloc xisb buffer\n"); 515 wsClose(pInfo); 516 return !Success; 517 } 518 xf86AddEnabledDevice(pInfo); 519 wsmbEmuOn(pInfo); 520 pWS->public.on = TRUE; 521 return Success; 522} 523 524static void 525wsDeviceOff(DeviceIntPtr pWS) 526{ 527 InputInfoPtr pInfo = (InputInfoPtr)pWS->public.devicePrivate; 528 WSDevicePtr priv = (WSDevicePtr)XI_PRIVATE(pWS); 529 struct wsmouse_calibcoords coords; 530 531 DBG(1, ErrorF("WS DEVICE OFF\n")); 532 wsmbEmuFinalize(pInfo); 533 534#ifndef __NetBSD__ 535 if (priv->type == WSMOUSE_TYPE_TPANEL) { 536 /* Restore calibration data */ 537 memcpy(&coords, &priv->coords, sizeof coords); 538 if (ioctl(pInfo->fd, WSMOUSEIO_SCALIBCOORDS, &coords) != 0) { 539 xf86Msg(X_ERROR, "SCALIBCOORS failed %s\n", 540 strerror(errno)); 541 } 542 } 543#endif 544 if (pInfo->fd >= 0) { 545 xf86RemoveEnabledDevice(pInfo); 546 wsClose(pInfo); 547 } 548 if (priv->buffer) { 549 XisbFree(priv->buffer); 550 priv->buffer = NULL; 551 } 552 pWS->public.on = FALSE; 553} 554 555static void 556wsReadInput(InputInfoPtr pInfo) 557{ 558 WSDevicePtr priv; 559 static struct wscons_event eventList[NUMEVENTS]; 560 int n, c; 561 struct wscons_event *event = eventList; 562 unsigned char *pBuf; 563 int ax, ay; 564 565 priv = pInfo->private; 566 567 XisbBlockDuration(priv->buffer, -1); 568 pBuf = (unsigned char *)eventList; 569 n = 0; 570 while (n < sizeof(eventList) && (c = XisbRead(priv->buffer)) >= 0) { 571 pBuf[n++] = (unsigned char)c; 572 } 573 574 if (n == 0) 575 return; 576 577 n /= sizeof(struct wscons_event); 578 while( n-- ) { 579 int buttons = priv->lastButtons; 580 int dx = 0, dy = 0, dz = 0, dw = 0; 581 int zbutton = 0, wbutton = 0; 582 583 ax = 0; ay = 0; 584 switch (event->type) { 585 case WSCONS_EVENT_MOUSE_UP: 586 587 buttons &= ~(1 << event->value); 588 DBG(4, ErrorF("Button %d up %x\n", event->value, 589 buttons)); 590 break; 591 case WSCONS_EVENT_MOUSE_DOWN: 592 buttons |= (1 << event->value); 593 DBG(4, ErrorF("Button %d down %x\n", event->value, 594 buttons)); 595 break; 596 case WSCONS_EVENT_MOUSE_DELTA_X: 597 dx = event->value; 598 DBG(4, ErrorF("Relative X %d\n", event->value)); 599 break; 600 case WSCONS_EVENT_MOUSE_DELTA_Y: 601 dy = -event->value; 602 DBG(4, ErrorF("Relative Y %d\n", event->value)); 603 break; 604 case WSCONS_EVENT_MOUSE_ABSOLUTE_X: 605 DBG(4, ErrorF("Absolute X %d\n", event->value)); 606 if (event->value != 4095) { 607 ax = event->value; 608 if (priv->inv_x) 609 ax = priv->max_x - ax + priv->min_x; 610 } 611 break; 612 case WSCONS_EVENT_MOUSE_ABSOLUTE_Y: 613 DBG(4, ErrorF("Absolute Y %d\n", event->value)); 614 ay = event->value; 615 if (priv->inv_y) 616 ay = priv->max_y - ay + priv->min_y; 617 break; 618#ifdef WSCONS_EVENT_MOUSE_DELTA_Z 619 case WSCONS_EVENT_MOUSE_DELTA_Z: 620 DBG(4, ErrorF("Relative Z %d\n", event->value)); 621 dz = event->value; 622 break; 623#endif 624#ifdef WSCONS_EVENT_MOUSE_ABSOLUTE_Z 625 case WSCONS_EVENT_MOUSE_ABSOLUTE_Z: 626 /* ignore those */ 627 ++event; 628 continue; 629 break; 630#endif 631#ifdef WSCONS_EVENT_MOUSE_DELTA_W 632 case WSCONS_EVENT_MOUSE_DELTA_W: 633 DBG(4, ErrorF("Relative W %d\n", event->value)); 634 dw = event->value; 635 break; 636#endif 637 default: 638 xf86Msg(X_WARNING, "%s: bad wsmouse event type=%d\n", 639 pInfo->name, event->type); 640 ++event; 641 continue; 642 } /* case */ 643 644 if (dx || dy) { 645 /* relative motion event */ 646 DBG(3, ErrorF("postMotionEvent dX %d dY %d\n", 647 dx, dy)); 648 xf86PostMotionEvent(pInfo->dev, 0, 0, 2, 649 dx, dy); 650 } 651 if (dz && priv->negativeZ != WS_NOZMAP 652 && priv->positiveZ != WS_NOZMAP) { 653 buttons &= ~(priv->negativeZ | priv->positiveZ); 654 if (dz < 0) { 655 DBG(4, ErrorF("Z -> button %d\n", 656 priv->negativeZ)); 657 zbutton = 1 << (priv->negativeZ - 1); 658 } else { 659 DBG(4, ErrorF("Z -> button %d\n", 660 priv->positiveZ)); 661 zbutton = 1 << (priv->positiveZ - 1); 662 } 663 buttons |= zbutton; 664 dz = 0; 665 } 666 if (dw && priv->negativeW != WS_NOZMAP 667 && priv->positiveW != WS_NOZMAP) { 668 buttons &= ~(priv->negativeW | priv->positiveW); 669 if (dw < 0) { 670 DBG(4, ErrorF("W -> button %d\n", 671 priv->negativeW)); 672 wbutton = 1 << (priv->negativeW - 1); 673 } else { 674 DBG(4, ErrorF("W -> button %d\n", 675 priv->positiveW)); 676 wbutton = 1 << (priv->positiveW - 1); 677 } 678 buttons |= wbutton; 679 dw = 0; 680 } 681 if (priv->lastButtons != buttons) { 682 /* button event */ 683 wsSendButtons(pInfo, buttons); 684 } 685 if (zbutton != 0) { 686 /* generate a button up event */ 687 buttons &= ~zbutton; 688 wsSendButtons(pInfo, buttons); 689 } 690 if (ax) { 691 /* absolute position event */ 692 DBG(3, ErrorF("postMotionEvent X %d\n", ax)); 693 xf86PostMotionEvent(pInfo->dev, 1, 0, 1, ax); 694 } 695 if (ay) { 696 /* absolute position event */ 697 DBG(3, ErrorF("postMotionEvent y %d\n", ay)); 698 xf86PostMotionEvent(pInfo->dev, 1, 1, 1, ay); 699 } 700 ++event; 701 } 702 return; 703} /* wsReadInput */ 704 705static void 706wsSendButtons(InputInfoPtr pInfo, int buttons) 707{ 708 WSDevicePtr priv = (WSDevicePtr)pInfo->private; 709 int button, mask; 710 711 712 for (button = 1; button < NBUTTONS; button++) { 713 mask = 1 << (button - 1); 714 if ((mask & priv->lastButtons) != (mask & buttons)) { 715 if (!wsmbEmuFilterEvent(pInfo, button, 716 (buttons & mask) != 0)) { 717 xf86PostButtonEvent(pInfo->dev, TRUE, 718 button, (buttons & mask) != 0, 719 0, 0); 720 DBG(3, ErrorF("post button event %d %d\n", 721 button, (buttons & mask) != 0)) 722 } 723 } 724 } /* for */ 725 priv->lastButtons = buttons; 726} /* wsSendButtons */ 727 728 729static int 730wsChangeControl(InputInfoPtr pInfo, xDeviceCtl *control) 731{ 732 return BadMatch; 733} 734 735static int 736wsSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode) 737{ 738 return BadMatch; 739} 740 741static Bool 742wsOpen(InputInfoPtr pInfo) 743{ 744 WSDevicePtr priv = (WSDevicePtr)pInfo->private; 745#ifdef __NetBSD__ 746 int version = WSMOUSE_EVENT_VERSION; 747#endif 748 749 DBG(1, ErrorF("WS open %s\n", priv->devName)); 750 pInfo->fd = xf86OpenSerial(pInfo->options); 751 if (pInfo->fd == -1) { 752 xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name); 753 return !Success; 754 } 755#ifdef __NetBSD__ 756 if (ioctl(pInfo->fd, WSMOUSEIO_SETVERSION, &version) == -1) { 757 xf86Msg(X_ERROR, "%s: cannot set wsmouse event version\n", 758 pInfo->name); 759 return !Success; 760 } 761#endif 762 return Success; 763} 764 765static void 766wsClose(InputInfoPtr pInfo) 767{ 768 xf86CloseSerial(pInfo->fd); 769 pInfo->fd = -1; 770} 771 772static void 773wsControlProc(DeviceIntPtr device, PtrCtrl *ctrl) 774{ 775 InputInfoPtr pInfo = device->public.devicePrivate; 776 WSDevicePtr priv = (WSDevicePtr)pInfo->private; 777 778 DBG(1, ErrorF("wsControlProc\n")); 779 priv->num = ctrl->num; 780 priv->den = ctrl->den; 781 priv->threshold = ctrl->threshold; 782} 783 784#ifdef HAVE_PROPERTIES 785static void 786wsInitProperty(DeviceIntPtr device) 787{ 788 InputInfoPtr pInfo = device->public.devicePrivate; 789 WSDevicePtr priv = (WSDevicePtr)pInfo->private; 790 int rc; 791 792 DBG(1, ErrorF("wsInitProperty\n")); 793 if (priv->type != WSMOUSE_TYPE_TPANEL) 794 return; 795 796 prop_calibration = MakeAtom(WS_PROP_CALIBRATION, 797 strlen(WS_PROP_CALIBRATION), TRUE); 798 rc = XIChangeDeviceProperty(device, prop_calibration, XA_INTEGER, 32, 799 PropModeReplace, 4, &priv->min_x, FALSE); 800 if (rc != Success) 801 return; 802 803 XISetDevicePropertyDeletable(device, prop_calibration, FALSE); 804 805 prop_swap = MakeAtom(WS_PROP_SWAP_AXES, 806 strlen(WS_PROP_SWAP_AXES), TRUE); 807 rc = XIChangeDeviceProperty(device, prop_swap, XA_INTEGER, 8, 808 PropModeReplace, 1, &priv->swap_axes, FALSE); 809 if (rc != Success) 810 return; 811 return; 812} 813 814static int 815wsSetProperty(DeviceIntPtr device, Atom atom, XIPropertyValuePtr val, 816 BOOL checkonly) 817{ 818 InputInfoPtr pInfo = device->public.devicePrivate; 819 WSDevicePtr priv = (WSDevicePtr)pInfo->private; 820 struct wsmouse_calibcoords coords; 821 int need_update = 0; 822 AxisInfoPtr ax = device->valuator->axes, 823 ay = device->valuator->axes + 1; 824 825 DBG(1, ErrorF("wsSetProperty %s\n", NameForAtom(atom))); 826 827 /* Ignore non panel devices */ 828 if (priv->type != WSMOUSE_TYPE_TPANEL) 829 return Success; 830 831 if (atom == prop_calibration) { 832 if (val->format != 32 || val->type != XA_INTEGER) 833 return BadMatch; 834 if (val->size != 4 && val->size != 0) 835 return BadMatch; 836 if (!checkonly) { 837 if (val->size == 0) { 838 DBG(1, ErrorF(" uncalibrate\n")); 839 priv->min_x = 0; 840 priv->max_x = -1; 841 priv->min_y = 0; 842 priv->max_y = -1; 843 } else { 844 priv->min_x = ((int *)(val->data))[0]; 845 priv->max_x = ((int *)(val->data))[1]; 846 priv->min_y = ((int *)(val->data))[2]; 847 priv->max_y = ((int *)(val->data))[3]; 848 DBG(1, ErrorF(" calibrate %d %d %d %d\n", 849 priv->min_x, priv->max_x, 850 priv->min_y, priv->max_y)); 851 need_update++; 852 } 853 /* Update axes descriptors */ 854 ax->min_value = priv->min_x; 855 ax->max_value = priv->max_x; 856 ay->min_value = priv->min_y; 857 ay->max_value = priv->max_y; 858 } 859 } else if (atom == prop_swap) { 860 if (val->format != 8 || val->type != XA_INTEGER || 861 val->size != 1) 862 return BadMatch; 863 if (!checkonly) { 864 priv->swap_axes = *((BOOL *)val->data); 865 DBG(1, ErrorF("swap_axes %d\n", priv->swap_axes)); 866 need_update++; 867 } 868 } 869 if (need_update) { 870 /* Update the saved values to be restored on device off */ 871 priv->coords.minx = priv->min_x; 872 priv->coords.maxx = priv->max_x; 873 priv->coords.miny = priv->min_y; 874 priv->coords.maxy = priv->max_y; 875#ifndef __NetBSD__ 876 priv->coords.swapxy = priv->swap_axes; 877#endif 878 /* Update the kernel calibration table */ 879 coords.minx = priv->min_x; 880 coords.maxx = priv->max_x; 881 coords.miny = priv->min_y; 882 coords.maxy = priv->max_y; 883 coords.samplelen = priv->raw; 884#ifndef __NetBSD__ 885 coords.swapxy = priv->swap_axes; 886 coords.resx = priv->coords.resx; 887 coords.resy = priv->coords.resy; 888#endif 889 if (ioctl(pInfo->fd, WSMOUSEIO_SCALIBCOORDS, &coords) != 0) { 890 xf86Msg(X_ERROR, "SCALIBCOORDS failed %s\n", 891 strerror(errno)); 892 } 893 } 894 return Success; 895} 896#endif 897