mirror of
https://github.com/archr-linux/Arch-R.git
synced 2026-03-31 14:41:55 -07:00
packages: remove unified-joypad driver
This commit is contained in:
@@ -1,2 +1 @@
|
||||
SUBSYSTEM=="input", ATTRS{name}=="AYN Odin2 Gamepad", MODE="0666", ENV{ID_INPUT_JOYSTICK}="1"
|
||||
SUBSYSTEM=="input", ATTRS{name}=="ROCKNIX Unified Joypad", MODE="0666", ENV{ID_INPUT_JOYSTICK}="1"
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
# for a list of additional drivers see packages/linux-drivers
|
||||
# Space separated list is supported,
|
||||
# e.g. ADDITIONAL_DRIVERS="DRIVER1 DRIVER2"
|
||||
ADDITIONAL_DRIVERS="unified-joypad"
|
||||
ADDITIONAL_DRIVERS=""
|
||||
|
||||
# Additional Firmware to use ( )
|
||||
# Space separated list is supported,
|
||||
|
||||
@@ -3,7 +3,7 @@ new file mode 100644
|
||||
index 000000000000..845a7cf600e2
|
||||
--- /dev/null
|
||||
+++ b/arch/arm64/boot/dts/qcom/qcs8550-ayaneo-pocketdmg.dts
|
||||
@@ -0,0 +1,150 @@
|
||||
@@ -0,0 +1,111 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * Copyright (c) 2025, ROCKNIX (https://github.com/ROCKNIX)
|
||||
@@ -19,45 +19,6 @@ index 000000000000..845a7cf600e2
|
||||
+ qcom,msm-id = <0x258 0x20000>, <0x259 0x20000>;
|
||||
+ compatible = "ayaneo,pocketdmg", "qcom,qcs8550", "qcom,sm8550";
|
||||
+ rocknix-u-boot-dt-id = "u-boot-pocket-dmg";
|
||||
+
|
||||
+ rocknix_unified_joypad {
|
||||
+ compatible = "rocknix,unified-joypad";
|
||||
+
|
||||
+ target-device-names = "AYANEO DEVICE",
|
||||
+ "AYANEO DEVICE",
|
||||
+ "AYANEO Controller";
|
||||
+
|
||||
+ virtual-device-name = "ROCKNIX Unified Joypad";
|
||||
+ virtual-vendor-id = <0x0fff>;
|
||||
+ virtual-product-id = <0x0fff>;
|
||||
+ virtual-version-id = <0x9001>;
|
||||
+
|
||||
+ ignore-events = <EV_ABS ABS_BRAKE // Ignore L2 axis
|
||||
+ EV_ABS ABS_GAS>; // Ignore R2 axis
|
||||
+
|
||||
+ remaps {
|
||||
+ remap_1 {
|
||||
+ target-device-name = "AYANEO Controller";
|
||||
+ target-device-phys = "usb-0001:01:00.0-2/input0";
|
||||
+
|
||||
+ key-remaps = <
|
||||
+ 304 0x131 // BTN_SOUTH -> BTN_EAST
|
||||
+ 305 0x130 // KEY_EAST -> BTN_SOUTH
|
||||
+ >;
|
||||
+ };
|
||||
+
|
||||
+ remap_2 {
|
||||
+ target-device-name = "AYANEO DEVICE";
|
||||
+ target-device-phys = "usb-0001:01:00.0-1/input1";
|
||||
+
|
||||
+ key-remaps = <
|
||||
+ 183 115 // KEY_F13 -> KEY_VOLUMEUP
|
||||
+ 184 114 // KEY_F14 -> KEY_VOLUMEDOWN
|
||||
+ 194 0x13c // KEY_F24 -> BTN_MODE
|
||||
+ >;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&tlmm {
|
||||
|
||||
@@ -20,5 +20,4 @@
|
||||
1900f6a24b480000df14000000010000,H700 Gamepad,platform:Linux,x:b3,a:b1,b:b0,y:b2,back:b8,guide:b10,start:b9,dpleft:b15,dpdown:b14,dpright:b16,dpup:b13,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,
|
||||
0300b605202000000130000001000000,AYN Odin2 Gamepad,platform:Linux,x:b2,a:b1,b:b0,y:b3,back:b6,guide:b8,start:b7,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,
|
||||
1900365541594e204f64696e20476100,AYN Odin Gamepad,platform:Linux,x:b2,a:b1,b:b0,y:b3,back:b8,guide:b10,start:b9,dpleft:b15,dpdown:b14,dpright:b16,dpup:b13,leftshoulder:b4,lefttrigger:a5,rightshoulder:b5,righttrigger:a4,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,
|
||||
060003bdff0f0000ff0f000001900000,ROCKNIX Unified Joypad,platform:Linux,x:b3,a:b1,b:b0,y:b4,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,
|
||||
030081b85e0400008e02000000020000,Xbox 360 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
input_driver = "udev"
|
||||
input_device = "AYANEO Controller"
|
||||
@@ -1,42 +0,0 @@
|
||||
input_driver = "udev"
|
||||
input_device = "ROCKNIX Unified Joypad"
|
||||
|
||||
input_b_btn = "0"
|
||||
input_y_btn = "3"
|
||||
input_select_btn = "4"
|
||||
input_start_btn = "6"
|
||||
input_up_btn = "11"
|
||||
input_down_btn = "12"
|
||||
input_left_btn = "13"
|
||||
input_right_btn = "14"
|
||||
input_a_btn = "1"
|
||||
input_x_btn = "2"
|
||||
input_l_btn = "9"
|
||||
input_r_btn = "10"
|
||||
input_l2_axis = "+4"
|
||||
input_r2_axis = "+5"
|
||||
input_l3_btn = "7"
|
||||
input_r3_btn = "8"
|
||||
input_l_x_plus_axis = "+0"
|
||||
input_l_x_minus_axis = "-0"
|
||||
input_l_y_plus_axis = "+1"
|
||||
input_l_y_minus_axis = "-1"
|
||||
input_r_x_plus_axis = "+2"
|
||||
input_r_x_minus_axis = "-2"
|
||||
input_r_y_plus_axis = "+3"
|
||||
input_r_y_minus_axis = "-3"
|
||||
|
||||
# Hotkeys
|
||||
input_enable_hotkey_btn = "5"
|
||||
input_exit_emulator_btn = "6"
|
||||
|
||||
input_menu_toggle_btn = "2"
|
||||
input_fps_toggle_btn = "3"
|
||||
input_screenshot_btn = "1"
|
||||
input_reset_btn = "0"
|
||||
|
||||
input_load_state_btn = "9"
|
||||
input_save_state_btn = "10"
|
||||
|
||||
input_rewind_axis = "+4"
|
||||
input_toggle_fast_forward_axis = "+5"
|
||||
@@ -1,20 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2024-present ROCKNIX (https://github.com/ROCKNIX)
|
||||
|
||||
PKG_NAME="unified-joypad"
|
||||
PKG_VERSION="1.0"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/ROCKNIX"
|
||||
PKG_URL=""
|
||||
PKG_LONGDESC="unified-joypad: ROCKNIX unified joypad driver"
|
||||
PKG_TOOLCHAIN="manual"
|
||||
PKG_IS_KERNEL_PKG="yes"
|
||||
|
||||
make_target() {
|
||||
kernel_make -C $(kernel_path) M=${PKG_BUILD}
|
||||
}
|
||||
|
||||
makeinstall_target() {
|
||||
mkdir -p ${INSTALL}/$(get_full_module_dir)/${PKG_NAME}
|
||||
cp *.ko ${INSTALL}/$(get_full_module_dir)/${PKG_NAME}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
obj-m += unified-joypad.o
|
||||
@@ -1,96 +0,0 @@
|
||||
/ {
|
||||
/*
|
||||
* This node configures the unified_joypad driver. It should be added
|
||||
* to your target device's main .dts file.
|
||||
*/
|
||||
rocknix_unified_joypad {
|
||||
/*
|
||||
* This 'compatible' string is mandatory. It's the key that the Linux
|
||||
* kernel uses to find and load the correct driver for this node.
|
||||
* It must not be changed.
|
||||
*/
|
||||
compatible = "rocknix,unified-joypad";
|
||||
|
||||
/*
|
||||
* A list of all physical device names the driver should manage.
|
||||
* A "slot" is reserved for each entry. If you have two physical
|
||||
* devices with the same name, you MUST list the name twice.
|
||||
*/
|
||||
target-device-names = "AYANEO DEVICE", // Slot for the first device
|
||||
"AYANEO DEVICE", // Slot for the second device
|
||||
"AYANEO Controller";
|
||||
|
||||
/*
|
||||
* --- Optional: Virtual Device Properties ---
|
||||
* These properties override the appearance of the final virtual device.
|
||||
* This is useful for ensuring compatibility with applications that
|
||||
* expect a standard controller.
|
||||
*/
|
||||
virtual-device-name = "ROCKNIX Unified Joypad";
|
||||
virtual-vendor-id = <0x0fff>; // USB Vendor ID in hexadecimal
|
||||
virtual-product-id = <0x0fff>; // USB Product ID in hexadecimal
|
||||
virtual-version-id = <0x9001>; // Device version in hexadecimal
|
||||
|
||||
/*
|
||||
* --- Optional: Event Ignore List ---
|
||||
*
|
||||
* Use this property to specify input events that should be completely
|
||||
* blocked from the source devices. This is useful for preventing
|
||||
* "double inputs" where a single button press generates both a
|
||||
* button event (EV_KEY) and an axis event (EV_ABS).
|
||||
*
|
||||
* The list consists of pairs of u32 values: <TYPE CODE>.
|
||||
* - The first value is the event type (e.g., EV_ABS).
|
||||
* - The second value is the event code (e.g., ABS_BRAKE).
|
||||
*
|
||||
* The total number of elements must be even. You can find the numerical
|
||||
* values for types and codes in the kernel's 'linux/input-event-codes.h'
|
||||
* or use the macros defined in 'dt-bindings/input/input.h'.
|
||||
*
|
||||
* Example: Block the analog axis events from the L2/R2 triggers that
|
||||
* also send digital button events.
|
||||
*/
|
||||
ignore-events = <
|
||||
/* Type Code */
|
||||
EV_ABS ABS_BRAKE, // Block the L2 trigger's analog axis (ABS_BRAKE)
|
||||
EV_ABS ABS_GAS // Block the R2 trigger's analog axis (ABS_GAS)
|
||||
>;
|
||||
|
||||
/*
|
||||
* --- Optional: Button Remapping Rules ---
|
||||
* This sub-node contains specific remapping configurations.
|
||||
*/
|
||||
remaps {
|
||||
/*
|
||||
* Remap rule for the "AYANEO Controller".
|
||||
* Since its name is unique, using 'target-device-phys' is optional
|
||||
* but recommended for a more robust configuration.
|
||||
*/
|
||||
remap_1 {
|
||||
target-device-name = "AYANEO Controller";
|
||||
target-device-phys = "usb-0001:01:00.0-2/input0";
|
||||
key-remaps = <
|
||||
/* from to */
|
||||
304 0x131 // BTN_SOUTH -> BTN_EAST
|
||||
305 0x130 // BTN_EAST -> BTN_SOUTH
|
||||
>;
|
||||
};
|
||||
|
||||
/*
|
||||
* Remap rule for a specific "AYANEO DEVICE". We use the unique
|
||||
* 'target-device-phys' property to distinguish it from the other
|
||||
* device that shares the same name.
|
||||
*/
|
||||
remap_2 {
|
||||
target-device-name = "AYANEO DEVICE";
|
||||
target-device-phys = "usb-0001:01:00.0-1/input1";
|
||||
key-remaps = <
|
||||
/* from to (decimal) */
|
||||
183 115 // KEY_F13 -> KEY_VOLUMEUP
|
||||
184 114 // KEY_F14 -> KEY_VOLUMEDOWN
|
||||
194 0x13c // KEY_F24 -> BTN_MODE
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1,473 +0,0 @@
|
||||
/*
|
||||
* unified_joypad.c - A kernel module to merge multiple input devices.
|
||||
*
|
||||
* This module creates a single virtual input device that combines events from
|
||||
* multiple physical input devices. It is configured via a Device Tree node,
|
||||
* including optional button remapping by device name or unique physical path.
|
||||
*
|
||||
* It will also grab the source devices to prevent them from reporting events
|
||||
* independently to the system.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#define DRV_NAME "unified_joypad"
|
||||
|
||||
/* --- Data Structures --- */
|
||||
|
||||
struct key_remap {
|
||||
u32 from;
|
||||
u32 to;
|
||||
};
|
||||
|
||||
struct event_filter {
|
||||
u32 type;
|
||||
u32 code;
|
||||
};
|
||||
|
||||
struct device_remap_config {
|
||||
const char *name;
|
||||
const char *phys;
|
||||
int num_remaps;
|
||||
struct key_remap *remaps;
|
||||
};
|
||||
|
||||
/* --- Module Information --- */
|
||||
|
||||
MODULE_AUTHOR("ROCKNIX");
|
||||
MODULE_DESCRIPTION("Merges multiple input devices into one unified input device");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_INFO(intree, "Y");
|
||||
|
||||
/* --- Global Variables --- */
|
||||
|
||||
static struct input_dev *vdev;
|
||||
static struct input_dev **source_devs;
|
||||
static int num_target_devices;
|
||||
static char **target_device_names;
|
||||
|
||||
static const char *vdev_name;
|
||||
static u16 vdev_vendor;
|
||||
static u16 vdev_product;
|
||||
static u16 vdev_version;
|
||||
|
||||
static struct device_remap_config *remap_configs;
|
||||
static int num_remap_configs;
|
||||
|
||||
static struct event_filter *ignored_events;
|
||||
static int num_ignored_events;
|
||||
|
||||
static struct delayed_work rebuild_work;
|
||||
static struct mutex dev_mutex;
|
||||
|
||||
/* --- Forward Declarations --- */
|
||||
|
||||
static void rebuild_virtual_device_work(struct work_struct *work);
|
||||
|
||||
/* --- Functions --- */
|
||||
|
||||
static void copy_attributes(struct input_dev *dev, struct input_dev *vdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BITS_TO_LONGS(EV_MAX); i++)
|
||||
vdev->evbit[i] |= dev->evbit[i];
|
||||
for (i = 0; i < BITS_TO_LONGS(KEY_MAX); i++)
|
||||
vdev->keybit[i] |= dev->keybit[i];
|
||||
for (i = 0; i < BITS_TO_LONGS(REL_MAX); i++)
|
||||
vdev->relbit[i] |= dev->relbit[i];
|
||||
for (i = 0; i < BITS_TO_LONGS(ABS_MAX); i++)
|
||||
vdev->absbit[i] |= dev->absbit[i];
|
||||
|
||||
for (i = 0; i < ABS_MAX; i++) {
|
||||
if (test_bit(i, dev->absbit)) {
|
||||
input_set_abs_params(vdev, i,
|
||||
dev->absinfo[i].minimum,
|
||||
dev->absinfo[i].maximum,
|
||||
dev->absinfo[i].fuzz,
|
||||
dev->absinfo[i].flat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rebuild_virtual_device(void)
|
||||
{
|
||||
int error;
|
||||
int i, j;
|
||||
bool has_devices = false;
|
||||
|
||||
if (vdev) {
|
||||
pr_info(DRV_NAME ": Destroying virtual device.\n");
|
||||
input_unregister_device(vdev);
|
||||
vdev = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_target_devices; i++) {
|
||||
if (source_devs[i]) {
|
||||
has_devices = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_devices)
|
||||
return;
|
||||
|
||||
pr_info(DRV_NAME ": Rebuilding virtual device...\n");
|
||||
vdev = input_allocate_device();
|
||||
if (!vdev) {
|
||||
pr_err(DRV_NAME ": Failed to allocate virtual device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vdev->name = vdev_name;
|
||||
vdev->id.bustype = BUS_VIRTUAL;
|
||||
vdev->id.vendor = vdev_vendor;
|
||||
vdev->id.product = vdev_product;
|
||||
vdev->id.version = vdev_version;
|
||||
|
||||
for (i = 0; i < num_target_devices; i++) {
|
||||
if (source_devs[i])
|
||||
copy_attributes(source_devs[i], vdev);
|
||||
}
|
||||
|
||||
__set_bit(EV_KEY, vdev->evbit);
|
||||
for (i = 0; i < num_remap_configs; i++) {
|
||||
for (j = 0; j < remap_configs[i].num_remaps; j++)
|
||||
__set_bit(remap_configs[i].remaps[j].to, vdev->keybit);
|
||||
}
|
||||
|
||||
error = input_register_device(vdev);
|
||||
if (error) {
|
||||
pr_err(DRV_NAME ": Failed to register virtual device, error %d\n", error);
|
||||
input_free_device(vdev);
|
||||
vdev = NULL;
|
||||
} else {
|
||||
pr_info(DRV_NAME ": Virtual device '%s' created/rebuilt successfully.\n", vdev->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void joypad_event(struct input_handle *handle, unsigned int type,
|
||||
unsigned int code, int value)
|
||||
{
|
||||
struct device_remap_config *remap_cfg = handle->private;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_ignored_events; i++) {
|
||||
if (type == ignored_events[i].type && code == ignored_events[i].code)
|
||||
return; /* This is an ignored event, do nothing. */
|
||||
}
|
||||
|
||||
if (vdev) {
|
||||
if (type == EV_KEY && remap_cfg) {
|
||||
for (i = 0; i < remap_cfg->num_remaps; i++) {
|
||||
if (code == remap_cfg->remaps[i].from) {
|
||||
code = remap_cfg->remaps[i].to;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
input_event(vdev, type, code, value);
|
||||
}
|
||||
}
|
||||
|
||||
static int joypad_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
{
|
||||
struct input_handle *handle;
|
||||
struct device_remap_config *name_match = NULL;
|
||||
struct device_remap_config *phys_match = NULL;
|
||||
int error, i, slot = -1;
|
||||
bool is_target = false;
|
||||
|
||||
for (i = 0; i < num_target_devices; i++) {
|
||||
if (strcmp(dev->name, target_device_names[i]) == 0) {
|
||||
is_target = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_target)
|
||||
return -ENODEV;
|
||||
|
||||
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
|
||||
if (!handle)
|
||||
return -ENOMEM;
|
||||
|
||||
handle->dev = dev;
|
||||
handle->handler = handler;
|
||||
handle->name = "joypad_handle";
|
||||
|
||||
for (i = 0; i < num_remap_configs; i++) {
|
||||
if (remap_configs[i].phys && dev->phys &&
|
||||
strcmp(remap_configs[i].phys, dev->phys) == 0) {
|
||||
phys_match = &remap_configs[i];
|
||||
break;
|
||||
}
|
||||
if (!name_match && remap_configs[i].name &&
|
||||
strcmp(remap_configs[i].name, dev->name) == 0) {
|
||||
name_match = &remap_configs[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (phys_match)
|
||||
handle->private = phys_match;
|
||||
else if (name_match)
|
||||
handle->private = name_match;
|
||||
|
||||
error = input_register_handle(handle);
|
||||
if (error) {
|
||||
kfree(handle);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = input_open_device(handle);
|
||||
if (error) {
|
||||
input_unregister_handle(handle);
|
||||
kfree(handle);
|
||||
return error;
|
||||
}
|
||||
|
||||
input_grab_device(handle);
|
||||
|
||||
mutex_lock(&dev_mutex);
|
||||
for (i = 0; i < num_target_devices; i++) {
|
||||
if (strcmp(dev->name, target_device_names[i]) == 0 && !source_devs[i]) {
|
||||
source_devs[i] = dev;
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev_mutex);
|
||||
|
||||
if (slot != -1) {
|
||||
pr_info(DRV_NAME ": Successfully connected to and grabbed '%s'\n", dev->name);
|
||||
/* Schedule a rebuild in 200ms. If another device connects, this will reset the timer. */
|
||||
schedule_delayed_work(&rebuild_work, msecs_to_jiffies(200));
|
||||
} else {
|
||||
pr_warn(DRV_NAME ": No free slot for '%s'\n", dev->name);
|
||||
input_release_device(handle);
|
||||
input_close_device(handle);
|
||||
input_unregister_handle(handle);
|
||||
kfree(handle);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void joypad_disconnect(struct input_handle *handle)
|
||||
{
|
||||
int i;
|
||||
pr_info(DRV_NAME ": Disconnecting from '%s'\n", handle->dev->name);
|
||||
|
||||
mutex_lock(&dev_mutex);
|
||||
for (i = 0; i < num_target_devices; i++) {
|
||||
if (source_devs[i] == handle->dev) {
|
||||
source_devs[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev_mutex);
|
||||
|
||||
/* Also schedule a rebuild on disconnect */
|
||||
schedule_delayed_work(&rebuild_work, msecs_to_jiffies(200));
|
||||
|
||||
input_release_device(handle);
|
||||
input_close_device(handle);
|
||||
input_unregister_handle(handle);
|
||||
kfree(handle);
|
||||
}
|
||||
|
||||
static const struct input_device_id joypad_ids[] = {
|
||||
{ .driver_info = 1 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct input_handler joypad_handler = {
|
||||
.event = joypad_event,
|
||||
.connect = joypad_connect,
|
||||
.disconnect = joypad_disconnect,
|
||||
.name = "unified_joypad_handler",
|
||||
.id_table = joypad_ids,
|
||||
};
|
||||
|
||||
static void rebuild_virtual_device_work(struct work_struct *work)
|
||||
{
|
||||
mutex_lock(&dev_mutex);
|
||||
rebuild_virtual_device();
|
||||
mutex_unlock(&dev_mutex);
|
||||
}
|
||||
|
||||
static int parse_ignore_list(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int n_vals;
|
||||
|
||||
n_vals = of_property_count_u32_elems(np, "ignore-events");
|
||||
if (n_vals <= 0)
|
||||
return 0; /* No property found, which is fine */
|
||||
|
||||
if (n_vals % 2 != 0) {
|
||||
dev_warn(&pdev->dev, "Property 'ignore-events' must have an even number of elements (type/code pairs).\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
num_ignored_events = n_vals / 2;
|
||||
ignored_events = devm_kcalloc(&pdev->dev, num_ignored_events, sizeof(*ignored_events), GFP_KERNEL);
|
||||
if (!ignored_events) {
|
||||
num_ignored_events = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (of_property_read_u32_array(np, "ignore-events", (u32 *)ignored_events, n_vals)) {
|
||||
dev_err(&pdev->dev, "Failed to read 'ignore-events' property.\n");
|
||||
num_ignored_events = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pr_info(DRV_NAME ": Will ignore %d event types.\n", num_ignored_events);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_remaps(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *remaps_np, *child;
|
||||
int count = 0;
|
||||
int valid_configs = 0;
|
||||
|
||||
remaps_np = of_get_child_by_name(pdev->dev.of_node, "remaps");
|
||||
if (!remaps_np)
|
||||
return 0;
|
||||
|
||||
count = of_get_child_count(remaps_np);
|
||||
if (count == 0) {
|
||||
of_node_put(remaps_np);
|
||||
return 0;
|
||||
}
|
||||
|
||||
remap_configs = devm_kcalloc(&pdev->dev, count, sizeof(*remap_configs), GFP_KERNEL);
|
||||
if (!remap_configs) {
|
||||
of_node_put(remaps_np);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for_each_child_of_node(remaps_np, child) {
|
||||
struct device_remap_config *cfg = &remap_configs[valid_configs];
|
||||
int n_vals;
|
||||
|
||||
of_property_read_string(child, "target-device-name", &cfg->name);
|
||||
of_property_read_string(child, "target-device-phys", &cfg->phys);
|
||||
|
||||
if (!cfg->name && !cfg->phys)
|
||||
continue;
|
||||
|
||||
n_vals = of_property_count_u32_elems(child, "key-remaps");
|
||||
if (n_vals <= 0 || n_vals % 2 != 0)
|
||||
continue;
|
||||
|
||||
cfg->num_remaps = n_vals / 2;
|
||||
cfg->remaps = devm_kcalloc(&pdev->dev, cfg->num_remaps, sizeof(*cfg->remaps), GFP_KERNEL);
|
||||
if (!cfg->remaps) {
|
||||
of_node_put(remaps_np);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (of_property_read_u32_array(child, "key-remaps", (u32 *)cfg->remaps, n_vals)) {
|
||||
cfg->num_remaps = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
valid_configs++;
|
||||
}
|
||||
|
||||
num_remap_configs = valid_configs;
|
||||
of_node_put(remaps_np);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unified_joypad_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int i, count, ret;
|
||||
u32 temp_val;
|
||||
|
||||
pr_info(DRV_NAME ": Loading module...\n");
|
||||
|
||||
count = of_property_count_strings(np, "target-device-names");
|
||||
if (count <= 0)
|
||||
return count == 0 ? -ENODEV : count;
|
||||
num_target_devices = count;
|
||||
|
||||
source_devs = devm_kcalloc(&pdev->dev, num_target_devices, sizeof(struct input_dev *), GFP_KERNEL);
|
||||
target_device_names = devm_kcalloc(&pdev->dev, num_target_devices, sizeof(char *), GFP_KERNEL);
|
||||
if (!source_devs || !target_device_names)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num_target_devices; i++) {
|
||||
if (of_property_read_string_index(np, "target-device-names", i, (const char **)&target_device_names[i]))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (of_property_read_string(np, "virtual-device-name", &vdev_name))
|
||||
vdev_name = "ROCKNIX Unified Joypad";
|
||||
if (of_property_read_u32(np, "virtual-vendor-id", &temp_val) == 0)
|
||||
vdev_vendor = (u16)temp_val;
|
||||
if (of_property_read_u32(np, "virtual-product-id", &temp_val) == 0)
|
||||
vdev_product = (u16)temp_val;
|
||||
if (of_property_read_u32(np, "virtual-version-id", &temp_val) == 0)
|
||||
vdev_version = (u16)temp_val;
|
||||
|
||||
ret = parse_ignore_list(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = parse_remaps(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&dev_mutex);
|
||||
INIT_DELAYED_WORK(&rebuild_work, rebuild_virtual_device_work);
|
||||
|
||||
return input_register_handler(&joypad_handler);
|
||||
}
|
||||
|
||||
static void unified_joypad_remove(struct platform_device *pdev)
|
||||
{
|
||||
input_unregister_handler(&joypad_handler);
|
||||
|
||||
/* Cancel any pending work before cleaning up */
|
||||
cancel_delayed_work_sync(&rebuild_work);
|
||||
|
||||
mutex_lock(&dev_mutex);
|
||||
if (vdev)
|
||||
input_unregister_device(vdev);
|
||||
mutex_unlock(&dev_mutex);
|
||||
|
||||
pr_info(DRV_NAME ": Module unloaded.\n");
|
||||
}
|
||||
|
||||
static const struct of_device_id unified_joypad_of_match[] = {
|
||||
{ .compatible = "rocknix,unified-joypad" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, unified_joypad_of_match);
|
||||
|
||||
static struct platform_driver unified_joypad_platform_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.of_match_table = unified_joypad_of_match,
|
||||
},
|
||||
.probe = unified_joypad_probe,
|
||||
.remove = unified_joypad_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(unified_joypad_platform_driver);
|
||||
@@ -1758,31 +1758,4 @@
|
||||
<input name="x" type="button" id="2" value="1" />
|
||||
<input name="y" type="button" id="3" value="1" />
|
||||
</inputConfig>
|
||||
<inputConfig type="joystick" deviceName="ROCKNIX Unified Joypad" deviceGUID="0600516fff0f0000ff0f000001900000">
|
||||
<input name="a" type="button" id="1" value="1" />
|
||||
<input name="b" type="button" id="0" value="1" />
|
||||
<input name="down" type="hat" id="0" value="4" />
|
||||
<input name="hotkeyenable" type="button" id="12" value="1" />
|
||||
<input name="left" type="hat" id="0" value="8" />
|
||||
<input name="leftanalogdown" type="axis" id="1" value="1" />
|
||||
<input name="leftanalogleft" type="axis" id="0" value="-1" />
|
||||
<input name="leftanalogright" type="axis" id="0" value="1" />
|
||||
<input name="leftanalogup" type="axis" id="1" value="-1" />
|
||||
<input name="leftshoulder" type="button" id="6" value="1" />
|
||||
<input name="leftthumb" type="button" id="13" value="1" />
|
||||
<input name="lefttrigger" type="axis" id="5" value="1" />
|
||||
<input name="right" type="hat" id="0" value="2" />
|
||||
<input name="rightanalogdown" type="axis" id="3" value="1" />
|
||||
<input name="rightanalogleft" type="axis" id="2" value="-1" />
|
||||
<input name="rightanalogright" type="axis" id="2" value="1" />
|
||||
<input name="rightanalogup" type="axis" id="3" value="-1" />
|
||||
<input name="rightshoulder" type="button" id="7" value="1" />
|
||||
<input name="rightthumb" type="button" id="14" value="1" />
|
||||
<input name="righttrigger" type="axis" id="4" value="1" />
|
||||
<input name="select" type="button" id="10" value="1" />
|
||||
<input name="start" type="button" id="11" value="1" />
|
||||
<input name="up" type="hat" id="0" value="1" />
|
||||
<input name="x" type="button" id="3" value="1" />
|
||||
<input name="y" type="button" id="4" value="1" />
|
||||
</inputConfig>
|
||||
</inputList>
|
||||
|
||||
Reference in New Issue
Block a user