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 const char *cs; 136 int rc; 137 138 priv = (WSDevicePtr)calloc(1, sizeof(WSDeviceRec)); 139 if (priv == NULL) { 140 rc = BadAlloc; 141 goto fail; 142 } 143 pInfo->private = priv; 144 145#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12 146 xf86CollectInputOptions(pInfo, NULL, NULL); 147 xf86ProcessCommonOptions(pInfo, pInfo->options); 148#else 149 xf86CollectInputOptions(pInfo, NULL); 150#endif 151#ifdef DEBUG 152 ws_debug_level = xf86SetIntOption(pInfo->options, "DebugLevel", 153 ws_debug_level); 154 xf86Msg(X_INFO, "%s: debuglevel %d\n", pInfo->name, 155 ws_debug_level); 156#endif 157 priv->devName = xf86FindOptionValue(pInfo->options, "Device"); 158 if (priv->devName == NULL) { 159 xf86Msg(X_ERROR, "%s: No Device specified.\n", 160 pInfo->name); 161 rc = BadValue; 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", "4 5 6 7"); 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 pInfo->name, 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 pInfo->name); 236 } 237 priv->inv_x = 0; 238 priv->inv_y = 0; 239 cs = xf86FindOptionValue(pInfo->options, "Rotate"); 240 if (cs) { 241 if (xf86NameCmp(cs, "CW") == 0) { 242 priv->inv_x = 1; 243 priv->inv_y = 0; 244 priv->swap_axes = 1; 245 } else if (xf86NameCmp(cs, "CCW") == 0) { 246 priv->inv_x = 0; 247 priv->inv_y = 1; 248 priv->swap_axes = 1; 249 } else if (xf86NameCmp(cs, "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", cs); 255 xf86Msg(X_ERROR, "Valid options are \"CW\", \"CCW\"," 256 " or \"UD\"\n"); 257 } 258 } 259 if (wsOpen(pInfo) != Success) { 260 rc = BadValue; 261 goto fail; 262 } 263 if (ioctl(pInfo->fd, WSMOUSEIO_GTYPE, &priv->type) != 0) { 264 wsClose(pInfo); 265 rc = BadValue; 266 goto fail; 267 } 268 269 /* assume screen coordinate space until proven wrong */ 270 priv->min_x = 0; 271 priv->max_x = screenInfo.screens[priv->screen_no]->width - 1; 272 priv->min_y = 0; 273 priv->max_y = screenInfo.screens[priv->screen_no]->height - 1; 274 priv->raw = 0; 275 276 /* don't rely on the device type - we may be listening to a mux */ 277 if (ioctl(pInfo->fd, WSMOUSEIO_GCALIBCOORDS, 278 &priv->coords) != 0) { 279 /* can't get absolute coordinate space - assume mouse */ 280 pInfo->type_name = XI_MOUSE; 281 } else if (priv->coords.samplelen == WSMOUSE_CALIBCOORDS_RESET) { 282 /* 283 * we're getting raw coordinates - update accordingly and hope 284 * that there is no other absolute positioning device on the 285 * same mux 286 */ 287 priv->min_x = priv->coords.minx; 288 priv->max_x = priv->coords.maxx; 289 priv->min_y = priv->coords.miny; 290 priv->max_y = priv->coords.maxy; 291 priv->raw = 1; 292 pInfo->type_name = XI_TOUCHSCREEN; 293 } else { 294 /* 295 * touchscreen not in raw mode, should send us screen 296 * coordinates 297 */ 298 pInfo->type_name = XI_TOUCHSCREEN; 299 } 300 301 /* 302 * Force TPANEL type for muxes have have calibration data. A mux 303 * may have a mix of absolute and relative positioning devices, 304 * and we need to ensure that the xinput layer translates raw 305 * absolute position events for us. 306 */ 307 if (priv->raw && priv->type != WSMOUSE_TYPE_TPANEL) { 308 xf86Msg(X_INFO, "%s detected calibration data in raw mode, " 309 "using touch panel mode\n", pInfo->name); 310 priv->type = WSMOUSE_TYPE_TPANEL; 311 } 312 313 if (priv->raw) { 314 xf86Msg(X_CONFIG, 315 "%s device will work in raw mode\n", 316 pInfo->name); 317 } 318 319 /* Allow options to override this */ 320 priv->min_x = xf86SetIntOption(pInfo->options, "MinX", priv->min_x); 321 xf86Msg(X_INFO, "%s minimum x position: %d\n", 322 pInfo->name, priv->min_x); 323 priv->max_x = xf86SetIntOption(pInfo->options, "MaxX", priv->max_x); 324 xf86Msg(X_INFO, "%s maximum x position: %d\n", 325 pInfo->name, priv->max_x); 326 priv->min_y = xf86SetIntOption(pInfo->options, "MinY", priv->min_y); 327 xf86Msg(X_INFO, "%s minimum y position: %d\n", 328 pInfo->name, priv->min_y); 329 priv->max_y = xf86SetIntOption(pInfo->options, "MaxY", priv->max_y); 330 xf86Msg(X_INFO, "%s maximum y position: %d\n", 331 pInfo->name, priv->max_y); 332 333 pInfo->device_control = wsProc; 334 pInfo->read_input = wsReadInput; 335 pInfo->control_proc = wsChangeControl; 336 pInfo->switch_mode = wsSwitchMode; 337 pInfo->private = priv; 338#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12 339 pInfo->conversion_proc = NULL; 340 pInfo->reverse_conversion_proc = NULL; 341 pInfo->old_x = -1; 342 pInfo->old_y = -1; 343#endif 344 xf86Msg(buttons_from, "%s: Buttons: %d\n", pInfo->name, priv->buttons); 345 346 wsClose(pInfo); 347 348 wsmbEmuPreInit(pInfo); 349 return Success; 350 351fail: 352 if (priv != NULL) { 353 free(priv); 354 pInfo->private = NULL; 355 } 356 return rc; 357} 358 359#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12 360static InputInfoPtr 361wsPreInit(InputDriverPtr drv, IDevPtr dev, int flags) 362{ 363 InputInfoPtr pInfo = NULL; 364 365 pInfo = xf86AllocateInput(drv, 0); 366 if (pInfo == NULL) { 367 return NULL; 368 } 369 pInfo->name = dev->identifier; 370 pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS; 371 pInfo->conf_idev = dev; 372 pInfo->close_proc = NULL; 373 pInfo->private_flags = 0; 374 pInfo->always_core_feedback = NULL; 375 376 if (wsPreInit12(drv, pInfo, flags) != Success) { 377 xf86DeleteInput(pInfo, 0); 378 return NULL; 379 } 380 /* mark the device configured */ 381 pInfo->flags |= XI86_CONFIGURED; 382 return pInfo; 383} 384#endif 385 386static int 387wsProc(DeviceIntPtr pWS, int what) 388{ 389 InputInfoPtr pInfo = (InputInfoPtr)pWS->public.devicePrivate; 390 391 switch (what) { 392 case DEVICE_INIT: 393 return wsDeviceInit(pWS); 394 395 case DEVICE_ON: 396 return wsDeviceOn(pWS); 397 398 case DEVICE_OFF: 399 wsDeviceOff(pWS); 400 break; 401 402 case DEVICE_CLOSE: 403 DBG(1, ErrorF("WS DEVICE_CLOSE\n")); 404 wsClose(pInfo); 405 break; 406 407 default: 408 xf86Msg(X_ERROR, "WS: unknown command %d\n", what); 409 return !Success; 410 } /* switch */ 411 return Success; 412} /* wsProc */ 413 414static int 415wsDeviceInit(DeviceIntPtr pWS) 416{ 417 InputInfoPtr pInfo = (InputInfoPtr)pWS->public.devicePrivate; 418 WSDevicePtr priv = (WSDevicePtr)pInfo->private; 419 unsigned char map[NBUTTONS + 1]; 420 int i, xmin, xmax, ymin, ymax; 421 Atom btn_labels[NBUTTONS] = {0}; 422 Atom axes_labels[NAXES] = {0}; 423 424 DBG(1, ErrorF("WS DEVICE_INIT\n")); 425 426 btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); 427 btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); 428 btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); 429 for (i = 0; i < NBUTTONS; i++) 430 map[i + 1] = i + 1; 431 if (!InitButtonClassDeviceStruct(pWS, 432 min(priv->buttons, NBUTTONS), 433 btn_labels, 434 map)) 435 return !Success; 436 437 if (priv->type == WSMOUSE_TYPE_TPANEL) { 438 xmin = priv->min_x; 439 xmax = priv->max_x; 440 ymin = priv->min_y; 441 ymax = priv->max_y; 442 } else { 443 xmin = -1; 444 xmax = -1; 445 ymin = -1; 446 ymax = -1; 447 } 448 449 if (priv->swap_axes) { 450 int tmp; 451 tmp = xmin; 452 xmin = ymin; 453 ymin = tmp; 454 tmp = xmax; 455 xmax = ymax; 456 ymax = tmp; 457 } 458 if ((priv->type == WSMOUSE_TYPE_TPANEL)) { 459 axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X); 460 axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y); 461 } else { 462 axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); 463 axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); 464 } 465#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 14 466 axes_labels[HSCROLL_AXIS] = 467 XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL); 468 axes_labels[VSCROLL_AXIS] = 469 XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL); 470#endif 471 if (!InitValuatorClassDeviceStruct(pWS, 472 NAXES, 473 axes_labels, 474 GetMotionHistorySize(), 475 priv->type == WSMOUSE_TYPE_TPANEL ? 476 Absolute : Relative)) 477 return !Success; 478 if (!InitPtrFeedbackClassDeviceStruct(pWS, wsControlProc)) 479 return !Success; 480 481 xf86InitValuatorAxisStruct(pWS, 0, 482 axes_labels[0], 483 xmin, xmax, 1, 0, 1 484#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12 485 , priv->type == WSMOUSE_TYPE_TPANEL ? Absolute : Relative 486#endif 487 ); 488 xf86InitValuatorDefaults(pWS, 0); 489 490 xf86InitValuatorAxisStruct(pWS, 1, 491 axes_labels[1], 492 ymin, ymax, 1, 0, 1 493#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12 494 , priv->type == WSMOUSE_TYPE_TPANEL ? Absolute : Relative 495#endif 496 ); 497 xf86InitValuatorDefaults(pWS, 1); 498 499 500#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 14 501 xf86InitValuatorAxisStruct(pWS, HSCROLL_AXIS, 502 axes_labels[HSCROLL_AXIS], 0, -1, 0, 0, 0, Relative); 503 xf86InitValuatorAxisStruct(pWS, VSCROLL_AXIS, 504 axes_labels[VSCROLL_AXIS], 0, -1, 0, 0, 0, Relative); 505 priv->scroll_mask = valuator_mask_new(MAX_VALUATORS); 506 if (!priv->scroll_mask) { 507 return !Success; 508 } 509 510 /* 511 * The value of an HSCROLL or VSCROLL event is the fraction 512 * motion_delta / scroll_distance 513 * in [*.12] fixed-point format. The 'increment' attribute of the 514 * scroll axes is constant: 515 */ 516 SetScrollValuator(pWS, HSCROLL_AXIS, SCROLL_TYPE_HORIZONTAL, 4096, 0); 517 SetScrollValuator(pWS, VSCROLL_AXIS, SCROLL_TYPE_VERTICAL, 4096, 0); 518#endif 519 520#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12 521 xf86MotionHistoryAllocate(pInfo); 522 AssignTypeAndName(pWS, pInfo->atom, pInfo->name); 523#endif 524 pWS->public.on = FALSE; 525 if (wsOpen(pInfo) != Success) { 526 return !Success; 527 } 528 wsInitProperty(pWS); 529 XIRegisterPropertyHandler(pWS, wsSetProperty, NULL, NULL); 530 wsmbEmuInitProperty(pWS); 531 return Success; 532} 533 534static int 535wsDeviceOn(DeviceIntPtr pWS) 536{ 537 InputInfoPtr pInfo = (InputInfoPtr)pWS->public.devicePrivate; 538 WSDevicePtr priv = (WSDevicePtr)pInfo->private; 539#ifndef __NetBSD__ 540 struct wsmouse_calibcoords coords; 541#endif 542 543 DBG(1, ErrorF("WS DEVICE ON\n")); 544 if ((pInfo->fd < 0) && (wsOpen(pInfo) != Success)) { 545 xf86Msg(X_ERROR, "wsOpen failed %s\n", 546 strerror(errno)); 547 return !Success; 548 } 549 550#ifndef __NetBSD__ 551 if (priv->type == WSMOUSE_TYPE_TPANEL) { 552 /* get calibration values */ 553 if (ioctl(pInfo->fd, WSMOUSEIO_GCALIBCOORDS, &coords) != 0) { 554 xf86Msg(X_ERROR, "GCALIBCOORS failed %s\n", 555 strerror(errno)); 556 return !Success; 557 } 558 memcpy(&priv->coords, &coords, sizeof coords); 559 /* set raw mode */ 560 if (coords.samplelen != priv->raw) { 561 coords.samplelen = priv->raw; 562 if (ioctl(pInfo->fd, WSMOUSEIO_SCALIBCOORDS, 563 &coords) != 0) { 564 xf86Msg(X_ERROR, "SCALIBCOORS failed %s\n", 565 strerror(errno)); 566 return !Success; 567 } 568 } 569 } 570#endif 571 priv->buffer = XisbNew(pInfo->fd, 572 sizeof(struct wscons_event) * NUMEVENTS); 573 if (priv->buffer == NULL) { 574 xf86Msg(X_ERROR, "cannot alloc xisb buffer\n"); 575 wsClose(pInfo); 576 return !Success; 577 } 578 xf86AddEnabledDevice(pInfo); 579 wsmbEmuOn(pInfo); 580 pWS->public.on = TRUE; 581 return Success; 582} 583 584static void 585wsDeviceOff(DeviceIntPtr pWS) 586{ 587 InputInfoPtr pInfo = (InputInfoPtr)pWS->public.devicePrivate; 588 WSDevicePtr priv = pInfo->private; 589#ifndef __NetBSD__ 590 struct wsmouse_calibcoords coords; 591#endif 592 593 DBG(1, ErrorF("WS DEVICE OFF\n")); 594 wsmbEmuFinalize(pInfo); 595#ifndef __NetBSD__ 596 if (priv->type == WSMOUSE_TYPE_TPANEL) { 597 /* Restore calibration data */ 598 memcpy(&coords, &priv->coords, sizeof coords); 599 if (ioctl(pInfo->fd, WSMOUSEIO_SCALIBCOORDS, &coords) != 0) { 600 xf86Msg(X_ERROR, "SCALIBCOORS failed %s\n", 601 strerror(errno)); 602 } 603 } 604#endif 605 if (pInfo->fd >= 0) { 606 xf86RemoveEnabledDevice(pInfo); 607 wsClose(pInfo); 608 } 609 if (priv->buffer) { 610 XisbFree(priv->buffer); 611 priv->buffer = NULL; 612 } 613 pWS->public.on = FALSE; 614} 615 616static void 617wsReadInput(InputInfoPtr pInfo) 618{ 619 WSDevicePtr priv; 620 static struct wscons_event eventList[NUMEVENTS]; 621 int n, c; 622 struct wscons_event *event = eventList; 623 unsigned char *pBuf; 624 int ax, ay; 625 626 priv = pInfo->private; 627 628 XisbBlockDuration(priv->buffer, -1); 629 pBuf = (unsigned char *)eventList; 630 n = 0; 631 while (n < sizeof(eventList) && (c = XisbRead(priv->buffer)) >= 0) { 632 pBuf[n++] = (unsigned char)c; 633 } 634 635 if (n == 0) 636 return; 637 638 n /= sizeof(struct wscons_event); 639 while( n-- ) { 640 int buttons = priv->lastButtons; 641 int dx = 0, dy = 0, dz = 0, dw = 0; 642 int zbutton = 0, wbutton = 0; 643#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 14 644 int hscroll = 0, vscroll = 0; 645#endif 646 647 ax = 0; ay = 0; 648 switch (event->type) { 649 case WSCONS_EVENT_MOUSE_UP: 650 651 buttons &= ~(1 << event->value); 652 DBG(4, ErrorF("Button %d up %x\n", event->value, 653 buttons)); 654 break; 655 case WSCONS_EVENT_MOUSE_DOWN: 656 buttons |= (1 << event->value); 657 DBG(4, ErrorF("Button %d down %x\n", event->value, 658 buttons)); 659 break; 660 case WSCONS_EVENT_MOUSE_DELTA_X: 661 dx = event->value; 662 DBG(4, ErrorF("Relative X %d\n", event->value)); 663 break; 664 case WSCONS_EVENT_MOUSE_DELTA_Y: 665 dy = -event->value; 666 DBG(4, ErrorF("Relative Y %d\n", event->value)); 667 break; 668 case WSCONS_EVENT_MOUSE_ABSOLUTE_X: 669 DBG(4, ErrorF("Absolute X %d\n", event->value)); 670 if (event->value == 4095) 671 break; 672 ax = event->value; 673 if (priv->inv_x) 674 ax = priv->max_x - ax + priv->min_x; 675 break; 676 case WSCONS_EVENT_MOUSE_ABSOLUTE_Y: 677 DBG(4, ErrorF("Absolute Y %d\n", event->value)); 678 ay = event->value; 679 if (priv->inv_y) 680 ay = priv->max_y - ay + priv->min_y; 681 break; 682 case WSCONS_EVENT_MOUSE_DELTA_Z: 683 DBG(4, ErrorF("Relative Z %d\n", event->value)); 684 dz = event->value; 685 break; 686 case WSCONS_EVENT_MOUSE_ABSOLUTE_Z: 687 /* ignore those */ 688 ++event; 689 continue; 690 break; 691 case WSCONS_EVENT_MOUSE_DELTA_W: 692 DBG(4, ErrorF("Relative W %d\n", event->value)); 693 dw = event->value; 694 break; 695#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 14 696 case WSCONS_EVENT_HSCROLL: 697 hscroll = event->value; 698 DBG(4, ErrorF("Horiz. Scrolling %d\n", event->value)); 699 break; 700 case WSCONS_EVENT_VSCROLL: 701 vscroll = event->value; 702 DBG(4, ErrorF("Vert. Scrolling %d\n", event->value)); 703 break; 704#endif 705 default: 706 xf86Msg(X_WARNING, "%s: bad wsmouse event type=%d\n", 707 pInfo->name, event->type); 708 ++event; 709 continue; 710 } /* case */ 711 712 if (dx || dy) { 713 /* relative motion event */ 714 DBG(3, ErrorF("postMotionEvent dX %d dY %d\n", 715 dx, dy)); 716 xf86PostMotionEvent(pInfo->dev, 0, 0, 2, 717 dx, dy); 718 } 719 if (dz && priv->negativeZ != WS_NOZMAP 720 && priv->positiveZ != WS_NOZMAP) { 721 buttons &= ~(priv->negativeZ | priv->positiveZ); 722 if (dz < 0) { 723 DBG(4, ErrorF("Z -> button %d\n", 724 priv->negativeZ)); 725 zbutton = 1 << (priv->negativeZ - 1); 726 } else { 727 DBG(4, ErrorF("Z -> button %d\n", 728 priv->positiveZ)); 729 zbutton = 1 << (priv->positiveZ - 1); 730 } 731 buttons |= zbutton; 732 dz = 0; 733 } 734 if (dw && priv->negativeW != WS_NOZMAP 735 && priv->positiveW != WS_NOZMAP) { 736 buttons &= ~(priv->negativeW | priv->positiveW); 737 if (dw < 0) { 738 DBG(4, ErrorF("W -> button %d\n", 739 priv->negativeW)); 740 wbutton = 1 << (priv->negativeW - 1); 741 } else { 742 DBG(4, ErrorF("W -> button %d\n", 743 priv->positiveW)); 744 wbutton = 1 << (priv->positiveW - 1); 745 } 746 buttons |= wbutton; 747 dw = 0; 748 } 749#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 14 750 if (hscroll || vscroll) { 751 static int warned = 0; 752 if (!warned) { 753 warned = 1; 754 xf86Msg(X_WARNING, "%s: hscroll=%d, vscroll=%d\n", 755 pInfo->name, hscroll, vscroll); 756 } 757 valuator_mask_zero(priv->scroll_mask); 758 valuator_mask_set_double(priv->scroll_mask, 759 HSCROLL_AXIS, (double) hscroll); 760 valuator_mask_set_double(priv->scroll_mask, 761 VSCROLL_AXIS, (double) vscroll); 762 xf86PostMotionEventM(pInfo->dev, FALSE, priv->scroll_mask); 763 } 764#endif 765 if (priv->lastButtons != buttons) { 766 /* button event */ 767 wsSendButtons(pInfo, buttons); 768 } 769 if (zbutton != 0) { 770 /* generate a button up event */ 771 buttons &= ~zbutton; 772 wsSendButtons(pInfo, buttons); 773 } 774 if (priv->swap_axes) { 775 int tmp; 776 777 tmp = ax; 778 ax = ay; 779 ay = tmp; 780 } 781 if (ax) { 782 /* absolute position event */ 783 DBG(3, ErrorF("postMotionEvent X %d\n", ax)); 784 xf86PostMotionEvent(pInfo->dev, 1, 0, 1, ax); 785 } 786 if (ay) { 787 /* absolute position event */ 788 DBG(3, ErrorF("postMotionEvent y %d\n", ay)); 789 xf86PostMotionEvent(pInfo->dev, 1, 1, 1, ay); 790 } 791 ++event; 792 } 793 return; 794} /* wsReadInput */ 795 796static void 797wsSendButtons(InputInfoPtr pInfo, int buttons) 798{ 799 WSDevicePtr priv = (WSDevicePtr)pInfo->private; 800 int button, mask; 801 802 for (button = 1; button < NBUTTONS; button++) { 803 mask = 1 << (button - 1); 804 if ((mask & priv->lastButtons) != (mask & buttons)) { 805 if (!wsmbEmuFilterEvent(pInfo, button, 806 (buttons & mask) != 0)) { 807 xf86PostButtonEvent(pInfo->dev, TRUE, 808 button, (buttons & mask) != 0, 809 0, 0); 810 DBG(3, ErrorF("post button event %d %d\n", 811 button, (buttons & mask) != 0)) 812 } 813 } 814 } /* for */ 815 priv->lastButtons = buttons; 816} /* wsSendButtons */ 817 818 819static int 820wsChangeControl(InputInfoPtr pInfo, xDeviceCtl *control) 821{ 822 return BadMatch; 823} 824 825static int 826wsSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode) 827{ 828 return BadMatch; 829} 830 831static Bool 832wsOpen(InputInfoPtr pInfo) 833{ 834 WSDevicePtr priv = (WSDevicePtr)pInfo->private; 835#ifdef __NetBSD__ 836 int version = WSMOUSE_EVENT_VERSION; 837#endif 838 839 DBG(1, ErrorF("WS open %s\n", priv->devName)); 840 pInfo->fd = xf86OpenSerial(pInfo->options); 841 if (pInfo->fd == -1) { 842 xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name); 843 return !Success; 844 } 845#ifdef __NetBSD__ 846 if (ioctl(pInfo->fd, WSMOUSEIO_SETVERSION, &version) == -1) { 847 xf86Msg(X_ERROR, "%s: cannot set wsmouse event version\n", 848 pInfo->name); 849 return !Success; 850 } 851#endif 852 return Success; 853} 854 855static void 856wsClose(InputInfoPtr pInfo) 857{ 858 xf86CloseSerial(pInfo->fd); 859 pInfo->fd = -1; 860} 861 862static void 863wsControlProc(DeviceIntPtr device, PtrCtrl *ctrl) 864{ 865 InputInfoPtr pInfo = device->public.devicePrivate; 866 WSDevicePtr priv = (WSDevicePtr)pInfo->private; 867 868 DBG(1, ErrorF("wsControlProc\n")); 869 priv->num = ctrl->num; 870 priv->den = ctrl->den; 871 priv->threshold = ctrl->threshold; 872} 873 874static void 875wsInitProperty(DeviceIntPtr device) 876{ 877 InputInfoPtr pInfo = device->public.devicePrivate; 878 WSDevicePtr priv = (WSDevicePtr)pInfo->private; 879 int rc; 880 881 DBG(1, ErrorF("wsInitProperty\n")); 882 if (priv->type != WSMOUSE_TYPE_TPANEL) 883 return; 884 885 prop_calibration = MakeAtom(WS_PROP_CALIBRATION, 886 strlen(WS_PROP_CALIBRATION), TRUE); 887 rc = XIChangeDeviceProperty(device, prop_calibration, XA_INTEGER, 32, 888 PropModeReplace, 4, &priv->min_x, FALSE); 889 if (rc != Success) 890 return; 891 892 XISetDevicePropertyDeletable(device, prop_calibration, FALSE); 893 894 prop_swap = MakeAtom(WS_PROP_SWAP_AXES, 895 strlen(WS_PROP_SWAP_AXES), TRUE); 896 rc = XIChangeDeviceProperty(device, prop_swap, XA_INTEGER, 8, 897 PropModeReplace, 1, &priv->swap_axes, FALSE); 898 if (rc != Success) 899 return; 900 return; 901} 902 903static int 904wsSetProperty(DeviceIntPtr device, Atom atom, XIPropertyValuePtr val, 905 BOOL checkonly) 906{ 907 InputInfoPtr pInfo = device->public.devicePrivate; 908 WSDevicePtr priv = (WSDevicePtr)pInfo->private; 909 struct wsmouse_calibcoords coords; 910 int need_update = 0; 911 AxisInfoPtr ax = device->valuator->axes, 912 ay = device->valuator->axes + 1; 913 914 DBG(1, ErrorF("wsSetProperty %s\n", NameForAtom(atom))); 915 916 /* Ignore non panel devices */ 917 if (priv->type != WSMOUSE_TYPE_TPANEL) 918 return Success; 919 920 if (atom == prop_calibration) { 921 if (val->format != 32 || val->type != XA_INTEGER) 922 return BadMatch; 923 if (val->size != 4 && val->size != 0) 924 return BadMatch; 925 if (!checkonly) { 926 if (val->size == 0) { 927 DBG(1, ErrorF(" uncalibrate\n")); 928 priv->min_x = 0; 929 priv->max_x = -1; 930 priv->min_y = 0; 931 priv->max_y = -1; 932 } else { 933 priv->min_x = ((int *)(val->data))[0]; 934 priv->max_x = ((int *)(val->data))[1]; 935 priv->min_y = ((int *)(val->data))[2]; 936 priv->max_y = ((int *)(val->data))[3]; 937 DBG(1, ErrorF(" calibrate %d %d %d %d\n", 938 priv->min_x, priv->max_x, 939 priv->min_y, priv->max_y)); 940 need_update++; 941 } 942 /* Update axes descriptors */ 943 if (!priv->swap_axes) { 944 ax->min_value = priv->min_x; 945 ax->max_value = priv->max_x; 946 ay->min_value = priv->min_y; 947 ay->max_value = priv->max_y; 948 } else { 949 ax->min_value = priv->min_y; 950 ax->max_value = priv->max_y; 951 ay->min_value = priv->min_x; 952 ay->max_value = priv->max_x; 953 } 954 } 955 } else if (atom == prop_swap) { 956 if (val->format != 8 || val->type != XA_INTEGER || 957 val->size != 1) 958 return BadMatch; 959 if (!checkonly) { 960 priv->swap_axes = *((BOOL *)val->data); 961 DBG(1, ErrorF("swap_axes %d\n", priv->swap_axes)); 962 need_update++; 963 } 964 } 965 if (need_update) { 966 /* Update the saved values to be restored on device off */ 967 priv->coords.minx = priv->min_x; 968 priv->coords.maxx = priv->max_x; 969 priv->coords.miny = priv->min_y; 970 priv->coords.maxy = priv->max_y; 971#ifndef __NetBSD__ 972 priv->coords.swapxy = priv->swap_axes; 973#endif 974 975 /* Update the kernel calibration table */ 976 coords.minx = priv->min_x; 977 coords.maxx = priv->max_x; 978 coords.miny = priv->min_y; 979 coords.maxy = priv->max_y; 980#ifndef __NetBSD__ 981 coords.swapxy = priv->swap_axes; 982#endif 983 coords.samplelen = priv->raw; 984#ifndef __NetBSD__ 985 coords.resx = priv->coords.resx; 986 coords.resy = priv->coords.resy; 987#endif 988 if (ioctl(pInfo->fd, WSMOUSEIO_SCALIBCOORDS, &coords) != 0) { 989 xf86Msg(X_ERROR, "SCALIBCOORDS failed %s\n", 990 strerror(errno)); 991 } 992 } 993 return Success; 994} 995