[PATCH] HID: Driver for Lenovo Keyboard w/ Trackpoint

Subsystems: hid core layer, the rest

STALE5611d

3 messages, 2 authors, 2011-06-13 · open the first message on its own page

[PATCH] HID: Driver for Lenovo Keyboard w/ Trackpoint

From: Bernhard Seibold <hidden>
Date: 2011-05-27 17:16:24

This patch adds support for setting the trackpoint sensitivity
of the "Lenovo ThinkPad USB Keyboard with Trackpoint".

Signed-off-by: Bernhard Seibold <redacted>
---
 drivers/hid/Kconfig            |   10 +++
 drivers/hid/Makefile           |    1 +
 drivers/hid/hid-core.c         |    1 +
 drivers/hid/hid-ids.h          |    3 +
 drivers/hid/hid-lenovo-tpkbd.c |  166 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 181 insertions(+), 0 deletions(-)
 create mode 100644 drivers/hid/hid-lenovo-tpkbd.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 67d2a75..85028c4 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -224,6 +224,16 @@ config HID_LCPOWER
 	---help---
 	Support for LC-Power RC1000MCE RF remote control.
 
+config HID_LENOVO_TPKBD
+	tristate "Lenovo ThinkPad USB Keyboard with TrackPoint"
+	depends on USB_HID
+	---help---
+	Support for the Lenovo ThinkPad USB Keyboard with TrackPoint.
+
+	Say Y here if you have a Lenovo ThinkPad USB Keyboard with TrackPoint
+	and would like to change the sensitivity of the trackpoint using a
+	sysfs attribute.
+
 config HID_LOGITECH
 	tristate "Logitech devices" if EXPERT
 	depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index f8cc4ea..8dc5890 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_HID_KENSINGTON)	+= hid-kensington.o
 obj-$(CONFIG_HID_KEYTOUCH)	+= hid-keytouch.o
 obj-$(CONFIG_HID_KYE)		+= hid-kye.o
 obj-$(CONFIG_HID_LCPOWER)       += hid-lcpower.o
+obj-$(CONFIG_HID_LENOVO_TPKBD)	+= hid-lenovo-tpkbd.o
 obj-$(CONFIG_HID_LOGITECH)	+= hid-logitech.o
 obj-$(CONFIG_HID_MAGICMOUSE)    += hid-magicmouse.o
 obj-$(CONFIG_HID_MICROSOFT)	+= hid-microsoft.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index c957c4b..baee8b0 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1394,6 +1394,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 0b374a6..1e1defd 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -413,6 +413,9 @@
 #define USB_DEVICE_ID_LD_HYBRID		0x2090
 #define USB_DEVICE_ID_LD_HEATCONTROL	0x20A0
 
