ps2 synaptics: implement 'extended W' mode.
"Newer" synaptics touchpad support a new mode where they can report more information to the host. In this mode, there is a different packet format for tracking extra data from the touchpad, including a wheel encoder (mousewheel) if available, and multitouch finger tracking. This mode is documented in the Synaptics touchpad interfacing guide (Synaptics document 511-000275-01 Rev. B), but was not yet implemented in our driver. It should help with detecting multiple fingers, or finger position on clickpads to determine right or left click. This change implements the following items from the Synaptics interfacing guide: - Cleanup and clarify the code for features detection to properly report clickpads - Enable "extended W" mode if supported - Process extended W values 0 (mouse wheels, reported in the touchpad_event structure and could be used by input_server for scrolling), 1 (secondary finger), and 2 (finger count) - Fix handling of wValue, which is not always a finger width - Add handling of vValuen which indicates the finger width when wValue doesn't Overall, this should provide the movement_maker with a better picture of what's happening. Also improve tracing to show received packets and the corresponding WValue since that's an important value in identifying which type of packet it is. Unfortunately I currently don't have a laptop with synaptics touchpad to test this with. Change-Id: If334392f4eb2a146955f6c8c897f0ab64d79b8d9 Reviewed-on: https://review.haiku-os.org/c/haiku/+/4425 Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org> Reviewed-by: Adrien Destugues <pulkomandy@pulkomandy.tk> Reviewed-by: nephele <nep@packageloss.eu>
This commit is contained in:
parent
64a48a5521
commit
49efa33dd0
@ -152,6 +152,10 @@ typedef struct {
|
||||
uint8 fingers;
|
||||
bool gesture;
|
||||
uint8 fingerWidth;
|
||||
int32 wheel_ydelta;
|
||||
int32 wheel_xdelta;
|
||||
int32 wheel_zdelta;
|
||||
int32 wheel_wdelta;
|
||||
// 1 - 4 normal width
|
||||
// 5 - 11 very wide finger or palm
|
||||
// 12 maximum reportable width; extreme wide contact
|
||||
|
@ -64,6 +64,29 @@ enum {
|
||||
static touchpad_specs gHardwareSpecs;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8 majorVersion;
|
||||
uint8 minorVersion;
|
||||
|
||||
uint8 nExtendedButtons;
|
||||
uint8 firstExtendedButton;
|
||||
uint8 extendedButtonsState;
|
||||
|
||||
bool capExtended : 1;
|
||||
bool capMiddleButton : 1;
|
||||
bool capSleep : 1;
|
||||
bool capFourButtons : 1;
|
||||
bool capMultiFinger : 1;
|
||||
bool capMultiFingerReport : 1;
|
||||
bool capPalmDetection : 1;
|
||||
bool capPassThrough : 1;
|
||||
bool capAdvancedGestures : 1;
|
||||
bool capExtendedWMode : 1;
|
||||
bool capClickPadUniform : 1;
|
||||
int capClickPadButtonCount : 2;
|
||||
} touchpad_info;
|
||||
|
||||
|
||||
const char* kSynapticsPath[4] = {
|
||||
"input/touchpad/ps2/synaptics_0",
|
||||
"input/touchpad/ps2/synaptics_1",
|
||||
@ -131,7 +154,7 @@ static status_t
|
||||
get_synaptics_movment(synaptics_cookie *cookie, touchpad_movement *_event, bigtime_t timeout)
|
||||
{
|
||||
status_t status;
|
||||
touchpad_movement event;
|
||||
touchpad_movement event = {};
|
||||
uint8 event_buffer[PS2_MAX_PACKET_SIZE];
|
||||
uint8 wValue0, wValue1, wValue2, wValue3, wValue;
|
||||
uint32 val32;
|
||||
@ -155,6 +178,7 @@ get_synaptics_movment(synaptics_cookie *cookie, touchpad_movement *_event, bigti
|
||||
|
||||
event.buttons = event_buffer[0] & 3;
|
||||
event.zPressure = event_buffer[2];
|
||||
bool isExtended = false;
|
||||
|
||||
if (sTouchpadInfo.capExtended) {
|
||||
wValue0 = event_buffer[3] >> 2 & 1;
|
||||
@ -167,12 +191,98 @@ get_synaptics_movment(synaptics_cookie *cookie, touchpad_movement *_event, bigti
|
||||
wValue = wValue | (wValue2 << 2);
|
||||
wValue = wValue | (wValue3 << 3);
|
||||
|
||||
event.fingerWidth = wValue;
|
||||
|
||||
TRACE("SYNAPTICS: received packet %02x %02x %02x %02x %02x %02x -> W = %d\n",
|
||||
event_buffer[0], event_buffer[1], event_buffer[2], event_buffer[3], event_buffer[4],
|
||||
event_buffer[5], wValue);
|
||||
|
||||
if (wValue <= 1) {
|
||||
// Multiple fingers detected, report the finger count.
|
||||
event.fingers = 2 + wValue;
|
||||
|
||||
// There is a separate "v" value indicating the finger width
|
||||
wValue0 = event_buffer[3] >> 1 & 1;
|
||||
wValue1 = event_buffer[4] >> 1 & 1;
|
||||
wValue2 = event_buffer[2] >> 0 & 1;
|
||||
|
||||
wValue = wValue0;
|
||||
wValue = wValue | (wValue1 << 1);
|
||||
wValue = wValue | (wValue2 << 2);
|
||||
|
||||
event.fingerWidth = wValue * 2;
|
||||
} else if (wValue >= 4) {
|
||||
// wValue = 4 to 15 corresponds to a finger width report for a single finger
|
||||
event.fingerWidth = wValue;
|
||||
event.fingers = 1;
|
||||
}
|
||||
// wValue = 2 - Extended W mode
|
||||
// wValue = 3 - Packet from pass-through device
|
||||
event.gesture = false;
|
||||
|
||||
if (sTouchpadInfo.capExtendedWMode && wValue == 2) {
|
||||
// The extended W can be encoded on 4 bits (values 0-7) or 8 bits (80-FF)
|
||||
uint8_t extendedWValue = event_buffer[5] >> 4;
|
||||
if (extendedWValue >= 8)
|
||||
extendedWValue = event_buffer[5];
|
||||
isExtended = true;
|
||||
|
||||
// Extended W = 0 - Scroll wheels
|
||||
if (extendedWValue == 0) {
|
||||
event.wheel_ydelta = event_buffer[2];
|
||||
event.wheel_xdelta = event_buffer[3];
|
||||
event.wheel_zdelta = event_buffer[4];
|
||||
event.wheel_wdelta = (event_buffer[5] & 0x0f) | (event_buffer[3] & 0x30);
|
||||
// Sign extend wdelta if needed
|
||||
if (event.wheel_wdelta & 0x20)
|
||||
event.wheel_wdelta |= 0xffffffc0;
|
||||
}
|
||||
|
||||
// Extended W = 1 - Secondary finger
|
||||
if (extendedWValue == 1) {
|
||||
event.xPosition = event_buffer[1];
|
||||
event.yPosition = event_buffer[2];
|
||||
|
||||
val32 = event_buffer[4] & 0x0F;
|
||||
event.xPosition += val32 << 8;
|
||||
val32 = event_buffer[4] & 0xF0;
|
||||
event.yPosition += val32 << 4;
|
||||
|
||||
event.xPosition *= 2;
|
||||
event.yPosition *= 2;
|
||||
|
||||
event.zPressure = event_buffer[5] & 0x0F;
|
||||
event.zPressure += event_buffer[3] & 0x30;
|
||||
|
||||
// There is a separate "v" value indicating the finger width
|
||||
wValue0 = event_buffer[1] >> 0 & 1;
|
||||
wValue1 = event_buffer[2] >> 0 & 1;
|
||||
wValue2 = event_buffer[5] >> 0 & 1;
|
||||
|
||||
wValue = wValue0;
|
||||
wValue = wValue | (wValue1 << 1);
|
||||
wValue = wValue | (wValue2 << 2);
|
||||
|
||||
event.fingerWidth = wValue * 2;
|
||||
}
|
||||
|
||||
// Extended W = 2 - Finger state info
|
||||
if (extendedWValue == 2) {
|
||||
event.fingers = event_buffer[1] & 0x0F;
|
||||
// TODO this event also provides primary and secondary finger indexes, what do
|
||||
// these mean?
|
||||
}
|
||||
|
||||
// Other values are reserved for other uses (usually enabled with special commands)
|
||||
|
||||
|
||||
*_event = event;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Clickpad pretends that all clicks on the touchpad are middle clicks.
|
||||
// Pass them to userspace as left clicks instead.
|
||||
if (sTouchpadInfo.capClickPad)
|
||||
if (sTouchpadInfo.capClickPadButtonCount == 1)
|
||||
event.buttons |= ((event_buffer[0] ^ event_buffer[3]) & 0x01);
|
||||
|
||||
if (sTouchpadInfo.capMiddleButton || sTouchpadInfo.capFourButtons)
|
||||
@ -212,18 +322,20 @@ get_synaptics_movment(synaptics_cookie *cookie, touchpad_movement *_event, bigti
|
||||
event.gesture = event_buffer[0] >> 2 & 1;
|
||||
}
|
||||
|
||||
event.xPosition = event_buffer[4];
|
||||
event.yPosition = event_buffer[5];
|
||||
if (!isExtended) {
|
||||
event.xPosition = event_buffer[4];
|
||||
event.yPosition = event_buffer[5];
|
||||
|
||||
val32 = event_buffer[1] & 0x0F;
|
||||
event.xPosition += val32 << 8;
|
||||
val32 = event_buffer[1] >> 4 & 0x0F;
|
||||
event.yPosition += val32 << 8;
|
||||
val32 = event_buffer[1] & 0x0F;
|
||||
event.xPosition += val32 << 8;
|
||||
val32 = event_buffer[1] >> 4 & 0x0F;
|
||||
event.yPosition += val32 << 8;
|
||||
|
||||
xTwelfBit = event_buffer[3] >> 4 & 1;
|
||||
event.xPosition += xTwelfBit << 12;
|
||||
yTwelfBit = event_buffer[3] >> 5 & 1;
|
||||
event.yPosition += yTwelfBit << 12;
|
||||
xTwelfBit = event_buffer[3] >> 4 & 1;
|
||||
event.xPosition += xTwelfBit << 12;
|
||||
yTwelfBit = event_buffer[3] >> 5 & 1;
|
||||
event.yPosition += yTwelfBit << 12;
|
||||
}
|
||||
|
||||
*_event = event;
|
||||
return B_OK;
|
||||
@ -245,35 +357,66 @@ query_capability(ps2_dev *dev)
|
||||
TRACE("SYNAPTICS: middle button %2x\n", val[0] >> 2 & 1);
|
||||
sTouchpadInfo.capMiddleButton = val[0] >> 2 & 1;
|
||||
|
||||
TRACE("SYNAPTICS: sleep mode %2x\n", val[2] >> 4 & 1);
|
||||
sTouchpadInfo.capSleep = val[2] >> 4 & 1;
|
||||
TRACE("SYNAPTICS: four buttons %2x\n", val[2] >> 3 & 1);
|
||||
sTouchpadInfo.capFourButtons = val[2] >> 3 & 1;
|
||||
TRACE("SYNAPTICS: multi finger %2x\n", val[2] >> 1 & 1);
|
||||
sTouchpadInfo.capMultiFinger = val[2] >> 1 & 1;
|
||||
TRACE("SYNAPTICS: palm detection %2x\n", val[2] & 1);
|
||||
sTouchpadInfo.capPalmDetection = val[2] & 1;
|
||||
TRACE("SYNAPTICS: pass through %2x\n", val[2] >> 7 & 1);
|
||||
sTouchpadInfo.capPassThrough = val[2] >> 7 & 1;
|
||||
|
||||
// bit 6, low power, is only informative (touchpad has an automatic powersave mode)
|
||||
|
||||
TRACE("SYNAPTICS: multi finger report %2x\n", val[2] >> 5 & 1);
|
||||
sTouchpadInfo.capMultiFingerReport = val[2] >> 5 & 1;
|
||||
|
||||
TRACE("SYNAPTICS: sleep mode %2x\n", val[2] >> 4 & 1);
|
||||
sTouchpadInfo.capSleep = val[2] >> 4 & 1;
|
||||
|
||||
TRACE("SYNAPTICS: four buttons %2x\n", val[2] >> 3 & 1);
|
||||
sTouchpadInfo.capFourButtons = val[2] >> 3 & 1;
|
||||
|
||||
// bit 2, TouchStyk ballistics, not further documented in the documents I have
|
||||
|
||||
TRACE("SYNAPTICS: multi finger %2x\n", val[2] >> 1 & 1);
|
||||
sTouchpadInfo.capMultiFinger = val[2] >> 1 & 1;
|
||||
|
||||
TRACE("SYNAPTICS: palm detection %2x\n", val[2] & 1);
|
||||
sTouchpadInfo.capPalmDetection = val[2] & 1;
|
||||
|
||||
if (get_information_query(dev, nExtendedQueries, kContinuedCapabilities,
|
||||
val) == B_OK) {
|
||||
sTouchpadInfo.capAdvancedGestures = val[0] >> 3 & 1;
|
||||
TRACE("SYNAPTICS: advanced gestures %x\n", sTouchpadInfo.capAdvancedGestures);
|
||||
|
||||
sTouchpadInfo.capClickPadButtonCount = (val[0] >> 4 & 1) | ((val[1] >> 0 & 1) << 1);
|
||||
sTouchpadInfo.capClickPadUniform = val[1] >> 4 & 1;
|
||||
TRACE("SYNAPTICS: clickpad buttons: %x\n", sTouchpadInfo.capClickPadButtonCount);
|
||||
TRACE("SYNAPTICS: clickpad type: %s\n",
|
||||
sTouchpadInfo.capClickPadUniform ? "uniform" : "hinged");
|
||||
|
||||
} else {
|
||||
sTouchpadInfo.capAdvancedGestures = 0;
|
||||
sTouchpadInfo.capClickPadButtonCount = 0;
|
||||
sTouchpadInfo.capClickPadUniform = 0;
|
||||
sTouchpadInfo.capAdvancedGestures = 0;
|
||||
}
|
||||
|
||||
if (get_information_query(dev, nExtendedQueries, kExtendedModelId, val)
|
||||
!= B_OK) {
|
||||
// "Extended Model ID" is not supported, so there cannot be extra
|
||||
// buttons.
|
||||
sTouchpadInfo.nExtendedButtons = 0;
|
||||
sTouchpadInfo.firstExtendedButton = 0;
|
||||
sTouchpadInfo.capClickPad = false;
|
||||
sTouchpadInfo.capExtendedWMode = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
sTouchpadInfo.capClickPad = (val[0] >> 5 & 1) | (val[1] >> 0 & 1);
|
||||
TRACE("SYNAPTICS: clickpad %x\n", sTouchpadInfo.capClickPad);
|
||||
|
||||
TRACE("SYNAPTICS: extended buttons %2x\n", val[1] >> 4 & 15);
|
||||
sTouchpadInfo.nExtendedButtons = val[1] >> 4 & 15;
|
||||
sTouchpadInfo.extendedButtonsState = 0;
|
||||
|
||||
if (sTouchpadInfo.capMiddleButton)
|
||||
sTouchpadInfo.capExtendedWMode = val[0] >> 2 & 1;
|
||||
TRACE("SYNAPTICS: extended wmode %2x\n", sTouchpadInfo.capExtendedWMode);
|
||||
|
||||
if (sTouchpadInfo.capFourButtons)
|
||||
sTouchpadInfo.firstExtendedButton = 4;
|
||||
else if (sTouchpadInfo.capMiddleButton)
|
||||
sTouchpadInfo.firstExtendedButton = 3;
|
||||
else
|
||||
sTouchpadInfo.firstExtendedButton = 2;
|
||||
@ -507,10 +650,12 @@ synaptics_open(const char *name, uint32 flags, void **_cookie)
|
||||
}
|
||||
|
||||
// Set Mode
|
||||
if (sTouchpadInfo.capExtended)
|
||||
cookie->mode = SYN_ABSOLUTE_W_MODE;
|
||||
if (sTouchpadInfo.capExtendedWMode)
|
||||
cookie->mode = SYN_MODE_ABSOLUTE | SYN_MODE_W | SYN_MODE_EXTENDED_W;
|
||||
else if (sTouchpadInfo.capExtended)
|
||||
cookie->mode = SYN_MODE_ABSOLUTE | SYN_MODE_W;
|
||||
else
|
||||
cookie->mode = SYN_ABSOLUTE_MODE;
|
||||
cookie->mode = SYN_MODE_ABSOLUTE;
|
||||
|
||||
status = set_touchpad_mode(dev, cookie->mode);
|
||||
if (status < B_OK) {
|
||||
@ -638,22 +783,21 @@ synaptics_handle_int(ps2_dev *dev)
|
||||
|
||||
val = cookie->dev->history[0].data;
|
||||
|
||||
if ((cookie->packet_index == 0 || cookie->packet_index == 3)
|
||||
&& (val & 8) != 0) {
|
||||
INFO("SYNAPTICS: bad mouse data, trying resync\n");
|
||||
if ((cookie->packet_index == 0 || cookie->packet_index == 3) && (val & 8) != 0) {
|
||||
INFO("SYNAPTICS: bad mouse data %#02x, trying resync\n", val);
|
||||
cookie->packet_index = 0;
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
}
|
||||
if (cookie->packet_index == 0 && val >> 6 != 0x02) {
|
||||
TRACE("SYNAPTICS: first package begins not with bit 1, 0\n");
|
||||
TRACE("SYNAPTICS: first package %#02x begins not with bit 1, 0\n", val);
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
}
|
||||
if (cookie->packet_index == 3 && val >> 6 != 0x03) {
|
||||
TRACE("SYNAPTICS: third package begins not with bit 1, 1\n");
|
||||
cookie->packet_index = 0;
|
||||
}
|
||||
if (cookie->packet_index == 3 && val >> 6 != 0x03) {
|
||||
TRACE("SYNAPTICS: third package %#02x begins not with bit 1, 1\n", val);
|
||||
cookie->packet_index = 0;
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
}
|
||||
cookie->buffer[cookie->packet_index] = val;
|
||||
}
|
||||
cookie->buffer[cookie->packet_index] = val;
|
||||
|
||||
cookie->packet_index++;
|
||||
if (cookie->packet_index >= 6) {
|
||||
@ -664,6 +808,7 @@ synaptics_handle_int(ps2_dev *dev)
|
||||
if (sPassthroughDevice->active
|
||||
&& sPassthroughDevice->handle_int != NULL
|
||||
&& IS_SYN_PT_PACKAGE(cookie->buffer)) {
|
||||
TRACE("SYNAPTICS: forward packet to passthrough device\n");
|
||||
status_t status;
|
||||
|
||||
sPassthroughDevice->history[0].data = cookie->buffer[1];
|
||||
|
@ -16,13 +16,25 @@
|
||||
|
||||
|
||||
#define SYN_TOUCHPAD 0x47
|
||||
// Synaptics modes
|
||||
#define SYN_ABSOLUTE_MODE 0x80
|
||||
// Absolute plus w mode
|
||||
#define SYN_ABSOLUTE_W_MODE 0x81
|
||||
|
||||
// Synaptics modes (values of the "mode" field in synaptics_cookie)
|
||||
#define SYN_MODE_ABSOLUTE (1 << 7)
|
||||
// Absolute mode reports the absolute X/Y position of the finger,
|
||||
// instead of relative X/Y movement
|
||||
|
||||
#define SYN_MODE_W (1 << 0)
|
||||
// Adds finger width (W) value in addition to absolute X/Y
|
||||
#define SYN_MODE_EXTENDED_W (1 << 2)
|
||||
// Supports tracking for multiple fingers
|
||||
#define SYN_FOUR_BYTE_CHILD (1 << 1)
|
||||
// Low power sleep mode
|
||||
#define SYN_SLEEP_MODE 0x0C
|
||||
// Guest packets size for pass-through device
|
||||
#define SYN_MODE_SLEEP (1 << 3)
|
||||
// Low power sleep mode
|
||||
#define SYN_MODE_PASSTHROUGH_ACPI (1 << 4)
|
||||
#define SYN_MODE_PASSTHROUGH_TRANSPARENT (1 << 5)
|
||||
#define SYN_MODE_HIGH_RATE (1 << 6)
|
||||
// Use 80 packets per second instead of 40
|
||||
|
||||
// Synaptics Passthrough port
|
||||
#define SYN_CHANGE_MODE 0x14
|
||||
#define SYN_PASSTHROUGH_CMD 0x28
|
||||
@ -35,25 +47,6 @@
|
||||
&& (val[3] & 0xCC) == 0xc4)
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8 majorVersion;
|
||||
uint8 minorVersion;
|
||||
|
||||
bool capExtended;
|
||||
bool capMiddleButton;
|
||||
bool capSleep;
|
||||
bool capFourButtons;
|
||||
bool capMultiFinger;
|
||||
bool capPalmDetection;
|
||||
bool capPassThrough;
|
||||
bool capClickPad;
|
||||
|
||||
uint8 nExtendedButtons;
|
||||
uint8 firstExtendedButton;
|
||||
uint8 extendedButtonsState;
|
||||
} touchpad_info;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ps2_dev* dev;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user