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