+#define USB_VENDOR_ID_LENOVO		0x17ef
+#define USB_DEVICE_ID_LENOVO_TPKBD	0x6009
+
 #define USB_VENDOR_ID_LOGITECH		0x046d
 #define USB_DEVICE_ID_LOGITECH_RECEIVER	0xc101
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c
new file mode 100644
index 0000000..90ebc3e
--- /dev/null
+++ b/drivers/hid/hid-lenovo-tpkbd.c
@@ -0,0 +1,166 @@
+/*
+ *  HID driver for Lenovo ThinkPad USB Keyboard with TrackPoint
+ *
+ *  Copyright (c) 2011 Bernhard Seibold
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/sysfs.h>
+#include <linux/device.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include "usbhid/usbhid.h"
+
+#include "hid-ids.h"
+
+static int lenovo_tpkbd_input_mapping(struct hid_device *hdev,
+		struct hid_input *hi, struct hid_field *field,
+		struct hid_usage *usage, unsigned long **bit, int *max)
+{
+	return 0;
+}
+
+static ssize_t pointer_sensitivity_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct hid_device *hdev;
+	struct hid_report *report;
+	hdev = container_of(dev, struct hid_device, dev);
+
+	if (hdev == NULL)
+		return -ENODEV;
+
+	report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4];
+	usbhid_submit_report(hdev, report, USB_DIR_IN);
+	usbhid_wait_io(hdev);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		report->field[2]->value[0]);
+}
+
+static ssize_t pointer_sensitivity_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct hid_device *hdev;
+	struct hid_report *report;
+	int value;
+
+	if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
+		return -EINVAL;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4];
+	usbhid_submit_report(hdev, report, USB_DIR_IN);
+	usbhid_wait_io(hdev);
+	report->field[0]->value[0] = 0x6a;
+	report->field[1]->value[0] = 0x03;
+	report->field[2]->value[0] = value;
+	report->field[3]->value[0] = 0x38;
+	usbhid_submit_report(hdev, report, USB_DIR_OUT);
+	return count;
+}
+
+static struct device_attribute dev_attr_pointer_sensitivity =
+	__ATTR(sensitivity, S_IWUSR | S_IRUGO,
+			pointer_sensitivity_show,
+			pointer_sensitivity_store);
+
+static struct attribute *lenovo_tpkbd_attributes_pointer[] = {
+	&dev_attr_pointer_sensitivity.attr,
+	NULL
+};
+
+static const struct attribute_group lenovo_tpkbd_attr_group_pointer = {
+	.attrs = lenovo_tpkbd_attributes_pointer,
+};
+
+static int lenovo_tpkbd_probe(struct hid_device *hdev,
+		const struct hid_device_id *id)
+{
+	int ret;
+	struct usbhid_device *uhdev;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "hid_parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		hid_err(hdev, "hid_hw_start failed\n");
+		goto err_free;
+	}
+
+	uhdev = (struct usbhid_device *) hdev->driver_data;
+
+	if (uhdev->ifnum == 1) {
+		if (sysfs_create_group(&hdev->dev.kobj,
+					&lenovo_tpkbd_attr_group_pointer)) {
+			printk(KERN_WARNING "hid-lenovo-tpkbd: Could not "
+						"create sysfs group\n");
+		}
+
+	}
+
+	return 0;
+err_free:
+	return ret;
+}
+
+static void lenovo_tpkbd_remove(struct hid_device *hdev)
+{
+	struct usbhid_device *uhdev;
+
+	uhdev = (struct usbhid_device *) hdev->driver_data;
+
+	if (uhdev->ifnum == 1)
+		sysfs_remove_group(&hdev->dev.kobj,
+				&lenovo_tpkbd_attr_group_pointer);
+
+	hid_hw_stop(hdev);
+}
+
+static const struct hid_device_id lenovo_tpkbd_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(hid, lenovo_tpkbd_devices);
+
+static struct hid_driver lenovo_tpkbd_driver = {
+	.name = "lenovo_tpkbd",
+	.id_table = lenovo_tpkbd_devices,
+	.input_mapping = lenovo_tpkbd_input_mapping,
+	.probe = lenovo_tpkbd_probe,
+	.remove = lenovo_tpkbd_remove,
+};
+
+static int __init lenovo_tpkbd_init(void)
+{
+	return hid_register_driver(&lenovo_tpkbd_driver);
+}
+
+static void __exit lenovo_tpkbd_exit(void)
+{
+	hid_unregister_driver(&lenovo_tpkbd_driver);
+}
+
+module_init(lenovo_tpkbd_init);
+module_exit(lenovo_tpkbd_exit);
+
+MODULE_LICENSE("GPL");
-- 
1.7.5.1

Re: [PATCH] HID: Driver for Lenovo Keyboard w/ Trackpoint

From: Jiri Kosina <hidden>
Date: 2011-06-13 13:25:00

On Fri, 27 May 2011, Bernhard Seibold wrote:
This patch adds support for setting the trackpoint sensitivity
of the "Lenovo ThinkPad USB Keyboard with Trackpoint".
Hi Bernhard,

thanks a lot for the patch.
quoted hunk
---
 drivers/hid/Kconfig            |   10 +++
 drivers/hid/Makefile           |    1 +
 drivers/hid/hid-core.c         |    1 +
 drivers/hid/hid-ids.h          |    3 +
 drivers/hid/hid-lenovo-tpkbd.c |  166 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 181 insertions(+), 0 deletions(-)
 create mode 100644 drivers/hid/hid-lenovo-tpkbd.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 67d2a75..85028c4 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -224,6 +224,16 @@ config HID_LCPOWER
 	---help---
 	Support for LC-Power RC1000MCE RF remote control.
 
+config HID_LENOVO_TPKBD
+	tristate "Lenovo ThinkPad USB Keyboard with TrackPoint"
+	depends on USB_HID
+	---help---
+	Support for the Lenovo ThinkPad USB Keyboard with TrackPoint.
+
+	Say Y here if you have a Lenovo ThinkPad USB Keyboard with TrackPoint
+	and would like to change the sensitivity of the trackpoint using a
+	sysfs attribute.
+
As you are adding sysfs attribute, we'd like to have it documented as well 
Documentation/ABI somewhere.
quoted hunk
--- /dev/null
+++ b/drivers/hid/hid-lenovo-tpkbd.c
@@ -0,0 +1,166 @@
+/*
+ *  HID driver for Lenovo ThinkPad USB Keyboard with TrackPoint
+ *
+ *  Copyright (c) 2011 Bernhard Seibold
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/sysfs.h>
+#include <linux/device.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include "usbhid/usbhid.h"
+
+#include "hid-ids.h"
+
+static int lenovo_tpkbd_input_mapping(struct hid_device *hdev,
+		struct hid_input *hi, struct hid_field *field,
+		struct hid_usage *usage, unsigned long **bit, int *max)
+{
+	return 0;
+}
+
Why is this empty stub needed?
quoted hunk
+static ssize_t pointer_sensitivity_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct hid_device *hdev;
+	struct hid_report *report;
+	hdev = container_of(dev, struct hid_device, dev);
+
+	if (hdev == NULL)
+		return -ENODEV;
+
+	report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4];
+	usbhid_submit_report(hdev, report, USB_DIR_IN);
+	usbhid_wait_io(hdev);
usbhid_wait_io() returns -1 in case it times out.
quoted hunk
+
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		report->field[2]->value[0]);
+}
+
+static ssize_t pointer_sensitivity_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct hid_device *hdev;
+	struct hid_report *report;
+	int value;
+
+	if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
+		return -EINVAL;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4];
+	usbhid_submit_report(hdev, report, USB_DIR_IN);
+	usbhid_wait_io(hdev);
The same here.

Thanks,

-- 
Jiri Kosina
SUSE Labs

Re: [PATCH] HID: Driver for Lenovo Keyboard w/ Trackpoint

From: Bernhard Seibold <hidden>
Date: 2011-06-13 14:15:08

On Mon, 13 Jun 2011 15:24:58 +0200 (CEST)
Jiri Kosina [off-list ref] wrote:
On Fri, 27 May 2011, Bernhard Seibold wrote:
quoted
This patch adds support for setting the trackpoint sensitivity
of the "Lenovo ThinkPad USB Keyboard with Trackpoint".
As you are adding sysfs attribute, we'd like to have it documented as
well Documentation/ABI somewhere.
Will do. Is there a generic way to make this setting available in
XInput? I feel this should show up as a device property when doing
something along the lines of "xinput list-props <DEV-ID>".
Why is this empty stub needed?
That's an oversight. I added support for microphone mute key here, but
removed it for patch submission since the patch adding KEY_MICMUTE
seems to be unapplied as of now (at least i didn't find any git tree
containing it)

The patch in question is:

[PATCH] Add KEY_MICMUTE and enable it on Lenovo X220
http://www.spinics.net/lists/linux-input/msg15394.html
quoted
+static ssize_t pointer_sensitivity_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct hid_device *hdev;
+	struct hid_report *report;
+	hdev = container_of(dev, struct hid_device, dev);
+
+	if (hdev == NULL)
+		return -ENODEV;
+
+	report =
hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4];
+	usbhid_submit_report(hdev, report, USB_DIR_IN);
+	usbhid_wait_io(hdev);
usbhid_wait_io() returns -1 in case it times out.
Whats the correct way to handle this? Since I'm a kernel-newbie I used
hid-ntrig.c among others as "inspiration" and there the return value
isn't checked either.

Frankly I'm not sure if the wait_io is necessary at all.
quoted
+static ssize_t pointer_sensitivity_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct hid_device *hdev;
+	struct hid_report *report;
+	int value;
+
+	if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
+		return -EINVAL;
+
+	hdev = container_of(dev, struct hid_device, dev);
+	if (hdev == NULL)
+		return -ENODEV;
+
+	report =
hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4];
+	usbhid_submit_report(hdev, report, USB_DIR_IN);
+	usbhid_wait_io(hdev);
The same here.

Thanks,
Thanks for your comments.

Should I just include KEY_MICMUTE in my patch or wait for that other
patch to show up somewhere in git before posting an updated version?
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help