1 /* 2 * Copyright 2008-2010, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors (in chronological order): 6 * Clemens Zeidler (haiku@Clemens-Zeidler.de) 7 * Axel Dörfler, axeld@pinc-software.de 8 */ 9 10 11 //! PS/2 synaptics touchpad 12 13 14 #include "ps2_synaptics.h" 15 16 #include <string.h> 17 #include <stdlib.h> 18 19 #include <keyboard_mouse_driver.h> 20 21 #include "ps2_service.h" 22 23 24 //#define TRACE_PS2_SYNAPTICS 25 #ifdef TRACE_PS2_SYNAPTICS 26 # define TRACE(x...) dprintf(x) 27 #else 28 # define TRACE(x...) 29 #endif 30 31 /*! The raw movement calculation is calibrated on ths synaptics touchpad. */ 32 // increase the touchpad size a little bit 33 #define SYN_AREA_TOP_LEFT_OFFSET 40 34 #define SYN_AREA_BOTTOM_RIGHT_OFFSET 60 35 #define SYN_AREA_START_X (1472 - SYN_AREA_TOP_LEFT_OFFSET) 36 #define SYN_AREA_END_X (5472 + SYN_AREA_BOTTOM_RIGHT_OFFSET) 37 #define SYN_AREA_START_Y (1408 - SYN_AREA_TOP_LEFT_OFFSET) 38 #define SYN_AREA_END_Y (4448 + SYN_AREA_BOTTOM_RIGHT_OFFSET) 39 40 // synaptics touchpad proportions 41 #define SYN_EDGE_MOTION_WIDTH 50 42 #define SYN_AREA_OFFSET 40 43 44 #define MIN_PRESSURE 30 45 #define REAL_MAX_PRESSURE 100 46 #define MAX_PRESSURE 200 47 48 enum { 49 kIdentify = 0x00, 50 kReadModes = 0x01, 51 kReadCapabilities = 0x02, 52 kReadModelId = 0x03, 53 kReadSerialNumberPrefix = 0x06, 54 kReadSerialModelSuffix = 0x07, 55 kReadResolutions = 0x08, 56 kExtendedModelId = 0x09, 57 kContinuedCapabilities = 0x0C, 58 kMaximumCoordinates = 0x0D, 59 kDeluxeLedInfo = 0x0E, 60 kMinimumCoordinates = 0x0F, 61 kTrackpointQuirk = 0x10 62 }; 63 64 static touchpad_specs gHardwareSpecs; 65 66 67 const char* kSynapticsPath[4] = { 68 "input/touchpad/ps2/synaptics_0", 69 "input/touchpad/ps2/synaptics_1", 70 "input/touchpad/ps2/synaptics_2", 71 "input/touchpad/ps2/synaptics_3" 72 }; 73 74 75 static touchpad_info sTouchpadInfo; 76 static ps2_dev *sPassthroughDevice = &ps2_device[PS2_DEVICE_SYN_PASSTHROUGH]; 77 78 79 static status_t 80 send_touchpad_arg_timeout(ps2_dev *dev, uint8 arg, bigtime_t timeout) 81 { 82 int8 i; 83 uint8 val[8]; 84 85 for (i = 0; i < 4; i++) { 86 val[2 * i] = (arg >> (6 - 2 * i)) & 3; 87 val[2 * i + 1] = 0xE8; 88 } 89 return ps2_dev_command_timeout(dev, 0xE8, val, 7, NULL, 0, timeout); 90 } 91 92 93 static status_t 94 send_touchpad_arg(ps2_dev *dev, uint8 arg) 95 { 96 return send_touchpad_arg_timeout(dev, arg, 4000000); 97 } 98 99 100 static status_t 101 set_touchpad_mode(ps2_dev *dev, uint8 mode) 102 { 103 uint8 sample_rate = SYN_CHANGE_MODE; 104 send_touchpad_arg(dev, mode); 105 return ps2_dev_command(dev, PS2_CMD_SET_SAMPLE_RATE, &sample_rate, 1, 106 NULL, 0); 107 } 108 109 110 static status_t 111 get_information_query(ps2_dev *dev, uint8 extendedQueries, uint8 query, 112 uint8 val[3]) 113 { 114 if (query == kTrackpointQuirk) { 115 // Special case: this information query is not reported in the 116 // "extended queries", but is still supported when the touchpad has 117 // a pass-through port. 118 if (!sTouchpadInfo.capPassThrough) 119 return B_NOT_SUPPORTED; 120 } else if (query > extendedQueries + 8) 121 return B_NOT_SUPPORTED; 122 123 status_t error = send_touchpad_arg(dev, query); 124 if (error != B_OK) 125 return error; 126 return ps2_dev_command(dev, 0xE9, NULL, 0, val, 3); 127 } 128 129 130 static status_t 131 get_synaptics_movment(synaptics_cookie *cookie, touchpad_movement *_event, bigtime_t timeout) 132 { 133 status_t status; 134 touchpad_movement event; 135 uint8 event_buffer[PS2_MAX_PACKET_SIZE]; 136 uint8 wValue0, wValue1, wValue2, wValue3, wValue; 137 uint32 val32; 138 uint32 xTwelfBit, yTwelfBit; 139 140 status = acquire_sem_etc(cookie->synaptics_sem, 1, B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, 141 timeout); 142 if (status < B_OK) 143 return status; 144 145 if (!cookie->dev->active) { 146 TRACE("SYNAPTICS: read_event: Error device no longer active\n"); 147 return B_ERROR; 148 } 149 150 if (packet_buffer_read(cookie->synaptics_ring_buffer, event_buffer, 151 cookie->dev->packet_size) != cookie->dev->packet_size) { 152 TRACE("SYNAPTICS: error copying buffer\n"); 153 return B_ERROR; 154 } 155 156 event.buttons = event_buffer[0] & 3; 157 event.zPressure = event_buffer[2]; 158 159 if (sTouchpadInfo.capExtended) { 160 wValue0 = event_buffer[3] >> 2 & 1; 161 wValue1 = event_buffer[0] >> 2 & 1; 162 wValue2 = event_buffer[0] >> 4 & 1; 163 wValue3 = event_buffer[0] >> 5 & 1; 164 165 wValue = wValue0; 166 wValue = wValue | (wValue1 << 1); 167 wValue = wValue | (wValue2 << 2); 168 wValue = wValue | (wValue3 << 3); 169 170 event.fingerWidth = wValue; 171 event.gesture = false; 172 173 // Clickpad pretends that all clicks on the touchpad are middle clicks. 174 // Pass them to userspace as left clicks instead. 175 if (sTouchpadInfo.capClickPad) 176 event.buttons |= ((event_buffer[0] ^ event_buffer[3]) & 0x01); 177 178 if (sTouchpadInfo.capMiddleButton || sTouchpadInfo.capFourButtons) 179 event.buttons |= ((event_buffer[0] ^ event_buffer[3]) & 0x01) << 2; 180 181 if (sTouchpadInfo.nExtendedButtons > 0) { 182 if (((event_buffer[0] ^ event_buffer[3]) & 0x02) != 0) { 183 // This packet includes extended buttons state. The state is 184 // only reported once when one of the buttons is pressed or 185 // released, so we must keep track of the buttons state. 186 187 // The values replace the lowest bits of the X and Y coordinates 188 // in the packet, we need to extract them from there. 189 190 bool pressed; 191 for (int button = 0; button < sTouchpadInfo.nExtendedButtons; 192 button++) { 193 // Even buttons are in the X byte 194 pressed = event_buffer[4 + button % 2] >> button / 2 & 0x1; 195 if (pressed) { 196 sTouchpadInfo.extendedButtonsState |= 1 << button; 197 } else { 198 sTouchpadInfo.extendedButtonsState &= ~(1 << button); 199 } 200 } 201 } 202 203 event.buttons |= sTouchpadInfo.extendedButtonsState 204 << sTouchpadInfo.firstExtendedButton; 205 } 206 } else { 207 bool finger = event_buffer[0] >> 5 & 1; 208 if (finger) { 209 // finger with normal width 210 event.fingerWidth = 4; 211 } 212 event.gesture = event_buffer[0] >> 2 & 1; 213 } 214 215 event.xPosition = event_buffer[4]; 216 event.yPosition = event_buffer[5]; 217 218 val32 = event_buffer[1] & 0x0F; 219 event.xPosition += val32 << 8; 220 val32 = event_buffer[1] >> 4 & 0x0F; 221 event.yPosition += val32 << 8; 222 223 xTwelfBit = event_buffer[3] >> 4 & 1; 224 event.xPosition += xTwelfBit << 12; 225 yTwelfBit = event_buffer[3] >> 5 & 1; 226 event.yPosition += yTwelfBit << 12; 227 228 *_event = event; 229 return B_OK; 230 } 231 232 233 static void 234 query_capability(ps2_dev *dev) 235 { 236 uint8 val[3]; 237 uint8 nExtendedQueries = 0; 238 239 get_information_query(dev, nExtendedQueries, kReadCapabilities, val); 240 241 TRACE("SYNAPTICS: extended mode %2x\n", val[0] >> 7 & 1); 242 sTouchpadInfo.capExtended = val[0] >> 7 & 1; 243 TRACE("SYNAPTICS: extended queries %2x\n", val[0] >> 4 & 7); 244 nExtendedQueries = val[0] >> 4 & 7; 245 TRACE("SYNAPTICS: middle button %2x\n", val[0] >> 2 & 1); 246 sTouchpadInfo.capMiddleButton = val[0] >> 2 & 1; 247 248 TRACE("SYNAPTICS: sleep mode %2x\n", val[2] >> 4 & 1); 249 sTouchpadInfo.capSleep = val[2] >> 4 & 1; 250 TRACE("SYNAPTICS: four buttons %2x\n", val[2] >> 3 & 1); 251 sTouchpadInfo.capFourButtons = val[2] >> 3 & 1; 252 TRACE("SYNAPTICS: multi finger %2x\n", val[2] >> 1 & 1); 253 sTouchpadInfo.capMultiFinger = val[2] >> 1 & 1; 254 TRACE("SYNAPTICS: palm detection %2x\n", val[2] & 1); 255 sTouchpadInfo.capPalmDetection = val[2] & 1; 256 TRACE("SYNAPTICS: pass through %2x\n", val[2] >> 7 & 1); 257 sTouchpadInfo.capPassThrough = val[2] >> 7 & 1; 258 259 if (get_information_query(dev, nExtendedQueries, kExtendedModelId, val) 260 != B_OK) { 261 // "Extended Model ID" is not supported, so there cannot be extra 262 // buttons. 263 sTouchpadInfo.nExtendedButtons = 0; 264 sTouchpadInfo.firstExtendedButton = 0; 265 sTouchpadInfo.capClickPad = false; 266 return; 267 } 268 269 sTouchpadInfo.capClickPad = (val[0] >> 5 & 1) | (val[1] >> 0 & 1); 270 TRACE("SYNAPTICS: clickpad %x\n", sTouchpadInfo.capClickPad); 271 272 TRACE("SYNAPTICS: extended buttons %2x\n", val[1] >> 4 & 15); 273 sTouchpadInfo.nExtendedButtons = val[1] >> 4 & 15; 274 sTouchpadInfo.extendedButtonsState = 0; 275 276 if (sTouchpadInfo.capMiddleButton) 277 sTouchpadInfo.firstExtendedButton = 3; 278 else 279 sTouchpadInfo.firstExtendedButton = 2; 280 281 // Capability 0x10 is not documented in the Synaptics Touchpad interfacing 282 // guide (at least the versions I could find), but we got the information 283 // from Linux patches: https://lkml.org/lkml/2015/2/6/621 284 if (get_information_query(dev, nExtendedQueries, kTrackpointQuirk, val) 285 != B_OK) 286 return; 287 288 // Workaround for Thinkpad use of the extended buttons: they are 289 // used as buttons for the trackpoint, so they should be reported 290 // as buttons 0, 1, 2 rather than 3, 4, 5. 291 TRACE("SYNAPTICS: alternate buttons %2x\n", val[0] >> 0 & 1); 292 if (val[0] >> 0 & 1) 293 sTouchpadInfo.firstExtendedButton = 0; 294 } 295 296 297 // #pragma mark - exported functions 298 299 300 status_t 301 synaptics_pass_through_set_packet_size(ps2_dev *dev, uint8 size) 302 { 303 synaptics_cookie *synapticsCookie 304 = (synaptics_cookie*)dev->parent_dev->cookie; 305 306 status_t status = ps2_dev_command(dev->parent_dev, PS2_CMD_DISABLE, NULL, 307 0, NULL, 0); 308 if (status < B_OK) { 309 INFO("SYNAPTICS: cannot disable touchpad %s\n", dev->parent_dev->name); 310 return B_ERROR; 311 } 312 313 synapticsCookie->packet_index = 0; 314 315 if (size == 4) 316 synapticsCookie->mode |= SYN_FOUR_BYTE_CHILD; 317 else 318 synapticsCookie->mode &= ~SYN_FOUR_BYTE_CHILD; 319 320 set_touchpad_mode(dev->parent_dev, synapticsCookie->mode); 321 322 status = ps2_dev_command(dev->parent_dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); 323 if (status < B_OK) { 324 INFO("SYNAPTICS: cannot enable touchpad %s\n", dev->parent_dev->name); 325 return B_ERROR; 326 } 327 return status; 328 } 329 330 331 status_t 332 passthrough_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int outCount, 333 uint8 *in, int inCount, bigtime_t timeout) 334 { 335 status_t status; 336 uint8 passThroughCmd = SYN_PASSTHROUGH_CMD; 337 uint8 val; 338 uint32 passThroughInCount = (inCount + 1) * 6; 339 uint8 passThroughIn[passThroughInCount]; 340 int8 i; 341 342 TRACE("SYNAPTICS: passthrough command 0x%x\n", cmd); 343 344 status = ps2_dev_command(dev->parent_dev, PS2_CMD_DISABLE, NULL, 0, 345 NULL, 0); 346 if (status != B_OK) 347 return status; 348 349 for (i = -1; i < outCount; i++) { 350 if (i == -1) 351 val = cmd; 352 else 353 val = out[i]; 354 status = send_touchpad_arg_timeout(dev->parent_dev, val, timeout); 355 if (status != B_OK) 356 goto finalize; 357 if (i != outCount -1) { 358 status = ps2_dev_command_timeout(dev->parent_dev, 359 PS2_CMD_SET_SAMPLE_RATE, &passThroughCmd, 1, NULL, 0, timeout); 360 if (status != B_OK) 361 goto finalize; 362 } 363 } 364 status = ps2_dev_command_timeout(dev->parent_dev, PS2_CMD_SET_SAMPLE_RATE, 365 &passThroughCmd, 1, passThroughIn, passThroughInCount, timeout); 366 if (status != B_OK) 367 goto finalize; 368 369 for (i = 0; i < inCount + 1; i++) { 370 uint8 *inPointer = &passThroughIn[i * 6]; 371 if (!IS_SYN_PT_PACKAGE(inPointer)) { 372 TRACE("SYNAPTICS: not a pass throught package\n"); 373 goto finalize; 374 } 375 if (i == 0) 376 continue; 377 378 in[i - 1] = passThroughIn[i * 6 + 1]; 379 } 380 381 finalize: 382 status_t statusOfEnable = ps2_dev_command(dev->parent_dev, PS2_CMD_ENABLE, 383 NULL, 0, NULL, 0); 384 if (statusOfEnable != B_OK) { 385 TRACE("SYNAPTICS: enabling of parent failed: 0x%" B_PRIx32 ".\n", 386 statusOfEnable); 387 } 388 389 return status != B_OK ? status : statusOfEnable; 390 } 391 392 393 status_t 394 probe_synaptics(ps2_dev *dev) 395 { 396 uint8 val[3]; 397 uint8 deviceId; 398 status_t status; 399 TRACE("SYNAPTICS: probe\n"); 400 401 // We reset the device here because it may have been left in a confused 402 // state by a previous probing attempt. Some synaptics touchpads are known 403 // to lockup when we attempt to detect them as IBM trackpoints. 404 ps2_reset_mouse(dev); 405 406 // Request "Identify touchpad" 407 // The touchpad will delay this, until it's ready and calibrated. 408 status = get_information_query(dev, 0, kIdentify, val); 409 if (status != B_OK) 410 return status; 411 412 sTouchpadInfo.minorVersion = val[0]; 413 deviceId = val[1]; 414 if (deviceId != SYN_TOUCHPAD) { 415 TRACE("SYNAPTICS: not found\n"); 416 return B_ERROR; 417 } 418 419 TRACE("SYNAPTICS: Touchpad found id:l %2x\n", deviceId); 420 sTouchpadInfo.majorVersion = val[2] & 0x0F; 421 TRACE("SYNAPTICS: version %d.%d\n", sTouchpadInfo.majorVersion, 422 sTouchpadInfo.minorVersion); 423 // version >= 4.0? 424 if (sTouchpadInfo.minorVersion <= 2 425 && sTouchpadInfo.majorVersion <= 3) { 426 TRACE("SYNAPTICS: too old touchpad not supported\n"); 427 return B_ERROR; 428 } 429 dev->name = kSynapticsPath[dev->idx]; 430 return B_OK; 431 } 432 433 434 // #pragma mark - Device functions 435 436 437 status_t 438 synaptics_open(const char *name, uint32 flags, void **_cookie) 439 { 440 status_t status; 441 synaptics_cookie *cookie; 442 ps2_dev *dev; 443 int i; 444 445 for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) { 446 if (0 == strcmp(ps2_device[i].name, name)) { 447 dev = &ps2_device[i]; 448 break; 449 } 450 } 451 452 if (dev == NULL) { 453 TRACE("ps2: dev = NULL\n"); 454 return B_ERROR; 455 } 456 457 if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN) 458 return B_BUSY; 459 460 cookie = (synaptics_cookie*)malloc(sizeof(synaptics_cookie)); 461 if (cookie == NULL) 462 goto err1; 463 memset(cookie, 0, sizeof(*cookie)); 464 465 *_cookie = cookie; 466 467 cookie->dev = dev; 468 dev->cookie = cookie; 469 dev->disconnect = &synaptics_disconnect; 470 dev->handle_int = &synaptics_handle_int; 471 472 gHardwareSpecs.edgeMotionWidth = SYN_EDGE_MOTION_WIDTH; 473 474 gHardwareSpecs.areaStartX = SYN_AREA_START_X; 475 gHardwareSpecs.areaEndX = SYN_AREA_END_X; 476 gHardwareSpecs.areaStartY = SYN_AREA_START_Y; 477 gHardwareSpecs.areaEndY = SYN_AREA_END_Y; 478 479 gHardwareSpecs.minPressure = MIN_PRESSURE; 480 gHardwareSpecs.realMaxPressure = REAL_MAX_PRESSURE; 481 gHardwareSpecs.maxPressure = MAX_PRESSURE; 482 483 dev->packet_size = PS2_PACKET_SYNAPTICS; 484 485 cookie->synaptics_ring_buffer 486 = create_packet_buffer(SYNAPTICS_HISTORY_SIZE * dev->packet_size); 487 if (cookie->synaptics_ring_buffer == NULL) { 488 TRACE("ps2: can't allocate mouse actions buffer\n"); 489 goto err2; 490 } 491 492 // create the mouse semaphore, used for synchronization between 493 // the interrupt handler and the read operation 494 cookie->synaptics_sem = create_sem(0, "ps2_synaptics_sem"); 495 if (cookie->synaptics_sem < 0) { 496 TRACE("SYNAPTICS: failed creating semaphore!\n"); 497 goto err3; 498 } 499 query_capability(dev); 500 501 // create pass through dev 502 if (sTouchpadInfo.capPassThrough) { 503 TRACE("SYNAPTICS: pass through detected\n"); 504 sPassthroughDevice->parent_dev = dev; 505 sPassthroughDevice->idx = dev->idx; 506 ps2_service_notify_device_added(sPassthroughDevice); 507 } 508 509 // Set Mode 510 if (sTouchpadInfo.capExtended) 511 cookie->mode = SYN_ABSOLUTE_W_MODE; 512 else 513 cookie->mode = SYN_ABSOLUTE_MODE; 514 515 status = set_touchpad_mode(dev, cookie->mode); 516 if (status < B_OK) { 517 INFO("SYNAPTICS: cannot set mode %s\n", name); 518 goto err4; 519 } 520 521 status = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); 522 if (status < B_OK) { 523 INFO("SYNAPTICS: cannot enable touchpad %s\n", name); 524 goto err4; 525 } 526 527 atomic_or(&dev->flags, PS2_FLAG_ENABLED); 528 529 TRACE("SYNAPTICS: open %s success\n", name); 530 return B_OK; 531 532 err4: 533 delete_sem(cookie->synaptics_sem); 534 err3: 535 delete_packet_buffer(cookie->synaptics_ring_buffer); 536 err2: 537 free(cookie); 538 err1: 539 atomic_and(&dev->flags, ~PS2_FLAG_OPEN); 540 541 TRACE("SYNAPTICS: synaptics_open %s failed\n", name); 542 return B_ERROR; 543 } 544 545 546 status_t 547 synaptics_close(void *_cookie) 548 { 549 status_t status; 550 synaptics_cookie *cookie = (synaptics_cookie*)_cookie; 551 552 ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0, 553 150000); 554 555 delete_packet_buffer(cookie->synaptics_ring_buffer); 556 delete_sem(cookie->synaptics_sem); 557 558 atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN); 559 atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED); 560 561 // Reset the touchpad so it generate standard ps2 packets instead of 562 // extended ones. If not, BeOS is confused with such packets when rebooting 563 // without a complete shutdown. 564 status = ps2_reset_mouse(cookie->dev); 565 if (status != B_OK) { 566 INFO("ps2_synaptics: reset failed\n"); 567 return B_ERROR; 568 } 569 570 if (sTouchpadInfo.capPassThrough) 571 ps2_service_notify_device_removed(sPassthroughDevice); 572 573 TRACE("SYNAPTICS: close %s done\n", cookie->dev->name); 574 return B_OK; 575 } 576 577 578 status_t 579 synaptics_freecookie(void *_cookie) 580 { 581 free(_cookie); 582 return B_OK; 583 } 584 585 586 static status_t 587 synaptics_read(void *cookie, off_t pos, void *buffer, size_t *_length) 588 { 589 *_length = 0; 590 return B_NOT_ALLOWED; 591 } 592 593 594 static status_t 595 synaptics_write(void *cookie, off_t pos, const void *buffer, size_t *_length) 596 { 597 *_length = 0; 598 return B_NOT_ALLOWED; 599 } 600 601 602 status_t 603 synaptics_ioctl(void *_cookie, uint32 op, void *buffer, size_t length) 604 { 605 synaptics_cookie *cookie = (synaptics_cookie*)_cookie; 606 touchpad_read read; 607 status_t status; 608 609 switch (op) { 610 case MS_IS_TOUCHPAD: 611 TRACE("SYNAPTICS: MS_IS_TOUCHPAD\n"); 612 if (buffer == NULL) 613 return B_OK; 614 return user_memcpy(buffer, &gHardwareSpecs, sizeof(gHardwareSpecs)); 615 616 case MS_READ_TOUCHPAD: 617 TRACE("SYNAPTICS: MS_READ get event\n"); 618 if (user_memcpy(&read.timeout, &(((touchpad_read*)buffer)->timeout), 619 sizeof(bigtime_t)) != B_OK) 620 return B_BAD_ADDRESS; 621 if ((status = get_synaptics_movment(cookie, &read.u.touchpad, read.timeout)) != B_OK) 622 return status; 623 read.event = MS_READ_TOUCHPAD; 624 return user_memcpy(buffer, &read, sizeof(read)); 625 626 default: 627 TRACE("SYNAPTICS: unknown opcode: %" B_PRIu32 "\n", op); 628 return B_DEV_INVALID_IOCTL; 629 } 630 } 631 632 633 int32 634 synaptics_handle_int(ps2_dev *dev) 635 { 636 synaptics_cookie *cookie = (synaptics_cookie*)dev->cookie; 637 uint8 val; 638 639 val = cookie->dev->history[0].data; 640 641 if ((cookie->packet_index == 0 || cookie->packet_index == 3) 642 && (val & 8) != 0) { 643 INFO("SYNAPTICS: bad mouse data, trying resync\n"); 644 cookie->packet_index = 0; 645 return B_UNHANDLED_INTERRUPT; 646 } 647 if (cookie->packet_index == 0 && val >> 6 != 0x02) { 648 TRACE("SYNAPTICS: first package begins not with bit 1, 0\n"); 649 return B_UNHANDLED_INTERRUPT; 650 } 651 if (cookie->packet_index == 3 && val >> 6 != 0x03) { 652 TRACE("SYNAPTICS: third package begins not with bit 1, 1\n"); 653 cookie->packet_index = 0; 654 return B_UNHANDLED_INTERRUPT; 655 } 656 cookie->buffer[cookie->packet_index] = val; 657 658 cookie->packet_index++; 659 if (cookie->packet_index >= 6) { 660 cookie->packet_index = 0; 661 662 // check if package is a pass through package if true pass it 663 // too the pass through interrupt handle 664 if (sPassthroughDevice->active 665 && sPassthroughDevice->handle_int != NULL 666 && IS_SYN_PT_PACKAGE(cookie->buffer)) { 667 status_t status; 668 669 sPassthroughDevice->history[0].data = cookie->buffer[1]; 670 sPassthroughDevice->handle_int(sPassthroughDevice); 671 sPassthroughDevice->history[0].data = cookie->buffer[4]; 672 sPassthroughDevice->handle_int(sPassthroughDevice); 673 sPassthroughDevice->history[0].data = cookie->buffer[5]; 674 status = sPassthroughDevice->handle_int(sPassthroughDevice); 675 676 if (cookie->dev->packet_size == 4) { 677 sPassthroughDevice->history[0].data = cookie->buffer[2]; 678 status = sPassthroughDevice->handle_int(sPassthroughDevice); 679 } 680 return status; 681 } 682 683 if (packet_buffer_write(cookie->synaptics_ring_buffer, 684 cookie->buffer, cookie->dev->packet_size) 685 != cookie->dev->packet_size) { 686 // buffer is full, drop new data 687 return B_HANDLED_INTERRUPT; 688 } 689 release_sem_etc(cookie->synaptics_sem, 1, B_DO_NOT_RESCHEDULE); 690 691 return B_INVOKE_SCHEDULER; 692 } 693 694 return B_HANDLED_INTERRUPT; 695 } 696 697 698 void 699 synaptics_disconnect(ps2_dev *dev) 700 { 701 synaptics_cookie *cookie = (synaptics_cookie*)dev->cookie; 702 // the mouse device might not be opened at this point 703 INFO("SYNAPTICS: synaptics_disconnect %s\n", dev->name); 704 if ((dev->flags & PS2_FLAG_OPEN) != 0) 705 release_sem(cookie->synaptics_sem); 706 } 707 708 709 device_hooks gSynapticsDeviceHooks = { 710 synaptics_open, 711 synaptics_close, 712 synaptics_freecookie, 713 synaptics_ioctl, 714 synaptics_read, 715 synaptics_write, 716 }; 717