Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 40 additions & 8 deletions workspace/all/common/udev_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "udev_input.h"

#include <errno.h>
#include <fcntl.h>
#include <libudev.h>
#include <stdio.h>
Expand Down Expand Up @@ -194,20 +195,23 @@ const char* udev_find_device_by_name(const char* device_name) {
struct udev_list_entry* devices = NULL;
struct udev_list_entry* entry = NULL;
const char* found = NULL;
int device_count = 0;

LOG_debug("udev_find_device_by_name: Searching for '%s'", device_name ? device_name : "(null)");

if (!device_name) {
return NULL;
}

udev = udev_new();
if (!udev) {
LOG_error("Failed to create udev context");
LOG_error("udev_find_device_by_name: Failed to create udev context");
return NULL;
}

enumerate = udev_enumerate_new(udev);
if (!enumerate) {
LOG_error("Failed to create udev enumerate");
LOG_error("udev_find_device_by_name: Failed to create udev enumerate");
udev_unref(udev);
return NULL;
}
Expand All @@ -217,6 +221,8 @@ const char* udev_find_device_by_name(const char* device_name) {

devices = udev_enumerate_get_list_entry(enumerate);

LOG_debug("udev_find_device_by_name: Enumerating input devices...");

udev_list_entry_foreach(entry, devices) {
const char* syspath = udev_list_entry_get_name(entry);
struct udev_device* dev = udev_device_new_from_syspath(udev, syspath);
Expand All @@ -229,12 +235,22 @@ const char* udev_find_device_by_name(const char* device_name) {
continue;
}

// Get the device name from sysattr
const char* name = udev_device_get_sysattr_value(dev, "name");
// Get the device name from the parent input device
// The "name" sysattr is at /sys/class/input/eventX/device/name, not on eventX itself
const char* name = NULL;
struct udev_device* parent = udev_device_get_parent(dev);
if (parent) {
name = udev_device_get_sysattr_value(parent, "name");
}

device_count++;
LOG_debug("udev_find_device_by_name: [%d] %s -> name='%s'", device_count, devnode,
name ? name : "(null)");

if (name && strcmp(name, device_name) == 0) {
(void)snprintf(result_path, sizeof(result_path), "%s", devnode);
found = result_path;
LOG_debug("Found '%s' at %s", device_name, result_path);
LOG_debug("udev_find_device_by_name: Found '%s' at %s", device_name, result_path);
udev_device_unref(dev);
break;
}
Expand All @@ -245,9 +261,8 @@ const char* udev_find_device_by_name(const char* device_name) {
udev_enumerate_unref(enumerate);
udev_unref(udev);

if (!found) {
LOG_warn("Device '%s' not found", device_name);
}
LOG_debug("udev_find_device_by_name: Scanned %d devices, found=%s", device_count,
found ? found : "(none)");

return found;
}
Expand All @@ -260,3 +275,20 @@ void udev_close_all(int* fds, int count) {
}
}
}

int udev_open_device_by_name(const char* device_name) {
const char* path = udev_find_device_by_name(device_name);
if (!path) {
LOG_debug("udev_open_device_by_name: Device '%s' not found", device_name);
return -1;
}

int fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (fd < 0) {
LOG_warn("udev_open_device_by_name: Failed to open %s: %s", path, strerror(errno));
} else {
LOG_debug("udev_open_device_by_name: Opened '%s' (fd=%d)", path, fd);
}

return fd;
}
11 changes: 11 additions & 0 deletions workspace/all/common/udev_input.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,15 @@ const char* udev_find_device_by_name(const char* device_name);
*/
void udev_close_all(int* fds, int count);

/**
* Open an input device by name.
*
* Finds and opens a specific input device matching the given name.
* Useful for opening dedicated hardware like lid switches.
*
* @param device_name Exact device name to search for (e.g., "gpio-keys-lid")
* @return File descriptor on success, -1 if device not found or open failed
*/
int udev_open_device_by_name(const char* device_name);

#endif // UDEV_INPUT_H
91 changes: 84 additions & 7 deletions workspace/retroid/platform/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ static const DeviceVariantMap retroid_device_map[] = {
{"Pocket 5", VARIANT_RETROID_FHD, &retroid_devices[0], 5.5f},
{"RP5", VARIANT_RETROID_FHD, &retroid_devices[0], 5.5f},

{"Retroid Pocket Flip 2", VARIANT_RETROID_FHD, &retroid_devices[1], 5.5f},
{"Pocket Flip 2", VARIANT_RETROID_FHD, &retroid_devices[1], 5.5f},
{"Flip 2", VARIANT_RETROID_FHD, &retroid_devices[1], 5.5f},
{"Retroid Pocket Flip2", VARIANT_RETROID_FHD, &retroid_devices[1], 5.5f},
{"Pocket Flip2", VARIANT_RETROID_FHD, &retroid_devices[1], 5.5f},
{"Flip2", VARIANT_RETROID_FHD, &retroid_devices[1], 5.5f},
{"RPF2", VARIANT_RETROID_FHD, &retroid_devices[1], 5.5f},

// 1280x960 (4:3 aspect) - Mini V1
Expand Down Expand Up @@ -336,6 +336,9 @@ int PLAT_supportsOverscan(void) {
static int inputs[UDEV_MAX_DEVICES];
static int input_count = 0;

// Lid detection (gpio-keys-lid on Pocket Flip 2)
#define LID_DEVICE_NAME "gpio-keys-lid"

/**
* Disable RGB LEDs on analog sticks.
* Retroid devices have HTR3212 LED controllers for stick lighting.
Expand Down Expand Up @@ -391,7 +394,10 @@ struct input_event {
__s32 value;
};
#define EV_KEY 0x01
#define EV_SW 0x05
#define EV_ABS 0x03
#define SW_LID 0x00
#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len)

void PLAT_pollInput(void) {
uint32_t tick = SDL_GetTicks();
Expand All @@ -403,6 +409,21 @@ void PLAT_pollInput(void) {
for (int i = 0; i < input_count; i++) {
input = inputs[i];
while (read(input, &event, sizeof(event)) == sizeof(event)) {
// Handle lid switch events (EV_SW)
if (event.type == EV_SW && event.code == SW_LID) {
// SW_LID: 0 = open, 1 = closed (inverted from our convention)
int new_is_open = (event.value == 0);
if (new_is_open != lid.is_open) {
lid.is_open = new_is_open;
LOG_info("PLAT_pollInput: Lid %s", lid.is_open ? "opened" : "closed");
if (!lid.is_open) {
// Lid closed - trigger sleep
pad.just_released |= BTN_SLEEP;
}
}
continue;
}

if (event.type != EV_KEY && event.type != EV_ABS)
continue;

Expand Down Expand Up @@ -490,18 +511,74 @@ void PLAT_pollInput(void) {
}

int PLAT_shouldWake(void) {
int input;
static struct input_event event;

for (int i = 0; i < input_count; i++) {
input = inputs[i];
while (read(input, &event, sizeof(event)) == sizeof(event)) {
if (event.type == EV_KEY && event.code == RAW_POWER && event.value == 0)
while (read(inputs[i], &event, sizeof(event)) == sizeof(event)) {
// Check for lid opening
if (event.type == EV_SW && event.code == SW_LID) {
int new_is_open = (event.value == 0);
int was_closed = !lid.is_open;
lid.is_open = new_is_open;
if (new_is_open && was_closed) {
LOG_info("PLAT_shouldWake: Lid opened");
return 1;
}
}
// Check for power button release
if (event.type == EV_KEY && event.code == RAW_POWER && event.value == 0) {
return 1;
}
}
}
return 0;
}

///////////////////////////////
// Lid Detection (Hall Sensor via input events)
///////////////////////////////

/**
* Initializes lid detection for Retroid Pocket Flip 2.
*
* The Flip 2 has a Hall effect sensor exposed as a gpio-keys-lid input device.
* Unlike sysfs-based sensors (Miyoo Mini, MY355), this uses Linux input events
* with SW_LID switch type. The device is already opened by udev_open_all_inputs(),
* so we just check if it exists and read the initial state.
*
* SW_LID values: 0 = open, 1 = closed (inverted to match LessUI convention)
*/
void PLAT_initLid(void) {
// Check if lid device exists
const char* lid_path = udev_find_device_by_name(LID_DEVICE_NAME);
if (!lid_path) {
lid.has_lid = 0;
LOG_info("PLAT_initLid: No lid sensor found");
return;
}

lid.has_lid = 1;

// Temporarily open to read initial state via ioctl
// (the device is also opened by udev_open_all_inputs for event handling)
int fd = open(lid_path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (fd >= 0) {
unsigned long sw_state = 0;
if (ioctl(fd, EVIOCGSW(sizeof(sw_state)), &sw_state) >= 0) {
lid.is_open = !(sw_state & (1 << SW_LID));
LOG_info("PLAT_initLid: Lid sensor found, initial state: %s",
lid.is_open ? "open" : "closed");
} else {
lid.is_open = 1;
LOG_warn("PLAT_initLid: Could not read initial state, assuming open");
}
close(fd);
} else {
lid.is_open = 1;
LOG_warn("PLAT_initLid: Could not open for initial state, assuming open");
}
}

///////////////////////////////
// Power Management
///////////////////////////////
Expand Down