ps2: added initial support for elantech pads.
* also added a license to ps2_alps.h * added ps2_dev_sliced_command() * moved some ps2 commands definitions to ps2_defs.h
This commit is contained in:
@@ -8,6 +8,7 @@ KernelAddon ps2 :
|
||||
ps2_alps.cpp
|
||||
ps2_common.cpp
|
||||
ps2_dev.cpp
|
||||
ps2_elantech.cpp
|
||||
ps2_keyboard.cpp
|
||||
ps2_module.cpp
|
||||
ps2_standard_mouse.cpp
|
||||
|
||||
@@ -67,8 +67,8 @@ public:
|
||||
private:
|
||||
bool fFired;
|
||||
uint8 fLastPackage[PS2_PACKET_ALPS];
|
||||
timer fEventTimer;
|
||||
alps_cookie* fCookie;
|
||||
timer fEventTimer;
|
||||
alps_cookie* fCookie;
|
||||
};
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ typedef struct alps_model_info {
|
||||
|
||||
static const struct alps_model_info gALPSModelInfos[] = {
|
||||
{{0x32, 0x02, 0x14}, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT},
|
||||
// Toshiba Salellite Pro M10
|
||||
// Toshiba Salellite Pro M10
|
||||
// {{0x33, 0x02, 0x0a}, 0x88, 0xf8, ALPS_OLDPROTO},
|
||||
// UMAX-530T
|
||||
{{0x53, 0x02, 0x0a}, 0xf8, 0xf8, 0},
|
||||
@@ -155,15 +155,6 @@ static const struct alps_model_info gALPSModelInfos[] = {
|
||||
static alps_model_info* sFoundModel = NULL;
|
||||
|
||||
|
||||
#define PS2_MOUSE_CMD_SET_SCALE11 0xe6
|
||||
#define PS2_MOUSE_CMD_SET_SCALE21 0xe7
|
||||
#define PS2_MOUSE_CMD_SET_RES 0xe8
|
||||
#define PS2_MOUSE_CMD_GET_INFO 0xe9
|
||||
#define PS2_MOUSE_CMD_SET_STREAM 0xea
|
||||
#define PS2_MOUSE_CMD_SET_POLL 0xf0
|
||||
#define PS2_MOUSE_CMD_SET_RATE 0xf3
|
||||
|
||||
|
||||
// touchpad proportions
|
||||
#define EDGE_MOTION_WIDTH 55
|
||||
// increase the touchpad size a little bit
|
||||
@@ -279,16 +270,16 @@ probe_alps(ps2_dev* dev)
|
||||
TRACE("ALPS: probe\n");
|
||||
|
||||
val[0] = 0;
|
||||
if (ps2_dev_command(dev, PS2_MOUSE_CMD_SET_RES, val, 1, NULL, 0) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_SCALE11, NULL, 0, NULL, 0)
|
||||
if (ps2_dev_command(dev, PS2_CMD_MOUSE_SET_RES, val, 1, NULL, 0) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11, NULL, 0, NULL, 0)
|
||||
!= B_OK
|
||||
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_SCALE11, NULL, 0, NULL, 0)
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11, NULL, 0, NULL, 0)
|
||||
!= B_OK
|
||||
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_SCALE11, NULL, 0, NULL, 0)
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11, NULL, 0, NULL, 0)
|
||||
!= B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
if (ps2_dev_command(dev, PS2_MOUSE_CMD_GET_INFO, NULL, 0, val, 3)
|
||||
if (ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, val, 3)
|
||||
!= B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
@@ -296,16 +287,16 @@ probe_alps(ps2_dev* dev)
|
||||
return B_ERROR;
|
||||
|
||||
val[0] = 0;
|
||||
if (ps2_dev_command(dev, PS2_MOUSE_CMD_SET_RES, val, 1, NULL, 0) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_SCALE21, NULL, 0, NULL, 0)
|
||||
if (ps2_dev_command(dev, PS2_CMD_MOUSE_SET_RES, val, 1, NULL, 0) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE21, NULL, 0, NULL, 0)
|
||||
!= B_OK
|
||||
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_SCALE21, NULL, 0, NULL, 0)
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE21, NULL, 0, NULL, 0)
|
||||
!= B_OK
|
||||
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_SCALE21, NULL, 0, NULL, 0)
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE21, NULL, 0, NULL, 0)
|
||||
!= B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
if (ps2_dev_command(dev, PS2_MOUSE_CMD_GET_INFO, NULL, 0, val, 3)
|
||||
if (ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, val, 3)
|
||||
!= B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
@@ -337,12 +328,12 @@ switch_hardware_tab(ps2_dev* dev, bool on)
|
||||
{
|
||||
uint8 val[3];
|
||||
uint8 arg = 0x00;
|
||||
uint8 command = PS2_MOUSE_CMD_SET_RES;
|
||||
uint8 command = PS2_CMD_MOUSE_SET_RES;
|
||||
if (on) {
|
||||
arg = 0x0A;
|
||||
command = PS2_MOUSE_CMD_SET_RATE;
|
||||
command = PS2_CMD_KEYBOARD_SET_TYPEMATIC;
|
||||
}
|
||||
if (ps2_dev_command(dev, PS2_MOUSE_CMD_GET_INFO, NULL, 0, val, 3) != B_OK
|
||||
if (ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, val, 3) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|
||||
|| ps2_dev_command(dev, command, &arg, 1, NULL, 0) != B_OK)
|
||||
@@ -355,9 +346,9 @@ switch_hardware_tab(ps2_dev* dev, bool on)
|
||||
status_t
|
||||
enable_passthrough(ps2_dev* dev, bool on)
|
||||
{
|
||||
uint8 command = PS2_MOUSE_CMD_SET_SCALE11;
|
||||
uint8 command = PS2_CMD_MOUSE_SET_SCALE11;
|
||||
if (on)
|
||||
command = PS2_MOUSE_CMD_SET_SCALE21;
|
||||
command = PS2_CMD_MOUSE_SET_SCALE21;
|
||||
|
||||
if (ps2_dev_command(dev, command, NULL, 0, NULL, 0) != B_OK
|
||||
|| ps2_dev_command(dev, command, NULL, 0, NULL, 0) != B_OK
|
||||
@@ -438,7 +429,7 @@ alps_open(const char *name, uint32 flags, void **_cookie)
|
||||
if ((sFoundModel->flags & ALPS_PASS) != 0
|
||||
&& enable_passthrough(dev, true) != B_OK)
|
||||
goto err4;
|
||||
|
||||
|
||||
// switch tap mode off
|
||||
if (switch_hardware_tab(dev, false) != B_OK)
|
||||
goto err4;
|
||||
@@ -455,7 +446,7 @@ alps_open(const char *name, uint32 flags, void **_cookie)
|
||||
&& enable_passthrough(dev, false) != B_OK)
|
||||
goto err4;
|
||||
|
||||
if (ps2_dev_command(dev, PS2_MOUSE_CMD_SET_STREAM, NULL, 0, NULL, 0) != B_OK)
|
||||
if (ps2_dev_command(dev, PS2_CMD_MOUSE_SET_STREAM, NULL, 0, NULL, 0) != B_OK)
|
||||
goto err4;
|
||||
|
||||
if (ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0) != B_OK)
|
||||
@@ -633,4 +624,3 @@ device_hooks gALPSDeviceHooks = {
|
||||
alps_read,
|
||||
alps_write,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright 2011, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Clemens Zeidler (haiku@Clemens-Zeidler.de)
|
||||
*/
|
||||
#ifndef ALPS_H
|
||||
#define ALPS_H
|
||||
|
||||
|
||||
@@ -369,7 +369,7 @@ ps2_init(void)
|
||||
//ps2_selftest();
|
||||
|
||||
// Setup the command byte with disabled keyboard and AUX interrupts
|
||||
// to prevent interrupts storm on some KBCs during active multiplexing
|
||||
// to prevent interrupts storm on some KBCs during active multiplexing
|
||||
// activation procedure. Fixes #7635.
|
||||
status = ps2_setup_command_byte(false);
|
||||
if (status) {
|
||||
@@ -391,8 +391,9 @@ ps2_init(void)
|
||||
}
|
||||
|
||||
if (gActiveMultiplexingEnabled) {
|
||||
if (ps2_dev_command_timeout(&ps2_device[PS2_DEVICE_MOUSE], 0xe6,
|
||||
NULL, 0, NULL, 0, 100000) == B_TIMED_OUT) {
|
||||
if (ps2_dev_command_timeout(&ps2_device[PS2_DEVICE_MOUSE],
|
||||
PS2_CMD_MOUSE_SET_SCALE11, NULL, 0, NULL, 0, 100000)
|
||||
== B_TIMED_OUT) {
|
||||
INFO("ps2: accessing multiplexed mouse port 0 timed out, ignoring it!\n");
|
||||
} else {
|
||||
ps2_service_notify_device_added(&ps2_device[PS2_DEVICE_MOUSE]);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#else
|
||||
# define INFO(x...)
|
||||
#endif
|
||||
#define ERROR(x...) dprintf(x)
|
||||
|
||||
//#define TRACE_PS2
|
||||
#ifdef TRACE_PS2
|
||||
|
||||
@@ -48,7 +48,13 @@
|
||||
#define PS2_BITS_TRANSLATE_SCANCODES 0x40
|
||||
|
||||
// data words
|
||||
#define PS2_CMD_MOUSE_SET_SCALE11 0xe6
|
||||
#define PS2_CMD_MOUSE_SET_SCALE21 0xe7
|
||||
#define PS2_CMD_MOUSE_SET_RES 0xe8
|
||||
#define PS2_CMD_MOUSE_GET_INFO 0xe9
|
||||
#define PS2_CMD_MOUSE_SET_STREAM 0xea
|
||||
#define PS2_CMD_KEYBOARD_SET_LEDS 0xed
|
||||
#define PS2_CMD_MOUSE_SET_POLL 0xf0
|
||||
#define PS2_CMD_KEYBOARD_SET_TYPEMATIC 0xf3
|
||||
#define PS2_CMD_ECHO 0xee
|
||||
#define PS2_CMD_TEST_PASSED 0xaa
|
||||
@@ -56,6 +62,7 @@
|
||||
#define PS2_CMD_SET_SAMPLE_RATE 0xf3
|
||||
#define PS2_CMD_ENABLE 0xf4
|
||||
#define PS2_CMD_DISABLE 0xf5
|
||||
#define PS2_CMD_MOUSE_RESET_DIS 0xf6
|
||||
#define PS2_CMD_RESET 0xff
|
||||
#define PS2_CMD_RESEND 0xfe
|
||||
|
||||
@@ -79,6 +86,7 @@
|
||||
#define PS2_PACKET_INTELLIMOUSE 4
|
||||
#define PS2_PACKET_SYNAPTICS 6
|
||||
#define PS2_PACKET_ALPS 6
|
||||
#define PS2_PACKET_ELANTECH 6 // version 1 is only 4
|
||||
#define PS2_MAX_PACKET_SIZE 6
|
||||
// Should be equal to the biggest packet size
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "ps2_service.h"
|
||||
|
||||
#include "ps2_alps.h"
|
||||
#include "ps2_elantech.h"
|
||||
#include "ps2_standard_mouse.h"
|
||||
#include "ps2_synaptics.h"
|
||||
#include "ps2_trackpoint.h"
|
||||
@@ -88,6 +89,12 @@ ps2_dev_detect_pointing(ps2_dev *dev, device_hooks **hooks)
|
||||
goto dev_found;
|
||||
}
|
||||
|
||||
status = probe_elantech(dev);
|
||||
if (status == B_OK) {
|
||||
*hooks = &gElantechDeviceHooks;
|
||||
goto dev_found;
|
||||
}
|
||||
|
||||
// reset the mouse for the case that the previous probes leaf the mouse in
|
||||
// a undefined state
|
||||
status = ps2_reset_mouse(dev);
|
||||
@@ -190,7 +197,7 @@ ps2_dev_publish(ps2_dev *dev)
|
||||
if (atomic_get(&dev->flags) & PS2_FLAG_KEYB) {
|
||||
status = devfs_publish_device(dev->name, &gKeyboardDeviceHooks);
|
||||
} else {
|
||||
// Check if this is the "pass-through" device and wait until
|
||||
// Check if this is the "pass-through" device and wait until
|
||||
// the parent_dev goes to enabled state. It is required to prevent
|
||||
// from messing up the Synaptics command sequences in synaptics_open.
|
||||
if (dev->parent_dev) {
|
||||
@@ -204,7 +211,7 @@ ps2_dev_publish(ps2_dev *dev)
|
||||
snooze(timeout / 20);
|
||||
}
|
||||
TRACE("ps2: publishing %s: parent %s is %s; wait time %" B_PRId64
|
||||
"\n", dev->name, dev->parent_dev->name,
|
||||
"\n", dev->name, dev->parent_dev->name,
|
||||
status == B_OK ? "enabled" : "busy", system_time() - start);
|
||||
}
|
||||
|
||||
@@ -490,3 +497,23 @@ ps2_dev_command_timeout(ps2_dev *dev, uint8 cmd, const uint8 *out,
|
||||
return dev->command(dev, cmd, out, out_count, in, in_count, timeout);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ps2_dev_sliced_command(ps2_dev *dev, uint8 cmd)
|
||||
{
|
||||
if (ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK)
|
||||
return B_ERROR;
|
||||
uint8 val = (cmd >> 6) & 3;
|
||||
if (ps2_dev_command(dev, PS2_CMD_MOUSE_SET_RES, &val, 1) != B_OK)
|
||||
return B_ERROR;
|
||||
val = (cmd >> 4) & 3;
|
||||
if (ps2_dev_command(dev, PS2_CMD_MOUSE_SET_RES, &val, 1) != B_OK)
|
||||
return B_ERROR;
|
||||
val = (cmd >> 2) & 3;
|
||||
if (ps2_dev_command(dev, PS2_CMD_MOUSE_SET_RES, &val, 1) != B_OK)
|
||||
return B_ERROR;
|
||||
val = cmd & 3;
|
||||
if (ps2_dev_command(dev, PS2_CMD_MOUSE_SET_RES, &val, 1) != B_OK)
|
||||
return B_ERROR;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -76,10 +76,12 @@ void ps2_dev_exit(void);
|
||||
status_t standard_command_timeout(ps2_dev *dev, uint8 cmd, const uint8 *out,
|
||||
int out_count, uint8 *in, int in_count, bigtime_t timeout);
|
||||
|
||||
status_t ps2_dev_command(ps2_dev *dev, uint8 cmd, const uint8 *out,
|
||||
int out_count, uint8 *in, int in_count);
|
||||
status_t ps2_dev_command(ps2_dev *dev, uint8 cmd, const uint8 *out = NULL,
|
||||
int out_count = 0, uint8 *in = NULL, int in_count = 0);
|
||||
status_t ps2_dev_command_timeout(ps2_dev *dev, uint8 cmd, const uint8 *out,
|
||||
int out_count, uint8 *in, int in_count, bigtime_t timeout);
|
||||
status_t ps2_dev_sliced_command(ps2_dev *dev, uint8 cmd);
|
||||
|
||||
|
||||
status_t ps2_reset_mouse(ps2_dev *dev);
|
||||
|
||||
|
||||
@@ -0,0 +1,801 @@
|
||||
/*
|
||||
* Copyright 2013, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Hardware specs taken from the linux driver, thanks a lot!
|
||||
* Based on ps2_alps.c
|
||||
*
|
||||
* Authors:
|
||||
* Jérôme Duval <korli@users.berlios.de>
|
||||
*/
|
||||
|
||||
|
||||
#include "ps2_elantech.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ps2_service.h"
|
||||
|
||||
|
||||
static int32 generate_event(timer* timer);
|
||||
|
||||
|
||||
const bigtime_t kEventInterval = 1000 * 50;
|
||||
|
||||
|
||||
class EventProducer {
|
||||
public:
|
||||
EventProducer()
|
||||
{
|
||||
fFired = false;
|
||||
}
|
||||
|
||||
status_t
|
||||
FireEvent(elantech_cookie* cookie, uint8* package)
|
||||
{
|
||||
fCookie = cookie;
|
||||
memcpy(fLastPackage, package, sizeof(uint8) * PS2_PACKET_ELANTECH);
|
||||
|
||||
status_t status = add_timer(&fEventTimer, &generate_event,
|
||||
kEventInterval, B_ONE_SHOT_RELATIVE_TIMER);
|
||||
if (status == B_OK)
|
||||
fFired = true;
|
||||
return status;
|
||||
}
|
||||
|
||||
bool
|
||||
CancelEvent()
|
||||
{
|
||||
if (!fFired)
|
||||
return false;
|
||||
fFired = false;
|
||||
return cancel_timer(&fEventTimer);
|
||||
}
|
||||
|
||||
void
|
||||
InjectEvent()
|
||||
{
|
||||
if (packet_buffer_write(fCookie->ring_buffer, fLastPackage,
|
||||
PS2_PACKET_ELANTECH) != PS2_PACKET_ELANTECH) {
|
||||
// buffer is full, drop new data
|
||||
return;
|
||||
}
|
||||
release_sem_etc(fCookie->sem, 1, B_DO_NOT_RESCHEDULE);
|
||||
}
|
||||
|
||||
private:
|
||||
bool fFired;
|
||||
uint8 fLastPackage[PS2_PACKET_ELANTECH];
|
||||
timer fEventTimer;
|
||||
elantech_cookie* fCookie;
|
||||
};
|
||||
|
||||
|
||||
static EventProducer gEventProducer;
|
||||
|
||||
|
||||
static int32
|
||||
generate_event(timer* timer)
|
||||
{
|
||||
gEventProducer.InjectEvent();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char* kElantechPath[4] = {
|
||||
"input/touchpad/ps2/elantech_0",
|
||||
"input/touchpad/ps2/elantech_1",
|
||||
"input/touchpad/ps2/elantech_2",
|
||||
"input/touchpad/ps2/elantech_3"
|
||||
};
|
||||
|
||||
|
||||
#define ELANTECH_CMD_GET_ID 0x00
|
||||
#define ELANTECH_CMD_GET_VERSION 0x01
|
||||
#define ELANTECH_CMD_GET_CAPABILITIES 0x02
|
||||
#define ELANTECH_CMD_GET_SAMPLE 0x03
|
||||
#define ELANTECH_CMD_GET_RESOLUTION 0x04
|
||||
|
||||
#define ELANTECH_CMD_REGISTER_READ 0x10
|
||||
#define ELANTECH_CMD_REGISTER_WRITE 0x11
|
||||
#define ELANTECH_CMD_REGISTER_READWRITE 0x00
|
||||
#define ELANTECH_CMD_PS2_CUSTOM_CMD 0xf8
|
||||
|
||||
|
||||
// touchpad proportions
|
||||
#define EDGE_MOTION_WIDTH 55
|
||||
|
||||
#define MIN_PRESSURE 0
|
||||
#define REAL_MAX_PRESSURE 50
|
||||
#define MAX_PRESSURE 255
|
||||
|
||||
#define ELANTECH_HISTORY_SIZE 256
|
||||
|
||||
|
||||
static hardware_specs gHardwareSpecs;
|
||||
|
||||
|
||||
static status_t
|
||||
get_elantech_movement(elantech_cookie *cookie, mouse_movement *movement)
|
||||
{
|
||||
touch_event event;
|
||||
uint8 event_buffer[PS2_PACKET_ELANTECH];
|
||||
|
||||
status_t status = acquire_sem_etc(cookie->sem, 1, B_CAN_INTERRUPT, 0);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
if (!cookie->dev->active) {
|
||||
TRACE("ELANTECH: read_event: Error device no longer active\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (packet_buffer_read(cookie->ring_buffer, event_buffer,
|
||||
cookie->dev->packet_size) != cookie->dev->packet_size) {
|
||||
TRACE("ELANTECH: error copying buffer\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (cookie->crcEnabled && (event_buffer[3] & 0x08) != 0) {
|
||||
TRACE("ELANTECH: bad crc buffer\n");
|
||||
return B_ERROR;
|
||||
} else if (!cookie->crcEnabled && ((event_buffer[0] & 0x0c) != 0x04
|
||||
|| (event_buffer[3] & 0x1c) != 0x10)) {
|
||||
TRACE("ELANTECH: bad crc buffer\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
uint8 type = event_buffer[3] & 3;
|
||||
TRACE("ELANTECH: packet type %d\n", type);
|
||||
TRACE("ELANTECH: packet content 0x%02x%02x%02x%02x%02x%02x\n",
|
||||
event_buffer[0], event_buffer[1], event_buffer[2], event_buffer[3],
|
||||
event_buffer[4], event_buffer[5]);
|
||||
switch (type) {
|
||||
case 0:
|
||||
// fingers
|
||||
cookie->fingers = event_buffer[1] & 0x1f;
|
||||
break;
|
||||
case 1:
|
||||
if ((((event_buffer[3] & 0xe0) >> 5) - 1) != 0) {
|
||||
// only process first finger
|
||||
return B_OK;
|
||||
}
|
||||
event.zPressure = (event_buffer[1] & 0xf0)
|
||||
| ((event_buffer[4] & 0xf0) >> 4);
|
||||
|
||||
cookie->previousZ = event.zPressure;
|
||||
|
||||
event.xPosition = ((event_buffer[1] & 0xf) << 8) | event_buffer[2];
|
||||
event.yPosition = (((event_buffer[4] & 0xf) << 8)
|
||||
| event_buffer[5]);
|
||||
TRACE("ELANTECH: buttons 0x%x x %ld y %ld z %d\n",
|
||||
event.buttons, event.xPosition, event.yPosition,
|
||||
event.zPressure);
|
||||
break;
|
||||
case 2:
|
||||
TRACE("ELANTECH: packet type motion\n");
|
||||
// TODO
|
||||
return B_OK;
|
||||
default:
|
||||
TRACE("ELANTECH: unknown packet type %d\n", type);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
event.buttons = 0;
|
||||
// finger on touchpad
|
||||
if ((cookie->fingers & 1) != 0) {
|
||||
// finger with normal width
|
||||
event.wValue = 4;
|
||||
} else {
|
||||
event.wValue = 3;
|
||||
}
|
||||
status = cookie->movementMaker.EventToMovement(&event, movement);
|
||||
|
||||
if (cookie->movementMaker.WasEdgeMotion()
|
||||
|| cookie->movementMaker.TapDragStarted()) {
|
||||
gEventProducer.FireEvent(cookie, event_buffer);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
default_settings(touchpad_settings *set)
|
||||
{
|
||||
memcpy(set, &kDefaultTouchpadSettings, sizeof(touchpad_settings));
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
synaptics_dev_send_command(ps2_dev* dev, uint8 cmd, uint8 *in, int in_count)
|
||||
{
|
||||
uint8 val;
|
||||
if (ps2_dev_sliced_command(dev, cmd) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, in, in_count)
|
||||
!= B_OK) {
|
||||
TRACE("ELANTECH: synaptics_dev_send_command failed\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
elantech_dev_send_command(ps2_dev* dev, uint8 cmd, uint8 *in, int in_count)
|
||||
{
|
||||
uint8 val;
|
||||
if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, cmd) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, in, in_count)
|
||||
!= B_OK) {
|
||||
TRACE("ELANTECH: elantech_dev_send_command failed\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
probe_elantech(ps2_dev* dev)
|
||||
{
|
||||
int i;
|
||||
uint8 val[3];
|
||||
TRACE("ELANTECH: probe\n");
|
||||
|
||||
ps2_dev_command(dev, PS2_CMD_MOUSE_RESET_DIS);
|
||||
|
||||
if (ps2_dev_command(dev, PS2_CMD_DISABLE) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK) {
|
||||
TRACE("ELANTECH: not found (1)\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, val, 3)
|
||||
!= B_OK) {
|
||||
TRACE("ELANTECH: not found (2)\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (val[0] != 0x3c || val[1] != 0x3 || (val[2] != 0xc8 && val[2] != 0x0)) {
|
||||
TRACE("ELANTECH: not found (3)\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
val[0] = 0;
|
||||
if (synaptics_dev_send_command(dev, ELANTECH_CMD_GET_VERSION, val, 3)
|
||||
!= B_OK) {
|
||||
TRACE("ELANTECH: not found (4)\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (val[0] == 0x0 || val[2] == 10 || val[2] == 20 || val[2] == 40
|
||||
|| val[2] == 60 || val[2] == 80 || val[2] == 100 || val[2] == 200) {
|
||||
TRACE("ELANTECH: not found (5)\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
INFO("Elantech found\n");
|
||||
|
||||
dev->name = kElantechPath[dev->idx];
|
||||
dev->packet_size = PS2_PACKET_ELANTECH;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
elantech_write_reg(elantech_cookie* cookie, uint8 reg, uint8 value)
|
||||
{
|
||||
if (reg < 0x7 || reg > 0x26)
|
||||
return B_BAD_VALUE;
|
||||
if (reg > 0x11 && reg < 0x20)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
ps2_dev* dev = cookie->dev;
|
||||
switch (cookie->version) {
|
||||
case 1:
|
||||
// TODO
|
||||
return B_ERROR;
|
||||
break;
|
||||
case 2:
|
||||
if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_REGISTER_WRITE) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, reg) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, value) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK)
|
||||
return B_ERROR;
|
||||
break;
|
||||
case 3:
|
||||
if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READWRITE) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, reg) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, value) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK)
|
||||
return B_ERROR;
|
||||
break;
|
||||
case 4:
|
||||
if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READWRITE) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, reg) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READWRITE) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, value) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_SET_SCALE11) != B_OK)
|
||||
return B_ERROR;
|
||||
break;
|
||||
default:
|
||||
TRACE("ELANTECH: read_write_reg: unknown version\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
elantech_read_reg(elantech_cookie* cookie, uint8 reg, uint8 *value)
|
||||
{
|
||||
if (reg < 0x7 || reg > 0x26)
|
||||
return B_BAD_VALUE;
|
||||
if (reg > 0x11 && reg < 0x20)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
ps2_dev* dev = cookie->dev;
|
||||
uint8 val[3];
|
||||
switch (cookie->version) {
|
||||
case 1:
|
||||
// TODO
|
||||
return B_ERROR;
|
||||
break;
|
||||
case 2:
|
||||
if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READ) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, reg) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, val,
|
||||
3) != B_OK)
|
||||
return B_ERROR;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
if (ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_REGISTER_READWRITE)
|
||||
!= B_OK
|
||||
|| ps2_dev_command(dev, ELANTECH_CMD_PS2_CUSTOM_CMD) != B_OK
|
||||
|| ps2_dev_command(dev, reg) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, val,
|
||||
3) != B_OK)
|
||||
return B_ERROR;
|
||||
break;
|
||||
default:
|
||||
TRACE("ELANTECH: read_write_reg: unknown version\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
if (cookie->version == 4)
|
||||
*value = val[1];
|
||||
else
|
||||
*value = val[0];
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static status_t
|
||||
switch_hardware_tab(ps2_dev* dev, bool on)
|
||||
{
|
||||
uint8 val[3];
|
||||
uint8 arg = 0x00;
|
||||
uint8 command = PS2_CMD_MOUSE_SET_RES;
|
||||
if (on) {
|
||||
arg = 0x0A;
|
||||
command = PS2_CMD_SET_SAMPLE_RATE;
|
||||
}
|
||||
if (ps2_dev_command(dev, PS2_CMD_MOUSE_GET_INFO, NULL, 0, val, 3) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|
||||
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|
||||
|| ps2_dev_command(dev, command, &arg, 1, NULL, 0) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
get_resolution_v4(elantech_cookie* cookie, uint32* x, uint32* y)
|
||||
{
|
||||
uint8 val[3];
|
||||
if (elantech_dev_send_command(cookie->dev, ELANTECH_CMD_GET_RESOLUTION,
|
||||
val, 3) != B_OK)
|
||||
return B_ERROR;
|
||||
*x = (val[1] & 0xf) * 10 + 790;
|
||||
*y = ((val[1] & 0xf) >> 4) * 10 + 790;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
get_range(elantech_cookie* cookie, uint32* x_min, uint32* y_min, uint32* x_max,
|
||||
uint32* y_max, uint32 *width)
|
||||
{
|
||||
status_t status = B_OK;
|
||||
uint8 val[3];
|
||||
switch (cookie->version) {
|
||||
case 1:
|
||||
*x_min = 32;
|
||||
*y_min = 32;
|
||||
*x_max = 544;
|
||||
*y_max = 344;
|
||||
*width = 0;
|
||||
break;
|
||||
case 2:
|
||||
// TODO
|
||||
break;
|
||||
case 3:
|
||||
if ((cookie->send_command)(cookie->dev, ELANTECH_CMD_GET_ID, val, 3)
|
||||
!= B_OK) {
|
||||
return B_ERROR;
|
||||
}
|
||||
*x_min = 0;
|
||||
*y_min = 0;
|
||||
*x_max = ((val[0] & 0xf) << 8) | val[1];
|
||||
*y_max = ((val[0] & 0xf0) << 4) | val[2];
|
||||
*width = 0;
|
||||
break;
|
||||
case 4:
|
||||
if ((cookie->send_command)(cookie->dev, ELANTECH_CMD_GET_ID, val, 3)
|
||||
!= B_OK) {
|
||||
return B_ERROR;
|
||||
}
|
||||
*x_min = 0;
|
||||
*y_min = 0;
|
||||
*x_max = ((val[0] & 0xf) << 8) | val[1];
|
||||
*y_max = ((val[0] & 0xf0) << 4) | val[2];
|
||||
if (cookie->capabilities[1] < 2 || cookie->capabilities[1] > *x_max)
|
||||
return B_ERROR;
|
||||
*width = *x_max / (cookie->capabilities[1] - 1);
|
||||
break;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
enable_absolute_mode(elantech_cookie* cookie)
|
||||
{
|
||||
status_t status = B_OK;
|
||||
switch (cookie->version) {
|
||||
case 1:
|
||||
status = elantech_write_reg(cookie, 0x10, 0x16);
|
||||
if (status == B_OK)
|
||||
status = elantech_write_reg(cookie, 0x11, 0x8f);
|
||||
break;
|
||||
case 2:
|
||||
status = elantech_write_reg(cookie, 0x10, 0x54);
|
||||
if (status == B_OK)
|
||||
status = elantech_write_reg(cookie, 0x11, 0x88);
|
||||
if (status == B_OK)
|
||||
status = elantech_write_reg(cookie, 0x12, 0x60);
|
||||
break;
|
||||
case 3:
|
||||
status = elantech_write_reg(cookie, 0x10, 0xb);
|
||||
break;
|
||||
case 4:
|
||||
status = elantech_write_reg(cookie, 0x7, 0x1);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (cookie->version < 4) {
|
||||
uint8 val;
|
||||
|
||||
for (uint8 retry = 0; retry < 5; retry++) {
|
||||
status = elantech_read_reg(cookie, 0x10, &val);
|
||||
if (status != B_OK)
|
||||
break;
|
||||
snooze(100);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
elantech_open(const char *name, uint32 flags, void **_cookie)
|
||||
{
|
||||
TRACE("ELANTECH: open %s\n", name);
|
||||
ps2_dev* dev;
|
||||
int i;
|
||||
for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) {
|
||||
if (0 == strcmp(ps2_device[i].name, name)) {
|
||||
dev = &ps2_device[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev == NULL) {
|
||||
TRACE("ps2: dev = NULL\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN)
|
||||
return B_BUSY;
|
||||
|
||||
elantech_cookie* cookie = (elantech_cookie*)malloc(
|
||||
sizeof(elantech_cookie));
|
||||
if (cookie == NULL)
|
||||
goto err1;
|
||||
memset(cookie, 0, sizeof(*cookie));
|
||||
|
||||
cookie->movementMaker.Init();
|
||||
cookie->previousZ = 0;
|
||||
*_cookie = cookie;
|
||||
|
||||
cookie->dev = dev;
|
||||
dev->cookie = cookie;
|
||||
dev->disconnect = &elantech_disconnect;
|
||||
dev->handle_int = &elantech_handle_int;
|
||||
|
||||
default_settings(&cookie->settings);
|
||||
|
||||
dev->packet_size = PS2_PACKET_ELANTECH;
|
||||
|
||||
cookie->ring_buffer = create_packet_buffer(
|
||||
ELANTECH_HISTORY_SIZE * dev->packet_size);
|
||||
if (cookie->ring_buffer == NULL) {
|
||||
TRACE("ELANTECH: can't allocate mouse actions buffer\n");
|
||||
goto err2;
|
||||
}
|
||||
// create the mouse semaphore, used for synchronization between
|
||||
// the interrupt handler and the read operation
|
||||
cookie->sem = create_sem(0, "ps2_elantech_sem");
|
||||
if (cookie->sem < 0) {
|
||||
TRACE("ELANTECH: failed creating semaphore!\n");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
uint8 val[3];
|
||||
if (synaptics_dev_send_command(dev, ELANTECH_CMD_GET_VERSION, val, 3)
|
||||
!= B_OK) {
|
||||
TRACE("ELANTECH: get version failed!\n");
|
||||
goto err4;
|
||||
}
|
||||
cookie->fwVersion = (val[0] << 16) | (val[1] << 8) | val[2];
|
||||
if (cookie->fwVersion < 0x020030 || cookie->fwVersion == 0x020600)
|
||||
cookie->version = 1;
|
||||
else {
|
||||
switch (val[0] & 0xf) {
|
||||
case 2:
|
||||
case 4:
|
||||
cookie->version = 2;
|
||||
break;
|
||||
case 5:
|
||||
cookie->version = 3;
|
||||
case 6:
|
||||
case 7:
|
||||
cookie->version = 4;
|
||||
break;
|
||||
default:
|
||||
TRACE("ELANTECH: unknown version!\n");
|
||||
goto err4;
|
||||
}
|
||||
}
|
||||
TRACE("ELANTECH: version 0x%lx (0x%lx)\n", cookie->version,
|
||||
cookie->fwVersion);
|
||||
|
||||
if (cookie->version >= 3)
|
||||
cookie->send_command = &elantech_dev_send_command;
|
||||
else
|
||||
cookie->send_command = &synaptics_dev_send_command;
|
||||
cookie->crcEnabled = (cookie->fwVersion & 0x4000) == 0x4000;
|
||||
|
||||
if ((cookie->send_command)(cookie->dev, ELANTECH_CMD_GET_CAPABILITIES,
|
||||
cookie->capabilities, 3) != B_OK) {
|
||||
TRACE("ELANTECH: get capabilities failed!\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (enable_absolute_mode(cookie) != B_OK) {
|
||||
TRACE("ELANTECH: failed enabling absolute mode!\n");
|
||||
goto err4;
|
||||
}
|
||||
TRACE("ELANTECH: enabled absolute mode!\n");
|
||||
|
||||
uint32 x_min, x_max, y_min, y_max, width;
|
||||
if (get_range(cookie, &x_min, &y_min, &x_max, &y_max, &width) != B_OK) {
|
||||
TRACE("ELANTECH: get range failed!\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
TRACE("ELANTECH: range x %ld-%ld y %ld-%ld (%ld)\n", x_min, x_max,
|
||||
y_min, y_max, width);
|
||||
|
||||
uint32 x_res, y_res;
|
||||
if (get_resolution_v4(cookie, &x_res, &y_res) != B_OK) {
|
||||
TRACE("ELANTECH: get resolution failed!\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
TRACE("ELANTECH: resolution x %ld y %ld (dpi)\n", x_res, y_res);
|
||||
|
||||
gHardwareSpecs.edgeMotionWidth = EDGE_MOTION_WIDTH;
|
||||
|
||||
gHardwareSpecs.areaStartX = x_min;
|
||||
gHardwareSpecs.areaEndX = x_max;
|
||||
gHardwareSpecs.areaStartY = y_min;
|
||||
gHardwareSpecs.areaEndY = y_max;
|
||||
|
||||
gHardwareSpecs.minPressure = MIN_PRESSURE;
|
||||
gHardwareSpecs.realMaxPressure = REAL_MAX_PRESSURE;
|
||||
gHardwareSpecs.maxPressure = MAX_PRESSURE;
|
||||
|
||||
cookie->movementMaker.SetSettings(&cookie->settings);
|
||||
cookie->movementMaker.SetSpecs(&gHardwareSpecs);
|
||||
|
||||
if (ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0) != B_OK)
|
||||
goto err4;
|
||||
|
||||
atomic_or(&dev->flags, PS2_FLAG_ENABLED);
|
||||
|
||||
TRACE("ELANTECH: open %s success\n", name);
|
||||
return B_OK;
|
||||
|
||||
err4:
|
||||
delete_sem(cookie->sem);
|
||||
err3:
|
||||
delete_packet_buffer(cookie->ring_buffer);
|
||||
err2:
|
||||
free(cookie);
|
||||
err1:
|
||||
atomic_and(&dev->flags, ~PS2_FLAG_OPEN);
|
||||
|
||||
TRACE("ELANTECH: open %s failed\n", name);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
elantech_close(void *_cookie)
|
||||
{
|
||||
gEventProducer.CancelEvent();
|
||||
|
||||
elantech_cookie *cookie = (elantech_cookie*)_cookie;
|
||||
|
||||
ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0,
|
||||
150000);
|
||||
|
||||
delete_packet_buffer(cookie->ring_buffer);
|
||||
delete_sem(cookie->sem);
|
||||
|
||||
atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN);
|
||||
atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED);
|
||||
|
||||
// Reset the touchpad so it generate standard ps2 packets instead of
|
||||
// extended ones. If not, BeOS is confused with such packets when rebooting
|
||||
// without a complete shutdown.
|
||||
status_t status = ps2_reset_mouse(cookie->dev);
|
||||
if (status != B_OK) {
|
||||
INFO("ps2: reset failed\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
TRACE("ELANTECH: close %s done\n", cookie->dev->name);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
elantech_freecookie(void *_cookie)
|
||||
{
|
||||
free(_cookie);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
elantech_ioctl(void *_cookie, uint32 op, void *buffer, size_t length)
|
||||
{
|
||||
elantech_cookie *cookie = (elantech_cookie*)_cookie;
|
||||
mouse_movement movement;
|
||||
status_t status;
|
||||
|
||||
switch (op) {
|
||||
case MS_READ:
|
||||
TRACE("ELANTECH: MS_READ get event\n");
|
||||
if ((status = get_elantech_movement(cookie, &movement)) != B_OK)
|
||||
return status;
|
||||
return user_memcpy(buffer, &movement, sizeof(movement));
|
||||
|
||||
case MS_IS_TOUCHPAD:
|
||||
TRACE("ELANTECH: MS_IS_TOUCHPAD\n");
|
||||
return B_OK;
|
||||
|
||||
case MS_SET_TOUCHPAD_SETTINGS:
|
||||
TRACE("ELANTECH: MS_SET_TOUCHPAD_SETTINGS");
|
||||
user_memcpy(&cookie->settings, buffer, sizeof(touchpad_settings));
|
||||
return B_OK;
|
||||
|
||||
case MS_SET_CLICKSPEED:
|
||||
TRACE("ELANTECH: ioctl MS_SETCLICK (set click speed)\n");
|
||||
return user_memcpy(&cookie->movementMaker.click_speed, buffer,
|
||||
sizeof(bigtime_t));
|
||||
|
||||
default:
|
||||
TRACE("ELANTECH: unknown opcode: %ld\n", op);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
elantech_read(void* cookie, off_t pos, void* buffer, size_t* _length)
|
||||
{
|
||||
*_length = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
elantech_write(void* cookie, off_t pos, const void* buffer, size_t* _length)
|
||||
{
|
||||
*_length = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
elantech_handle_int(ps2_dev* dev)
|
||||
{
|
||||
elantech_cookie* cookie = (elantech_cookie*)dev->cookie;
|
||||
|
||||
// we got a real event cancel the fake event
|
||||
gEventProducer.CancelEvent();
|
||||
|
||||
uint8 val;
|
||||
val = cookie->dev->history[0].data;
|
||||
cookie->buffer[cookie->packet_index] = val;
|
||||
cookie->packet_index++;
|
||||
|
||||
if (cookie->packet_index < PS2_PACKET_ELANTECH)
|
||||
return B_HANDLED_INTERRUPT;
|
||||
|
||||
cookie->packet_index = 0;
|
||||
if (packet_buffer_write(cookie->ring_buffer,
|
||||
cookie->buffer, cookie->dev->packet_size)
|
||||
!= cookie->dev->packet_size) {
|
||||
// buffer is full, drop new data
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
release_sem_etc(cookie->sem, 1, B_DO_NOT_RESCHEDULE);
|
||||
return B_INVOKE_SCHEDULER;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
elantech_disconnect(ps2_dev *dev)
|
||||
{
|
||||
elantech_cookie *cookie = (elantech_cookie*)dev->cookie;
|
||||
// the mouse device might not be opened at this point
|
||||
INFO("ELANTECH: elantech_disconnect %s\n", dev->name);
|
||||
if ((dev->flags & PS2_FLAG_OPEN) != 0)
|
||||
release_sem(cookie->sem);
|
||||
}
|
||||
|
||||
|
||||
device_hooks gElantechDeviceHooks = {
|
||||
elantech_open,
|
||||
elantech_close,
|
||||
elantech_freecookie,
|
||||
elantech_ioctl,
|
||||
elantech_read,
|
||||
elantech_write,
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2013, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* The elantech_model_info struct and all the hardware specs are taken from the
|
||||
* linux driver, thanks a lot!
|
||||
*
|
||||
* Authors:
|
||||
* Jérôme Duval <korli@users.berlios.de>
|
||||
*/
|
||||
#ifndef _PS2_ELANTECH_H
|
||||
#define _PS2_ELANTECH_H
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <touchpad_settings.h>
|
||||
|
||||
#include "movement_maker.h"
|
||||
#include "packet_buffer.h"
|
||||
#include "ps2_dev.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
ps2_dev* dev;
|
||||
|
||||
sem_id sem;
|
||||
struct packet_buffer* ring_buffer;
|
||||
size_t packet_index;
|
||||
uint8 buffer[PS2_PACKET_ELANTECH];
|
||||
uint8 mode;
|
||||
|
||||
uint8 previousZ;
|
||||
TouchpadMovement movementMaker;
|
||||
|
||||
touchpad_settings settings;
|
||||
uint32 version;
|
||||
uint32 fwVersion;
|
||||
uint8 capabilities[3];
|
||||
bool crcEnabled;
|
||||
uint32 fingers;
|
||||
status_t (*send_command)(ps2_dev* dev, uint8 cmd, uint8 *in, int in_count);
|
||||
} elantech_cookie;
|
||||
|
||||
|
||||
status_t probe_elantech(ps2_dev *dev);
|
||||
|
||||
status_t elantech_open(const char *name, uint32 flags, void **_cookie);
|
||||
status_t elantech_close(void *_cookie);
|
||||
status_t elantech_freecookie(void *_cookie);
|
||||
status_t elantech_ioctl(void *_cookie, uint32 op, void *buffer, size_t length);
|
||||
|
||||
int32 elantech_handle_int(ps2_dev *dev);
|
||||
void elantech_disconnect(ps2_dev *dev);
|
||||
|
||||
extern device_hooks gElantechDeviceHooks;
|
||||
|
||||
|
||||
#endif /* _PS2_ELANTECH_H */
|
||||
Reference in New Issue
Block a user