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