⛏️ index : haiku.git

author Samuel Rodríguez Pérez <samuelgaliza@gmail.com> 2025-11-14 23:36:41.0 +00:00:00
committer Adrien Destugues <pulkomandy@pulkomandy.tk> 2026-01-02 11:01:29.0 +00:00:00
commit
5578783036049c6b746d72a59bb4dba2b0b2a4e4 [patch]
tree
04990c0a7eeb9b92ba42a6ef498c16f2713e0b9d
parent
a3f6c4d48477406e608c333a1bee5aac8f7338e9
download
5578783036049c6b746d72a59bb4dba2b0b2a4e4.tar.gz

ps/2 elantech: Initial cleanups and fixes to support input devices

- Add references for driver implementation.
  References from FreeBSD 14.3, OpenBSD 7.8, Linux 6.17 sources
  and Linux 4.16 documentation.
- Add pragma marks for easy navigation
- Add missing define to fetch firware info from hardware
- Reduce size of version field
- Update probe function to be able to enable supported devices
- Update open function to add missing v4 devices
- Fix enable_absolute_mode and use same snooze time as BSDs and Linux drivers
- Fix get_resolution_v4 and set sane defaults instead of failing with error
- Update license for ps2_elantech.{h,cpp}

Change-Id: I76fba3be04d7b940079fc78c3b7fe7d8bf8dfa06
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10011
Reviewed-by: Adrien Destugues <pulkomandy@pulkomandy.tk>

Diff

 src/add-ons/kernel/bus_managers/ps2/ps2_elantech.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
 src/add-ons/kernel/bus_managers/ps2/ps2_elantech.h   | 15 ++++++++++++---
 2 files changed, 73 insertions(+), 22 deletions(-)

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 91c0ac9..3977a6a 100644
--- a/src/add-ons/kernel/bus_managers/ps2/ps2_elantech.cpp
+++ b/src/add-ons/kernel/bus_managers/ps2/ps2_elantech.cpp
@@ -1,12 +1,18 @@
/*
 * Copyright 2013, Haiku, Inc.
 * Copyright 2013-2025, 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
 * Hardware specs taken from the linux and BSDs drivers, thanks a lot!
 *
 * References:
 *	- https://cgit.freebsd.org/src/tree/sys/dev/atkbdc/psm.c?h=releng/14.3
 *	- https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/dev/pckbc/?only_with_tag=OPENBSD_7_8_BASE
 *	- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/input/mouse/elantech.c?h=v6.17
 *	- https://www.kernel.org/doc/html/v4.16/input/devices/elantech.html
 *
 * Authors:
 *		Jérôme Duval <korli@users.berlios.de>
 *		Samuel Rodríguez Pérez <samuelrp84@gmail.com>
 */


@@ -26,7 +32,6 @@
#else
#	define TRACE(x...)
#endif


const char* kElantechPath[4] = {
	"input/touchpad/ps2/elantech_0",
@@ -41,13 +46,14 @@
#define ELANTECH_CMD_GET_CAPABILITIES	0x02
#define ELANTECH_CMD_GET_SAMPLE			0x03
#define ELANTECH_CMD_GET_RESOLUTION		0x04
#define ELANTECH_CMD_GET_ICBODY			0x05


#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

@@ -94,7 +100,7 @@
		TRACE("ELANTECH: bad crc buffer\n");
		return B_ERROR;
	}
		// https://www.kernel.org/doc/html/v4.16/input/devices/elantech.html

	uint8 packet_type = packet[3] & 3;
	TRACE("ELANTECH: packet type %d\n", packet_type);
	TRACE("ELANTECH: packet content 0x%02x%02x%02x%02x%02x%02x\n",
@@ -180,6 +186,9 @@
}


//	#pragma mark - exported functions


