lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20250623155517.492051-1-danascape@gmail.com>
Date: Mon, 23 Jun 2025 21:25:17 +0530
From: Saalim Quadri <danascape@...il.com>
To: jikos@...nel.org,
	bentiss@...nel.org
Cc: linux-input@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	Saalim Quadri <danascape@...il.com>
Subject: [PATCH] HID: Xinmeng: Add driver for Xinmeng M71 Keyboard

In this driver, the battery is probed, and it checks the capacity
and charging status of the battery

Signed-off-by: Saalim Quadri <danascape@...il.com>
---
 drivers/hid/Kconfig       |  12 +++
 drivers/hid/Makefile      |   1 +
 drivers/hid/hid-ids.h     |   3 +
 drivers/hid/hid-xinmeng.c | 168 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 184 insertions(+)
 create mode 100644 drivers/hid/hid-xinmeng.c

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 43859fc75747..534d5ca151f0 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -536,6 +536,18 @@ config HID_XIAOMI
 	  Adds support for side buttons of Xiaomi Mi Dual Mode Wireless
 	  Mouse Silent Edition.
 
+config HID_XINMENG
+	tristate "Xinmeng Keyboards"
+	depends on USB_HID
+	help
+		Support for Xinmeng Keyboard.
+
+		Say Y here if you have a Xinmeng M71 Keyboard
+		and want to be able to read its battery capacity.
+
+		To compile this driver as a module, choose M here: the
+		module will be called hid-icade.
+
 config HID_GYRATION
 	tristate "Gyration remote control"
 	help
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 10ae5dedbd84..e5c9d1276138 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -145,6 +145,7 @@ obj-$(CONFIG_HID_UDRAW_PS3)	+= hid-udraw-ps3.o
 obj-$(CONFIG_HID_UNIVERSAL_PIDFF)	+= hid-universal-pidff.o
 obj-$(CONFIG_HID_LED)		+= hid-led.o
 obj-$(CONFIG_HID_XIAOMI)	+= hid-xiaomi.o
+obj-$(CONFIG_HID_XINMENG)	+= hid-xinmeng.o
 obj-$(CONFIG_HID_XINMO)		+= hid-xinmo.o
 obj-$(CONFIG_HID_ZEROPLUS)	+= hid-zpff.o
 obj-$(CONFIG_HID_ZYDACRON)	+= hid-zydacron.o
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index e3fb4e2fe911..f649549bd58c 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -1471,6 +1471,9 @@
 #define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE	0x05e1
 #define USB_DEVICE_ID_THT_2P_ARCADE		0x75e1
 
+#define USB_VENDOR_ID_XINMENG   0x3554
+#define USB_DEVICE_ID_XINMENG_M71_RECEIVER  0xfa09
+
 #define USB_VENDOR_ID_XIROKU		0x1477
 #define USB_DEVICE_ID_XIROKU_SPX	0x1006
 #define USB_DEVICE_ID_XIROKU_MPX	0x1007
diff --git a/drivers/hid/hid-xinmeng.c b/drivers/hid/hid-xinmeng.c
new file mode 100644
index 000000000000..53f0a96e7f3d
--- /dev/null
+++ b/drivers/hid/hid-xinmeng.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  HID driver for Xinmeng M71 Keyboard.
+ *
+ *  Copyright (c) 2025 Saalim Quadri <saalimquadri2@...il.com>
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+#define	BATTERY_REPORT_ID	(0x13)
+
+struct xinmeng_drvdata {
+	struct hid_device *hdev;
+	bool online;
+
+	struct power_supply *battery;
+	struct power_supply_desc battery_desc;
+	u8 battery_capacity;
+	bool battery_charging;
+};
+
+static enum power_supply_property xinmeng_battery_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_ONLINE
+};
+
+static int xinmeng_battery_get_property(struct power_supply *psy,
+				       enum power_supply_property psp,
+				       union power_supply_propval *val)
+{
+	struct xinmeng_drvdata *drv_data = power_supply_get_drvdata(psy);
+	int ret = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = 1;
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = drv_data->online;
+		break;
+	case POWER_SUPPLY_PROP_STATUS:
+		if (drv_data->online)
+			val->intval = drv_data->battery_charging ?
+					POWER_SUPPLY_STATUS_CHARGING :
+					POWER_SUPPLY_STATUS_DISCHARGING;
+		else
+			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = drv_data->battery_capacity;
+		break;
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = drv_data->hdev->name;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int xinmeng_battery_probe(struct hid_device *hdev)
+{
+	struct xinmeng_drvdata *drv_data = hid_get_drvdata(hdev);
+	struct power_supply_config pscfg = { .drv_data = drv_data };
+	int ret = 0;
+
+	drv_data->online = false;
+	drv_data->battery_capacity = 0;
+
+	drv_data->battery_desc.name = "xinmeng-m71-battery";
+	drv_data->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY;
+	drv_data->battery_desc.properties = xinmeng_battery_props;
+	drv_data->battery_desc.num_properties = ARRAY_SIZE(xinmeng_battery_props);
+	drv_data->battery_desc.get_property = xinmeng_battery_get_property;
+
+	drv_data->battery = devm_power_supply_register(&hdev->dev,
+						       &drv_data->battery_desc, &pscfg);
+
+	if (IS_ERR(drv_data->battery)) {
+		ret = PTR_ERR(drv_data->battery);
+		drv_data->battery = NULL;
+		hid_err(hdev, "Unable to register battery device\n");
+		return ret;
+	}
+
+	power_supply_powers(drv_data->battery, &hdev->dev);
+
+	return ret;
+}
+
+static int xinmeng_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int ret;
+	struct xinmeng_drvdata *drv_data;
+	struct usb_interface *usbif;
+
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
+	usbif = to_usb_interface(hdev->dev.parent);
+
+	drv_data = devm_kzalloc(&hdev->dev, sizeof(*drv_data), GFP_KERNEL);
+	if (!drv_data)
+		return -ENOMEM;
+
+	hid_set_drvdata(hdev, drv_data);
+	drv_data->hdev = hdev;
+
+	ret = hid_parse(hdev);
+	if (ret)
+		return ret;
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret)
+		return ret;
+
+	if (usbif->cur_altsetting->desc.bInterfaceNumber == 1) {
+		if (xinmeng_battery_probe(hdev) < 0)
+			hid_err(hdev, "Xinmeng hid battery_probe failed: %d\n", ret);
+	}
+
+	return 0;
+}
+
+static int xinmeng_raw_event(struct hid_device *hdev,
+	struct hid_report *report, u8 *data, int size)
+{
+
+	struct xinmeng_drvdata *drv_data = hid_get_drvdata(hdev);
+
+	if (drv_data->battery && data[0] == BATTERY_REPORT_ID) {
+		u8 charging_status = data[7];
+		bool is_charging = (charging_status == 0x11 || charging_status == 0x10);
+
+		drv_data->battery_capacity = data[6];
+		drv_data->battery_charging = is_charging;
+		drv_data->online = true;
+	}
+
+	return 0;
+}
+
+static const struct hid_device_id xinmeng_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_XINMENG, USB_DEVICE_ID_XINMENG_M71_RECEIVER) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, xinmeng_devices);
+
+static struct hid_driver xinmeng_driver = {
+	.name = "xinmeng",
+	.id_table = xinmeng_devices,
+	.probe = xinmeng_probe,
+	.raw_event = xinmeng_raw_event
+};
+module_hid_driver(xinmeng_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("HID driver for Xinmeng keyboards");
+MODULE_AUTHOR("Saalim Quadri <saalimquadri2@...il.com>");
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