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 typedef struct { 68 uint8 majorVersion; 69 uint8 minorVersion; 70 71 uint8 nExtendedButtons; 72 uint8 firstExtendedButton; 73 uint8 extendedButtonsState; 74 75 bool capExtended : 1; 76 bool capMiddleButton : 1; 77 bool capSleep : 1; 78 bool capFourButtons : 1; 79 bool capMultiFinger : 1; 80 bool capMultiFingerReport : 1; 81 bool capPalmDetection : 1; 82 bool capPassThrough : 1; 83 bool capAdvancedGestures : 1; 84 bool capExtendedWMode : 1; 85 bool capClickPadUniform : 1; 86 int capClickPadButtonCount : 2; 87 } touchpad_info; 88 89 90 const char* kSynapticsPath[4] = { 91 "input/touchpad/ps2/synaptics_0", 92 "input/touchpad/ps2/synaptics_1", 93 "input/touchpad/ps2/synaptics_2", 94 "input/touchpad/ps2/synaptics_3" 95 }; 96 97 98 static touchpad_info sTouchpadInfo; 99 static ps2_dev *sPassthroughDevice = &ps2_device[PS2_DEVICE_SYN_PASSTHROUGH]; 100 101 102 static status_t 103 send_touchpad_arg_timeout(ps2_dev *dev, uint8 arg, bigtime_t timeout) 104 { 105 int8 i; 106 uint8 val[8]; 107 108 for (i = 0; i < 4; i++) { 109 val[2 * i] = (arg >> (6 - 2 * i)) & 3; 110 val[2 * i + 1] = 0xE8; 111 } 112 return ps2_dev_command_timeout(dev, 0xE8, val, 7, NULL, 0, timeout); 113 } 114 115 116 static status_t 117 send_touchpad_arg(ps2_dev *dev, uint8 arg) 118 { 119 return send_touchpad_arg_timeout(dev, arg, 4000000); 120 } 121 122 123 static status_t 124 set_touchpad_mode(ps2_dev *dev, uint8 mode) 125 { 126 uint8 sample_rate = SYN_CHANGE_MODE; 127 send_touchpad_arg(dev, mode); 128 return ps2_dev_command(dev, PS2_CMD_SET_SAMPLE_RATE, &sample_rate, 1, 129 NULL, 0); 130 } 131 132 133 static status_t 134 get_information_query(ps2_dev *dev, uint8 extendedQueries, uint8 query, 135 uint8 val[3]) 136 { 137 if (query == kTrackpointQuirk) { 138 // Special case: this information query is not reported in the 139 // "extended queries", but is still supported when the touchpad has 140 // a pass-through port. 141 if (!sTouchpadInfo.capPassThrough) 142 return B_NOT_SUPPORTED; 143 } else if (query > extendedQueries + 8) 144 return B_NOT_SUPPORTED; 145 146 status_t error = send_touchpad_arg(dev, query); 147 if (error != B_OK) 148 return error; 149 return ps2_dev_command(dev, 0xE9, NULL, 0, val, 3); 150 } 151 152 153 static status_t 154 get_synaptics_movment(synaptics_cookie *cookie, touchpad_movement *_event, bigtime_t timeout) 155 { 156 status_t status; 157 touchpad_movement event = {}; 158 uint8 event_buffer[PS2_MAX_PACKET_SIZE]; 159 uint8 wValue0, wValue1, wValue2, wValue3, wValue; 160 uint32 val32; 161 uint32 xTwelfBit, yTwelfBit; 162 163 status = acquire_sem_etc(cookie->synaptics_sem, 1, B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, 164 timeout); 165 if (status < B_OK) 166 return status; 167 168 if (!cookie->dev->active) { 169 TRACE("SYNAPTICS: read_event: Error device no longer active\n"); 170 return B_ERROR; 171 } 172 173 if (packet_buffer_read(cookie->synaptics_ring_buffer, event_buffer, 174 cookie->dev->packet_size) != cookie->dev->packet_size) { 175 TRACE("SYNAPTICS: error copying buffer\n"); 176 return B_ERROR; 177 } 178 179 event.buttons = event_buffer[0] & 3; 180 event.zPressure = event_buffer[2]; 181 bool isExtended = false; 182 183 if (sTouchpadInfo.capExtended) { 184 wValue0 = event_buffer[3] >> 2 & 1; 185 wValue1 = event_buffer[0] >> 2 & 1; 186 wValue2 = event_buffer[0] >> 4 & 1; 187 wValue3 = event_buffer[0] >> 5 & 1; 188 189 wValue = wValue0; 190 wValue = wValue | (wValue1 << 1); 191 wValue = wValue | (wValue2 << 2); 192 wValue = wValue | (wValue3 << 3); 193 194 195 TRACE("SYNAPTICS: received packet %02x %02x %02x %02x %02x %02x -> W = %d\n", 196 event_buffer[0], event_buffer[1], event_buffer[2], event_buffer[3], event_buffer[4], 197 event_buffer[5], wValue); 198 199 if (wValue <= 1) { 200 // Multiple fingers detected, report the finger count. 201 event.fingers = 2 + wValue; 202 203 // There is a separate "v" value indicating the finger width 204 wValue0 = event_buffer[3] >> 1 & 1; 205 wValue1 = event_buffer[4] >> 1 & 1; 206 wValue2 = event_buffer[2] >> 0 & 1; 207 208 wValue = wValue0; 209 wValue = wValue | (wValue1 << 1); 210 wValue = wValue | (wValue2 << 2); 211 212 event.fingerWidth = wValue * 2; 213 } else if (wValue >= 4) { 214 // wValue = 4 to 15 corresponds to a finger width report for a single finger 215 event.fingerWidth = wValue; 216 event.fingers = 1; 217 } 218 // wValue = 2 - Extended W mode 219 // wValue = 3 - Packet from pass-through device 220 event.gesture = false; 221 222 if (sTouchpadInfo.capExtendedWMode && wValue == 2) { 223 // The extended W can be encoded on 4 bits (values 0-7) or 8 bits (80-FF) 224 uint8_t extendedWValue = event_buffer[5] >> 4; 225 if (extendedWValue >= 8) 226 extendedWValue = event_buffer[5]; 227 isExtended = true; 228 229 // Extended W = 0 - Scroll wheels 230 if (extendedWValue == 0) { 231 event.wheel_ydelta = event_buffer[2]; 232 event.wheel_xdelta = event_buffer[3]; 233 event.wheel_zdelta = event_buffer[4]; 234 event.wheel_wdelta = (event_buffer[5] & 0x0f) | (event_buffer[3] & 0x30); 235 // Sign extend wdelta if needed 236 if (event.wheel_wdelta & 0x20) 237 event.wheel_wdelta |= 0xffffffc0; 238 } 239 240 // Extended W = 1 - Secondary finger 241 if (extendedWValue == 1) { 242 event.xPosition = event_buffer[1]; 243 event.yPosition = event_buffer[2]; 244 245 val32 = event_buffer[4] & 0x0F; 246 event.xPosition += val32 << 8; 247 val32 = event_buffer[4] & 0xF0; 248 event.yPosition += val32 << 4; 249 250 event.xPosition *= 2; 251 event.yPosition *= 2; 252 253 event.zPressure = event_buffer[5] & 0x0F; 254 event.zPressure += event_buffer[3] & 0x30; 255 256 // There is a separate "v" value indicating the finger width 257 wValue0 = event_buffer[1] >> 0 & 1; 258 wValue1 = event_buffer[2] >> 0 & 1; 259 wValue2 = event_buffer[5] >> 0 & 1; 260 261 wValue = wValue0; 262 wValue = wValue | (wValue1 << 1); 263 wValue = wValue | (wValue2 << 2); 264 265 event.fingerWidth = wValue * 2; 266 } 267 268 // Extended W = 2 - Finger state info 269 if (extendedWValue == 2) { 270 event.fingers = event_buffer[1] & 0x0F; 271 // TODO this event also provides primary and secondary finger indexes, what do 272 // these mean? 273 } 274 275 // Other values are reserved for other uses (usually enabled with special commands) 276 277 278 *_event = event; 279 280 return status; 281 } 282 283 // Clickpad pretends that all clicks on the touchpad are middle clicks. 284 // Pass them to userspace as left clicks instead. 285 if (sTouchpadInfo.capClickPadButtonCount == 1) 286 event.buttons |= ((event_buffer[0] ^ event_buffer[3]) & 0x01); 287 288 if (sTouchpadInfo.capMiddleButton || sTouchpadInfo.capFourButtons) 289 event.buttons |= ((event_buffer[0] ^ event_buffer[3]) & 0x01) << 2; 290 291 if (sTouchpadInfo.nExtendedButtons > 0) { 292 if (((event_buffer[0] ^ event_buffer[3]) & 0x02) != 0) { 293 // This packet includes extended buttons state. The state is 294 // only reported once when one of the buttons is pressed or 295 // released, so we must keep track of the buttons state. 296 297 // The values replace the lowest bits of the X and Y coordinates 298 // in the packet, we need to extract them from there. 299 300 bool pressed; 301 for (int button = 0; button < sTouchpadInfo.nExtendedButtons; 302 button++) { 303 // Even buttons are in the X byte 304 pressed = event_buffer[4 + button % 2] >> button / 2 & 0x1; 305 if (pressed) { 306 sTouchpadInfo.extendedButtonsState |= 1 << button; 307 } else { 308 sTouchpadInfo.extendedButtonsState &= ~(1 << button); 309 } 310 } 311 } 312 313 event.buttons |= sTouchpadInfo.extendedButtonsState 314 << sTouchpadInfo.firstExtendedButton; 315 } 316 } else { 317 bool finger = event_buffer[0] >> 5 & 1; 318 if (finger) { 319 // finger with normal width 320 event.fingerWidth = 4; 321 } 322 event.gesture = event_buffer[0] >> 2 & 1; 323 } 324 325 if (!isExtended) { 326 event.xPosition = event_buffer[4]; 327 event.yPosition = event_buffer[5]; 328 329 val32 = event_buffer[1] & 0x0F; 330 event.xPosition += val32 << 8; 331 val32 = event_buffer[1] >> 4 & 0x0F; 332 event.yPosition += val32 << 8; 333 334 xTwelfBit = event_buffer[3] >> 4 & 1; 335 event.xPosition += xTwelfBit << 12; 336 yTwelfBit = event_buffer[3] >> 5 & 1; 337 event.yPosition += yTwelfBit << 12; 338 } 339 340 *_event = event; 341 return B_OK; 342 } 343 344 345 static void 346 query_capability(ps2_dev *dev) 347 { 348 uint8 val[3]; 349 uint8 nExtendedQueries = 0; 350 351 get_information_query(dev, nExtendedQueries, kReadCapabilities, val); 352 353 TRACE("SYNAPTICS: extended mode %2x\n", val[0] >> 7 & 1); 354 sTouchpadInfo.capExtended = val[0] >> 7 & 1; 355 TRACE("SYNAPTICS: extended queries %2x\n", val[0] >> 4 & 7); 356 nExtendedQueries = val[0] >> 4 & 7; 357 TRACE("SYNAPTICS: middle button %2x\n", val[0] >> 2 & 1); 358 sTouchpadInfo.capMiddleButton = val[0] >> 2 & 1; 359 360 TRACE("SYNAPTICS: pass through %2x\n", val[2] >> 7 & 1); 361 sTouchpadInfo.capPassThrough = val[2] >> 7 & 1; 362 363 // bit 6, low power, is only informative (touchpad has an automatic powersave mode) 364 365 TRACE("SYNAPTICS: multi finger report %2x\n", val[2] >> 5 & 1); 366 sTouchpadInfo.capMultiFingerReport = val[2] >> 5 & 1; 367 368 TRACE("SYNAPTICS: sleep mode %2x\n", val[2] >> 4 & 1); 369 sTouchpadInfo.capSleep = val[2] >> 4 & 1; 370 371 TRACE("SYNAPTICS: four buttons %2x\n", val[2] >> 3 & 1); 372 sTouchpadInfo.capFourButtons = val[2] >> 3 & 1; 373 374 // bit 2, TouchStyk ballistics, not further documented in the documents I have 375 376 TRACE("SYNAPTICS: multi finger %2x\n", val[2] >> 1 & 1); 377 sTouchpadInfo.capMultiFinger = val[2] >> 1 & 1; 378 379 TRACE("SYNAPTICS: palm detection %2x\n", val[2] & 1); 380 sTouchpadInfo.capPalmDetection = val[2] & 1; 381 382 if (get_information_query(dev, nExtendedQueries, kContinuedCapabilities, 383 val) == B_OK) { 384 sTouchpadInfo.capAdvancedGestures = val[0] >> 3 & 1; 385 TRACE("SYNAPTICS: advanced gestures %x\n", sTouchpadInfo.capAdvancedGestures); 386 387 sTouchpadInfo.capClickPadButtonCount = (val[0] >> 4 & 1) | ((val[1] >> 0 & 1) << 1); 388 sTouchpadInfo.capClickPadUniform = val[1] >> 4 & 1; 389 TRACE("SYNAPTICS: clickpad buttons: %x\n", sTouchpadInfo.capClickPadButtonCount); 390 TRACE("SYNAPTICS: clickpad type: %s\n", 391 sTouchpadInfo.capClickPadUniform ? "uniform" : "hinged"); 392 393 } else { 394 sTouchpadInfo.capAdvancedGestures = 0; 395 sTouchpadInfo.capClickPadButtonCount = 0; 396 sTouchpadInfo.capClickPadUniform = 0; 397 sTouchpadInfo.capAdvancedGestures = 0; 398 } 399 400 if (get_information_query(dev, nExtendedQueries, kExtendedModelId, val) 401 != B_OK) { 402 // "Extended Model ID" is not supported, so there cannot be extra 403 // buttons. 404 sTouchpadInfo.nExtendedButtons = 0; 405 sTouchpadInfo.firstExtendedButton = 0; 406 sTouchpadInfo.capExtendedWMode = 0; 407 return; 408 } 409 410 TRACE("SYNAPTICS: extended buttons %2x\n", val[1] >> 4 & 15); 411 sTouchpadInfo.nExtendedButtons = val[1] >> 4 & 15; 412 sTouchpadInfo.extendedButtonsState = 0; 413 414 sTouchpadInfo.capExtendedWMode = val[0] >> 2 & 1; 415 TRACE("SYNAPTICS: extended wmode %2x\n", sTouchpadInfo.capExtendedWMode); 416 417 if (sTouchpadInfo.capFourButtons) 418 sTouchpadInfo.firstExtendedButton = 4; 419 else if (sTouchpadInfo.capMiddleButton) 420 sTouchpadInfo.firstExtendedButton = 3; 421 else 422 sTouchpadInfo.firstExtendedButton = 2; 423 424 // Capability 0x10 is not documented in the Synaptics Touchpad interfacing 425 // guide (at least the versions I could find), but we got the information 426 // from Linux patches: https://lkml.org/lkml/2015/2/6/621 427 if (get_information_query(dev, nExtendedQueries, kTrackpointQuirk, val) 428 != B_OK) 429 return; 430 431 // Workaround for Thinkpad use of the extended buttons: they are 432 // used as buttons for the trackpoint, so they should be reported 433 // as buttons 0, 1, 2 rather than 3, 4, 5. 434 TRACE("SYNAPTICS: alternate buttons %2x\n", val[0] >> 0 & 1); 435 if (val[0] >> 0 & 1) 436 sTouchpadInfo.firstExtendedButton = 0; 437 } 438 439 440 // #pragma mark - exported functions 441 442 443 status_t 444 synaptics_pass_through_set_packet_size(ps2_dev *dev, uint8 size) 445 { 446 synaptics_cookie *synapticsCookie 447 = (synaptics_cookie*)dev->parent_dev->cookie; 448 449 status_t status = ps2_dev_command(dev->parent_dev, PS2_CMD_DISABLE, NULL, 450 0, NULL, 0); 451 if (status < B_OK) { 452 INFO("SYNAPTICS: cannot disable touchpad %s\n", dev->parent_dev->name); 453 return B_ERROR; 454 } 455 456 synapticsCookie->packet_index = 0; 457 458 if (size == 4) 459 synapticsCookie->mode |= SYN_FOUR_BYTE_CHILD; 460 else 461 synapticsCookie->mode &= ~SYN_FOUR_BYTE_CHILD; 462 463 set_touchpad_mode(dev->parent_dev, synapticsCookie->mode); 464 465 status = ps2_dev_command(dev->parent_dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); 466 if (status < B_OK) { 467 INFO("SYNAPTICS: cannot enable touchpad %s\n", dev->parent_dev->name); 468 return B_ERROR; 469 } 470 return status; 471 } 472 473 474 status_t 475 passthrough_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int outCount, 476 uint8 *in, int inCount, bigtime_t timeout) 477 { 478 status_t status; 479 uint8 passThroughCmd = SYN_PASSTHROUGH_CMD; 480 uint8 val; 481 uint32 passThroughInCount = (inCount + 1) * 6; 482 uint8 passThroughIn[passThroughInCount]; 483 int8 i; 484 485 TRACE("SYNAPTICS: passthrough command 0x%x\n", cmd); 486 487 status = ps2_dev_command(dev->parent_dev, PS2_CMD_DISABLE, NULL, 0, 488 NULL, 0); 489 if (status != B_OK) 490 return status; 491 492 for (i = -1; i < outCount; i++) { 493 if (i == -1) 494 val = cmd; 495 else 496 val = out[i]; 497 status = send_touchpad_arg_timeout(dev->parent_dev, val, timeout); 498 if (status != B_OK) 499 goto finalize; 500 if (i != outCount -1) { 501 status = ps2_dev_command_timeout(dev->parent_dev, 502 PS2_CMD_SET_SAMPLE_RATE, &passThroughCmd, 1, NULL, 0, timeout); 503 if (status != B_OK) 504 goto finalize; 505 } 506 } 507 status = ps2_dev_command_timeout(dev->parent_dev, PS2_CMD_SET_SAMPLE_RATE, 508 &passThroughCmd, 1, passThroughIn, passThroughInCount, timeout); 509 if (status != B_OK) 510 goto finalize; 511 512 for (i = 0; i < inCount + 1; i++) { 513 uint8 *inPointer = &passThroughIn[i * 6]; 514 if (!IS_SYN_PT_PACKAGE(inPointer)) { 515 TRACE("SYNAPTICS: not a pass throught package\n"); 516 goto finalize; 517 } 518 if (i == 0) 519 continue; 520 521 in[i - 1] = passThroughIn[i * 6 + 1]; 522 } 523 524 finalize: 525 status_t statusOfEnable = ps2_dev_command(dev->parent_dev, PS2_CMD_ENABLE, 526 NULL, 0, NULL, 0); 527 if (statusOfEnable != B_OK) { 528 TRACE("SYNAPTICS: enabling of parent failed: 0x%" B_PRIx32 ".\n", 529 statusOfEnable); 530 } 531 532 return status != B_OK ? status : statusOfEnable; 533 } 534 535 536 status_t 537 probe_synaptics(ps2_dev *dev) 538 { 539 uint8 val[3]; 540 uint8 deviceId; 541 status_t status; 542 TRACE("SYNAPTICS: probe\n"); 543 544 // We reset the device here because it may have been left in a confused 545 // state by a previous probing attempt. Some synaptics touchpads are known 546 // to lockup when we attempt to detect them as IBM trackpoints. 547 ps2_reset_mouse(dev); 548 549 // Request "Identify touchpad" 550 // The touchpad will delay this, until it's ready and calibrated. 551 status = get_information_query(dev, 0, kIdentify, val); 552 if (status != B_OK) 553 return status; 554 555 sTouchpadInfo.minorVersion = val[0]; 556 deviceId = val[1]; 557 if (deviceId != SYN_TOUCHPAD) { 558 TRACE("SYNAPTICS: not found\n"); 559 return B_ERROR; 560 } 561 562 TRACE("SYNAPTICS: Touchpad found id:l %2x\n", deviceId); 563 sTouchpadInfo.majorVersion = val[2] & 0x0F; 564 TRACE("SYNAPTICS: version %d.%d\n", sTouchpadInfo.majorVersion, 565 sTouchpadInfo.minorVersion); 566 // version >= 4.0? 567 if (sTouchpadInfo.minorVersion <= 2 568 && sTouchpadInfo.majorVersion <= 3) { 569 TRACE("SYNAPTICS: too old touchpad not supported\n"); 570 return B_ERROR; 571 } 572 dev->name = kSynapticsPath[dev->idx]; 573 return B_OK; 574 } 575 576 577 // #pragma mark - Device functions 578 579 580 status_t 581 synaptics_open(const char *name, uint32 flags, void **_cookie) 582 { 583 status_t status; 584 synaptics_cookie *cookie; 585 ps2_dev *dev; 586 int i; 587 588 for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) { 589 if (0 == strcmp(ps2_device[i].name, name)) { 590 dev = &ps2_device[i]; 591 break; 592 } 593 } 594 595 if (dev == NULL) { 596 TRACE("ps2: dev = NULL\n"); 597 return B_ERROR; 598 } 599 600 if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN) 601 return B_BUSY; 602 603 cookie = (synaptics_cookie*)malloc(sizeof(synaptics_cookie)); 604 if (cookie == NULL) 605 goto err1; 606 memset(cookie, 0, sizeof(*cookie)); 607 608 *_cookie = cookie; 609 610 cookie->dev = dev; 611 dev->cookie = cookie; 612 dev->disconnect = &synaptics_disconnect; 613 dev->handle_int = &synaptics_handle_int; 614 615 gHardwareSpecs.edgeMotionWidth = SYN_EDGE_MOTION_WIDTH; 616 617 gHardwareSpecs.areaStartX = SYN_AREA_START_X; 618 gHardwareSpecs.areaEndX = SYN_AREA_END_X; 619 gHardwareSpecs.areaStartY = SYN_AREA_START_Y; 620 gHardwareSpecs.areaEndY = SYN_AREA_END_Y; 621 622 gHardwareSpecs.minPressure = MIN_PRESSURE; 623 gHardwareSpecs.realMaxPressure = REAL_MAX_PRESSURE; 624 gHardwareSpecs.maxPressure = MAX_PRESSURE; 625 626 dev->packet_size = PS2_PACKET_SYNAPTICS; 627 628 cookie->synaptics_ring_buffer 629 = create_packet_buffer(SYNAPTICS_HISTORY_SIZE * dev->packet_size); 630 if (cookie->synaptics_ring_buffer == NULL) { 631 TRACE("ps2: can't allocate mouse actions buffer\n"); 632 goto err2; 633 } 634 635 // create the mouse semaphore, used for synchronization between 636 // the interrupt handler and the read operation 637 cookie->synaptics_sem = create_sem(0, "ps2_synaptics_sem"); 638 if (cookie->synaptics_sem < 0) { 639 TRACE("SYNAPTICS: failed creating semaphore!\n"); 640 goto err3; 641 } 642 query_capability(dev); 643 644 // create pass through dev 645 if (sTouchpadInfo.capPassThrough) { 646 TRACE("SYNAPTICS: pass through detected\n"); 647 sPassthroughDevice->parent_dev = dev; 648 sPassthroughDevice->idx = dev->idx; 649 ps2_service_notify_device_added(sPassthroughDevice); 650 } 651 652 // Set Mode 653 if (sTouchpadInfo.capExtendedWMode) 654 cookie->mode = SYN_MODE_ABSOLUTE | SYN_MODE_W | SYN_MODE_EXTENDED_W; 655 else if (sTouchpadInfo.capExtended) 656 cookie->mode = SYN_MODE_ABSOLUTE | SYN_MODE_W; 657 else 658 cookie->mode = SYN_MODE_ABSOLUTE; 659 660 status = set_touchpad_mode(dev, cookie->mode); 661 if (status < B_OK) { 662 INFO("SYNAPTICS: cannot set mode %s\n", name); 663 goto err4; 664 } 665 666 status = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); 667 if (status < B_OK) { 668 INFO("SYNAPTICS: cannot enable touchpad %s\n", name); 669 goto err4; 670 } 671 672 atomic_or(&dev->flags, PS2_FLAG_ENABLED); 673 674 TRACE("SYNAPTICS: open %s success\n", name); 675 return B_OK; 676 677 err4: 678 delete_sem(cookie->synaptics_sem); 679 err3: 680 delete_packet_buffer(cookie->synaptics_ring_buffer); 681 err2: 682 free(cookie); 683 err1: 684 atomic_and(&dev->flags, ~PS2_FLAG_OPEN); 685 686 TRACE("SYNAPTICS: synaptics_open %s failed\n", name); 687 return B_ERROR; 688 } 689 690 691 status_t 692 synaptics_close(void *_cookie) 693 { 694 status_t status; 695 synaptics_cookie *cookie = (synaptics_cookie*)_cookie; 696 697 ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0, 698 150000); 699 700 delete_packet_buffer(cookie->synaptics_ring_buffer); 701 delete_sem(cookie->synaptics_sem); 702 703 atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN); 704 atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED); 705 706 // Reset the touchpad so it generate standard ps2 packets instead of 707 // extended ones. If not, BeOS is confused with such packets when rebooting 708 // without a complete shutdown. 709 status = ps2_reset_mouse(cookie->dev); 710 if (status != B_OK) { 711 INFO("ps2_synaptics: reset failed\n"); 712 return B_ERROR; 713 } 714 715 if (sTouchpadInfo.capPassThrough) 716 ps2_service_notify_device_removed(sPassthroughDevice); 717 718 TRACE("SYNAPTICS: close %s done\n", cookie->dev->name); 719 return B_OK; 720 } 721 722 723 status_t 724 synaptics_freecookie(void *_cookie) 725 { 726 free(_cookie); 727 return B_OK; 728 } 729 730 731 static status_t 732 synaptics_read(void *cookie, off_t pos, void *buffer, size_t *_length) 733 { 734 *_length = 0; 735 return B_NOT_ALLOWED; 736 } 737 738 739 static status_t 740 synaptics_write(void *cookie, off_t pos, const void *buffer, size_t *_length) 741 { 742 *_length = 0; 743 return B_NOT_ALLOWED; 744 } 745 746 747 status_t 748 synaptics_ioctl(void *_cookie, uint32 op, void *buffer, size_t length) 749 { 750 synaptics_cookie *cookie = (synaptics_cookie*)_cookie; 751 touchpad_read read; 752 status_t status; 753 754 switch (op) { 755 case MS_IS_TOUCHPAD: 756 TRACE("SYNAPTICS: MS_IS_TOUCHPAD\n"); 757 if (buffer == NULL) 758 return B_OK; 759 return user_memcpy(buffer, &gHardwareSpecs, sizeof(gHardwareSpecs)); 760 761 case MS_READ_TOUCHPAD: 762 TRACE("SYNAPTICS: MS_READ get event\n"); 763 if (user_memcpy(&read.timeout, &(((touchpad_read*)buffer)->timeout), 764 sizeof(bigtime_t)) != B_OK) 765 return B_BAD_ADDRESS; 766 if ((status = get_synaptics_movment(cookie, &read.u.touchpad, read.timeout)) != B_OK) 767 return status; 768 read.event = MS_READ_TOUCHPAD; 769 return user_memcpy(buffer, &read, sizeof(read)); 770 771 default: 772 TRACE("SYNAPTICS: unknown opcode: %" B_PRIu32 "\n", op); 773 return B_DEV_INVALID_IOCTL; 774 } 775 } 776 777 778 int32 779 synaptics_handle_int(ps2_dev *dev) 780 { 781 synaptics_cookie *cookie = (synaptics_cookie*)dev->cookie; 782 uint8 val; 783 784 val = cookie->dev->history[0].data; 785 786 if ((cookie->packet_index == 0 || cookie->packet_index == 3) && (val & 8) != 0) { 787 INFO("SYNAPTICS: bad mouse data %#02x, trying resync\n", val); 788 cookie->packet_index = 0; 789 return B_UNHANDLED_INTERRUPT; 790 } 791 if (cookie->packet_index == 0 && val >> 6 != 0x02) { 792 TRACE("SYNAPTICS: first package %#02x begins not with bit 1, 0\n", val); 793 return B_UNHANDLED_INTERRUPT; 794 } 795 if (cookie->packet_index == 3 && val >> 6 != 0x03) { 796 TRACE("SYNAPTICS: third package %#02x begins not with bit 1, 1\n", val); 797 cookie->packet_index = 0; 798 return B_UNHANDLED_INTERRUPT; 799 } 800 cookie->buffer[cookie->packet_index] = val; 801 802 cookie->packet_index++; 803 if (cookie->packet_index >= 6) { 804 cookie->packet_index = 0; 805 806 // check if package is a pass through package if true pass it 807 // too the pass through interrupt handle 808 if (sPassthroughDevice->active 809 && sPassthroughDevice->handle_int != NULL 810 && IS_SYN_PT_PACKAGE(cookie->buffer)) { 811 TRACE("SYNAPTICS: forward packet to passthrough device\n"); 812 status_t status; 813 814 sPassthroughDevice->history[0].data = cookie->buffer[1]; 815 sPassthroughDevice->handle_int(sPassthroughDevice); 816 sPassthroughDevice->history[0].data = cookie->buffer[4]; 817 sPassthroughDevice->handle_int(sPassthroughDevice); 818 sPassthroughDevice->history[0].data = cookie->buffer[5]; 819 status = sPassthroughDevice->handle_int(sPassthroughDevice); 820 821 if (cookie->dev->packet_size == 4) { 822 sPassthroughDevice->history[0].data = cookie->buffer[2]; 823 status = sPassthroughDevice->handle_int(sPassthroughDevice); 824 } 825 return status; 826 } 827 828 if (packet_buffer_write(cookie->synaptics_ring_buffer, 829 cookie->buffer, cookie->dev->packet_size) 830 != cookie->dev->packet_size) { 831 // buffer is full, drop new data 832 return B_HANDLED_INTERRUPT; 833 } 834 release_sem_etc(cookie->synaptics_sem, 1, B_DO_NOT_RESCHEDULE); 835 836 return B_INVOKE_SCHEDULER; 837 } 838 839 return B_HANDLED_INTERRUPT; 840 } 841 842 843 void 844 synaptics_disconnect(ps2_dev *dev) 845 { 846 synaptics_cookie *cookie = (synaptics_cookie*)dev->cookie; 847 // the mouse device might not be opened at this point 848 INFO("SYNAPTICS: synaptics_disconnect %s\n", dev->name); 849 if ((dev->flags & PS2_FLAG_OPEN) != 0) 850 release_sem(cookie->synaptics_sem); 851 } 852 853 854 device_hooks gSynapticsDeviceHooks = { 855 synaptics_open, 856 synaptics_close, 857 synaptics_freecookie, 858 synaptics_ioctl, 859 synaptics_read, 860 synaptics_write, 861 }; 862