summaryrefslogtreecommitdiff
path: root/drivers/hid/hid-uclogic-params.c
diff options
context:
space:
mode:
authorJosé Expósito <jose.exposito89@gmail.com>2022-10-29 19:12:40 +0300
committerJiri Kosina <jkosina@suse.cz>2022-11-04 17:53:25 +0300
commitf9ce4db0ec2b6301f4264ba8627863e2632c922b (patch)
treea6ed246b8b3a7724fcc4311ff14a3feb84ecb6d4 /drivers/hid/hid-uclogic-params.c
parent037c1aaeb96fe5f778026f4c1ef28b26cf600bfa (diff)
downloadlinux-f9ce4db0ec2b6301f4264ba8627863e2632c922b.tar.xz
HID: uclogic: Add support for XP-PEN Deco LW
The XP-PEN Deco LW is a UGEE v2 device with a frame with 8 buttons. Its pen has 2 buttons, supports tilt and pressure. It can be connected by USB cable or using a USB Bluetooth dongle to use it in wireless mode. When it is connected using the dongle, the device battery is used to power it. Its vendor, product and version are identical to the Deco L. The only difference reported by its firmware is the product name. In order to add support for battery reporting, add a new HID descriptor and a quirk to detect the wireless version of the tablet. Link: https://github.com/DIGImend/digimend-kernel-drivers/issues/635 Tested-by: Mia Kanashi <chad@redpilled.dev> Tested-by: Andreas Grosse <andig.mail@t-online.de> Tested-by: Mia Kanashi <chad@redpilled.dev> Signed-off-by: José Expósito <jose.exposito89@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-uclogic-params.c')
-rw-r--r--drivers/hid/hid-uclogic-params.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c
index 34fa991e6267..cd1233d7e253 100644
--- a/drivers/hid/hid-uclogic-params.c
+++ b/drivers/hid/hid-uclogic-params.c
@@ -18,6 +18,7 @@
#include "usbhid/usbhid.h"
#include "hid-ids.h"
#include <linux/ctype.h>
+#include <linux/string.h>
#include <asm/unaligned.h>
/**
@@ -1212,6 +1213,69 @@ static int uclogic_params_ugee_v2_init_frame_mouse(struct uclogic_params *p)
}
/**
+ * uclogic_params_ugee_v2_has_battery() - check whether a UGEE v2 device has
+ * battery or not.
+ * @hdev: The HID device of the tablet interface.
+ *
+ * Returns:
+ * True if the device has battery, false otherwise.
+ */
+static bool uclogic_params_ugee_v2_has_battery(struct hid_device *hdev)
+{
+ /* The XP-PEN Deco LW vendor, product and version are identical to the
+ * Deco L. The only difference reported by their firmware is the product
+ * name. Add a quirk to support battery reporting on the wireless
+ * version.
+ */
+ if (hdev->vendor == USB_VENDOR_ID_UGEE &&
+ hdev->product == USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) {
+ struct usb_device *udev = hid_to_usb_dev(hdev);
+
+ if (strstarts(udev->product, "Deco LW"))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * uclogic_params_ugee_v2_init_battery() - initialize UGEE v2 battery reporting.
+ * @hdev: The HID device of the tablet interface, cannot be NULL.
+ * @p: Parameters to fill in, cannot be NULL.
+ *
+ * Returns:
+ * Zero, if successful. A negative errno code on error.
+ */
+static int uclogic_params_ugee_v2_init_battery(struct hid_device *hdev,
+ struct uclogic_params *p)
+{
+ int rc = 0;
+
+ if (!hdev || !p)
+ return -EINVAL;
+
+ /* Some tablets contain invalid characters in hdev->uniq, throwing a
+ * "hwmon: '<name>' is not a valid name attribute, please fix" error.
+ * Use the device vendor and product IDs instead.
+ */
+ snprintf(hdev->uniq, sizeof(hdev->uniq), "%x-%x", hdev->vendor,
+ hdev->product);
+
+ rc = uclogic_params_frame_init_with_desc(&p->frame_list[1],
+ uclogic_rdesc_ugee_v2_battery_template_arr,
+ uclogic_rdesc_ugee_v2_battery_template_size,
+ UCLOGIC_RDESC_UGEE_V2_BATTERY_ID);
+ if (rc)
+ return rc;
+
+ p->frame_list[1].suffix = "Battery";
+ p->pen.subreport_list[1].value = 0xf2;
+ p->pen.subreport_list[1].id = UCLOGIC_RDESC_UGEE_V2_BATTERY_ID;
+
+ return rc;
+}
+
+/**
* uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by
* discovering their parameters.
*
@@ -1334,6 +1398,15 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
if (rc)
goto cleanup;
+ /* Initialize the battery interface*/
+ if (uclogic_params_ugee_v2_has_battery(hdev)) {
+ rc = uclogic_params_ugee_v2_init_battery(hdev, &p);
+ if (rc) {
+ hid_err(hdev, "error initializing battery: %d\n", rc);
+ goto cleanup;
+ }
+ }
+
output:
/* Output parameters */
memcpy(params, &p, sizeof(*params));