diff mbox series

HID: input: HID driver for IRMP USB-HID-keyboard remote control receiver

Message ID 3f5971ee-8d84-b049-20d9-46d9e3df8b0b@gmx.de (mailing list archive)
State New, archived
Delegated to: Jiri Kosina
Headers show
Series HID: input: HID driver for IRMP USB-HID-keyboard remote control receiver | expand

Commit Message

Joerg Riechardt Dec. 13, 2018, 4 p.m. UTC
There are remote control receivers, which register as an USB HID 
keyboard and
receive and decode signals from many IR remote controls with all kinds 
of IR
protocols (for instance IRMP, the Infra Red Multi Protocol library). 
Most of
  those IR remote controls only send keys on key press, but not on key 
release.
  Because of that, the receiver sends either a release after each key 
press or
  after a timeout, when no key was pressed any more. The first has the
  disadvantage, that each key is processed as new, even if it is a 
repeat. The
  second has the disadvantage, that the autorepeat feature of the input 
core
  may generate keys during the timeout, while the user actually already has
  taken his  finger of the remote control button.
  In order to solve the problem, this driver was made. It processes keys
exactly as they were sent. Autorepeat is turned off and key repeats are 
taken
from raw events, get translated and are passed on to input.

This is my first time on this list and I am a hobbyist only.
The patch is for 4.20-rc6.
checkpatch.pl shows many errors because of hid_keyboard[], but that is 
just a copy from hid-input.c.
https://github.com/j1rie/IRMP_STM32_KBD
Signed-off-by: Joerg Riechardt <J.Riechardt@gmx.de>
diff mbox series

Patch

diff -Nrup A/drivers/hid/Kconfig B/drivers/hid/Kconfig
--- A/drivers/hid/Kconfig	2018-12-10 00:31:00.000000000 +0100
+++ B/drivers/hid/Kconfig	2018-12-13 01:25:16.995349622 +0100
@@ -1093,6 +1093,13 @@  config HID_ALPS
  	Say Y here if you have a Alps touchpads over i2c-hid or usbhid
  	and want support for its special functionalities.

+config HID_IRMP
+	tristate "IRMP USB-HID-keyboard support"
+	depends on HID
+	---help---
+	Support for IRMP STM32 KBD remote control receivers.
+	Say Y here if you have a IRMP STM32 KBD.
+
  endmenu

  endif # HID
diff -Nrup A/drivers/hid/Makefile B/drivers/hid/Makefile
--- A/drivers/hid/Makefile	2018-12-10 00:31:00.000000000 +0100
+++ B/drivers/hid/Makefile	2018-12-13 01:25:16.995349622 +0100
@@ -121,6 +121,7 @@  obj-$(CONFIG_HID_WALTOP)	+= hid-waltop.o
  obj-$(CONFIG_HID_WIIMOTE)	+= hid-wiimote.o
  obj-$(CONFIG_HID_SENSOR_HUB)	+= hid-sensor-hub.o
  obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR)	+= hid-sensor-custom.o
+obj-$(CONFIG_HID_IRMP)		+= hid-irmp.o

  obj-$(CONFIG_USB_HID)		+= usbhid/
  obj-$(CONFIG_USB_MOUSE)		+= usbhid/
diff -Nrup A/drivers/hid/hid-ids.h B/drivers/hid/hid-ids.h
--- A/drivers/hid/hid-ids.h	2018-12-10 00:31:00.000000000 +0100
+++ B/drivers/hid/hid-ids.h	2018-12-13 01:25:16.995349622 +0100
@@ -1227,4 +1227,7 @@ 
  #define USB_VENDOR_ID_UGTIZER			0x2179
  #define USB_DEVICE_ID_UGTIZER_TABLET_GP0610	0x0053

+#define USB_VENDOR_ID_IRMP		0x1209
+#define USB_DEVICE_ID_IRMP_STM32_KBD	0x4445
+
  #endif
diff -Nrup A/drivers/hid/hid-irmp.c B/drivers/hid/hid-irmp.c
--- A/drivers/hid/hid-irmp.c	1970-01-01 01:00:00.000000000 +0100
+++ B/drivers/hid/hid-irmp.c	2018-12-13 16:39:11.297811930 +0100
@@ -0,0 +1,149 @@ 
+/*
+ *  HID driver for IRMP STM32 KBD remote control receiver
+ *
+ *  Copyright (c) 2018 Joerg Riechardt
+ *
+ * There are remote control receivers, which register as an USB HID 
keyboard and
+ * receive and decode signals from many IR remote controls with all 
kinds of IR
+ * protocols (for instance IRMP, the Infra Red Multi Protocol library). 
Most of
+ * those IR remote controls only send keys on key press, but not on key 
release.
+ * Because of that, the receiver sends either a release after each key 
press or
+ * after a timeout, when no key was pressed any more. The first has the
+ * disadvantage, that each key is processed as new, even if it is a 
repeat. The
+ * second has the disadvantage, that the autorepeat feature of the 
input core
+ * may generate keys during the timeout, while the user actually 
already has
+ * taken his  finger of the remote control button.
+ * In order to solve the problem, this driver was made. It processes keys
+ * exactly as they were sent. Autorepeat is turned off and key repeats 
are taken
+ * from raw events, get translated and are passed on to input.
+ */
+
+/*
+ * 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"
+
+struct irmp_data {
+	struct hid_device *hdev;
+	struct input_dev *input;
+};
+
+/* copy of hid_keyboard[] from hid-input.c */
+#define unk	KEY_UNKNOWN
+
+static const unsigned char hid_keyboard[256] = {
+	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
+	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
+	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
+	 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
+	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
+	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
+	 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
+	191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
+	115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
+	122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,
+	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+	unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk,
+	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+	unk,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,unk,unk,unk,unk,
+	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
+	150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
+};
+
+static int irmp_raw_event(struct hid_device *hdev, struct hid_report 
*report,
+							u8 *raw_data, int size)
+{
+	struct irmp_data *hdata = hid_get_drvdata(hdev);
+	struct input_dev *input = hdata->input;
+	static unsigned int last_key;
+	unsigned int key;
+
+	key = (raw_data[1] << 8) + raw_data[3];
+	if (key) {
+		if (key == last_key) {
+			/* modifier */
+			if (raw_data[1]) {
+				input_event(input, EV_KEY, hid_keyboard[raw_data[1]], 2);
+				input_sync(input);
+			}
+			/* key */
+			if (raw_data[3]) {
+				input_event(input, EV_KEY, hid_keyboard[raw_data[3]], 2);
+				input_sync(input);
+			}
+		} else {
+			last_key = key;
+		}
+	} else {
+		last_key = 0;
+	}
+
+	return 1;
+}
+
+static int irmp_input_configured(struct hid_device *hdev, struct 
hid_input *hidinput)
+{
+	struct irmp_data *irmp_data = hid_get_drvdata(hdev);
+	struct input_dev *input = hidinput->input;
+
+	irmp_data->input = input;
+	/* turn off repeat */
+	__clear_bit(EV_REP, input->evbit);
+	hid_set_drvdata(hdev, irmp_data);
+	printk(KERN_INFO "irmp configured\n");
+
+	return 0;
+}
+
+static int irmp_probe(struct hid_device *hdev, const struct 
hid_device_id *id)
+{
+	int ret;
+	struct irmp_data *irmp_data;
+
+	irmp_data = devm_kzalloc(&hdev->dev, sizeof(struct irmp_data), 
GFP_KERNEL);
+	if (irmp_data == NULL) {
+		hid_err(hdev, "can't alloc irmp descriptor\n");
+		return -ENOMEM;
+	}
+	irmp_data->hdev = hdev;
+	hid_set_drvdata(hdev, irmp_data);
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "parse failed\n");
+		goto err_free;
+	}
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		hid_err(hdev, "hw start failed\n");
+		goto err_free;
+	}
+	return 0;
+err_free:
+	return ret;
+}
+
+static const struct hid_device_id irmp_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_IRMP, USB_DEVICE_ID_IRMP_STM32_KBD) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, irmp_devices);
+
+static struct hid_driver irmp_driver = {
+	.name = "irmp",
+	.id_table = irmp_devices,
+	.probe = irmp_probe,
+	.raw_event = irmp_raw_event,
+	.input_configured = irmp_input_configured,
+};
+module_hid_driver(irmp_driver);
+
+MODULE_LICENSE("GPL v2");
diff -Nrup A/drivers/hid/hid-quirks.c B/drivers/hid/hid-quirks.c
--- A/drivers/hid/hid-quirks.c	2018-12-10 00:31:00.000000000 +0100
+++ B/drivers/hid/hid-quirks.c	2018-12-13 01:25:16.996349568 +0100
@@ -395,6 +395,9 @@  static const struct hid_device_id hid_ha
  #if IS_ENABLED(CONFIG_HID_ICADE)
  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
  #endif
+#if IS_ENABLED(CONFIG_HID_IRMP)
+	{ HID_USB_DEVICE(USB_VENDOR_ID_IRMP, USB_DEVICE_ID_IRMP_STM32_KBD) },
+#endif
  #if IS_ENABLED(CONFIG_HID_JABRA)
  	{ HID_USB_DEVICE(USB_VENDOR_ID_JABRA, HID_ANY_ID) },
  #endif