status_t
probe_elantech(ps2_dev* dev)
{
@@ -213,23 +222,53 @@
		TRACE("ELANTECH: not found (4)\n");
		return B_ERROR;
	}

	uint32 fwVersion = ((val[0] << 16) | (val[1] << 8) | val[2]);
	bool v1 = fwVersion < 0x020030 || fwVersion == 0x020600;
	bool v2 = (val[0] & 0xf) == 4 || ((val[0] & 0xf) == 2 && !v1);
	bool v3 = (val[0] & 0xf) == 5;
	bool v4 = (val[0] & 0xf) >= 6 && (val[0] & 0xf) <= 15;

	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;
	}

	// TODO: Update supported after testing all versions.
	bool supported = !v4 || !v3 || !v2 || !v1;

	if (supported && v3) {
		uint8 samples[3];
		if (elantech_dev_send_command(dev, ELANTECH_CMD_GET_SAMPLE, samples, 3) != B_OK) {
			TRACE("ELANTECH: failed to query sample data\n");
			return B_ERROR;
		}

		if (samples[1] == 0x74) {
			TRACE("ELANTECH: Absolute mode broken, forcing standard PS/2 protocol\n");
			supported = false;
		}
	}

	INFO("Elantech version %02X%02X%02X, under developement! Using fallback.\n",
		val[0], val[1], val[2]);
	if (supported) {
		INFO("Elantech version %02X%02X%02X detected.\n",
			val[0], val[1], val[2]);
	} else {
		INFO("Elantech version %02X%02X%02X, under developement! Using fallback.\n",
			val[0], val[1], val[2]);
	}

	dev->name = kElantechPath[dev->idx];
	dev->packet_size = PS2_PACKET_ELANTECH;

	return B_ERROR;
	return supported ? B_OK : B_ERROR;
}


//	#pragma mark - Setup functions


static status_t
elantech_write_reg(elantech_cookie* cookie, uint8 reg, uint8 value)
{
@@ -339,8 +378,8 @@
	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;
	*x = ((val[1] & 0xf) * 10 + 790) * 10 / 254;
	*y = (((val[1] & 0xf) >> 4) * 10 + 790) * 10 / 254;
	return B_OK;
}

@@ -416,21 +455,24 @@

	}

	if (cookie->version < 4) {
	if (status == B_OK && 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);
			snooze(2000);
		}
	}

	return status;
}


//	#pragma mark - Device functions


status_t
elantech_open(const char *name, uint32 flags, void **_cookie)
{
@@ -502,8 +544,7 @@
			case 5:
				cookie->version = 3;
				break;
			case 6:
			case 7:
			case 6 ... 15:
				cookie->version = 4;
				break;
			default:
@@ -541,9 +582,12 @@
		"-%" B_PRIu32 " (%" B_PRIu32 ")\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;
	x_res = 31;
	y_res = 31;
	if (cookie->version == 4) {
		if (get_resolution_v4(cookie, &x_res, &y_res) != B_OK) {
			TRACE("ELANTECH: get resolution failed!\n");
		}
	}

	TRACE("ELANTECH: resolution x %" B_PRIu32 " y %" B_PRIu32 " (dpi)\n",
diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_elantech.h b/src/add-ons/kernel/bus_managers/ps2/ps2_elantech.h
index bc2adb2..5660596 100644
--- a/src/add-ons/kernel/bus_managers/ps2/ps2_elantech.h
+++ b/src/add-ons/kernel/bus_managers/ps2/ps2_elantech.h
@@ -1,13 +1,20 @@
/*
 * Copyright 2013, Haiku, Inc.
 * Copyright 2013-2025, 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!
 * Hardware specs taken from the linux and BSDs drivers, thanks a lot!
 *
 * References:
 *	- https://cgit.freebsd.org/src/tree/sys/dev/atkbdc/psm.c?h=releng/14.3
 *	- https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/dev/pckbc/?only_with_tag=OPENBSD_7_8_BASE
 *	- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/input/mouse/elantech.c?h=v6.17
 *	- https://www.kernel.org/doc/html/v4.16/input/devices/elantech.html
 *
 * Authors:
 *		Jérôme Duval <korli@users.berlios.de>
 *		Samuel Rodríguez Pérez <samuelrp84@gmail.com>
 */

#ifndef _PS2_ELANTECH_H
#define _PS2_ELANTECH_H

@@ -25,7 +32,7 @@
	struct	packet_buffer*		ring_buffer;
			size_t				packet_index;

			uint32				version;
			uint8				version;
			uint32				fwVersion;

			uint32				x;