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