* [PATCH 0/4] HID: add Kysona driver
@ 2024-10-05 11:57 Lode Willems
2024-10-05 11:57 ` [PATCH 1/4] HID: Add IDs for Kysona Lode Willems
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Lode Willems @ 2024-10-05 11:57 UTC (permalink / raw)
To: linux-input; +Cc: jikos, bentiss, linux-kernel, Lode Willems
This patchset adds a driver for the Kysona M600 mouse
with support for battery reporting.
Tested with a Kysona M600 V-HUB Special Edition
Lode Willems (4):
HID: Add IDs for Kysona
HID: Kysona: Add basic battery reporting for Kysona M600
HID: Kysona: check battery status every 5s using a workqueue
HID: Kysona: add basic online status
drivers/hid/Kconfig | 9 ++
drivers/hid/Makefile | 1 +
drivers/hid/hid-ids.h | 4 +
drivers/hid/hid-kysona.c | 248 +++++++++++++++++++++++++++++++++++++++
4 files changed, 262 insertions(+)
create mode 100644 drivers/hid/hid-kysona.c
--
2.46.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/4] HID: Add IDs for Kysona
2024-10-05 11:57 [PATCH 0/4] HID: add Kysona driver Lode Willems
@ 2024-10-05 11:57 ` Lode Willems
2024-10-05 11:57 ` [PATCH 2/4] HID: Kysona: Add basic battery reporting for Kysona M600 Lode Willems
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Lode Willems @ 2024-10-05 11:57 UTC (permalink / raw)
To: linux-input; +Cc: jikos, bentiss, linux-kernel, Lode Willems
Add the vendor ID for Kysona and the product IDs for the M600 mouse
(both the dongle and the mouse itself)
Signed-off-by: Lode Willems <me@lodewillems.com>
---
drivers/hid/hid-ids.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 781c5aa29859..76052c653112 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -749,6 +749,10 @@
#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2 0x501A
#define USB_DEVICE_ID_KYE_PENSKETCH_T609A 0x501B
+#define USB_VENDOR_ID_KYSONA 0x3554
+#define USB_DEVICE_ID_KYSONA_M600_DONGLE 0xF57C
+#define USB_DEVICE_ID_KYSONA_M600_WIRED 0xF57D
+
#define USB_VENDOR_ID_LABTEC 0x1020
#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006
#define USB_DEVICE_ID_LABTEC_ODDOR_HANDBRAKE 0x8888
--
2.46.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/4] HID: Kysona: Add basic battery reporting for Kysona M600
2024-10-05 11:57 [PATCH 0/4] HID: add Kysona driver Lode Willems
2024-10-05 11:57 ` [PATCH 1/4] HID: Add IDs for Kysona Lode Willems
@ 2024-10-05 11:57 ` Lode Willems
2024-10-05 11:57 ` [PATCH 3/4] HID: Kysona: check battery status every 5s using a workqueue Lode Willems
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Lode Willems @ 2024-10-05 11:57 UTC (permalink / raw)
To: linux-input; +Cc: jikos, bentiss, linux-kernel, Lode Willems
In this initial the battery is only probed once, a following patch will add
periodic checking.
Signed-off-by: Lode Willems <me@lodewillems.com>
---
drivers/hid/Kconfig | 9 ++
drivers/hid/Makefile | 1 +
drivers/hid/hid-kysona.c | 208 +++++++++++++++++++++++++++++++++++++++
3 files changed, 218 insertions(+)
create mode 100644 drivers/hid/hid-kysona.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 08446c89eff6..541dbee4fa00 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -459,6 +459,15 @@ config HID_KYE
- MousePen i608X tablet
- EasyPen M610X tablet
+config HID_KYSONA
+ tristate "Kysona devices"
+ depends on USB_HID
+ help
+ Support for Kysona mice.
+
+ Say Y here if you have a Kysona M600 mouse
+ and want to be able to read its battery capacity.
+
config HID_UCLOGIC
tristate "UC-Logic"
depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index e40f1ddebbb7..c39ef074ac66 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_HID_JABRA) += hid-jabra.o
obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o
obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o
obj-$(CONFIG_HID_KYE) += hid-kye.o
+obj-$(CONFIG_HID_KYSONA) += hid-kysona.o
obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o
obj-$(CONFIG_HID_LENOVO) += hid-lenovo.o
obj-$(CONFIG_HID_LETSKETCH) += hid-letsketch.o
diff --git a/drivers/hid/hid-kysona.c b/drivers/hid/hid-kysona.c
new file mode 100644
index 000000000000..91e359c31fa1
--- /dev/null
+++ b/drivers/hid/hid-kysona.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * USB HID driver for Kysona
+ * Kysona M600 mice.
+ *
+ * Copyright (c) 2024 Lode Willems <me@lodewillems.com>
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+#define BATTERY_REPORT_ID 4
+
+struct kysona_drvdata {
+ struct hid_device *hdev;
+ struct power_supply_desc battery_desc;
+ struct power_supply *battery;
+ u8 battery_capacity;
+ bool battery_charging;
+ u16 battery_voltage;
+};
+
+static enum power_supply_property kysona_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_SCOPE,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW
+};
+
+static int kysona_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct kysona_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_STATUS:
+ // TODO: check if device is online
+ val->intval = drv_data->battery_charging ?
+ POWER_SUPPLY_STATUS_CHARGING :
+ POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ case POWER_SUPPLY_PROP_SCOPE:
+ val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = drv_data->battery_capacity;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ /* hardware reports voltage in mV. sysfs expects uV */
+ val->intval = drv_data->battery_voltage * 1000;
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = drv_data->hdev->name;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static const char kysona_battery_request[] = {
+ 0x08, BATTERY_REPORT_ID, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49
+};
+
+static int kysona_m600_fetch_battery(struct hid_device *hdev)
+{
+ u8 *write_buf;
+ int ret;
+
+ /* Request battery information */
+ write_buf = kmemdup(kysona_battery_request, sizeof(kysona_battery_request), GFP_KERNEL);
+ if (!write_buf)
+ return -ENOMEM;
+
+ ret = hid_hw_raw_request(hdev, kysona_battery_request[0],
+ write_buf, sizeof(kysona_battery_request),
+ HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
+ if (ret < (int)sizeof(kysona_battery_request)) {
+ hid_err(hdev, "hid_hw_raw_request() failed with %d\n", ret);
+ ret = -ENODATA;
+ }
+ kfree(write_buf);
+ return ret;
+}
+
+static void kysona_fetch_battery(struct hid_device *hdev)
+{
+ int ret = kysona_m600_fetch_battery(hdev);
+
+ if (ret < 0)
+ hid_dbg(hdev,
+ "Battery query failed (err: %d)\n", ret);
+}
+
+static int kysona_battery_probe(struct hid_device *hdev)
+{
+ struct kysona_drvdata *drv_data = hid_get_drvdata(hdev);
+ struct power_supply_config pscfg = { .drv_data = drv_data };
+ int ret = 0;
+
+ drv_data->battery_capacity = 100;
+
+ drv_data->battery_desc.properties = kysona_battery_props;
+ drv_data->battery_desc.num_properties = ARRAY_SIZE(kysona_battery_props);
+ drv_data->battery_desc.get_property = kysona_battery_get_property;
+ drv_data->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY;
+ drv_data->battery_desc.use_for_apm = 0;
+ drv_data->battery_desc.name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
+ "kysona-%s-battery",
+ strlen(hdev->uniq) ?
+ hdev->uniq : dev_name(&hdev->dev));
+ if (!drv_data->battery_desc.name)
+ return -ENOMEM;
+
+ 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);
+ kysona_fetch_battery(hdev);
+
+ return ret;
+}
+
+static int kysona_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+ struct kysona_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 (kysona_battery_probe(hdev) < 0)
+ hid_err(hdev, "Kysona hid battery_probe failed: %d\n", ret);
+ }
+
+ return 0;
+}
+
+static int kysona_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data, int size)
+{
+ struct kysona_drvdata *drv_data = hid_get_drvdata(hdev);
+
+ if (drv_data->battery && size == sizeof(kysona_battery_request) &&
+ data[0] == 8 && data[1] == BATTERY_REPORT_ID) {
+ drv_data->battery_capacity = data[6];
+ drv_data->battery_charging = data[7];
+ drv_data->battery_voltage = (data[8] << 8) | data[9];
+ }
+
+ return 0;
+}
+
+static const struct hid_device_id kysona_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYSONA, USB_DEVICE_ID_KYSONA_M600_DONGLE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYSONA, USB_DEVICE_ID_KYSONA_M600_WIRED) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, kysona_devices);
+
+static struct hid_driver kysona_driver = {
+ .name = "kysona",
+ .id_table = kysona_devices,
+ .probe = kysona_probe,
+ .raw_event = kysona_raw_event
+};
+module_hid_driver(kysona_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("HID driver for Kysona devices");
+MODULE_AUTHOR("Lode Willems <me@lodewillems.com>");
--
2.46.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 3/4] HID: Kysona: check battery status every 5s using a workqueue
2024-10-05 11:57 [PATCH 0/4] HID: add Kysona driver Lode Willems
2024-10-05 11:57 ` [PATCH 1/4] HID: Add IDs for Kysona Lode Willems
2024-10-05 11:57 ` [PATCH 2/4] HID: Kysona: Add basic battery reporting for Kysona M600 Lode Willems
@ 2024-10-05 11:57 ` Lode Willems
2024-10-05 11:57 ` [PATCH 4/4] HID: Kysona: add basic online status Lode Willems
2024-10-18 10:29 ` [PATCH 0/4] HID: add Kysona driver Jiri Kosina
4 siblings, 0 replies; 6+ messages in thread
From: Lode Willems @ 2024-10-05 11:57 UTC (permalink / raw)
To: linux-input; +Cc: jikos, bentiss, linux-kernel, Lode Willems
Use a workqueue to periodically check the battery status
Signed-off-by: Lode Willems <me@lodewillems.com>
---
drivers/hid/hid-kysona.c | 31 ++++++++++++++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-kysona.c b/drivers/hid/hid-kysona.c
index 91e359c31fa1..403bdc4a5e12 100644
--- a/drivers/hid/hid-kysona.c
+++ b/drivers/hid/hid-kysona.c
@@ -12,6 +12,8 @@
#include "hid-ids.h"
+#define BATTERY_TIMEOUT_MS 5000
+
#define BATTERY_REPORT_ID 4
struct kysona_drvdata {
@@ -21,6 +23,7 @@ struct kysona_drvdata {
u8 battery_capacity;
bool battery_charging;
u16 battery_voltage;
+ struct delayed_work battery_work;
};
static enum power_supply_property kysona_battery_props[] = {
@@ -104,6 +107,17 @@ static void kysona_fetch_battery(struct hid_device *hdev)
"Battery query failed (err: %d)\n", ret);
}
+static void kysona_battery_timer_tick(struct work_struct *work)
+{
+ struct kysona_drvdata *drv_data = container_of(work,
+ struct kysona_drvdata, battery_work.work);
+ struct hid_device *hdev = drv_data->hdev;
+
+ kysona_fetch_battery(hdev);
+ schedule_delayed_work(&drv_data->battery_work,
+ msecs_to_jiffies(BATTERY_TIMEOUT_MS));
+}
+
static int kysona_battery_probe(struct hid_device *hdev)
{
struct kysona_drvdata *drv_data = hid_get_drvdata(hdev);
@@ -134,7 +148,11 @@ static int kysona_battery_probe(struct hid_device *hdev)
}
power_supply_powers(drv_data->battery, &hdev->dev);
+
+ INIT_DELAYED_WORK(&drv_data->battery_work, kysona_battery_timer_tick);
kysona_fetch_battery(hdev);
+ schedule_delayed_work(&drv_data->battery_work,
+ msecs_to_jiffies(BATTERY_TIMEOUT_MS));
return ret;
}
@@ -188,6 +206,16 @@ static int kysona_raw_event(struct hid_device *hdev,
return 0;
}
+static void kysona_remove(struct hid_device *hdev)
+{
+ struct kysona_drvdata *drv_data = hid_get_drvdata(hdev);
+
+ if (drv_data->battery)
+ cancel_delayed_work_sync(&drv_data->battery_work);
+
+ hid_hw_stop(hdev);
+}
+
static const struct hid_device_id kysona_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYSONA, USB_DEVICE_ID_KYSONA_M600_DONGLE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYSONA, USB_DEVICE_ID_KYSONA_M600_WIRED) },
@@ -199,7 +227,8 @@ static struct hid_driver kysona_driver = {
.name = "kysona",
.id_table = kysona_devices,
.probe = kysona_probe,
- .raw_event = kysona_raw_event
+ .raw_event = kysona_raw_event,
+ .remove = kysona_remove
};
module_hid_driver(kysona_driver);
--
2.46.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 4/4] HID: Kysona: add basic online status
2024-10-05 11:57 [PATCH 0/4] HID: add Kysona driver Lode Willems
` (2 preceding siblings ...)
2024-10-05 11:57 ` [PATCH 3/4] HID: Kysona: check battery status every 5s using a workqueue Lode Willems
@ 2024-10-05 11:57 ` Lode Willems
2024-10-18 10:29 ` [PATCH 0/4] HID: add Kysona driver Jiri Kosina
4 siblings, 0 replies; 6+ messages in thread
From: Lode Willems @ 2024-10-05 11:57 UTC (permalink / raw)
To: linux-input; +Cc: jikos, bentiss, linux-kernel, Lode Willems
Wait for a response to the battery status request to set the device as
online. This prevent wrong power info when the dongle is connected but
the mouse is turned off.
Signed-off-by: Lode Willems <me@lodewillems.com>
---
drivers/hid/hid-kysona.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/drivers/hid/hid-kysona.c b/drivers/hid/hid-kysona.c
index 403bdc4a5e12..d4c0406b3323 100644
--- a/drivers/hid/hid-kysona.c
+++ b/drivers/hid/hid-kysona.c
@@ -18,6 +18,8 @@
struct kysona_drvdata {
struct hid_device *hdev;
+ bool online;
+
struct power_supply_desc battery_desc;
struct power_supply *battery;
u8 battery_capacity;
@@ -32,7 +34,8 @@ static enum power_supply_property kysona_battery_props[] = {
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_SCOPE,
POWER_SUPPLY_PROP_MODEL_NAME,
- POWER_SUPPLY_PROP_VOLTAGE_NOW
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_ONLINE
};
static int kysona_battery_get_property(struct power_supply *psy,
@@ -46,11 +49,16 @@ static int kysona_battery_get_property(struct power_supply *psy,
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:
- // TODO: check if device is online
- val->intval = drv_data->battery_charging ?
- POWER_SUPPLY_STATUS_CHARGING :
- POWER_SUPPLY_STATUS_DISCHARGING;
+ 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_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
@@ -124,7 +132,9 @@ static int kysona_battery_probe(struct hid_device *hdev)
struct power_supply_config pscfg = { .drv_data = drv_data };
int ret = 0;
+ drv_data->online = false;
drv_data->battery_capacity = 100;
+ drv_data->battery_voltage = 4200;
drv_data->battery_desc.properties = kysona_battery_props;
drv_data->battery_desc.num_properties = ARRAY_SIZE(kysona_battery_props);
@@ -201,6 +211,7 @@ static int kysona_raw_event(struct hid_device *hdev,
drv_data->battery_capacity = data[6];
drv_data->battery_charging = data[7];
drv_data->battery_voltage = (data[8] << 8) | data[9];
+ drv_data->online = true;
}
return 0;
--
2.46.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 0/4] HID: add Kysona driver
2024-10-05 11:57 [PATCH 0/4] HID: add Kysona driver Lode Willems
` (3 preceding siblings ...)
2024-10-05 11:57 ` [PATCH 4/4] HID: Kysona: add basic online status Lode Willems
@ 2024-10-18 10:29 ` Jiri Kosina
4 siblings, 0 replies; 6+ messages in thread
From: Jiri Kosina @ 2024-10-18 10:29 UTC (permalink / raw)
To: Lode Willems; +Cc: linux-input, bentiss, linux-kernel
On Sat, 5 Oct 2024, Lode Willems wrote:
> This patchset adds a driver for the Kysona M600 mouse
> with support for battery reporting.
>
> Tested with a Kysona M600 V-HUB Special Edition
>
> Lode Willems (4):
> HID: Add IDs for Kysona
> HID: Kysona: Add basic battery reporting for Kysona M600
> HID: Kysona: check battery status every 5s using a workqueue
> HID: Kysona: add basic online status
>
> drivers/hid/Kconfig | 9 ++
> drivers/hid/Makefile | 1 +
> drivers/hid/hid-ids.h | 4 +
> drivers/hid/hid-kysona.c | 248 +++++++++++++++++++++++++++++++++++++++
> 4 files changed, 262 insertions(+)
> create mode 100644 drivers/hid/hid-kysona.c
Now queued in hid.git#for-6.13/kysona.
Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-10-18 10:29 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-05 11:57 [PATCH 0/4] HID: add Kysona driver Lode Willems
2024-10-05 11:57 ` [PATCH 1/4] HID: Add IDs for Kysona Lode Willems
2024-10-05 11:57 ` [PATCH 2/4] HID: Kysona: Add basic battery reporting for Kysona M600 Lode Willems
2024-10-05 11:57 ` [PATCH 3/4] HID: Kysona: check battery status every 5s using a workqueue Lode Willems
2024-10-05 11:57 ` [PATCH 4/4] HID: Kysona: add basic online status Lode Willems
2024-10-18 10:29 ` [PATCH 0/4] HID: add Kysona driver Jiri Kosina
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®