Files
u-boot/drivers/input/efi_mouse.c
Simon Glass 03c65c2b94 mouse: Replace press_state with bool pressed
Change the mouse_button structure to use a bool pressed field instead
of an unsigned char press_state. This simplifies the API by using a
natural boolean type for a binary state.

Remove the BUTTON_PRESSED/BUTTON_RELEASED defines as they're no longer
needed.

Update all mouse drivers, tests, and the mouse command to use the new
field name and type.

Series-changes: 2
- Add new patch to replace press_state with bool pressed

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
2025-10-07 09:54:43 -06:00

222 lines
5.4 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* EFI mouse driver using Simple Pointer Protocol
*
* Copyright 2025 Google LLC
* Written by Claude <noreply@anthropic.com>
*/
#define LOG_CATEGORY UCLASS_MOUSE
#include <dm.h>
#include <efi.h>
#include <efi_api.h>
#include <log.h>
#include <mouse.h>
struct efi_mouse_priv {
struct efi_simple_pointer_protocol *pointer;
struct efi_simple_pointer_state last_state;
bool has_last_state;
int x, y;
int buttons;
int old_buttons;
struct efi_event *timer_event;
};
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;
int new_buttons;
if (!priv->pointer)
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->pointer->wait_for_input) {
events[1] = priv->pointer->wait_for_input;
num_events = 2;
}
ret = boot->wait_for_event(num_events, events, &index);
if (ret != EFI_SUCCESS)
return -EAGAIN;
}
/* Get current pointer state */
ret = priv->pointer->get_state(priv->pointer, &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;
}
/* Check for button changes */
new_buttons = 0;
if (state.left_button)
new_buttons |= 1 << 0;
if (state.right_button)
new_buttons |= 1 << 1;
if (new_buttons != priv->old_buttons) {
struct mouse_button *but = &event->button;
u8 diff = new_buttons ^ priv->old_buttons;
int i;
event->type = MOUSE_EV_BUTTON;
/* Find first changed button */
for (i = 0; i < 2; i++) {
u8 mask = 1 << i;
if (diff & mask) {
but->button = i;
but->pressed = (new_buttons & mask) ? true : false;
but->clicks = 1;
but->x = priv->x;
but->y = priv->y;
priv->old_buttons ^= mask;
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;
priv->buttons = new_buttons;
return 0;
}
priv->buttons = new_buttons;
return -EAGAIN;
}
static int efi_mouse_probe(struct udevice *dev)
{
struct efi_mouse_priv *priv = dev_get_priv(dev);
struct efi_boot_services *boot = efi_get_boot();
efi_status_t ret;
efi_handle_t *handles;
efi_uintn_t num_handles;
log_debug("EFI mouse probe\n");
/* Find Simple Pointer Protocol handles */
ret = boot->locate_handle_buffer(BY_PROTOCOL, &efi_guid_simple_pointer,
NULL, &num_handles, &handles);
if (ret != EFI_SUCCESS) {
printf("EFI mouse: No EFI pointer devices found (ret=0x%lx)\n", ret);
return -ENODEV;
}
log_debug("Found %zu EFI pointer device(s)\n", num_handles);
/* Use the first pointer device */
ret = boot->open_protocol(handles[0], &efi_guid_simple_pointer,
(void **)&priv->pointer, efi_get_parent_image(),
NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (ret != EFI_SUCCESS) {
printf("EFI mouse: Failed to open EFI pointer protocol (ret=0x%lx)\n", ret);
efi_free_pool(handles);
return -ENODEV;
}
efi_free_pool(handles);
/* Reset the pointer device */
ret = priv->pointer->reset(priv->pointer, false);
if (ret != EFI_SUCCESS) {
log_warning("Failed to reset EFI pointer device\n");
/* Continue anyway - some devices might not support reset */
}
priv->x = 0;
priv->y = 0;
priv->buttons = 0;
priv->old_buttons = 0;
priv->has_last_state = false;
/* Create a timer event for periodic checking */
ret = boot->create_event(EVT_TIMER, TPL_NOTIFY, NULL, NULL,
&priv->timer_event);
if (ret != EFI_SUCCESS) {
printf("EFI mouse: Failed to create timer event (ret=0x%lx)\n", ret);
/* Continue without timer - fallback to direct polling */
priv->timer_event = NULL;
} else {
/* Set timer to trigger every 10ms (100000 x 100ns = 10ms) */
ret = boot->set_timer(priv->timer_event, EFI_TIMER_PERIODIC, 10000);
if (ret != EFI_SUCCESS) {
printf("EFI mouse: Failed to set timer (ret=0x%lx)\n", ret);
boot->close_event(priv->timer_event);
priv->timer_event = NULL;
}
}
log_info("EFI mouse initialized\n");
return 0;
}
static int efi_mouse_remove(struct udevice *dev)
{
struct efi_mouse_priv *priv = dev_get_priv(dev);
struct efi_boot_services *boot = efi_get_boot();
if (priv->timer_event) {
boot->close_event(priv->timer_event);
priv->timer_event = NULL;
}
if (priv->pointer) {
/* Protocol will be automatically closed when the image is unloaded */
priv->pointer = NULL;
}
return 0;
}
static const struct mouse_ops efi_mouse_ops = {
.get_event = efi_mouse_get_event,
};
static const struct udevice_id efi_mouse_ids[] = {
{ .compatible = "efi,mouse" },
{ }
};
U_BOOT_DRIVER(efi_mouse) = {
.name = "efi_mouse",
.id = UCLASS_MOUSE,
.of_match = efi_mouse_ids,
.ops = &efi_mouse_ops,
.probe = efi_mouse_probe,
.remove = efi_mouse_remove,
.priv_auto = sizeof(struct efi_mouse_priv),
};