1 /* 2 * Copyright 2013, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Hardware specs taken from the linux driver, thanks a lot! 6 * Based on ps2_alps.c 7 * 8 * Authors: 9 * Jérôme Duval <korli@users.berlios.de> 10 */ 11 12 13 #include "ps2_elantech.h" 14 15 #include <stdlib.h> 16 #include <string.h> 17 18 #include "ps2_service.h" 19 20 21 static int32 generate_event(timer* timer); 22 23 24 const bigtime_t kEventInterval = 1000 * 50; 25 26 27 class EventProducer { 28 public: 29 EventProducer() 30 { 31 fFired = false; 32 } 33 34 status_t 35 FireEvent(elantech_cookie* cookie, uint8* package) 36 { 37 fCookie = cookie; 38 memcpy(fLastPackage, package, sizeof(uint8) * PS2_PACKET_ELANTECH); 39 40 status_t status = add_timer(&fEventTimer, &generate_event, 41 kEventInterval, B_ONE_SHOT_RELATIVE_TIMER); 42 if (status == B_OK) 43 fFired = true; 44 return status; 45 } 46 47 bool 48 CancelEvent() 49 { 50 if (!fFired) 51 return false; 52 fFired = false; 53 return cancel_timer(&fEventTimer); 54 } 55 56 void 57 InjectEvent() 58 { 59 if (packet_buffer_write(fCookie->ring_buffer, fLastPackage, 60 PS2_PACKET_ELANTECH) != PS2_PACKET_ELANTECH) { 61 // buffer is full, drop new data 62 return; 63 } 64 release_sem_etc(fCookie->sem, 1, B_DO_NOT_RESCHEDULE); 65 } 66 67 private: 68 bool fFired; 69 uint8 fLastPackage[PS2_PACKET_ELANTECH]; 70 timer fEventTimer; 71 elantech_cookie* fCookie; 72 }; 73 74 75 static EventProducer gEventProducer; 76 77 78 static int32 79 generate_event(timer* timer) 80 { 81 gEventProducer.InjectEvent(); 82 return 0; 83 } 84 85 86 const char* kElantechPath[4] = { 87 "input/touchpad/ps2/elantech_0", 88 "input/touchpad/ps2/elantech_1", 89 "input/touchpad/ps2/elantech_2", 90 "input/touchpad/ps2/elantech_3" 91 }; 92 93 94 #define ELANTECH_CMD_GET_ID 0x00 95 #define ELANTECH_CMD_GET_VERSION 0x01 96 #define ELANTECH_CMD_GET_CAPABILITIES 0x02 97 #define ELANTECH_CMD_GET_SAMPLE 0x03 98 #define ELANTECH_CMD_GET_RESOLUTION 0x04 99 100 #define ELANTECH_CMD_REGISTER_READ 0x10 101 #define ELANTECH_CMD_REGISTER_WRITE 0x11 102 #define ELANTECH_CMD_REGISTER_READWRITE 0x00 103 #define ELANTECH_CMD_PS2_CUSTOM_CMD 0xf8 104 105 106 // touchpad proportions 107 #define EDGE_MOTION_WIDTH 55 108 109 #define MIN_PRESSURE 0 110 #define REAL_MAX_PRESSURE 50 111 #define MAX_PRESSURE 255 112 113 #define ELANTECH_HISTORY_SIZE 256 114 115 116 static hardware_specs gHardwareSpecs; 117 118 119 static status_t 120 get_elantech_movement(elantech_cookie *cookie, mouse_movement *movement) 121 { 122 touch_event event; 123 uint8 event_buffer[PS2_PACKET_ELANTECH]; 124 125 status_t status = acquire_sem_etc(cookie->sem, 1, B_CAN_INTERRUPT, 0); 126 if (status < B_OK) 127 return status; 128 129 if (!cookie->dev->active) { 130 TRACE("ELANTECH: read_event: Error device no longer active\n"); 131 return B_ERROR; 132 } 133 134 if (packet_buffer_read(cookie->ring_buffer, event_buffer, 135 cookie->dev->packet_size) != cookie->dev->packet_size) { 136 TRACE("ELANTECH: error copying buffer\n"); 137 return B_ERROR; 138 } 139 140 if (cookie->crcEnabled && (event_buffer[3] & 0x08) != 0) { 141 TRACE("ELANTECH: bad crc buffer\n"); 142 return B_ERROR; 143 } else if (!cookie->crcEnabled && ((event_buffer[0] & 0x0c) != 0x04 144 || (event_buffer[3] & 0x1c) != 0x10)) { 145 TRACE("ELANTECH: bad crc buffer\n"); 146 return B_ERROR; 147 } 148 uint8 type = event_buffer[3] & 3; 149 TRACE("ELANTECH: packet type %d\n", type); 150 TRACE("ELANTECH: packet content 0x%02x%02x%02x%02x%02x%02x\n", 151 event_buffer[0], event_buffer[1], event_buffer[2], event_buffer[3], 152 event_buffer[4], event_buffer[5]); 153 switch (type) { 154 case 0: 155 // fingers 156 cookie->fingers = event_buffer[1] & 0x1f; 157 break; 158 case 1: 159 if ((((event_buffer[3] & 0xe0) >> 5) - 1) != 0) { 160 // only process first finger 161 return B_OK; 162 } 163 event.zPressure = (event_buffer[1] & 0xf0) 164 | ((event_buffer[4] & 0xf0) >> 4); 165 166 cookie->previousZ = event.zPressure; 167 168 event.xPosition = ((event_buffer[1] & 0xf) << 8) | event_buffer[2]; 169 event.yPosition = (((event_buffer[4] & 0xf) << 8) 170 | event_buffer[5]); 171 TRACE("ELANTECH: buttons 0x%x x %ld y %ld z %d\n", 172 event.buttons, event.xPosition, event.yPosition, 173 event.zPressure); 174 break; 175 case 2: 176 TRACE("ELANTECH: packet type motion\n"); 177 // TODO 178 return B_OK; 179 default: 180 TRACE("ELANTECH: unknown packet type %d\n", type); 181 return B_ERROR; 182 } 183 184 event.buttons = 0; 185 // finger on touchpad 186 if ((cookie->fingers & 1) != 0) { 187 // finger with normal width 188 event.wValue = 4; 189 } else { 190 event.wValue = 3; 191 } 192 status = cookie->movementMaker.EventToMovement(&event, movement); 193 194 if (cookie->movementMaker.WasEdgeMotion() 195 || cookie->movementMaker.TapDragStarted()) { 196 gEventProducer.FireEvent(cookie, event_buffer); 197 } 198 199 return status; 200 } 201 202 203 static void 204 default_settings(touchpad_settings *set) 205 { 206 memcpy(set, &kDefaultTouchpadSettings, sizeof(touchpad_settings)); 207 } 208 209 210 static status_t 211 synaptics_dev_send_command(ps2_dev* dev, uint8 cmd, uint8 *in, int in_count) 212 { 213 if (ps2_dev_sliced_command(dev, cmd) != B_OK 214 || ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, in, in_count) 215 != B_OK) { 216 TRACE("ELANTECH: synaptics_dev_send_command failed\n"); 217 return B_ERROR; 218 } 219 return B_OK; 220 } 221 222 223 static status_t 224 elantech_dev_send_command(ps2_dev* dev, uint8 cmd, uint8 *in, int in_count) 225 { 226 if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 227 || ps2_dev_command(dev, cmd) != B_OK 228 || ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, in, in_count) 229 != B_OK) { 230 TRACE("ELANTECH: elantech_dev_send_command failed\n"); 231 return B_ERROR; 232 } 233 return B_OK; 234 } 235 236 237 status_t 238 probe_elantech(ps2_dev* dev) 239 { 240 uint8 val[3]; 241 TRACE("ELANTECH: probe\n"); 242 243 ps2_dev_command(dev, PS2_CMD_MOUSE_RESET_DIS); 244 245 if (ps2_dev_command(dev, PS2_CMD_DISABLE) != B_OK 246 || ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK 247 || ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK 248 || ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK) { 249 TRACE("ELANTECH: not found (1)\n"); 250 return B_ERROR; 251 } 252 253 if (ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, val, 3) 254 != B_OK) { 255 TRACE("ELANTECH: not found (2)\n"); 256 return B_ERROR; 257 } 258 259 if (val[0] != 0x3c || val[1] != 0x3 || (val[2] != 0xc8 && val[2] != 0x0)) { 260 TRACE("ELANTECH: not found (3)\n"); 261 return B_ERROR; 262 } 263 264 val[0] = 0; 265 if (synaptics_dev_send_command(dev, ELANTECH_CMD_GET_VERSION, val, 3) 266 != B_OK) { 267 TRACE("ELANTECH: not found (4)\n"); 268 return B_ERROR; 269 } 270 271 if (val[0] == 0x0 || val[2] == 10 || val[2] == 20 || val[2] == 40 272 || val[2] == 60 || val[2] == 80 || val[2] == 100 || val[2] == 200) { 273 TRACE("ELANTECH: not found (5)\n"); 274 return B_ERROR; 275 } 276 277 INFO("Elantech found\n"); 278 279 dev->name = kElantechPath[dev->idx]; 280 dev->packet_size = PS2_PACKET_ELANTECH; 281 282 return B_OK; 283 } 284 285 286 static status_t 287 elantech_write_reg(elantech_cookie* cookie, uint8 reg, uint8 value) 288 { 289 if (reg < 0x7 || reg > 0x26) 290 return B_BAD_VALUE; 291 if (reg > 0x11 && reg < 0x20) 292 return B_BAD_VALUE; 293 294 ps2_dev* dev = cookie->dev; 295 switch (cookie->version) { 296 case 1: 297 // TODO 298 return B_ERROR; 299 break; 300 case 2: 301 if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 302 || ps2_dev_command(dev, ELANTECH_CMD_REGISTER_WRITE) != B_OK 303 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 304 || ps2_dev_command(dev, reg) != B_OK 305 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 306 || ps2_dev_command(dev, value) != B_OK 307 || ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK) 308 return B_ERROR; 309 break; 310 case 3: 311 if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 312 || ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READWRITE) != B_OK 313 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 314 || ps2_dev_command(dev, reg) != B_OK 315 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 316 || ps2_dev_command(dev, value) != B_OK 317 || ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK) 318 return B_ERROR; 319 break; 320 case 4: 321 if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 322 || ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READWRITE) != B_OK 323 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 324 || ps2_dev_command(dev, reg) != B_OK 325 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 326 || ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READWRITE) != B_OK 327 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 328 || ps2_dev_command(dev, value) != B_OK 329 || ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK) 330 return B_ERROR; 331 break; 332 default: 333 TRACE("ELANTECH: read_write_reg: unknown version\n"); 334 return B_ERROR; 335 } 336 return B_OK; 337 } 338 339 340 static status_t 341 elantech_read_reg(elantech_cookie* cookie, uint8 reg, uint8 *value) 342 { 343 if (reg < 0x7 || reg > 0x26) 344 return B_BAD_VALUE; 345 if (reg > 0x11 && reg < 0x20) 346 return B_BAD_VALUE; 347 348 ps2_dev* dev = cookie->dev; 349 uint8 val[3]; 350 switch (cookie->version) { 351 case 1: 352 // TODO 353 return B_ERROR; 354 break; 355 case 2: 356 if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 357 || ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READ) != B_OK 358 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 359 || ps2_dev_command(dev, reg) != B_OK 360 || ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, val, 361 3) != B_OK) 362 return B_ERROR; 363 break; 364 case 3: 365 case 4: 366 if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 367 || ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READWRITE) 368 != B_OK 369 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK 370 || ps2_dev_command(dev, reg) != B_OK 371 || ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, val, 372 3) != B_OK) 373 return B_ERROR; 374 break; 375 default: 376 TRACE("ELANTECH: read_write_reg: unknown version\n"); 377 return B_ERROR; 378 } 379 if (cookie->version == 4) 380 *value = val[1]; 381 else 382 *value = val[0]; 383 384 return B_OK; 385 } 386 387 388 static status_t 389 get_resolution_v4(elantech_cookie* cookie, uint32* x, uint32* y) 390 { 391 uint8 val[3]; 392 if (elantech_dev_send_command(cookie->dev, ELANTECH_CMD_GET_RESOLUTION, 393 val, 3) != B_OK) 394 return B_ERROR; 395 *x = (val[1] & 0xf) * 10 + 790; 396 *y = ((val[1] & 0xf) >> 4) * 10 + 790; 397 return B_OK; 398 } 399 400 401 static status_t 402 get_range(elantech_cookie* cookie, uint32* x_min, uint32* y_min, uint32* x_max, 403 uint32* y_max, uint32 *width) 404 { 405 uint8 val[3]; 406 switch (cookie->version) { 407 case 1: 408 *x_min = 32; 409 *y_min = 32; 410 *x_max = 544; 411 *y_max = 344; 412 *width = 0; 413 break; 414 case 2: 415 // TODO 416 break; 417 case 3: 418 if ((cookie->send_command)(cookie->dev, ELANTECH_CMD_GET_ID, val, 3) 419 != B_OK) { 420 return B_ERROR; 421 } 422 *x_min = 0; 423 *y_min = 0; 424 *x_max = ((val[0] & 0xf) << 8) | val[1]; 425 *y_max = ((val[0] & 0xf0) << 4) | val[2]; 426 *width = 0; 427 break; 428 case 4: 429 if ((cookie->send_command)(cookie->dev, ELANTECH_CMD_GET_ID, val, 3) 430 != B_OK) { 431 return B_ERROR; 432 } 433 *x_min = 0; 434 *y_min = 0; 435 *x_max = ((val[0] & 0xf) << 8) | val[1]; 436 *y_max = ((val[0] & 0xf0) << 4) | val[2]; 437 if (cookie->capabilities[1] < 2 || cookie->capabilities[1] > *x_max) 438 return B_ERROR; 439 *width = *x_max / (cookie->capabilities[1] - 1); 440 break; 441 } 442 return B_OK; 443 } 444 445 446 static status_t 447 enable_absolute_mode(elantech_cookie* cookie) 448 { 449 status_t status = B_OK; 450 switch (cookie->version) { 451 case 1: 452 status = elantech_write_reg(cookie, 0x10, 0x16); 453 if (status == B_OK) 454 status = elantech_write_reg(cookie, 0x11, 0x8f); 455 break; 456 case 2: 457 status = elantech_write_reg(cookie, 0x10, 0x54); 458 if (status == B_OK) 459 status = elantech_write_reg(cookie, 0x11, 0x88); 460 if (status == B_OK) 461 status = elantech_write_reg(cookie, 0x12, 0x60); 462 break; 463 case 3: 464 status = elantech_write_reg(cookie, 0x10, 0xb); 465 break; 466 case 4: 467 status = elantech_write_reg(cookie, 0x7, 0x1); 468 break; 469 470 } 471 472 if (cookie->version < 4) { 473 uint8 val; 474 475 for (uint8 retry = 0; retry < 5; retry++) { 476 status = elantech_read_reg(cookie, 0x10, &val); 477 if (status != B_OK) 478 break; 479 snooze(100); 480 } 481 } 482 483 return status; 484 } 485 486 487 status_t 488 elantech_open(const char *name, uint32 flags, void **_cookie) 489 { 490 TRACE("ELANTECH: open %s\n", name); 491 ps2_dev* dev; 492 int i; 493 for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) { 494 if (0 == strcmp(ps2_device[i].name, name)) { 495 dev = &ps2_device[i]; 496 break; 497 } 498 } 499 500 if (dev == NULL) { 501 TRACE("ps2: dev = NULL\n"); 502 return B_ERROR; 503 } 504 505 if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN) 506 return B_BUSY; 507 508 elantech_cookie* cookie = (elantech_cookie*)malloc( 509 sizeof(elantech_cookie)); 510 if (cookie == NULL) 511 goto err1; 512 memset(cookie, 0, sizeof(*cookie)); 513 514 cookie->movementMaker.Init(); 515 cookie->previousZ = 0; 516 *_cookie = cookie; 517 518 cookie->dev = dev; 519 dev->cookie = cookie; 520 dev->disconnect = &elantech_disconnect; 521 dev->handle_int = &elantech_handle_int; 522 523 default_settings(&cookie->settings); 524 525 dev->packet_size = PS2_PACKET_ELANTECH; 526 527 cookie->ring_buffer = create_packet_buffer( 528 ELANTECH_HISTORY_SIZE * dev->packet_size); 529 if (cookie->ring_buffer == NULL) { 530 TRACE("ELANTECH: can't allocate mouse actions buffer\n"); 531 goto err2; 532 } 533 // create the mouse semaphore, used for synchronization between 534 // the interrupt handler and the read operation 535 cookie->sem = create_sem(0, "ps2_elantech_sem"); 536 if (cookie->sem < 0) { 537 TRACE("ELANTECH: failed creating semaphore!\n"); 538 goto err3; 539 } 540 541 uint8 val[3]; 542 if (synaptics_dev_send_command(dev, ELANTECH_CMD_GET_VERSION, val, 3) 543 != B_OK) { 544 TRACE("ELANTECH: get version failed!\n"); 545 goto err4; 546 } 547 cookie->fwVersion = (val[0] << 16) | (val[1] << 8) | val[2]; 548 if (cookie->fwVersion < 0x020030 || cookie->fwVersion == 0x020600) 549 cookie->version = 1; 550 else { 551 switch (val[0] & 0xf) { 552 case 2: 553 case 4: 554 cookie->version = 2; 555 break; 556 case 5: 557 cookie->version = 3; 558 break; 559 case 6: 560 case 7: 561 cookie->version = 4; 562 break; 563 default: 564 TRACE("ELANTECH: unknown version!\n"); 565 goto err4; 566 } 567 } 568 TRACE("ELANTECH: version 0x%lx (0x%lx)\n", cookie->version, 569 cookie->fwVersion); 570 571 if (cookie->version >= 3) 572 cookie->send_command = &elantech_dev_send_command; 573 else 574 cookie->send_command = &synaptics_dev_send_command; 575 cookie->crcEnabled = (cookie->fwVersion & 0x4000) == 0x4000; 576 577 if ((cookie->send_command)(cookie->dev, ELANTECH_CMD_GET_CAPABILITIES, 578 cookie->capabilities, 3) != B_OK) { 579 TRACE("ELANTECH: get capabilities failed!\n"); 580 return B_ERROR; 581 } 582 583 if (enable_absolute_mode(cookie) != B_OK) { 584 TRACE("ELANTECH: failed enabling absolute mode!\n"); 585 goto err4; 586 } 587 TRACE("ELANTECH: enabled absolute mode!\n"); 588 589 uint32 x_min, x_max, y_min, y_max, width; 590 if (get_range(cookie, &x_min, &y_min, &x_max, &y_max, &width) != B_OK) { 591 TRACE("ELANTECH: get range failed!\n"); 592 goto err4; 593 } 594 595 TRACE("ELANTECH: range x %ld-%ld y %ld-%ld (%ld)\n", x_min, x_max, 596 y_min, y_max, width); 597 598 uint32 x_res, y_res; 599 if (get_resolution_v4(cookie, &x_res, &y_res) != B_OK) { 600 TRACE("ELANTECH: get resolution failed!\n"); 601 goto err4; 602 } 603 604 TRACE("ELANTECH: resolution x %ld y %ld (dpi)\n", x_res, y_res); 605 606 gHardwareSpecs.edgeMotionWidth = EDGE_MOTION_WIDTH; 607 608 gHardwareSpecs.areaStartX = x_min; 609 gHardwareSpecs.areaEndX = x_max; 610 gHardwareSpecs.areaStartY = y_min; 611 gHardwareSpecs.areaEndY = y_max; 612 613 gHardwareSpecs.minPressure = MIN_PRESSURE; 614 gHardwareSpecs.realMaxPressure = REAL_MAX_PRESSURE; 615 gHardwareSpecs.maxPressure = MAX_PRESSURE; 616 617 cookie->movementMaker.SetSettings(&cookie->settings); 618 cookie->movementMaker.SetSpecs(&gHardwareSpecs); 619 620 if (ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0) != B_OK) 621 goto err4; 622 623 atomic_or(&dev->flags, PS2_FLAG_ENABLED); 624 625 TRACE("ELANTECH: open %s success\n", name); 626 return B_OK; 627 628 err4: 629 delete_sem(cookie->sem); 630 err3: 631 delete_packet_buffer(cookie->ring_buffer); 632 err2: 633 free(cookie); 634 err1: 635 atomic_and(&dev->flags, ~PS2_FLAG_OPEN); 636 637 TRACE("ELANTECH: open %s failed\n", name); 638 return B_ERROR; 639 } 640 641 642 status_t 643 elantech_close(void *_cookie) 644 { 645 gEventProducer.CancelEvent(); 646 647 elantech_cookie *cookie = (elantech_cookie*)_cookie; 648 649 ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0, 650 150000); 651 652 delete_packet_buffer(cookie->ring_buffer); 653 delete_sem(cookie->sem); 654 655 atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN); 656 atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED); 657 658 // Reset the touchpad so it generate standard ps2 packets instead of 659 // extended ones. If not, BeOS is confused with such packets when rebooting 660 // without a complete shutdown. 661 status_t status = ps2_reset_mouse(cookie->dev); 662 if (status != B_OK) { 663 INFO("ps2: reset failed\n"); 664 return B_ERROR; 665 } 666 667 TRACE("ELANTECH: close %s done\n", cookie->dev->name); 668 return B_OK; 669 } 670 671 672 status_t 673 elantech_freecookie(void *_cookie) 674 { 675 free(_cookie); 676 return B_OK; 677 } 678 679 680 status_t 681 elantech_ioctl(void *_cookie, uint32 op, void *buffer, size_t length) 682 { 683 elantech_cookie *cookie = (elantech_cookie*)_cookie; 684 mouse_movement movement; 685 status_t status; 686 687 switch (op) { 688 case MS_READ: 689 TRACE("ELANTECH: MS_READ get event\n"); 690 if ((status = get_elantech_movement(cookie, &movement)) != B_OK) 691 return status; 692 return user_memcpy(buffer, &movement, sizeof(movement)); 693 694 case MS_IS_TOUCHPAD: 695 TRACE("ELANTECH: MS_IS_TOUCHPAD\n"); 696 return B_OK; 697 698 case MS_SET_TOUCHPAD_SETTINGS: 699 TRACE("ELANTECH: MS_SET_TOUCHPAD_SETTINGS"); 700 user_memcpy(&cookie->settings, buffer, sizeof(touchpad_settings)); 701 return B_OK; 702 703 case MS_SET_CLICKSPEED: 704 TRACE("ELANTECH: ioctl MS_SETCLICK (set click speed)\n"); 705 return user_memcpy(&cookie->movementMaker.click_speed, buffer, 706 sizeof(bigtime_t)); 707 708 default: 709 TRACE("ELANTECH: unknown opcode: %ld\n", op); 710 return B_BAD_VALUE; 711 } 712 } 713 714 715 static status_t 716 elantech_read(void* cookie, off_t pos, void* buffer, size_t* _length) 717 { 718 *_length = 0; 719 return B_NOT_ALLOWED; 720 } 721 722 723 static status_t 724 elantech_write(void* cookie, off_t pos, const void* buffer, size_t* _length) 725 { 726 *_length = 0; 727 return B_NOT_ALLOWED; 728 } 729 730 731 int32 732 elantech_handle_int(ps2_dev* dev) 733 { 734 elantech_cookie* cookie = (elantech_cookie*)dev->cookie; 735 736 // we got a real event cancel the fake event 737 gEventProducer.CancelEvent(); 738 739 uint8 val; 740 val = cookie->dev->history[0].data; 741 cookie->buffer[cookie->packet_index] = val; 742 cookie->packet_index++; 743 744 if (cookie->packet_index < PS2_PACKET_ELANTECH) 745 return B_HANDLED_INTERRUPT; 746 747 cookie->packet_index = 0; 748 if (packet_buffer_write(cookie->ring_buffer, 749 cookie->buffer, cookie->dev->packet_size) 750 != cookie->dev->packet_size) { 751 // buffer is full, drop new data 752 return B_HANDLED_INTERRUPT; 753 } 754 release_sem_etc(cookie->sem, 1, B_DO_NOT_RESCHEDULE); 755 return B_INVOKE_SCHEDULER; 756 } 757 758 759 void 760 elantech_disconnect(ps2_dev *dev) 761 { 762 elantech_cookie *cookie = (elantech_cookie*)dev->cookie; 763 // the mouse device might not be opened at this point 764 INFO("ELANTECH: elantech_disconnect %s\n", dev->name); 765 if ((dev->flags & PS2_FLAG_OPEN) != 0) 766 release_sem(cookie->sem); 767 } 768 769 770 device_hooks gElantechDeviceHooks = { 771 elantech_open, 772 elantech_close, 773 elantech_freecookie, 774 elantech_ioctl, 775 elantech_read, 776 elantech_write, 777 }; 778