[Concept,14/17] efi: mouse: Split out event handling further

Message ID 20251006232236.2091941-15-sjg@u-boot.org
State New
Headers
Series expo: Complete mouse operation in the EFI app |

Commit Message

Simon Glass Oct. 6, 2025, 11:21 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

Create a function which handles getting the pointer position using the
simple-pointer protocol. Call this from efi_mouse_get_event()

Return immediately if there is a button event. Otherwise return a motion
event if motion is detected.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/input/efi_mouse.c | 162 +++++++++++++++++++++++++-------------
 1 file changed, 106 insertions(+), 56 deletions(-)
  

Patch

diff --git a/drivers/input/efi_mouse.c b/drivers/input/efi_mouse.c
index 3e9ec370a50..81c3fcb862e 100644
--- a/drivers/input/efi_mouse.c
+++ b/drivers/input/efi_mouse.c
@@ -39,6 +39,93 @@  struct efi_mouse_priv {
 	struct efi_event *timer_event;
 };
 
+/**
+ * get_rel_pointer() - Handle relative pointer input
+ *
+ * @priv: Private data
+ * @rel_x: Returns relative X movement
+ * @rel_y: Returns relative Y movement
+ * @new_buttons: Returns button state
+ * Return: 0 if OK, -EAGAIN if no event, -ve on error
+ */
+static int get_rel_pointer(struct efi_mouse_priv *priv, int *rel_x,
+			   int *rel_y, int *new_buttons)
+{
+	struct efi_simple_pointer_state state;
+	efi_status_t ret;
+
+	/* Use timer-based polling approach like EFI keyboard */
+	if (priv->timer_event) {
+		struct efi_boot_services *boot = efi_get_boot();
+		efi_uintn_t index;
+		struct efi_event *events[2];
+		efi_uintn_t num_events = 1;
+
+		events[0] = priv->timer_event;
+		if (priv->simple->wait_for_input) {
+			events[1] = priv->simple->wait_for_input;
+			num_events = 2;
+		}
+
+		ret = boot->wait_for_event(num_events, events, &index);
+		if (ret != EFI_SUCCESS)
+			return -EAGAIN;
+	}
+
+	log_debug("rel: calling get_state\n");
+	ret = priv->simple->get_state(priv->simple, &state);
+	log_debug("rel: get_state returned 0x%lx\n", ret);
+	if (ret == EFI_NOT_READY)
+		return -EAGAIN;
+	if (ret) {
+		log_debug("rel: get_state failed (ret=0x%lx)\n", ret);
+		return -EIO;
+	}
+
+	log_debug("rel: RelX=%d RelY=%d LeftBtn=%d RightBtn=%d\n",
+		  state.relative_movement_x, state.relative_movement_y,
+		  state.left_button, state.right_button);
+
+	/*
+	 * Scale down large movement values that seem to be incorrectly
+	 * reported
+	 */
+	*rel_x = state.relative_movement_x;
+	*rel_y = state.relative_movement_y;
+
+	/* If movement values are very large, scale them down */
+	if (abs(*rel_x) > 1000) {
+		*rel_x = *rel_x / 1000;
+		if (*rel_x == 0 && state.relative_movement_x != 0)
+			*rel_x = (state.relative_movement_x > 0) ? 1 : -1;
+	}
+	if (abs(*rel_y) > 1000) {
+		*rel_y = *rel_y / 1000;
+		if (*rel_y == 0 && state.relative_movement_y != 0)
+			*rel_y = (state.relative_movement_y > 0) ? 1 : -1;
+	}
+
+	log_debug("rel: scaled RelX=%d RelY=%d\n", *rel_x, *rel_y);
+
+	/* Update absolute position */
+	priv->x += *rel_x;
+	priv->x = max(priv->x, 0);
+	priv->x = min(priv->x, MOUSE_MAX_COORD);
+
+	priv->y += *rel_y;
+	priv->y = max(priv->y, 0);
+	priv->y = min(priv->y, MOUSE_MAX_COORD);
+
+	/* Extract button state */
+	*new_buttons = 0;
+	if (state.left_button)
+		*new_buttons |= 1 << 0;
+	if (state.right_button)
+		*new_buttons |= 1 << 1;
+
+	return 0;
+}
+
 /**
  * get_button_event() - Check for button-change events
  *
@@ -80,76 +167,39 @@  static int get_button_event(struct efi_mouse_priv *priv, int new_buttons,
 static int efi_mouse_get_event(struct udevice *dev, struct mouse_event *event)
 {
 	struct efi_mouse_priv *priv = dev_get_priv(dev);
-	struct efi_simple_pointer_state state;
-	efi_status_t ret;
+	struct mouse_motion *motion;
 	int new_buttons;
-	if (!priv->simple)
-		return -ENODEV;
-
-	/* Use timer-based polling approach like EFI keyboard */
-	if (priv->timer_event) {
-		struct efi_boot_services *boot = efi_get_boot();
-		efi_uintn_t index;
-		struct efi_event *events[2];
-		efi_uintn_t num_events = 1;
-
-		events[0] = priv->timer_event;
-		if (priv->simple->wait_for_input) {
-			events[1] = priv->simple->wait_for_input;
-			num_events = 2;
-		}
-
-		ret = boot->wait_for_event(num_events, events, &index);
-		if (ret != EFI_SUCCESS)
-			return -EAGAIN;
-	}
+	int rel_x, rel_y;
+	int ret;
 
 	/* Get current pointer state */
-	ret = priv->simple->get_state(priv->simple, &state);
-	if (ret != EFI_SUCCESS) {
-		if (ret == EFI_NOT_READY)
-			return -EAGAIN;
-		printf("EFI mouse: get_state failed (ret=0x%lx)\n", ret);
-		return -EIO;
-	}
+	ret = get_rel_pointer(priv, &rel_x, &rel_y, &new_buttons);
+	if (ret)
+		return ret;
+
+	priv->has_last_state = true;
 
 	/* Check for button changes */
-	new_buttons = 0;
-	if (state.left_button)
-		new_buttons |= 1 << 0;
-	if (state.right_button)
-		new_buttons |= 1 << 1;
 	ret = get_button_event(priv, new_buttons, event);
 	if (!ret)
 		return 0;
 
-	/* Check for movement */
-	if (state.relative_movement_x || state.relative_movement_y) {
-		struct mouse_motion *motion = &event->motion;
-
-		/* Update absolute position */
-		priv->x += state.relative_movement_x;
-		priv->x = max(priv->x, 0);
-		priv->x = min(priv->x, 0xffff);
-
-		priv->y += state.relative_movement_y;
-		priv->y = max(priv->y, 0);
-		priv->y = min(priv->y, 0xffff);
-
-		event->type = MOUSE_EV_MOTION;
-		motion->state = new_buttons;
-		motion->x = priv->x;
-		motion->y = priv->y;
-		motion->xrel = state.relative_movement_x;
-		motion->yrel = state.relative_movement_y;
-
+	/* If there's no movement, nothing to do */
+	if (!rel_x && !rel_y) {
 		priv->buttons = new_buttons;
-		return 0;
+		return -EAGAIN;
 	}
 
+	motion = &event->motion;
+	event->type = MOUSE_EV_MOTION;
+	motion->state = new_buttons;
+	motion->x = priv->x;
+	motion->y = priv->y;
+	motion->xrel = rel_x;
+	motion->yrel = rel_y;
 	priv->buttons = new_buttons;
 
-	return -EAGAIN;
+	return 0;
 }
 
 /**