⛏️ index : haiku.git

author Samuel Rodríguez Pérez <samuelgaliza@gmail.com> 2025-11-18 14:19:08.0 +00:00:00
committer Adrien Destugues <pulkomandy@pulkomandy.tk> 2026-01-02 11:01:29.0 +00:00:00
commit
35e407488af88ae5c9c4839da9de5c4fc29328d5 [patch]
tree
f9a4aff6d4914b816f2849f0fb09bfc97709731b
parent
42c5c30bc750d796f548c2802604aabe3e2163c0
download
35e407488af88ae5c9c4839da9de5c4fc29328d5.tar.gz

ps/2 elantech: v3 support (untested)

Trackpoint related packets are ignored as of now.
Packet description and validations based on FreeBSD 14.3 psm driver.
Packet processing code based on OpenBSD 7.8 pms driver with variable
naming adjustments to match FreeBSD and Haiku.
Excluded v3 faulty devices as described on Linux ETPS/2 driver.

Change-Id: I5493128557b72fe72f0ea72e225854b745da459a
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9953
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Reviewed-by: Adrien Destugues <pulkomandy@pulkomandy.tk>

Diff

 src/add-ons/kernel/bus_managers/ps2/ps2_elantech.cpp | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+), 1 deletion(-)

diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_elantech.cpp b/src/add-ons/kernel/bus_managers/ps2/ps2_elantech.cpp
index af6c043..fea68a2 100644
--- a/src/add-ons/kernel/bus_managers/ps2/ps2_elantech.cpp
+++ b/src/add-ons/kernel/bus_managers/ps2/ps2_elantech.cpp
@@ -80,6 +80,9 @@


static status_t
elantech_process_packet_v3(elantech_cookie *cookie, touchpad_movement *_event,
	uint8 packet[PS2_PACKET_ELANTECH]);
static status_t
elantech_process_packet_v4(elantech_cookie *cookie, touchpad_movement *_event,
	uint8 packet[PS2_PACKET_ELANTECH]);

@@ -112,9 +115,119 @@
			cookie->dev->packet_size) != cookie->dev->packet_size) {
		TRACE("ELANTECH: error copying buffer\n");
		return B_ERROR;
	}

	if ((cookie->capabilities[0] & 0x80) != 0 && (packet[3] & 0x0f) == 0x06) {
		status = IGNORE_EVENT;
	} else {
		switch (cookie->version) {
			case 3:
				status = elantech_process_packet_v3(cookie, _event, packet);
				break;
			case 4:
				status = elantech_process_packet_v4(cookie, _event, packet);
				break;
			default:
				TRACE("ELANTECH: Unknown version %d.\n", cookie->version);
				return B_ERROR;
		}
	}
	return status;
}


static status_t
elantech_process_packet_v3(elantech_cookie *cookie, touchpad_movement *_event,
	uint8 packet[PS2_PACKET_ELANTECH])
{
	/*               7   6   5   4   3   2   1   0 (LSB)
	 * -------------------------------------------
	 * ipacket[0]:  N1  N0  W3  W2   0   1   R   L
	 * ipacket[1]:  P7  P6  P5  P4 X11 X10  X9  X8
	 * ipacket[2]:  X7  X6  X5  X4  X3  X2  X1  X0
	 * ipacket[3]:   0   0  W1  W0   0   0   1   0
	 * ipacket[4]:  P3  P1  P2  P0 Y11 Y10  Y9  Y8
	 * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
	 * -------------------------------------------
	 */

	// Validation based on FreeBSD psm.c driver.
	bool valid;
	valid = false;
	if (cookie->crcEnabled) {
		if ((packet[3] & 0x09) == 0x08 || (packet[3] & 0xcf) == 0x02)
			valid = true;
	} else if (((packet[0] & 0x0c) == 0x04 && (packet[3] & 0xcf) == 0x02)
				|| ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c))
		valid = true;

	if (!valid)
		return IGNORE_EVENT;

	const uint8 debounce_pkt[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff };
	uint32 x, y;
	uint8 n, w, z;
	uint8 buttons;

	buttons = packet[0] & 3;

	x = ((packet[1] & 0x0f) << 8 | packet[2]);
	y = ((packet[4] & 0x0f) << 8 | packet[5]);
	z = 0;
	n = (packet[0] & 0xc0) >> 6;
	if (n == 2) {
		/*
		 * Two-finger touch causes two packets -- a head packet
		 * and a tail packet. We report a single event and ignore
		 * the tail packet.
		 */
		if (cookie->crcEnabled) {
			if ((packet[3] & 0x09) != 0x08)
				return IGNORE_EVENT;
		} else {
			/* The hardware sends this packet when in debounce state.
			 * The packet should be ignored. */
			if (!memcmp(packet, debounce_pkt, sizeof(debounce_pkt)))
				return IGNORE_EVENT;
			if ((packet[0] & 0x0c) != 0x04 &&
				(packet[3] & 0xcf) != 0x02) {
				/* not the head packet -- ignore */
				return IGNORE_EVENT;
			}
		}
	}

	return elantech_process_packet_v4(cookie, _event, packet);
	/* Prevent jumping cursor if pad isn't touched or reports garbage. */
	if (n == 0 ||
		((x == 0 || y == 0 || x == gHardwareSpecs.areaEndX || y == gHardwareSpecs.areaEndY)
		&& (x != cookie->x || y != cookie->y))) {
		x = cookie->x;
		y = cookie->y;
	}

	if (cookie->fwVersion >= 0x020800)
		z = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4);
	else if (n)
		z = DEFAULT_PRESSURE;

	w = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4);

	cookie->x = x;
	cookie->y = y;

	touchpad_movement event = {
		.buttons = buttons,
		.xPosition = x,
		.yPosition = y,
		.zPressure = z,
		//.nFingers = n,
		.fingers = (uint8)((1 << n) - 1),
		.fingerWidth = w,
	};

	*_event = event;

	return B_OK;
}


@@ -803,6 +916,11 @@
		if (cookie->send_command(cookie->dev, ELANTECH_CMD_GET_SAMPLE, cookie->samples, 3)
			!= B_OK) {
			TRACE("ELANTECH: failed to query sample data\n");
			return B_ERROR;
		}

		if (cookie->samples[1] == 0x74 && cookie->version == 3) {
			TRACE("ELANTECH: absolute mode broken, forcing standard PS/2 protocol\n");
			return B_ERROR;
		}
	}