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>
---
(no changes since v1)
drivers/input/efi_mouse.c | 162 +++++++++++++++++++++++++-------------
1 file changed, 106 insertions(+), 56 deletions(-)
@@ -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;
}
/**