vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / bus_managers / ps2 / ps2_elantech.cpp
blob6ec921a6f57d8ed7471433ec0b23fd393c862b21
1 /*
2 * Copyright 2013, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
5 * Hardware specs taken from the linux driver, thanks a lot!
6 * Based on ps2_alps.c
8 * Authors:
9 * Jérôme Duval <korli@users.berlios.de>
13 #include "ps2_elantech.h"
15 #include <stdlib.h>
16 #include <string.h>
18 #include "ps2_service.h"
21 static int32 generate_event(timer* timer);
24 const bigtime_t kEventInterval = 1000 * 50;
27 class EventProducer {
28 public:
29 EventProducer()
31 fFired = false;
34 status_t
35 FireEvent(elantech_cookie* cookie, uint8* package)
37 fCookie = cookie;
38 memcpy(fLastPackage, package, sizeof(uint8) * PS2_PACKET_ELANTECH);
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;
47 bool
48 CancelEvent()
50 if (!fFired)
51 return false;
52 fFired = false;
53 return cancel_timer(&fEventTimer);
56 void
57 InjectEvent()
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;
64 release_sem_etc(fCookie->sem, 1, B_DO_NOT_RESCHEDULE);
67 private:
68 bool fFired;
69 uint8 fLastPackage[PS2_PACKET_ELANTECH];
70 timer fEventTimer;
71 elantech_cookie* fCookie;
75 static EventProducer gEventProducer;
78 static int32
79 generate_event(timer* timer)
81 gEventProducer.InjectEvent();
82 return 0;
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"
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
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
106 // touchpad proportions
107 #define EDGE_MOTION_WIDTH 55
109 #define MIN_PRESSURE 0
110 #define REAL_MAX_PRESSURE 50
111 #define MAX_PRESSURE 255
113 #define ELANTECH_HISTORY_SIZE 256
116 static hardware_specs gHardwareSpecs;
119 static status_t
120 get_elantech_movement(elantech_cookie *cookie, mouse_movement *movement)
122 touch_event event;
123 uint8 event_buffer[PS2_PACKET_ELANTECH];
125 status_t status = acquire_sem_etc(cookie->sem, 1, B_CAN_INTERRUPT, 0);
126 if (status < B_OK)
127 return status;
129 if (!cookie->dev->active) {
130 TRACE("ELANTECH: read_event: Error device no longer active\n");
131 return B_ERROR;
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;
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;
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;
163 event.zPressure = (event_buffer[1] & 0xf0)
164 | ((event_buffer[4] & 0xf0) >> 4);
166 cookie->previousZ = event.zPressure;
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;
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;
192 status = cookie->movementMaker.EventToMovement(&event, movement);
194 if (cookie->movementMaker.WasEdgeMotion()
195 || cookie->movementMaker.TapDragStarted()) {
196 gEventProducer.FireEvent(cookie, event_buffer);
199 return status;
203 static void
204 default_settings(touchpad_settings *set)
206 memcpy(set, &kDefaultTouchpadSettings, sizeof(touchpad_settings));
210 static status_t
211 synaptics_dev_send_command(ps2_dev* dev, uint8 cmd, uint8 *in, int in_count)
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;
219 return B_OK;
223 static status_t
224 elantech_dev_send_command(ps2_dev* dev, uint8 cmd, uint8 *in, int in_count)
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;
233 return B_OK;
237 status_t
238 probe_elantech(ps2_dev* dev)
240 uint8 val[3];
241 TRACE("ELANTECH: probe\n");
243 ps2_dev_command(dev, PS2_CMD_MOUSE_RESET_DIS);
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;
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;
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;
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;
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;
277 INFO("Elantech version %02X%02X%02X, under developement! Using fallback.\n",
278 val[0], val[1], val[2]);
280 dev->name = kElantechPath[dev->idx];
281 dev->packet_size = PS2_PACKET_ELANTECH;
283 return B_ERROR;
287 static status_t
288 elantech_write_reg(elantech_cookie* cookie, uint8 reg, uint8 value)
290 if (reg < 0x7 || reg > 0x26)
291 return B_BAD_VALUE;
292 if (reg > 0x11 && reg < 0x20)
293 return B_BAD_VALUE;
295 ps2_dev* dev = cookie->dev;
296 switch (cookie->version) {
297 case 1:
298 // TODO
299 return B_ERROR;
300 break;
301 case 2:
302 if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
303 || ps2_dev_command(dev, ELANTECH_CMD_REGISTER_WRITE) != B_OK
304 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
305 || ps2_dev_command(dev, reg) != B_OK
306 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
307 || ps2_dev_command(dev, value) != B_OK
308 || ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK)
309 return B_ERROR;
310 break;
311 case 3:
312 if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
313 || ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READWRITE) != B_OK
314 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
315 || ps2_dev_command(dev, reg) != B_OK
316 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
317 || ps2_dev_command(dev, value) != B_OK
318 || ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK)
319 return B_ERROR;
320 break;
321 case 4:
322 if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
323 || ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READWRITE) != B_OK
324 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
325 || ps2_dev_command(dev, reg) != B_OK
326 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
327 || ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READWRITE) != B_OK
328 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
329 || ps2_dev_command(dev, value) != B_OK
330 || ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK)
331 return B_ERROR;
332 break;
333 default:
334 TRACE("ELANTECH: read_write_reg: unknown version\n");
335 return B_ERROR;
337 return B_OK;
341 static status_t
342 elantech_read_reg(elantech_cookie* cookie, uint8 reg, uint8 *value)
344 if (reg < 0x7 || reg > 0x26)
345 return B_BAD_VALUE;
346 if (reg > 0x11 && reg < 0x20)
347 return B_BAD_VALUE;
349 ps2_dev* dev = cookie->dev;
350 uint8 val[3];
351 switch (cookie->version) {
352 case 1:
353 // TODO
354 return B_ERROR;
355 break;
356 case 2:
357 if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
358 || ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READ) != B_OK
359 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
360 || ps2_dev_command(dev, reg) != B_OK
361 || ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, val,
362 3) != B_OK)
363 return B_ERROR;
364 break;
365 case 3:
366 case 4:
367 if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
368 || ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READWRITE)
369 != B_OK
370 || ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
371 || ps2_dev_command(dev, reg) != B_OK
372 || ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, val,
373 3) != B_OK)
374 return B_ERROR;
375 break;
376 default:
377 TRACE("ELANTECH: read_write_reg: unknown version\n");
378 return B_ERROR;
380 if (cookie->version == 4)
381 *value = val[1];
382 else
383 *value = val[0];
385 return B_OK;
389 static status_t
390 get_resolution_v4(elantech_cookie* cookie, uint32* x, uint32* y)
392 uint8 val[3];
393 if (elantech_dev_send_command(cookie->dev, ELANTECH_CMD_GET_RESOLUTION,
394 val, 3) != B_OK)
395 return B_ERROR;
396 *x = (val[1] & 0xf) * 10 + 790;
397 *y = ((val[1] & 0xf) >> 4) * 10 + 790;
398 return B_OK;
402 static status_t
403 get_range(elantech_cookie* cookie, uint32* x_min, uint32* y_min, uint32* x_max,
404 uint32* y_max, uint32 *width)
406 uint8 val[3];
407 switch (cookie->version) {
408 case 1:
409 *x_min = 32;
410 *y_min = 32;
411 *x_max = 544;
412 *y_max = 344;
413 *width = 0;
414 break;
415 case 2:
416 // TODO
417 break;
418 case 3:
419 if ((cookie->send_command)(cookie->dev, ELANTECH_CMD_GET_ID, val, 3)
420 != B_OK) {
421 return B_ERROR;
423 *x_min = 0;
424 *y_min = 0;
425 *x_max = ((val[0] & 0xf) << 8) | val[1];
426 *y_max = ((val[0] & 0xf0) << 4) | val[2];
427 *width = 0;
428 break;
429 case 4:
430 if ((cookie->send_command)(cookie->dev, ELANTECH_CMD_GET_ID, val, 3)
431 != B_OK) {
432 return B_ERROR;
434 *x_min = 0;
435 *y_min = 0;
436 *x_max = ((val[0] & 0xf) << 8) | val[1];
437 *y_max = ((val[0] & 0xf0) << 4) | val[2];
438 if (cookie->capabilities[1] < 2 || cookie->capabilities[1] > *x_max)
439 return B_ERROR;
440 *width = *x_max / (cookie->capabilities[1] - 1);
441 break;
443 return B_OK;
447 static status_t
448 enable_absolute_mode(elantech_cookie* cookie)
450 status_t status = B_OK;
451 switch (cookie->version) {
452 case 1:
453 status = elantech_write_reg(cookie, 0x10, 0x16);
454 if (status == B_OK)
455 status = elantech_write_reg(cookie, 0x11, 0x8f);
456 break;
457 case 2:
458 status = elantech_write_reg(cookie, 0x10, 0x54);
459 if (status == B_OK)
460 status = elantech_write_reg(cookie, 0x11, 0x88);
461 if (status == B_OK)
462 status = elantech_write_reg(cookie, 0x12, 0x60);
463 break;
464 case 3:
465 status = elantech_write_reg(cookie, 0x10, 0xb);
466 break;
467 case 4:
468 status = elantech_write_reg(cookie, 0x7, 0x1);
469 break;
473 if (cookie->version < 4) {
474 uint8 val;
476 for (uint8 retry = 0; retry < 5; retry++) {
477 status = elantech_read_reg(cookie, 0x10, &val);
478 if (status != B_OK)
479 break;
480 snooze(100);
484 return status;
488 status_t
489 elantech_open(const char *name, uint32 flags, void **_cookie)
491 TRACE("ELANTECH: open %s\n", name);
492 ps2_dev* dev;
493 int i;
494 for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) {
495 if (0 == strcmp(ps2_device[i].name, name)) {
496 dev = &ps2_device[i];
497 break;
501 if (dev == NULL) {
502 TRACE("ps2: dev = NULL\n");
503 return B_ERROR;
506 if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN)
507 return B_BUSY;
509 elantech_cookie* cookie = (elantech_cookie*)malloc(
510 sizeof(elantech_cookie));
511 if (cookie == NULL)
512 goto err1;
513 memset(cookie, 0, sizeof(*cookie));
515 cookie->movementMaker.Init();
516 cookie->previousZ = 0;
517 *_cookie = cookie;
519 cookie->dev = dev;
520 dev->cookie = cookie;
521 dev->disconnect = &elantech_disconnect;
522 dev->handle_int = &elantech_handle_int;
524 default_settings(&cookie->settings);
526 dev->packet_size = PS2_PACKET_ELANTECH;
528 cookie->ring_buffer = create_packet_buffer(
529 ELANTECH_HISTORY_SIZE * dev->packet_size);
530 if (cookie->ring_buffer == NULL) {
531 TRACE("ELANTECH: can't allocate mouse actions buffer\n");
532 goto err2;
534 // create the mouse semaphore, used for synchronization between
535 // the interrupt handler and the read operation
536 cookie->sem = create_sem(0, "ps2_elantech_sem");
537 if (cookie->sem < 0) {
538 TRACE("ELANTECH: failed creating semaphore!\n");
539 goto err3;
542 uint8 val[3];
543 if (synaptics_dev_send_command(dev, ELANTECH_CMD_GET_VERSION, val, 3)
544 != B_OK) {
545 TRACE("ELANTECH: get version failed!\n");
546 goto err4;
548 cookie->fwVersion = (val[0] << 16) | (val[1] << 8) | val[2];
549 if (cookie->fwVersion < 0x020030 || cookie->fwVersion == 0x020600)
550 cookie->version = 1;
551 else {
552 switch (val[0] & 0xf) {
553 case 2:
554 case 4:
555 cookie->version = 2;
556 break;
557 case 5:
558 cookie->version = 3;
559 break;
560 case 6:
561 case 7:
562 cookie->version = 4;
563 break;
564 default:
565 TRACE("ELANTECH: unknown version!\n");
566 goto err4;
569 TRACE("ELANTECH: version 0x%lx (0x%lx)\n", cookie->version,
570 cookie->fwVersion);
572 if (cookie->version >= 3)
573 cookie->send_command = &elantech_dev_send_command;
574 else
575 cookie->send_command = &synaptics_dev_send_command;
576 cookie->crcEnabled = (cookie->fwVersion & 0x4000) == 0x4000;
578 if ((cookie->send_command)(cookie->dev, ELANTECH_CMD_GET_CAPABILITIES,
579 cookie->capabilities, 3) != B_OK) {
580 TRACE("ELANTECH: get capabilities failed!\n");
581 return B_ERROR;
584 if (enable_absolute_mode(cookie) != B_OK) {
585 TRACE("ELANTECH: failed enabling absolute mode!\n");
586 goto err4;
588 TRACE("ELANTECH: enabled absolute mode!\n");
590 uint32 x_min, x_max, y_min, y_max, width;
591 if (get_range(cookie, &x_min, &y_min, &x_max, &y_max, &width) != B_OK) {
592 TRACE("ELANTECH: get range failed!\n");
593 goto err4;
596 TRACE("ELANTECH: range x %ld-%ld y %ld-%ld (%ld)\n", x_min, x_max,
597 y_min, y_max, width);
599 uint32 x_res, y_res;
600 if (get_resolution_v4(cookie, &x_res, &y_res) != B_OK) {
601 TRACE("ELANTECH: get resolution failed!\n");
602 goto err4;
605 TRACE("ELANTECH: resolution x %ld y %ld (dpi)\n", x_res, y_res);
607 gHardwareSpecs.edgeMotionWidth = EDGE_MOTION_WIDTH;
609 gHardwareSpecs.areaStartX = x_min;
610 gHardwareSpecs.areaEndX = x_max;
611 gHardwareSpecs.areaStartY = y_min;
612 gHardwareSpecs.areaEndY = y_max;
614 gHardwareSpecs.minPressure = MIN_PRESSURE;
615 gHardwareSpecs.realMaxPressure = REAL_MAX_PRESSURE;
616 gHardwareSpecs.maxPressure = MAX_PRESSURE;
618 cookie->movementMaker.SetSettings(&cookie->settings);
619 cookie->movementMaker.SetSpecs(&gHardwareSpecs);
621 if (ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0) != B_OK)
622 goto err4;
624 atomic_or(&dev->flags, PS2_FLAG_ENABLED);
626 TRACE("ELANTECH: open %s success\n", name);
627 return B_OK;
629 err4:
630 delete_sem(cookie->sem);
631 err3:
632 delete_packet_buffer(cookie->ring_buffer);
633 err2:
634 free(cookie);
635 err1:
636 atomic_and(&dev->flags, ~PS2_FLAG_OPEN);
638 TRACE("ELANTECH: open %s failed\n", name);
639 return B_ERROR;
643 status_t
644 elantech_close(void *_cookie)
646 gEventProducer.CancelEvent();
648 elantech_cookie *cookie = (elantech_cookie*)_cookie;
650 ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0,
651 150000);
653 delete_packet_buffer(cookie->ring_buffer);
654 delete_sem(cookie->sem);
656 atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN);
657 atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED);
659 // Reset the touchpad so it generate standard ps2 packets instead of
660 // extended ones. If not, BeOS is confused with such packets when rebooting
661 // without a complete shutdown.
662 status_t status = ps2_reset_mouse(cookie->dev);
663 if (status != B_OK) {
664 INFO("ps2: reset failed\n");
665 return B_ERROR;
668 TRACE("ELANTECH: close %s done\n", cookie->dev->name);
669 return B_OK;
673 status_t
674 elantech_freecookie(void *_cookie)
676 free(_cookie);
677 return B_OK;
681 status_t
682 elantech_ioctl(void *_cookie, uint32 op, void *buffer, size_t length)
684 elantech_cookie *cookie = (elantech_cookie*)_cookie;
685 mouse_movement movement;
686 status_t status;
688 switch (op) {
689 case MS_READ:
690 TRACE("ELANTECH: MS_READ get event\n");
691 if ((status = get_elantech_movement(cookie, &movement)) != B_OK)
692 return status;
693 return user_memcpy(buffer, &movement, sizeof(movement));
695 case MS_IS_TOUCHPAD:
696 TRACE("ELANTECH: MS_IS_TOUCHPAD\n");
697 return B_OK;
699 case MS_SET_TOUCHPAD_SETTINGS:
700 TRACE("ELANTECH: MS_SET_TOUCHPAD_SETTINGS");
701 user_memcpy(&cookie->settings, buffer, sizeof(touchpad_settings));
702 return B_OK;
704 case MS_SET_CLICKSPEED:
705 TRACE("ELANTECH: ioctl MS_SETCLICK (set click speed)\n");
706 return user_memcpy(&cookie->movementMaker.click_speed, buffer,
707 sizeof(bigtime_t));
709 default:
710 TRACE("ELANTECH: unknown opcode: %ld\n", op);
711 return B_BAD_VALUE;
716 static status_t
717 elantech_read(void* cookie, off_t pos, void* buffer, size_t* _length)
719 *_length = 0;
720 return B_NOT_ALLOWED;
724 static status_t
725 elantech_write(void* cookie, off_t pos, const void* buffer, size_t* _length)
727 *_length = 0;
728 return B_NOT_ALLOWED;
732 int32
733 elantech_handle_int(ps2_dev* dev)
735 elantech_cookie* cookie = (elantech_cookie*)dev->cookie;
737 // we got a real event cancel the fake event
738 gEventProducer.CancelEvent();
740 uint8 val;
741 val = cookie->dev->history[0].data;
742 cookie->buffer[cookie->packet_index] = val;
743 cookie->packet_index++;
745 if (cookie->packet_index < PS2_PACKET_ELANTECH)
746 return B_HANDLED_INTERRUPT;
748 cookie->packet_index = 0;
749 if (packet_buffer_write(cookie->ring_buffer,
750 cookie->buffer, cookie->dev->packet_size)
751 != cookie->dev->packet_size) {
752 // buffer is full, drop new data
753 return B_HANDLED_INTERRUPT;
755 release_sem_etc(cookie->sem, 1, B_DO_NOT_RESCHEDULE);
756 return B_INVOKE_SCHEDULER;
760 void
761 elantech_disconnect(ps2_dev *dev)
763 elantech_cookie *cookie = (elantech_cookie*)dev->cookie;
764 // the mouse device might not be opened at this point
765 INFO("ELANTECH: elantech_disconnect %s\n", dev->name);
766 if ((dev->flags & PS2_FLAG_OPEN) != 0)
767 release_sem(cookie->sem);
771 device_hooks gElantechDeviceHooks = {
772 elantech_open,
773 elantech_close,
774 elantech_freecookie,
775 elantech_ioctl,
776 elantech_read,
777 elantech_write,