From 20835280ce0495f933bc8a69f2faac31f23daa2f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 1 Dec 2017 08:47:08 -0500 Subject: media: rc: add SPDX identifiers to the code I wrote As we're now using SPDX identifiers, on the several media drivers I wrote, add the proper SPDX, identifying the license I meant. As we're now using the short license, it doesn't make sense to keep the original license text. Also, fix MODULE_LICENSE to properly identify GPL v2. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Philippe Ombredanne Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers/media/rc/rc-main.c') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index c144b77eac98..372f4d61cb48 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1,16 +1,7 @@ -/* rc-main.c - Remote Controller core module - * - * Copyright (C) 2009-2010 by Mauro Carvalho Chehab - * - * 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 version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0 +// rc-main.c - Remote Controller core module +// +// Copyright (C) 2009-2010 by Mauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -1905,4 +1896,4 @@ EXPORT_SYMBOL_GPL(rc_core_debug); module_param_named(debug, rc_core_debug, int, 0644); MODULE_AUTHOR("Mauro Carvalho Chehab"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); -- cgit From 0d39ab0b628b38acf83506d36e9ec969055698df Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 25 Feb 2017 06:51:31 -0500 Subject: media: rc: auto load encoder if necessary When sending scancodes, load the encoder if we need it. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/rc/rc-main.c') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 372f4d61cb48..29a90adb0f7c 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1082,7 +1082,7 @@ static int parse_protocol_change(u64 *protocols, const char *buf) return count; } -static void ir_raw_load_modules(u64 *protocols) +void ir_raw_load_modules(u64 *protocols) { u64 available; int i, ret; -- cgit From a60d64b15c20d178ba3a9bc3a542492b4ddeea70 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 23 Sep 2017 10:41:13 -0400 Subject: media: lirc: lirc interface should not be a raw decoder The lirc user interface exists as a raw decoder, which does not make much sense for transmit-only devices. In addition, we want to have lirc char devices for devices which do not use raw IR, i.e. scancode only devices. Note that rc-code, lirc_dev, ir-lirc-codec are now calling functions of each other, so they've been merged into one module rc-core to avoid circular dependencies. Since ir-lirc-codec no longer exists as separate codec module, there is no need for RC_DRIVER_IR_RAW_TX type drivers to call ir_raw_event_register(). Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 52 ++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 25 deletions(-) (limited to 'drivers/media/rc/rc-main.c') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 29a90adb0f7c..56b322b3d325 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -846,7 +846,6 @@ int rc_open(struct rc_dev *rdev) return rval; } -EXPORT_SYMBOL_GPL(rc_open); static int ir_open(struct input_dev *idev) { @@ -866,7 +865,6 @@ void rc_close(struct rc_dev *rdev) mutex_unlock(&rdev->lock); } } -EXPORT_SYMBOL_GPL(rc_close); static void ir_close(struct input_dev *idev) { @@ -941,23 +939,6 @@ struct rc_filter_attribute { .mask = (_mask), \ } -static bool lirc_is_present(void) -{ -#if defined(CONFIG_LIRC_MODULE) - struct module *lirc; - - mutex_lock(&module_mutex); - lirc = find_module("lirc_dev"); - mutex_unlock(&module_mutex); - - return lirc ? true : false; -#elif defined(CONFIG_LIRC) - return true; -#else - return false; -#endif -} - /** * show_protocols() - shows the current IR protocol(s) * @device: the device descriptor @@ -1002,8 +983,10 @@ static ssize_t show_protocols(struct device *device, allowed &= ~proto_names[i].type; } - if (dev->driver_type == RC_DRIVER_IR_RAW && lirc_is_present()) +#ifdef CONFIG_LIRC + if (dev->driver_type == RC_DRIVER_IR_RAW) tmp += sprintf(tmp, "[lirc] "); +#endif if (tmp != buf) tmp--; @@ -1759,8 +1742,7 @@ int rc_register_device(struct rc_dev *dev) dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp; dev->sysfs_groups[attr++] = NULL; - if (dev->driver_type == RC_DRIVER_IR_RAW || - dev->driver_type == RC_DRIVER_IR_RAW_TX) { + if (dev->driver_type == RC_DRIVER_IR_RAW) { rc = ir_raw_event_prepare(dev); if (rc < 0) goto out_minor; @@ -1787,19 +1769,28 @@ int rc_register_device(struct rc_dev *dev) goto out_dev; } - if (dev->driver_type == RC_DRIVER_IR_RAW || - dev->driver_type == RC_DRIVER_IR_RAW_TX) { - rc = ir_raw_event_register(dev); + /* Ensure that the lirc kfifo is setup before we start the thread */ + if (dev->driver_type != RC_DRIVER_SCANCODE) { + rc = ir_lirc_register(dev); if (rc < 0) goto out_rx; } + if (dev->driver_type == RC_DRIVER_IR_RAW) { + rc = ir_raw_event_register(dev); + if (rc < 0) + goto out_lirc; + } + IR_dprintk(1, "Registered rc%u (driver: %s)\n", dev->minor, dev->driver_name ? dev->driver_name : "unknown"); return 0; +out_lirc: + if (dev->driver_type != RC_DRIVER_SCANCODE) + ir_lirc_unregister(dev); out_rx: rc_free_rx_device(dev); out_dev: @@ -1853,6 +1844,9 @@ void rc_unregister_device(struct rc_dev *dev) rc_free_rx_device(dev); + if (dev->driver_type != RC_DRIVER_SCANCODE) + ir_lirc_unregister(dev); + device_del(&dev->dev); ida_simple_remove(&rc_ida, dev->minor); @@ -1875,6 +1869,13 @@ static int __init rc_core_init(void) return rc; } + rc = lirc_dev_init(); + if (rc) { + pr_err("rc_core: unable to init lirc\n"); + class_unregister(&rc_class); + return 0; + } + led_trigger_register_simple("rc-feedback", &led_feedback); rc_map_register(&empty_map); @@ -1883,6 +1884,7 @@ static int __init rc_core_init(void) static void __exit rc_core_exit(void) { + lirc_dev_exit(); class_unregister(&rc_class); led_trigger_unregister_simple(led_feedback); rc_map_unregister(&empty_map); -- cgit From 49a4b36ada336270b564cabbbcb727cadebd024d Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 27 Sep 2017 16:00:49 -0400 Subject: media: lirc: validate scancode for transmit Ensure we reject an attempt to transmit invalid scancodes. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 53 +++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 20 deletions(-) (limited to 'drivers/media/rc/rc-main.c') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 56b322b3d325..ce8837b1facd 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -775,6 +775,37 @@ void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol, } EXPORT_SYMBOL_GPL(rc_keydown_notimeout); +/** + * rc_validate_scancode() - checks that a scancode is valid for a protocol + * @proto: protocol + * @scancode: scancode + */ +bool rc_validate_scancode(enum rc_proto proto, u32 scancode) +{ + switch (proto) { + case RC_PROTO_NECX: + if ((((scancode >> 16) ^ ~(scancode >> 8)) & 0xff) == 0) + return false; + break; + case RC_PROTO_NEC32: + if ((((scancode >> 24) ^ ~(scancode >> 16)) & 0xff) == 0) + return false; + break; + case RC_PROTO_RC6_MCE: + if ((scancode & 0xffff0000) != 0x800f0000) + return false; + break; + case RC_PROTO_RC6_6A_32: + if ((scancode & 0xffff0000) == 0x800f0000) + return false; + break; + default: + break; + } + + return true; +} + /** * rc_validate_filter() - checks that the scancode and mask are valid and * provides sensible defaults @@ -794,26 +825,8 @@ static int rc_validate_filter(struct rc_dev *dev, mask = protocols[protocol].scancode_bits; - switch (protocol) { - case RC_PROTO_NECX: - if ((((s >> 16) ^ ~(s >> 8)) & 0xff) == 0) - return -EINVAL; - break; - case RC_PROTO_NEC32: - if ((((s >> 24) ^ ~(s >> 16)) & 0xff) == 0) - return -EINVAL; - break; - case RC_PROTO_RC6_MCE: - if ((s & 0xffff0000) != 0x800f0000) - return -EINVAL; - break; - case RC_PROTO_RC6_6A_32: - if ((s & 0xffff0000) == 0x800f0000) - return -EINVAL; - break; - default: - break; - } + if (!rc_validate_scancode(protocol, s)) + return -EINVAL; filter->data &= mask; filter->mask &= mask; -- cgit From 6b514c4a50cbbb9bd2080a95ed83d834b11f1e40 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 9 Oct 2017 16:32:41 -0400 Subject: media: rc: document and fix rc_validate_scancode() For some IR protocols, some scancode values not valid, i.e. they're part of a different protocol variant. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/media/rc/rc-main.c') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index ce8837b1facd..e944d28b96d2 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -776,21 +776,35 @@ void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol, EXPORT_SYMBOL_GPL(rc_keydown_notimeout); /** - * rc_validate_scancode() - checks that a scancode is valid for a protocol + * rc_validate_scancode() - checks that a scancode is valid for a protocol. + * For nec, it should do the opposite of ir_nec_bytes_to_scancode() * @proto: protocol * @scancode: scancode */ bool rc_validate_scancode(enum rc_proto proto, u32 scancode) { switch (proto) { + /* + * NECX has a 16-bit address; if the lower 8 bits match the upper + * 8 bits inverted, then the address would match regular nec. + */ case RC_PROTO_NECX: if ((((scancode >> 16) ^ ~(scancode >> 8)) & 0xff) == 0) return false; break; + /* + * NEC32 has a 16 bit address and 16 bit command. If the lower 8 bits + * of the command match the upper 8 bits inverted, then it would + * be either NEC or NECX. + */ case RC_PROTO_NEC32: - if ((((scancode >> 24) ^ ~(scancode >> 16)) & 0xff) == 0) + if ((((scancode >> 8) ^ ~scancode) & 0xff) == 0) return false; break; + /* + * If the customer code (top 32-bit) is 0x800f, it is MCE else it + * is regular mode-6a 32 bit + */ case RC_PROTO_RC6_MCE: if ((scancode & 0xffff0000) != 0x800f0000) return false; -- cgit From 7790e81f7e1f7f122f8fcccd91443a2571421aba Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 26 Sep 2017 07:31:29 -0400 Subject: media: lirc: move lirc_dev->attached to rc_dev->registered This is done to further remove the lirc kernel api. Ensure that every fops checks for this. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/media/rc/rc-main.c') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index e944d28b96d2..8b1b20e7a3c3 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1809,6 +1809,8 @@ int rc_register_device(struct rc_dev *dev) goto out_lirc; } + dev->registered = true; + IR_dprintk(1, "Registered rc%u (driver: %s)\n", dev->minor, dev->driver_name ? dev->driver_name : "unknown"); @@ -1871,6 +1873,14 @@ void rc_unregister_device(struct rc_dev *dev) rc_free_rx_device(dev); + mutex_lock(&dev->lock); + dev->registered = false; + mutex_unlock(&dev->lock); + + /* + * lirc device should be freed with dev->registered = false, so + * that userspace polling will get notified. + */ if (dev->driver_type != RC_DRIVER_SCANCODE) ir_lirc_unregister(dev); -- cgit From cb84343fced1febb5b21a9ef9082a07bfc3e7427 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 23 Sep 2017 17:44:03 -0400 Subject: media: lirc: do not call close() or open() on unregistered devices If a lirc chardev is held open after a device is unplugged, rc_close() will be called after rc_unregister_device(). The driver is not expecting any calls at this point, and the iguanair driver causes an oops in this scenario. rc_open() can be called when the device is removed too, by calling open on the chardev whilst the device is being removed. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/media/rc/rc-main.c') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 8b1b20e7a3c3..ace00e77c96a 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -863,11 +863,15 @@ int rc_open(struct rc_dev *rdev) mutex_lock(&rdev->lock); - if (!rdev->users++ && rdev->open != NULL) - rval = rdev->open(rdev); + if (!rdev->registered) { + rval = -ENODEV; + } else { + if (!rdev->users++ && rdev->open) + rval = rdev->open(rdev); - if (rval) - rdev->users--; + if (rval) + rdev->users--; + } mutex_unlock(&rdev->lock); @@ -886,7 +890,7 @@ void rc_close(struct rc_dev *rdev) if (rdev) { mutex_lock(&rdev->lock); - if (!--rdev->users && rdev->close != NULL) + if (!--rdev->users && rdev->close && rdev->registered) rdev->close(rdev); mutex_unlock(&rdev->lock); -- cgit From a6ddd4fecbb02d8ec5a865621bd2b746d585a01c Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 26 Sep 2017 09:34:47 -0400 Subject: media: lirc: remove last remnants of lirc kapi rc-core has replaced the lirc kapi many years ago, and now with the last driver ported to rc-core, we can finally remove it. Note this has no effect on userspace. All future IR drivers should use the rc-core api. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media/rc/rc-main.c') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index ace00e77c96a..12ff6d87b113 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -20,7 +20,6 @@ /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */ #define IR_TAB_MIN_SIZE 256 #define IR_TAB_MAX_SIZE 8192 -#define RC_DEV_MAX 256 static const struct { const char *name; -- cgit From de142c32410649e64d44928505ffad2176a96a9e Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 25 Feb 2017 06:51:32 -0500 Subject: media: lirc: implement reading scancode This implements LIRC_MODE_SCANCODE reading from the lirc device. The scancode can be read from the input device too, but with this interface you get the rc protocol, keycode, toggle and repeat status in addition to just the scancode. int main() { int fd, mode, rc; fd = open("/dev/lirc0", O_RDWR); mode = LIRC_MODE_SCANCODE; if (ioctl(fd, LIRC_SET_REC_MODE, &mode)) { // kernel too old or lirc does not support transmit } struct lirc_scancode scancode; while (read(fd, &scancode, sizeof(scancode)) == sizeof(scancode)) { printf("protocol:%d scancode:0x%x toggle:%d repeat:%d\n", scancode.rc_proto, scancode.scancode, !!(scancode.flags & LIRC_SCANCODE_FLAG_TOGGLE), !!(scancode.flags & LIRC_SCANCODE_FLAG_REPEAT)); } close(fd); } Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/media/rc/rc-main.c') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 12ff6d87b113..b22443fe8c34 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -697,6 +697,13 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol, dev->last_protocol != protocol || dev->last_scancode != scancode || dev->last_toggle != toggle); + struct lirc_scancode sc = { + .scancode = scancode, .rc_proto = protocol, + .flags = toggle ? LIRC_SCANCODE_FLAG_TOGGLE : 0, + .keycode = keycode + }; + + ir_lirc_scancode_event(dev, &sc); if (new_event && dev->keypressed) ir_do_keyup(dev, false); -- cgit From b66218fddfd29f315a103db811152ab0c95fb054 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 30 Sep 2017 07:13:37 -0400 Subject: media: lirc: ensure lirc device receives nec repeats The lirc device should get lirc repeats whether there is a keymap match or not. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'drivers/media/rc/rc-main.c') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index b22443fe8c34..058807bc80dc 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -662,19 +662,25 @@ void rc_repeat(struct rc_dev *dev) { unsigned long flags; unsigned int timeout = protocols[dev->last_protocol].repeat_period; + struct lirc_scancode sc = { + .scancode = dev->last_scancode, .rc_proto = dev->last_protocol, + .keycode = dev->keypressed ? dev->last_keycode : KEY_RESERVED, + .flags = LIRC_SCANCODE_FLAG_REPEAT | + (dev->last_toggle ? LIRC_SCANCODE_FLAG_TOGGLE : 0) + }; - spin_lock_irqsave(&dev->keylock, flags); + ir_lirc_scancode_event(dev, &sc); - if (!dev->keypressed) - goto out; + spin_lock_irqsave(&dev->keylock, flags); input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode); input_sync(dev->input_dev); - dev->keyup_jiffies = jiffies + msecs_to_jiffies(timeout); - mod_timer(&dev->timer_keyup, dev->keyup_jiffies); + if (dev->keypressed) { + dev->keyup_jiffies = jiffies + msecs_to_jiffies(timeout); + mod_timer(&dev->timer_keyup, dev->keyup_jiffies); + } -out: spin_unlock_irqrestore(&dev->keylock, flags); } EXPORT_SYMBOL_GPL(rc_repeat); @@ -710,13 +716,14 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol, input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); + dev->last_protocol = protocol; + dev->last_scancode = scancode; + dev->last_toggle = toggle; + dev->last_keycode = keycode; + if (new_event && keycode != KEY_RESERVED) { /* Register a keypress */ dev->keypressed = true; - dev->last_protocol = protocol; - dev->last_scancode = scancode; - dev->last_toggle = toggle; - dev->last_keycode = keycode; IR_dprintk(1, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n", dev->device_name, keycode, protocol, scancode); -- cgit From 62d6f1994b41b9210b07ca453372797f59141e5c Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 24 Sep 2017 12:43:24 -0400 Subject: media: lirc: scancode rc devices should have a lirc device too Now that the lirc interface supports scancodes, RC scancode devices can also have a lirc device. The only receiving feature they will have enabled is LIRC_CAN_REC_SCANCODE. Note that CEC devices have no lirc device, since they can be controlled from their /dev/cecN chardev. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media/rc/rc-main.c') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 058807bc80dc..5830cb2c5943 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1814,7 +1814,7 @@ int rc_register_device(struct rc_dev *dev) } /* Ensure that the lirc kfifo is setup before we start the thread */ - if (dev->driver_type != RC_DRIVER_SCANCODE) { + if (dev->allowed_protocols != RC_PROTO_BIT_CEC) { rc = ir_lirc_register(dev); if (rc < 0) goto out_rx; @@ -1835,7 +1835,7 @@ int rc_register_device(struct rc_dev *dev) return 0; out_lirc: - if (dev->driver_type != RC_DRIVER_SCANCODE) + if (dev->allowed_protocols != RC_PROTO_BIT_CEC) ir_lirc_unregister(dev); out_rx: rc_free_rx_device(dev); @@ -1898,7 +1898,7 @@ void rc_unregister_device(struct rc_dev *dev) * lirc device should be freed with dev->registered = false, so * that userspace polling will get notified. */ - if (dev->driver_type != RC_DRIVER_SCANCODE) + if (dev->allowed_protocols != RC_PROTO_BIT_CEC) ir_lirc_unregister(dev); device_del(&dev->dev); -- cgit From 57c642cb45d6f7d0d950c3bc67439989062ac743 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 23 Nov 2017 17:37:10 -0500 Subject: media: cec: move cec autorepeat handling to rc-core CEC autorepeat is different than other protocols. Autorepeat is triggered by the first repeated user control pressed CEC message, rather than a fixed REP_DELAY. This change also does away with the KEY_UP event directly after the first KEY_DOWN event, which was used to stop autorepeat from starting. See commit a9a249a2c997 ("media: cec: fix remote control passthrough") for the original change. Acked-by: Hans Verkuil Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 49 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'drivers/media/rc/rc-main.c') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 5830cb2c5943..1870b7999062 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -597,6 +597,7 @@ static void ir_do_keyup(struct rc_dev *dev, bool sync) return; IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode); + del_timer_sync(&dev->timer_repeat); input_report_key(dev->input_dev, dev->last_keycode, 0); led_trigger_event(led_feedback, LED_OFF); if (sync) @@ -650,6 +651,31 @@ static void ir_timer_keyup(struct timer_list *t) spin_unlock_irqrestore(&dev->keylock, flags); } +/** + * ir_timer_repeat() - generates a repeat event after a timeout + * + * @t: a pointer to the struct timer_list + * + * This routine will generate a soft repeat event every REP_PERIOD + * milliseconds. + */ +static void ir_timer_repeat(struct timer_list *t) +{ + struct rc_dev *dev = from_timer(dev, t, timer_repeat); + struct input_dev *input = dev->input_dev; + unsigned long flags; + + spin_lock_irqsave(&dev->keylock, flags); + if (dev->keypressed) { + input_event(input, EV_KEY, dev->last_keycode, 2); + input_sync(input); + if (input->rep[REP_PERIOD]) + mod_timer(&dev->timer_repeat, jiffies + + msecs_to_jiffies(input->rep[REP_PERIOD])); + } + spin_unlock_irqrestore(&dev->keylock, flags); +} + /** * rc_repeat() - signals that a key is still pressed * @dev: the struct rc_dev descriptor of the device @@ -732,6 +758,22 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol, led_trigger_event(led_feedback, LED_FULL); } + /* + * For CEC, start sending repeat messages as soon as the first + * repeated message is sent, as long as REP_DELAY = 0 and REP_PERIOD + * is non-zero. Otherwise, the input layer will generate repeat + * messages. + */ + if (!new_event && keycode != KEY_RESERVED && + dev->allowed_protocols == RC_PROTO_BIT_CEC && + !timer_pending(&dev->timer_repeat) && + dev->input_dev->rep[REP_PERIOD] && + !dev->input_dev->rep[REP_DELAY]) { + input_event(dev->input_dev, EV_KEY, keycode, 2); + mod_timer(&dev->timer_repeat, jiffies + + msecs_to_jiffies(dev->input_dev->rep[REP_PERIOD])); + } + input_sync(dev->input_dev); } @@ -1599,6 +1641,7 @@ struct rc_dev *rc_allocate_device(enum rc_driver_type type) input_set_drvdata(dev->input_dev, dev); timer_setup(&dev->timer_keyup, ir_timer_keyup, 0); + timer_setup(&dev->timer_repeat, ir_timer_repeat, 0); spin_lock_init(&dev->rc_map.lock); spin_lock_init(&dev->keylock); @@ -1732,7 +1775,10 @@ static int rc_setup_rx_device(struct rc_dev *dev) * to avoid wrong repetition of the keycodes. Note that this must be * set after the call to input_register_device(). */ - dev->input_dev->rep[REP_DELAY] = 500; + if (dev->allowed_protocols == RC_PROTO_BIT_CEC) + dev->input_dev->rep[REP_DELAY] = 0; + else + dev->input_dev->rep[REP_DELAY] = 500; /* * As a repeat event on protocols like RC-5 and NEC take as long as @@ -1884,6 +1930,7 @@ void rc_unregister_device(struct rc_dev *dev) return; del_timer_sync(&dev->timer_keyup); + del_timer_sync(&dev->timer_repeat); if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); -- cgit From fb7ccc61802a7845ba1caa7e5c1f7fa8a62a2d80 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 3 Dec 2017 08:55:24 -0500 Subject: media: rc: bang in ir_do_keyup rc_keydown() can be called from interrupt context, by e.g. an rc scancode driver. Since commit b2c96ba352b5 ("media: cec: move cec autorepeat handling to rc-core"), the del_timer_sync() call is not happy about being called in interrupt connect. del_timer() will suffice. WARNING: CPU: 0 PID: 0 at kernel/time/timer.c:1285 del_timer_sync+0x1d/0x40 CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 4.15.0-rc1+ #1 Hardware name: /DG45ID, BIOS IDG4510H.86A.0135.2011.0225.1100 02/25/2011 task: ffffffffa3e10480 task.stack: ffffffffa3e00000 RIP: 0010:del_timer_sync+0x1d/0x40 RSP: 0018:ffff8b396bc03db0 EFLAGS: 00010046 RAX: 0000000080010000 RBX: ffff8b394d70e410 RCX: 0000000000000073 RDX: 0000000000000001 RSI: 0000000000000001 RDI: ffff8b394d70e410 RBP: 0000000000000001 R08: ffffffffc0616000 R09: ffff8b396bfa3000 R10: 0000000000000000 R11: 0000000000000390 R12: ffff8b394f003800 R13: 0000000000000000 R14: ffff8b3771c19630 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff8b396bc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f1944469000 CR3: 00000001ebe09000 CR4: 00000000000006f0 Call Trace: ir_do_keyup.part.5+0x22/0x90 [rc_core] rc_keyup+0x37/0x50 [rc_core] usb_rx_callback_intf0+0x79/0x90 [imon] __usb_hcd_giveback_urb+0x90/0x130 uhci_giveback_urb+0xab/0x250 uhci_scan_schedule.part.34+0x806/0xb00 uhci_irq+0xab/0x150 usb_hcd_irq+0x22/0x30 __handle_irq_event_percpu+0x3a/0x180 handle_irq_event_percpu+0x30/0x70 handle_irq_event+0x27/0x50 handle_fasteoi_irq+0x6b/0x110 handle_irq+0xa5/0x100 do_IRQ+0x41/0xc0 common_interrupt+0x96/0x96 RIP: 0010:cpuidle_enter_state+0x9a/0x2d0 RSP: 0018:ffffffffa3e03e88 EFLAGS: 00000246 ORIG_RAX: ffffffffffffffda RAX: ffff8b396bc1a000 RBX: 00000010da7bcd63 RCX: 00000010da7bccf6 RDX: 00000010da7bcd63 RSI: 00000010da7bcd63 RDI: 0000000000000000 RBP: ffff8b394f587400 R08: 0000000000000000 R09: 0000000000000002 R10: ffffffffa3e03e48 R11: 0000000000000390 R12: 0000000000000003 R13: ffffffffa3ebf018 R14: 0000000000000000 R15: 00000010da7ba772 ? cpuidle_enter_state+0x8d/0x2d0 do_idle+0x17b/0x1d0 cpu_startup_entry+0x6f/0x80 start_kernel+0x4a7/0x4c7 secondary_startup_64+0xa5/0xb0 Code: e7 5b 5d 41 5c e9 84 88 05 00 0f 1f 40 00 66 66 66 66 90 65 8b 05 e4 6f ef 5c a9 00 00 0f 00 53 48 89 fb 74 16 f6 47 22 20 75 10 <0f> ff 48 89 df e8 89 f1 ff ff 85 c0 79 0e f3 90 48 89 df e8 7b Fixes: b2c96ba352b5 ("media: cec: move cec autorepeat handling to rc-core") Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/rc/rc-main.c') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 1870b7999062..1db8d38fed7c 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -597,7 +597,7 @@ static void ir_do_keyup(struct rc_dev *dev, bool sync) return; IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode); - del_timer_sync(&dev->timer_repeat); + del_timer(&dev->timer_repeat); input_report_key(dev->input_dev, dev->last_keycode, 0); led_trigger_event(led_feedback, LED_OFF); if (sync) -- cgit