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