* [PATCH] hid: Add custom driver for Lenovo ThinkPad Compact Bluetooth Keyboard
@ 2014-03-25 22:26 Jamie Lentin
2014-05-20 14:47 ` Jiri Kosina
0 siblings, 1 reply; 4+ messages in thread
From: Jamie Lentin @ 2014-03-25 22:26 UTC (permalink / raw)
To: Jiri Kosina; +Cc: linux-input, linux-kernel, Jamie Lentin
This keyboard requires some custom mappings for all keys to be
available, and the Fn-lock toggle needs to be controlled in software.
Signed-off-by: Jamie Lentin <jm@lentin.co.uk>
---
I assume that Linux users want Fn-Lock enabled by default, so they can
get at the function keys. If this is an incorrect assumption then can
change it---so long as there's some way of me leaving it enabled :)
Tested with and applies cleanly to 3.13.6.
drivers/hid/Kconfig | 10 ++
drivers/hid/Makefile | 1 +
drivers/hid/hid-core.c | 3 +
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-lenovo-tpcompactkbd.c | 191 ++++++++++++++++++++++++++++++++++
5 files changed, 206 insertions(+)
create mode 100644 drivers/hid/hid-lenovo-tpcompactkbd.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 34e2d39..8e45413 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -335,6 +335,16 @@ config HID_LENOVO_TPKBD
sensitivity of the trackpoint, using the microphone mute button or
controlling the mute and microphone mute LEDs.
+config HID_LENOVO_CBTKBD
+ tristate "Lenovo ThinkPad Compact Bluetooth Keyboard with TrackPoint"
+ depends on HID
+ ---help---
+ Support for the Lenovo ThinkPad Compact Bluetooth Keyboard with TrackPoint.
+
+ Say Y here if you have a Lenovo ThinkPad Compact Bluetooth Keyboard with
+ TrackPoint and would like to use the function keys as function keys, as
+ well as letting linux recognise the special functions such as brightness.
+
config HID_LOGITECH
tristate "Logitech devices" if EXPERT
depends on HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 30e4431..c0a2f89 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -59,6 +59,7 @@ 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_LENOVO_CBTKBD) += hid-lenovo-tpcompactkbd.o
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o
obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 253fe23..77bce8f 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1734,6 +1734,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
#if IS_ENABLED(CONFIG_HID_LENOVO_TPKBD)
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
#endif
+#if IS_ENABLED(CONFIG_HID_LENOVO_CBTKBD)
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) },
+#endif
{ 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 f9304cb..6802166 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -539,6 +539,7 @@
#define USB_VENDOR_ID_LENOVO 0x17ef
#define USB_DEVICE_ID_LENOVO_TPKBD 0x6009
+#define USB_DEVICE_ID_LENOVO_CBTKBD 0x6048
#define USB_VENDOR_ID_LG 0x1fd2
#define USB_DEVICE_ID_LG_MULTITOUCH 0x0064
diff --git a/drivers/hid/hid-lenovo-tpcompactkbd.c b/drivers/hid/hid-lenovo-tpcompactkbd.c
new file mode 100644
index 0000000..0fd085b
--- /dev/null
+++ b/drivers/hid/hid-lenovo-tpcompactkbd.c
@@ -0,0 +1,191 @@
+/*
+ * ThinkPad Compact (Bluetooth|USB) Keyboard with TrackPoint
+ *
+ * Copyright (c) 2014 Jamie Lentin <jm@lentin.co.uk>
+ *
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static unsigned int fnmode;
+module_param(fnmode, uint, 0644);
+MODULE_PARM_DESC(fnmode, "Fn lock mode ([0] = normal (Fn Lock toggles), 1 = Permanently on, 2 = Permanently off)");
+
+struct tpcompactkbd_sc {
+ unsigned int fn_lock;
+};
+
+/* Send a config command to the keyboard */
+static int tpcompactkbd_send_cmd(struct hid_device *hdev,
+ unsigned char byte2, unsigned char byte3)
+{
+ unsigned char buf[] = {0x18, byte2, byte3};
+
+ return hdev->hid_output_raw_report(hdev, buf, sizeof(buf),
+ HID_OUTPUT_REPORT);
+}
+
+/* Toggle fnlock on or off, if fnmode allows */
+static void tpcompactkbd_toggle_fnlock(struct hid_device *hdev)
+{
+ struct tpcompactkbd_sc *tpcsc = hid_get_drvdata(hdev);
+
+ tpcsc->fn_lock = fnmode == 2 ? 0 : fnmode == 1 ? 1 : !tpcsc->fn_lock;
+ if (tpcompactkbd_send_cmd(hdev, 0x05, tpcsc->fn_lock ? 0x01 : 0x00))
+ hid_err(hdev, "Fn-lock toggle failed\n");
+}
+
+/*
+ * Keyboard sends non-standard reports for most "hotkey" Fn functions.
+ * Map these back to regular keys.
+ *
+ * Esc: KEY_FN_ESC FnLock
+ * (F1--F3 are regular keys)
+ * F4: KEY_MICMUTE Mic Mute
+ * F5: KEY_BRIGHTNESSDOWN Brightness down
+ * F6: KEY_BRIGHTNESSUP Brightness up
+ * F7: KEY_SWITCHVIDEOMODE External display (projector)
+ * F8: KEY_FN_F8 Wireless
+ * F9: KEY_CONFIG Control panel / settings
+ * F10: KEY_SEARCH Search
+ * F11: KEY_FN_F11 View open applications (3 boxes)
+ * F12: KEY_FN_F12 Open My computer (6 boxes)
+ */
+
+#define tpckbd_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+static int tpcompactkbd_input_mapping(struct hid_device *hdev,
+ struct hid_input *hi, struct hid_field *field,
+ struct hid_usage *usage, unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
+ set_bit(EV_REP, hi->input->evbit);
+ switch (usage->hid & HID_USAGE) {
+ case 0x03f1:
+ tpckbd_map_key_clear(KEY_FN_F8);
+ return 1;
+ case 0x0221:
+ tpckbd_map_key_clear(KEY_SEARCH);
+ return 1;
+ case 0x03f2:
+ tpckbd_map_key_clear(KEY_FN_F12);
+ return 1;
+ }
+ }
+
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) {
+ set_bit(EV_REP, hi->input->evbit);
+ switch (usage->hid & HID_USAGE) {
+ case 0x00f0:
+ tpckbd_map_key_clear(KEY_FN_ESC);
+ return 1;
+ case 0x00f1:
+ tpckbd_map_key_clear(KEY_MICMUTE);
+ return 1;
+ case 0x00f2:
+ tpckbd_map_key_clear(KEY_BRIGHTNESSDOWN);
+ return 1;
+ case 0x00f3:
+ tpckbd_map_key_clear(KEY_BRIGHTNESSUP);
+ return 1;
+ case 0x00f4:
+ tpckbd_map_key_clear(KEY_SWITCHVIDEOMODE);
+ return 1;
+ case 0x00f5:
+ tpckbd_map_key_clear(KEY_FN_F8);
+ return 1;
+ case 0x00f6:
+ tpckbd_map_key_clear(KEY_CONFIG);
+ return 1;
+ case 0x00f8:
+ tpckbd_map_key_clear(KEY_FN_F11);
+ return 1;
+ case 0x00fa:
+ tpckbd_map_key_clear(KEY_FN_ESC);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int tpcompactkbd_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ /* Switch fn-lock on fn-esc */
+ if (unlikely(usage->code == KEY_FN_ESC && value))
+ tpcompactkbd_toggle_fnlock(hdev);
+
+ return 0;
+}
+
+static int tpcompactkbd_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int ret;
+ struct tpcompactkbd_sc *tpcsc;
+
+ tpcsc = devm_kzalloc(&hdev->dev, sizeof(*tpcsc), GFP_KERNEL);
+ if (tpcsc == NULL) {
+ hid_err(hdev, "can't alloc keyboard descriptor\n");
+ return -ENOMEM;
+ }
+ hid_set_drvdata(hdev, tpcsc);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "hid_parse failed\n");
+ return ret;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ hid_err(hdev, "hid_hw_start failed\n");
+ return ret;
+ }
+
+ /*
+ * Tell the keyboard a driver understands it, and turn F7, F9, F11 into
+ * regular keys
+ */
+ ret = tpcompactkbd_send_cmd(hdev, 0x01, 0x03);
+ if (ret)
+ hid_warn(hdev, "Failed to switch F7/9/11 into regular keys\n");
+
+ /* Toggle once to init the state of fn-lock */
+ tpcsc->fn_lock = 0;
+ tpcompactkbd_toggle_fnlock(hdev);
+
+ return 0;
+}
+
+static const struct hid_device_id tpcompactkbd_devices[] = {
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) },
+
+ { }
+};
+MODULE_DEVICE_TABLE(hid, tpcompactkbd_devices);
+
+static struct hid_driver tpcompactkbd_driver = {
+ .name = "lenovo_tpcompactkbd",
+ .id_table = tpcompactkbd_devices,
+ .input_mapping = tpcompactkbd_input_mapping,
+ .probe = tpcompactkbd_probe,
+ .event = tpcompactkbd_event,
+};
+module_hid_driver(tpcompactkbd_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jamie Lentin <jm@lentin.co.uk>");
+MODULE_DESCRIPTION("ThinkPad Compact Keyboard with TrackPoint input driver");
--
1.8.5.2
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH] hid: Add custom driver for Lenovo ThinkPad Compact Bluetooth Keyboard
2014-03-25 22:26 [PATCH] hid: Add custom driver for Lenovo ThinkPad Compact Bluetooth Keyboard Jamie Lentin
@ 2014-05-20 14:47 ` Jiri Kosina
2014-05-20 15:19 ` Jamie Lentin
0 siblings, 1 reply; 4+ messages in thread
From: Jiri Kosina @ 2014-05-20 14:47 UTC (permalink / raw)
To: Jamie Lentin; +Cc: linux-input, linux-kernel
On Tue, 25 Mar 2014, Jamie Lentin wrote:
> This keyboard requires some custom mappings for all keys to be
> available, and the Fn-lock toggle needs to be controlled in software.
>
> Signed-off-by: Jamie Lentin <jm@lentin.co.uk>
> ---
> I assume that Linux users want Fn-Lock enabled by default, so they can
> get at the function keys. If this is an incorrect assumption then can
> change it---so long as there's some way of me leaving it enabled :)
>
> Tested with and applies cleanly to 3.13.6.
>
> drivers/hid/Kconfig | 10 ++
> drivers/hid/Makefile | 1 +
> drivers/hid/hid-core.c | 3 +
> drivers/hid/hid-ids.h | 1 +
> drivers/hid/hid-lenovo-tpcompactkbd.c | 191 ++++++++++++++++++++++++++++++++++
> 5 files changed, 206 insertions(+)
Jamie,
thanks for the driver.
I think it'd make more sense if this could be folded into hid-lenovo-tpkbd
driver. Could you please do that and resubmit?
--
Jiri Kosina
SUSE Labs
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] hid: Add custom driver for Lenovo ThinkPad Compact Bluetooth Keyboard
2014-05-20 14:47 ` Jiri Kosina
@ 2014-05-20 15:19 ` Jamie Lentin
2014-05-20 15:31 ` Jiri Kosina
0 siblings, 1 reply; 4+ messages in thread
From: Jamie Lentin @ 2014-05-20 15:19 UTC (permalink / raw)
To: Jiri Kosina; +Cc: linux-input, linux-kernel
On Tue, 20 May 2014, Jiri Kosina wrote:
> On Tue, 25 Mar 2014, Jamie Lentin wrote:
>
>> This keyboard requires some custom mappings for all keys to be
>> available, and the Fn-lock toggle needs to be controlled in software.
>>
>> Signed-off-by: Jamie Lentin <jm@lentin.co.uk>
>> ---
>> I assume that Linux users want Fn-Lock enabled by default, so they can
>> get at the function keys. If this is an incorrect assumption then can
>> change it---so long as there's some way of me leaving it enabled :)
>>
>> Tested with and applies cleanly to 3.13.6.
>>
>> drivers/hid/Kconfig | 10 ++
>> drivers/hid/Makefile | 1 +
>> drivers/hid/hid-core.c | 3 +
>> drivers/hid/hid-ids.h | 1 +
>> drivers/hid/hid-lenovo-tpcompactkbd.c | 191 ++++++++++++++++++++++++++++++++++
>> 5 files changed, 206 insertions(+)
>
> Jamie,
>
> thanks for the driver.
>
> I think it'd make more sense if this could be folded into hid-lenovo-tpkbd
> driver. Could you please do that and resubmit?
I can do if required, although I didn't originally since there would be no
common code whatsoever between the keyboards. The newer keyboard has no
leds to register, and no trackpoint settings are exposed like on the older
keyboard. Equally the newer Fn-Lock setting wouldn't make sense for the
older keyboards, since they have grown-up function keys. The similarity
stops with the name.
I have both the USB and the Bluetooth versions of this keyboard now,
once I have finished support for both[0] I will resubmit support for both.
Cheers,
[0] https://github.com/lentinj/tp-compact-keyboard/blob/usb-keyboard-support/module/hid-lenovo-tpcompactkbd.c
if anyone is interested
--
Jamie Lentin
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] hid: Add custom driver for Lenovo ThinkPad Compact Bluetooth Keyboard
2014-05-20 15:19 ` Jamie Lentin
@ 2014-05-20 15:31 ` Jiri Kosina
0 siblings, 0 replies; 4+ messages in thread
From: Jiri Kosina @ 2014-05-20 15:31 UTC (permalink / raw)
To: Jamie Lentin; +Cc: linux-input, linux-kernel
On Tue, 20 May 2014, Jamie Lentin wrote:
> > I think it'd make more sense if this could be folded into
> > hid-lenovo-tpkbd driver. Could you please do that and resubmit?
>
> I can do if required, although I didn't originally since there would be no
> common code whatsoever between the keyboards.
That's not a problem really. I am trying to have the functionality mostly
grouped together by vendor, and not pollute the tree by gazillion of tiny
single-function driver.
> I have both the USB and the Bluetooth versions of this keyboard now, once I
> have finished support for both[0] I will resubmit support for both.
Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2014-05-20 15:46 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-03-25 22:26 [PATCH] hid: Add custom driver for Lenovo ThinkPad Compact Bluetooth Keyboard Jamie Lentin
2014-05-20 14:47 ` Jiri Kosina
2014-05-20 15:19 ` Jamie Lentin
2014-05-20 15:31 ` Jiri Kosina
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox