From patchwork Thu Dec 13 16:00:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joerg Riechardt X-Patchwork-Id: 10729055 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9CFD416B1 for ; Thu, 13 Dec 2018 16:00:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 83DE12C66A for ; Thu, 13 Dec 2018 16:00:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 783B82C656; Thu, 13 Dec 2018 16:00:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,FREEMAIL_FROM, MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 963DB2C661 for ; Thu, 13 Dec 2018 16:00:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728552AbeLMQAr (ORCPT ); Thu, 13 Dec 2018 11:00:47 -0500 Received: from mout.gmx.net ([212.227.17.21]:60351 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727942AbeLMQAr (ORCPT ); Thu, 13 Dec 2018 11:00:47 -0500 Received: from [192.168.137.3] ([88.130.105.150]) by mail.gmx.com (mrgmx103 [212.227.17.168]) with ESMTPSA (Nemesis) id 0Lw2dd-1hWF4C2adB-017pJu; Thu, 13 Dec 2018 17:00:45 +0100 To: linux-input@vger.kernel.org From: Joerg Riechardt Subject: [PATCH] HID: input: HID driver for IRMP USB-HID-keyboard remote control receiver Message-ID: <3f5971ee-8d84-b049-20d9-46d9e3df8b0b@gmx.de> Date: Thu, 13 Dec 2018 17:00:42 +0100 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:60.0) Gecko/20100101 Thunderbird/60.3.3 MIME-Version: 1.0 Content-Language: en-GB X-Antivirus: Avast (VPS 181213-0, 13.12.2018), Outbound message X-Antivirus-Status: Clean X-Provags-ID: V03:K1:Mr9MbUimuh5PBLZwulT2UuwJ+jq35rm7d4LgD2RFLh8A/kSE2y+ HNtfo3G3v0zfz7jAqzptsjylJXtfNgmbcRLmRh2/hN45woaeCiDN68JX4V53ZIqH3BClxO5 ewTmkZtiES1dUvFGBhtf9BlFBfGFtX1NvHlCqP5KU4HkUIy2GBMdh/jjaaWeXm404zUd9FE 0z2gKXpxA6GKhbxhpx1kw== X-UI-Out-Filterresults: notjunk:1;V03:K0:Weqg1JWPtxI=:oMoE3SJ3/gSFDU4w9R75i3 zayEiQ4wLnMFjKqsJUy/knbEkAzWLu2ZhlaZ8pGV3GzGACDHkiA1axste5V8SmUdYnk0IgJz2 3EXw8qztgRpfc/A5aTtZg+22ZZB/vUkZ61+qExH3koM756+YVMGH3Rz/K+g8/E/ubPJPnOxxa wWwsJMcOL1Emax2uZe1RdxI+S9RSZeBhNLEOVQpCwjM9HlsUtzf8tRTA7atXPch7tcAj8dvYo y3K5X2FLBbB1yDDUH3jQXLFMx5Q5RWKBDmPC8vOGBSHCPWuz9iDMu6gMA+mh0E39kc0E37lfs z0molry7T/BNDPbaBDnU8Y3v7GGOn2FMiPGKdUKdkCoP6lf4AG2qf6JZrXUbJyRHJ6PBN3oou RXO31j8+L/tKm9UZ52aU+BKW53dcFijDHQgr8IPVuQDGA8KtiImjver4aUF+3ujBiUOV7TCwY DXM2Tk00jxempKyuU5DUf32n8soiYkHB7UMJCXoIIFSZoARIuHLAgQ9zEJ5XKkzv+knM/4yQl 9gPv4W7FSVwVjjsohlIeXAEZn7D9XGBy0Z7oCHAueg7IaoWCeGvzLJdbOepFymGsLkMRJHaNw vuutfL+75WjF9D/L+t9aoaONFpdOfYCdXXFR/X76so3PWqN5E824UDguA0iJJwPgFWBcZCBnx jXafXh4GEZoBfX6Auu1Wwuesj6mBIGTtTqVPTSuGr0O1EJHNMfAR5HyTNg5lrlXcvX66e6H5P 3mk1Hk/tqxRO4OtCgxIM0PNf2olNLH5d3dSTJK1mtvMdG8khyyjcBQ9yA1soD84TM3T7d2xuk FTn2R/ok1Ge6Ujh8e5aWm/7AhLOKVE+34jMxYyf9pdu7ol3Bg5bYci/uxBsYdYd2mhaqoVOu9 5P9i1iQaCk7KlIDfE23dqPpR857hYw92IKiQ5sPnj5TAwIxckdWrLSNTdoqSWn Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 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 +#include +#include + +#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