From ee2d243d6beea21e79631fa3442e92ad0fa11a6a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 12 Apr 2018 06:32:18 -0400 Subject: media: st_rc: Don't stay on an IRQ handler forever As warned by smatch: drivers/media/rc/st_rc.c:110 st_rc_rx_interrupt() warn: this loop depends on readl() succeeding If something goes wrong at readl(), the logic will stay there inside an IRQ code forever. This is not the nicest thing to do :-) So, add a timeout there, preventing staying inside the IRQ for more than 10ms. Acked-by: Patrice Chotard Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/st_rc.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index d2efd7b..c855b17 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -96,19 +96,24 @@ static void st_rc_send_lirc_timeout(struct rc_dev *rdev) static irqreturn_t st_rc_rx_interrupt(int irq, void *data) { + unsigned long timeout; unsigned int symbol, mark = 0; struct st_rc_device *dev = data; int last_symbol = 0; - u32 status; + u32 status, int_status; DEFINE_IR_RAW_EVENT(ev); if (dev->irq_wake) pm_wakeup_event(dev->dev, 0); - status = readl(dev->rx_base + IRB_RX_STATUS); + /* FIXME: is 10ms good enough ? */ + timeout = jiffies + msecs_to_jiffies(10); + do { + status = readl(dev->rx_base + IRB_RX_STATUS); + if (!(status & (IRB_FIFO_NOT_EMPTY | IRB_OVERFLOW))) + break; - while (status & (IRB_FIFO_NOT_EMPTY | IRB_OVERFLOW)) { - u32 int_status = readl(dev->rx_base + IRB_RX_INT_STATUS); + int_status = readl(dev->rx_base + IRB_RX_INT_STATUS); if (unlikely(int_status & IRB_RX_OVERRUN_INT)) { /* discard the entire collection in case of errors! */ ir_raw_event_reset(dev->rdev); @@ -148,8 +153,7 @@ static irqreturn_t st_rc_rx_interrupt(int irq, void *data) } last_symbol = 0; - status = readl(dev->rx_base + IRB_RX_STATUS); - } + } while (time_is_after_jiffies(timeout)); writel(IRB_RX_INTS, dev->rx_base + IRB_RX_INT_CLEAR); -- cgit v1.1 From ed8c34d7ec35b0a265f1b4d9ed6ab75e9f6facd7 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 27 Mar 2018 11:24:05 -0400 Subject: media: rc: report receiver and transmitter type on device register On the raspberry pi, we might have two lirc devices; one for sending and one for receiving. This change makes it much more apparent which one is which. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 24e9fbb..247e6fc 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -735,6 +735,7 @@ static void lirc_release_device(struct device *ld) int ir_lirc_register(struct rc_dev *dev) { + const char *rx_type, *tx_type; int err, minor; minor = ida_simple_get(&lirc_ida, 0, RC_DEV_MAX, GFP_KERNEL); @@ -759,8 +760,25 @@ int ir_lirc_register(struct rc_dev *dev) get_device(&dev->dev); - dev_info(&dev->dev, "lirc_dev: driver %s registered at minor = %d", - dev->driver_name, minor); + switch (dev->driver_type) { + case RC_DRIVER_SCANCODE: + rx_type = "scancode"; + break; + case RC_DRIVER_IR_RAW: + rx_type = "raw IR"; + break; + default: + rx_type = "no"; + break; + } + + if (dev->tx_ir) + tx_type = "raw IR"; + else + tx_type = "no"; + + dev_info(&dev->dev, "lirc_dev: driver %s registered at minor = %d, %s receiver, %s transmitter", + dev->driver_name, minor, rx_type, tx_type); return 0; -- cgit v1.1 From a86d6df84ae6eb1fd1ca6cbd03f16637674a6af8 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 23 Mar 2018 16:47:37 -0400 Subject: media: rc: set timeout to smallest value required by enabled protocols The longer the IR timeout, the longer the rc device waits until delivering the trailing space. So, by reducing this timeout, we reduce the delay for the last scancode to be delivered. Note that the lirc daemon disables all protocols, in which case we revert back to the default value. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-imon-decoder.c | 1 + drivers/media/rc/ir-jvc-decoder.c | 1 + drivers/media/rc/ir-mce_kbd-decoder.c | 1 + drivers/media/rc/ir-nec-decoder.c | 1 + drivers/media/rc/ir-rc5-decoder.c | 1 + drivers/media/rc/ir-rc6-decoder.c | 1 + drivers/media/rc/ir-sanyo-decoder.c | 1 + drivers/media/rc/ir-sharp-decoder.c | 1 + drivers/media/rc/ir-sony-decoder.c | 1 + drivers/media/rc/ir-xmp-decoder.c | 1 + drivers/media/rc/rc-core-priv.h | 1 + drivers/media/rc/rc-ir-raw.c | 31 ++++++++++++++++++++++++++++++- drivers/media/rc/rc-main.c | 12 ++++++------ 13 files changed, 47 insertions(+), 7 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-imon-decoder.c b/drivers/media/rc/ir-imon-decoder.c index a1ff06a..52ea3b2 100644 --- a/drivers/media/rc/ir-imon-decoder.c +++ b/drivers/media/rc/ir-imon-decoder.c @@ -170,6 +170,7 @@ static struct ir_raw_handler imon_handler = { .decode = ir_imon_decode, .encode = ir_imon_encode, .carrier = 38000, + .min_timeout = IMON_UNIT * IMON_BITS * 2, }; static int __init ir_imon_decode_init(void) diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c index 8cb68ae..5706cfe 100644 --- a/drivers/media/rc/ir-jvc-decoder.c +++ b/drivers/media/rc/ir-jvc-decoder.c @@ -213,6 +213,7 @@ static struct ir_raw_handler jvc_handler = { .decode = ir_jvc_decode, .encode = ir_jvc_encode, .carrier = 38000, + .min_timeout = JVC_TRAILER_SPACE, }; static int __init ir_jvc_decode_init(void) diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index c110984..05f2a36 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -475,6 +475,7 @@ static struct ir_raw_handler mce_kbd_handler = { .raw_register = ir_mce_kbd_register, .raw_unregister = ir_mce_kbd_unregister, .carrier = 36000, + .min_timeout = MCIR2_MAX_LEN + MCIR2_UNIT / 2, }; static int __init ir_mce_kbd_decode_init(void) diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 21647b8..6a8973a 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -253,6 +253,7 @@ static struct ir_raw_handler nec_handler = { .decode = ir_nec_decode, .encode = ir_nec_encode, .carrier = 38000, + .min_timeout = NEC_TRAILER_SPACE, }; static int __init ir_nec_decode_init(void) diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index 74d3b85..cbfaadb 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -274,6 +274,7 @@ static struct ir_raw_handler rc5_handler = { .decode = ir_rc5_decode, .encode = ir_rc5_encode, .carrier = 36000, + .min_timeout = RC5_TRAILER, }; static int __init ir_rc5_decode_init(void) diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index 8314da3..66e0710 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -394,6 +394,7 @@ static struct ir_raw_handler rc6_handler = { .decode = ir_rc6_decode, .encode = ir_rc6_encode, .carrier = 36000, + .min_timeout = RC6_SUFFIX_SPACE, }; static int __init ir_rc6_decode_init(void) diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c index 4efe6db..dd6ee1e 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -210,6 +210,7 @@ static struct ir_raw_handler sanyo_handler = { .decode = ir_sanyo_decode, .encode = ir_sanyo_encode, .carrier = 38000, + .min_timeout = SANYO_TRAILER_SPACE, }; static int __init ir_sanyo_decode_init(void) diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c index 6a38c50..f96e0c9 100644 --- a/drivers/media/rc/ir-sharp-decoder.c +++ b/drivers/media/rc/ir-sharp-decoder.c @@ -226,6 +226,7 @@ static struct ir_raw_handler sharp_handler = { .decode = ir_sharp_decode, .encode = ir_sharp_encode, .carrier = 38000, + .min_timeout = SHARP_ECHO_SPACE + SHARP_ECHO_SPACE / 4, }; static int __init ir_sharp_decode_init(void) diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index 6764ec9..5065c08 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c @@ -224,6 +224,7 @@ static struct ir_raw_handler sony_handler = { .decode = ir_sony_decode, .encode = ir_sony_encode, .carrier = 40000, + .min_timeout = SONY_TRAILER_SPACE, }; static int __init ir_sony_decode_init(void) diff --git a/drivers/media/rc/ir-xmp-decoder.c b/drivers/media/rc/ir-xmp-decoder.c index 58b47af..c965f51 100644 --- a/drivers/media/rc/ir-xmp-decoder.c +++ b/drivers/media/rc/ir-xmp-decoder.c @@ -199,6 +199,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) static struct ir_raw_handler xmp_handler = { .protocols = RC_PROTO_BIT_XMP, .decode = ir_xmp_decode, + .min_timeout = XMP_TRAILER_SPACE, }; static int __init ir_xmp_decode_init(void) diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index e0e6a17..f785513 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -37,6 +37,7 @@ struct ir_raw_handler { int (*encode)(enum rc_proto protocol, u32 scancode, struct ir_raw_event *events, unsigned int max); u32 carrier; + u32 min_timeout; /* These two should only be used by the mce kbd decoder */ int (*raw_register)(struct rc_dev *dev); diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 374f831..22e44c8 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -233,7 +233,36 @@ ir_raw_get_allowed_protocols(void) static int change_protocol(struct rc_dev *dev, u64 *rc_proto) { - /* the caller will update dev->enabled_protocols */ + struct ir_raw_handler *handler; + u32 timeout = 0; + + if (!dev->max_timeout) + return 0; + + mutex_lock(&ir_raw_handler_lock); + list_for_each_entry(handler, &ir_raw_handler_list, list) { + if (handler->protocols & *rc_proto) { + if (timeout < handler->min_timeout) + timeout = handler->min_timeout; + } + } + mutex_unlock(&ir_raw_handler_lock); + + if (timeout == 0) + timeout = IR_DEFAULT_TIMEOUT; + else + timeout += MS_TO_NS(10); + + if (timeout < dev->min_timeout) + timeout = dev->min_timeout; + else if (timeout > dev->max_timeout) + timeout = dev->max_timeout; + + if (dev->s_timeout) + dev->s_timeout(dev, timeout); + else + dev->timeout = timeout; + return 0; } diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index b67be33..6a720e9 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1241,6 +1241,9 @@ static ssize_t store_protocols(struct device *device, if (rc < 0) goto out; + if (dev->driver_type == RC_DRIVER_IR_RAW) + ir_raw_load_modules(&new_protocols); + rc = dev->change_protocol(dev, &new_protocols); if (rc < 0) { dev_dbg(&dev->dev, "Error setting protocols to 0x%llx\n", @@ -1248,9 +1251,6 @@ static ssize_t store_protocols(struct device *device, goto out; } - if (dev->driver_type == RC_DRIVER_IR_RAW) - ir_raw_load_modules(&new_protocols); - if (new_protocols != old_protocols) { *current_protocols = new_protocols; dev_dbg(&dev->dev, "Protocols changed to 0x%llx\n", @@ -1735,6 +1735,9 @@ static int rc_prepare_rx_device(struct rc_dev *dev) if (dev->driver_type == RC_DRIVER_SCANCODE && !dev->change_protocol) dev->enabled_protocols = dev->allowed_protocols; + if (dev->driver_type == RC_DRIVER_IR_RAW) + ir_raw_load_modules(&rc_proto); + if (dev->change_protocol) { rc = dev->change_protocol(dev, &rc_proto); if (rc < 0) @@ -1742,9 +1745,6 @@ static int rc_prepare_rx_device(struct rc_dev *dev) dev->enabled_protocols = rc_proto; } - if (dev->driver_type == RC_DRIVER_IR_RAW) - ir_raw_load_modules(&rc_proto); - set_bit(EV_KEY, dev->input_dev->evbit); set_bit(EV_REP, dev->input_dev->evbit); set_bit(EV_MSC, dev->input_dev->evbit); -- cgit v1.1 From 95d1544eb643847e05df06c3de252609593c9073 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 23 Mar 2018 16:59:52 -0400 Subject: media: rc: add ioctl to get the current timeout Since the kernel now modifies the timeout, make it possible to retrieve the current value. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 247e6fc..6b4755e 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -575,6 +575,13 @@ static long ir_lirc_ioctl(struct file *file, unsigned int cmd, } break; + case LIRC_GET_REC_TIMEOUT: + if (!dev->timeout) + ret = -ENOTTY; + else + val = DIV_ROUND_UP(dev->timeout, 1000); + break; + case LIRC_SET_REC_TIMEOUT_REPORTS: if (!dev->timeout) ret = -ENOTTY; -- cgit v1.1 From 284922562b8170a030fb130ead98224f7211d1ef Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 24 Mar 2018 08:02:48 -0400 Subject: media: rc: per-protocol repeat period and minimum keyup timer Each IR protocol has its own repeat period. We can minimise the keyup timer to be the protocol period + IR timeout. This makes keys less "sticky" and makes IR more reactive and nicer to use. This feature was previously attempted in commit d57ea877af38 ("media: rc: per-protocol repeat period"), but that did not take the IR timeout into account, and had to be reverted. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 2 +- drivers/media/rc/rc-main.c | 56 +++++++++++++++++++++++---------------------- 2 files changed, 30 insertions(+), 28 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 6b4755e..cc58ed7 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -583,7 +583,7 @@ static long ir_lirc_ioctl(struct file *file, unsigned int cmd, break; case LIRC_SET_REC_TIMEOUT_REPORTS: - if (!dev->timeout) + if (dev->driver_type != RC_DRIVER_IR_RAW) ret = -ENOTTY; else fh->send_timeout_reports = !!val; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 6a720e9..9f4df60 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -26,50 +26,50 @@ static const struct { unsigned int repeat_period; unsigned int scancode_bits; } protocols[] = { - [RC_PROTO_UNKNOWN] = { .name = "unknown", .repeat_period = 250 }, - [RC_PROTO_OTHER] = { .name = "other", .repeat_period = 250 }, + [RC_PROTO_UNKNOWN] = { .name = "unknown", .repeat_period = 125 }, + [RC_PROTO_OTHER] = { .name = "other", .repeat_period = 125 }, [RC_PROTO_RC5] = { .name = "rc-5", - .scancode_bits = 0x1f7f, .repeat_period = 250 }, + .scancode_bits = 0x1f7f, .repeat_period = 114 }, [RC_PROTO_RC5X_20] = { .name = "rc-5x-20", - .scancode_bits = 0x1f7f3f, .repeat_period = 250 }, + .scancode_bits = 0x1f7f3f, .repeat_period = 114 }, [RC_PROTO_RC5_SZ] = { .name = "rc-5-sz", - .scancode_bits = 0x2fff, .repeat_period = 250 }, + .scancode_bits = 0x2fff, .repeat_period = 114 }, [RC_PROTO_JVC] = { .name = "jvc", - .scancode_bits = 0xffff, .repeat_period = 250 }, + .scancode_bits = 0xffff, .repeat_period = 125 }, [RC_PROTO_SONY12] = { .name = "sony-12", - .scancode_bits = 0x1f007f, .repeat_period = 250 }, + .scancode_bits = 0x1f007f, .repeat_period = 100 }, [RC_PROTO_SONY15] = { .name = "sony-15", - .scancode_bits = 0xff007f, .repeat_period = 250 }, + .scancode_bits = 0xff007f, .repeat_period = 100 }, [RC_PROTO_SONY20] = { .name = "sony-20", - .scancode_bits = 0x1fff7f, .repeat_period = 250 }, + .scancode_bits = 0x1fff7f, .repeat_period = 100 }, [RC_PROTO_NEC] = { .name = "nec", - .scancode_bits = 0xffff, .repeat_period = 250 }, + .scancode_bits = 0xffff, .repeat_period = 110 }, [RC_PROTO_NECX] = { .name = "nec-x", - .scancode_bits = 0xffffff, .repeat_period = 250 }, + .scancode_bits = 0xffffff, .repeat_period = 110 }, [RC_PROTO_NEC32] = { .name = "nec-32", - .scancode_bits = 0xffffffff, .repeat_period = 250 }, + .scancode_bits = 0xffffffff, .repeat_period = 110 }, [RC_PROTO_SANYO] = { .name = "sanyo", - .scancode_bits = 0x1fffff, .repeat_period = 250 }, + .scancode_bits = 0x1fffff, .repeat_period = 125 }, [RC_PROTO_MCIR2_KBD] = { .name = "mcir2-kbd", - .scancode_bits = 0xffff, .repeat_period = 250 }, + .scancode_bits = 0xffff, .repeat_period = 100 }, [RC_PROTO_MCIR2_MSE] = { .name = "mcir2-mse", - .scancode_bits = 0x1fffff, .repeat_period = 250 }, + .scancode_bits = 0x1fffff, .repeat_period = 100 }, [RC_PROTO_RC6_0] = { .name = "rc-6-0", - .scancode_bits = 0xffff, .repeat_period = 250 }, + .scancode_bits = 0xffff, .repeat_period = 114 }, [RC_PROTO_RC6_6A_20] = { .name = "rc-6-6a-20", - .scancode_bits = 0xfffff, .repeat_period = 250 }, + .scancode_bits = 0xfffff, .repeat_period = 114 }, [RC_PROTO_RC6_6A_24] = { .name = "rc-6-6a-24", - .scancode_bits = 0xffffff, .repeat_period = 250 }, + .scancode_bits = 0xffffff, .repeat_period = 114 }, [RC_PROTO_RC6_6A_32] = { .name = "rc-6-6a-32", - .scancode_bits = 0xffffffff, .repeat_period = 250 }, + .scancode_bits = 0xffffffff, .repeat_period = 114 }, [RC_PROTO_RC6_MCE] = { .name = "rc-6-mce", - .scancode_bits = 0xffff7fff, .repeat_period = 250 }, + .scancode_bits = 0xffff7fff, .repeat_period = 114 }, [RC_PROTO_SHARP] = { .name = "sharp", - .scancode_bits = 0x1fff, .repeat_period = 250 }, - [RC_PROTO_XMP] = { .name = "xmp", .repeat_period = 250 }, - [RC_PROTO_CEC] = { .name = "cec", .repeat_period = 550 }, + .scancode_bits = 0x1fff, .repeat_period = 125 }, + [RC_PROTO_XMP] = { .name = "xmp", .repeat_period = 125 }, + [RC_PROTO_CEC] = { .name = "cec", .repeat_period = 0 }, [RC_PROTO_IMON] = { .name = "imon", - .scancode_bits = 0x7fffffff, .repeat_period = 250 }, + .scancode_bits = 0x7fffffff, .repeat_period = 114 }, }; /* Used to keep track of known keymaps */ @@ -690,7 +690,8 @@ static void ir_timer_repeat(struct timer_list *t) void rc_repeat(struct rc_dev *dev) { unsigned long flags; - unsigned int timeout = protocols[dev->last_protocol].repeat_period; + unsigned int timeout = nsecs_to_jiffies(dev->timeout) + + msecs_to_jiffies(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, @@ -706,7 +707,7 @@ void rc_repeat(struct rc_dev *dev) input_sync(dev->input_dev); if (dev->keypressed) { - dev->keyup_jiffies = jiffies + msecs_to_jiffies(timeout); + dev->keyup_jiffies = jiffies + timeout; mod_timer(&dev->timer_keyup, dev->keyup_jiffies); } @@ -801,7 +802,7 @@ void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u32 scancode, ir_do_keydown(dev, protocol, scancode, keycode, toggle); if (dev->keypressed) { - dev->keyup_jiffies = jiffies + + dev->keyup_jiffies = jiffies + nsecs_to_jiffies(dev->timeout) + msecs_to_jiffies(protocols[protocol].repeat_period); mod_timer(&dev->timer_keyup, dev->keyup_jiffies); } @@ -1647,6 +1648,7 @@ struct rc_dev *rc_allocate_device(enum rc_driver_type type) dev->input_dev->setkeycode = ir_setkeycode; input_set_drvdata(dev->input_dev, dev); + dev->timeout = IR_DEFAULT_TIMEOUT; timer_setup(&dev->timer_keyup, ir_timer_keyup, 0); timer_setup(&dev->timer_repeat, ir_timer_repeat, 0); -- cgit v1.1 From c421c62a4a08aba220ad7176ef4aa4b0ced9480a Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 25 Mar 2018 11:45:40 -0400 Subject: media: rc: mce_kbd decoder: low timeout values cause double keydowns The mce keyboard repeats pressed keys every 100ms. If the IR timeout is set to less than that, we send key up events before the repeat arrives, so we have key up/key down for each IR repeat. The keyboard ends any sequence with a 0 scancode, in which case all keys are cleared so there is no need to run the timeout timer: it only exists for the case that the final 0 was not received. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-mce_kbd-decoder.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 05f2a36..9d609dc 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -322,11 +322,13 @@ again: scancode = data->body & 0xffff; dev_dbg(&dev->dev, "keyboard data 0x%08x\n", data->body); - if (dev->timeout) - delay = usecs_to_jiffies(dev->timeout / 1000); - else - delay = msecs_to_jiffies(100); - mod_timer(&data->rx_timeout, jiffies + delay); + if (scancode) { + delay = nsecs_to_jiffies(dev->timeout) + + msecs_to_jiffies(100); + mod_timer(&data->rx_timeout, jiffies + delay); + } else { + del_timer(&data->rx_timeout); + } /* Pass data to keyboard buffer parser */ ir_mce_kbd_process_keyboard_data(dev, scancode); lsc.rc_proto = RC_PROTO_MCIR2_KBD; -- cgit v1.1 From 539327608dbedf242131fc6f1b8bcca712952c45 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 7 Apr 2018 17:41:17 -0400 Subject: media: rc: mce_kbd protocol encodes two scancodes If two keys are pressed, then both keys are encoded in the scancode. This makes the mce keyboard more responsive. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-mce_kbd-decoder.c | 21 ++++++++++++--------- drivers/media/rc/rc-main.c | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 9d609dc..f94e89e 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -147,13 +147,14 @@ static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data) static void ir_mce_kbd_process_keyboard_data(struct rc_dev *dev, u32 scancode) { struct mce_kbd_dec *data = &dev->raw->mce_kbd; - u8 keydata = (scancode >> 8) & 0xff; + u8 keydata1 = (scancode >> 8) & 0xff; + u8 keydata2 = (scancode >> 16) & 0xff; u8 shiftmask = scancode & 0xff; - unsigned char keycode, maskcode; + unsigned char maskcode; int i, keystate; - dev_dbg(&dev->dev, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n", - keydata, shiftmask); + dev_dbg(&dev->dev, "keyboard: keydata2 = 0x%02x, keydata1 = 0x%02x, shiftmask = 0x%02x\n", + keydata2, keydata1, shiftmask); for (i = 0; i < 7; i++) { maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; @@ -164,10 +165,12 @@ static void ir_mce_kbd_process_keyboard_data(struct rc_dev *dev, u32 scancode) input_report_key(data->idev, maskcode, keystate); } - if (keydata) { - keycode = kbd_keycodes[keydata]; - input_report_key(data->idev, keycode, 1); - } else { + if (keydata1) + input_report_key(data->idev, kbd_keycodes[keydata1], 1); + if (keydata2) + input_report_key(data->idev, kbd_keycodes[keydata2], 1); + + if (!keydata1 && !keydata2) { for (i = 0; i < MCIR2_MASK_KEYS_START; i++) input_report_key(data->idev, kbd_keycodes[i], 0); } @@ -319,7 +322,7 @@ again: switch (data->wanted_bits) { case MCIR2_KEYBOARD_NBITS: - scancode = data->body & 0xffff; + scancode = data->body & 0xffffff; dev_dbg(&dev->dev, "keyboard data 0x%08x\n", data->body); if (scancode) { diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 9f4df60..b7071bd 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -51,7 +51,7 @@ static const struct { [RC_PROTO_SANYO] = { .name = "sanyo", .scancode_bits = 0x1fffff, .repeat_period = 125 }, [RC_PROTO_MCIR2_KBD] = { .name = "mcir2-kbd", - .scancode_bits = 0xffff, .repeat_period = 100 }, + .scancode_bits = 0xffffff, .repeat_period = 100 }, [RC_PROTO_MCIR2_MSE] = { .name = "mcir2-mse", .scancode_bits = 0x1fffff, .repeat_period = 100 }, [RC_PROTO_RC6_0] = { .name = "rc-6-0", -- cgit v1.1 From 63039c29f7a4ce8a8bd165173840543c0098d7b0 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 8 Apr 2018 06:36:40 -0400 Subject: media: rc: mce_kbd decoder: fix stuck keys The MCE Remote sends a 0 scancode when keys are released. If this is not received or decoded, then keys can get "stuck"; the keyup event is not sent since the input_sync() is missing from the timeout handler. Cc: stable@vger.kernel.org Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-mce_kbd-decoder.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index f94e89e..002b832 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -130,6 +130,8 @@ static void mce_kbd_rx_timeout(struct timer_list *t) for (i = 0; i < MCIR2_MASK_KEYS_START; i++) input_report_key(raw->mce_kbd.idev, kbd_keycodes[i], 0); + + input_sync(raw->mce_kbd.idev); } static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data) -- cgit v1.1 From cb5bd0575c41ac34c62a7784da7232d1c90e6eca Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 11 Apr 2018 11:02:16 -0400 Subject: media: rc: mce_kbd decoder: remove superfluous call to input_sync There is nothing to sync in this code path. Reported-by: Matthias Reichl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-mce_kbd-decoder.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 002b832..2fc7871 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -362,7 +362,6 @@ out: dev_dbg(&dev->dev, "failed at state %i (%uus %s)\n", data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; - input_sync(data->idev); return -EINVAL; } -- cgit v1.1 From 53a62800efb2f0ebc1972cab242461ae8c57bfd4 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 12 Apr 2018 16:28:39 -0400 Subject: media: rc: mce_kbd decoder: fix race condition The MCE keyboard sends both key down and key up events. We have a timeout handler mce_kbd_rx_timeout() in case the keyup event is never received; however, this may race with new key down events from occurring. The race is that key down scancode arrives and key down events are generated. The timeout handler races this and generates key up events straight afterwards. Since the keyboard generates scancodes every 100ms, most likely the keys will be repeated 100ms later, and now we have new key down events and the user sees duplicate key presses. Reported-by: Matthias Reichl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-mce_kbd-decoder.c | 23 ++++++++++++++++------- drivers/media/rc/rc-core-priv.h | 2 ++ 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 2fc7871..9574c3d 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -119,19 +119,25 @@ static void mce_kbd_rx_timeout(struct timer_list *t) { struct ir_raw_event_ctrl *raw = from_timer(raw, t, mce_kbd.rx_timeout); unsigned char maskcode; + unsigned long flags; int i; dev_dbg(&raw->dev->dev, "timer callback clearing all keys\n"); - for (i = 0; i < 7; i++) { - maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; - input_report_key(raw->mce_kbd.idev, maskcode, 0); - } + spin_lock_irqsave(&raw->mce_kbd.keylock, flags); - for (i = 0; i < MCIR2_MASK_KEYS_START; i++) - input_report_key(raw->mce_kbd.idev, kbd_keycodes[i], 0); + if (time_is_before_eq_jiffies(raw->mce_kbd.rx_timeout.expires)) { + for (i = 0; i < 7; i++) { + maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; + input_report_key(raw->mce_kbd.idev, maskcode, 0); + } - input_sync(raw->mce_kbd.idev); + for (i = 0; i < MCIR2_MASK_KEYS_START; i++) + input_report_key(raw->mce_kbd.idev, kbd_keycodes[i], 0); + + input_sync(raw->mce_kbd.idev); + } + spin_unlock_irqrestore(&raw->mce_kbd.keylock, flags); } static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data) @@ -327,6 +333,7 @@ again: scancode = data->body & 0xffffff; dev_dbg(&dev->dev, "keyboard data 0x%08x\n", data->body); + spin_lock(&data->keylock); if (scancode) { delay = nsecs_to_jiffies(dev->timeout) + msecs_to_jiffies(100); @@ -336,6 +343,7 @@ again: } /* Pass data to keyboard buffer parser */ ir_mce_kbd_process_keyboard_data(dev, scancode); + spin_unlock(&data->keylock); lsc.rc_proto = RC_PROTO_MCIR2_KBD; break; case MCIR2_MOUSE_NBITS: @@ -400,6 +408,7 @@ static int ir_mce_kbd_register(struct rc_dev *dev) set_bit(MSC_SCAN, idev->mscbit); timer_setup(&mce_kbd->rx_timeout, mce_kbd_rx_timeout, 0); + spin_lock_init(&mce_kbd->keylock); input_set_drvdata(idev, mce_kbd); diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index f785513..07ba77f 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -105,6 +105,8 @@ struct ir_raw_event_ctrl { } sharp; struct mce_kbd_dec { struct input_dev *idev; + /* locks key up timer */ + spinlock_t keylock; struct timer_list rx_timeout; char name[64]; char phys[64]; -- cgit v1.1 From 91352b572786a49f26a12e8b1b7571bc3df64bab Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 18 Apr 2018 05:36:25 -0400 Subject: media: rc: mceusb: IR of length 0 means IR timeout, not reset The last usb packet with IR data will end with 0x80 (MCE_IRDATA_TRAILER). If we reset the decoder state at this point, IR decoding can fail. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 69ba573..a1c2190 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1182,7 +1182,12 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) if (ir->rem) { ir->parser_state = PARSE_IRDATA; } else { - ir_raw_event_reset(ir->rc); + init_ir_raw_event(&rawir); + rawir.timeout = 1; + rawir.duration = ir->rc->timeout; + if (ir_raw_event_store_with_filter(ir->rc, + &rawir)) + event = true; ir->pulse_tunit = 0; ir->pulse_count = 0; } -- cgit v1.1 From 877f1a7cee3f5dd7a08bdabb52948f155c8f267e Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 8 Apr 2018 11:06:49 -0400 Subject: media: rc: mceusb: allow the timeout to be configurable mceusb devices have a default timeout of 100ms, but this can be changed. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index a1c2190..5c0bf61 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -982,6 +982,25 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) return 0; } +static int mceusb_set_timeout(struct rc_dev *dev, unsigned int timeout) +{ + u8 cmdbuf[4] = { MCE_CMD_PORT_IR, MCE_CMD_SETIRTIMEOUT, 0, 0 }; + struct mceusb_dev *ir = dev->priv; + unsigned int units; + + units = DIV_ROUND_CLOSEST(timeout, US_TO_NS(MCE_TIME_UNIT)); + + cmdbuf[2] = units >> 8; + cmdbuf[3] = units; + + mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + + /* get receiver timeout value */ + mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); + + return 0; +} + /* * Select or deselect the 2nd receiver port. * Second receiver is learning mode, wide-band, short-range receiver. @@ -1420,7 +1439,10 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->dev.parent = dev; rc->priv = ir; rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + rc->min_timeout = US_TO_NS(MCE_TIME_UNIT); rc->timeout = MS_TO_NS(100); + rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; + rc->s_timeout = mceusb_set_timeout; if (!ir->flags.no_tx) { rc->s_tx_mask = mceusb_set_tx_mask; rc->s_tx_carrier = mceusb_set_tx_carrier; -- cgit v1.1 From c42c3e61bf037cdfc503e7d83e2df118f5570f76 Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Fri, 13 Apr 2018 09:48:29 -0400 Subject: media: rc: ir-spi: update Andi's e-mail Because I will be leaving Samsung soon, update my e-mail to the etezian.org mail. Cc: Andi Shyti Signed-off-by: Andi Shyti Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c index 7163d5c..66334e8 100644 --- a/drivers/media/rc/ir-spi.c +++ b/drivers/media/rc/ir-spi.c @@ -2,7 +2,7 @@ // SPI driven IR LED device driver // // Copyright (c) 2016 Samsung Electronics Co., Ltd. -// Copyright (c) Andi Shyti +// Copyright (c) Andi Shyti #include #include @@ -173,6 +173,6 @@ static struct spi_driver ir_spi_driver = { module_spi_driver(ir_spi_driver); -MODULE_AUTHOR("Andi Shyti "); +MODULE_AUTHOR("Andi Shyti "); MODULE_DESCRIPTION("SPI IR LED"); MODULE_LICENSE("GPL v2"); -- cgit v1.1 From 5d0af51face3ef84c23dd4e8d8b8c2730450bf0a Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sun, 15 Apr 2018 22:34:30 -0400 Subject: media: rc: mtk-cir: use of_device_get_match_data() The usage of of_device_get_match_data() reduce the code size a bit. Signed-off-by: Ryder Lee Acked-by: Sean Wang Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mtk-cir.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c index e88eb64..e42efd9 100644 --- a/drivers/media/rc/mtk-cir.c +++ b/drivers/media/rc/mtk-cir.c @@ -299,8 +299,6 @@ static int mtk_ir_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *dn = dev->of_node; - const struct of_device_id *of_id = - of_match_device(mtk_ir_match, &pdev->dev); struct resource *res; struct mtk_ir *ir; u32 val; @@ -312,7 +310,7 @@ static int mtk_ir_probe(struct platform_device *pdev) return -ENOMEM; ir->dev = dev; - ir->data = of_id->data; + ir->data = of_device_get_match_data(dev); ir->clk = devm_clk_get(dev, "clk"); if (IS_ERR(ir->clk)) { -- cgit v1.1 From c00cb587a2745eb49916db912be7b3d362c6a2f9 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 12 Nov 2017 16:34:59 -0500 Subject: media: rc: only register protocol for rc device if enabled The raw_register function exists to create input devices associated with that IR protocol. If the mce_kbd module is loaded, then every rc device will have mce_kbd input devices, even if the protocol is not enabled. Change this to call the register function to when the protocol is enabled. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-ir-raw.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 22e44c8..2ab8a2b 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -236,6 +236,19 @@ static int change_protocol(struct rc_dev *dev, u64 *rc_proto) struct ir_raw_handler *handler; u32 timeout = 0; + mutex_lock(&ir_raw_handler_lock); + list_for_each_entry(handler, &ir_raw_handler_list, list) { + if (!(dev->enabled_protocols & handler->protocols) && + (*rc_proto & handler->protocols) && handler->raw_register) + handler->raw_register(dev); + + if ((dev->enabled_protocols & handler->protocols) && + !(*rc_proto & handler->protocols) && + handler->raw_unregister) + handler->raw_unregister(dev); + } + mutex_unlock(&ir_raw_handler_lock); + if (!dev->max_timeout) return 0; @@ -607,7 +620,6 @@ int ir_raw_event_prepare(struct rc_dev *dev) int ir_raw_event_register(struct rc_dev *dev) { - struct ir_raw_handler *handler; struct task_struct *thread; thread = kthread_run(ir_raw_event_thread, dev->raw, "rc%u", dev->minor); @@ -618,9 +630,6 @@ int ir_raw_event_register(struct rc_dev *dev) mutex_lock(&ir_raw_handler_lock); list_add_tail(&dev->raw->list, &ir_raw_client_list); - list_for_each_entry(handler, &ir_raw_handler_list, list) - if (handler->raw_register) - handler->raw_register(dev); mutex_unlock(&ir_raw_handler_lock); return 0; @@ -648,7 +657,8 @@ void ir_raw_event_unregister(struct rc_dev *dev) mutex_lock(&ir_raw_handler_lock); list_del(&dev->raw->list); list_for_each_entry(handler, &ir_raw_handler_list, list) - if (handler->raw_unregister) + if (handler->raw_unregister && + (handler->protocols & dev->enabled_protocols)) handler->raw_unregister(dev); mutex_unlock(&ir_raw_handler_lock); @@ -661,13 +671,8 @@ void ir_raw_event_unregister(struct rc_dev *dev) int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) { - struct ir_raw_event_ctrl *raw; - mutex_lock(&ir_raw_handler_lock); list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list); - if (ir_raw_handler->raw_register) - list_for_each_entry(raw, &ir_raw_client_list, list) - ir_raw_handler->raw_register(raw->dev); atomic64_or(ir_raw_handler->protocols, &available_protocols); mutex_unlock(&ir_raw_handler_lock); @@ -683,9 +688,10 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) mutex_lock(&ir_raw_handler_lock); list_del(&ir_raw_handler->list); list_for_each_entry(raw, &ir_raw_client_list, list) { - ir_raw_disable_protocols(raw->dev, protocols); - if (ir_raw_handler->raw_unregister) + if (ir_raw_handler->raw_unregister && + (raw->dev->enabled_protocols & protocols)) ir_raw_handler->raw_unregister(raw->dev); + ir_raw_disable_protocols(raw->dev, protocols); } atomic64_andnot(protocols, &available_protocols); mutex_unlock(&ir_raw_handler_lock); -- cgit v1.1 From f9d94a10dad89ae01c0ff816022a8bdd6e1acda0 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 18 Apr 2018 16:44:58 -0400 Subject: media: rc: imon decoder: support the stick The iMON PAD controller has a analog stick, which can be switched to keyboard mode (cursor keys) or work as a crappy mouse. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-imon-decoder.c | 135 ++++++++++++++++++++++++++++++++++++- drivers/media/rc/rc-core-priv.h | 3 + 2 files changed, 135 insertions(+), 3 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-imon-decoder.c b/drivers/media/rc/ir-imon-decoder.c index 52ea3b2..67c1b0c 100644 --- a/drivers/media/rc/ir-imon-decoder.c +++ b/drivers/media/rc/ir-imon-decoder.c @@ -31,9 +31,69 @@ enum imon_state { STATE_INACTIVE, STATE_BIT_CHK, STATE_BIT_START, - STATE_FINISHED + STATE_FINISHED, + STATE_ERROR, }; +static void ir_imon_decode_scancode(struct rc_dev *dev) +{ + struct imon_dec *imon = &dev->raw->imon; + + /* Keyboard/Mouse toggle */ + if (imon->bits == 0x299115b7) + imon->stick_keyboard = !imon->stick_keyboard; + + if ((imon->bits & 0xfc0000ff) == 0x680000b7) { + int rel_x, rel_y; + u8 buf; + + buf = imon->bits >> 16; + rel_x = (buf & 0x08) | (buf & 0x10) >> 2 | + (buf & 0x20) >> 4 | (buf & 0x40) >> 6; + if (imon->bits & 0x02000000) + rel_x |= ~0x0f; + buf = imon->bits >> 8; + rel_y = (buf & 0x08) | (buf & 0x10) >> 2 | + (buf & 0x20) >> 4 | (buf & 0x40) >> 6; + if (imon->bits & 0x01000000) + rel_y |= ~0x0f; + + if (rel_x && rel_y && imon->stick_keyboard) { + if (abs(rel_y) > abs(rel_x)) + imon->bits = rel_y > 0 ? + 0x289515b7 : /* KEY_DOWN */ + 0x2aa515b7; /* KEY_UP */ + else + imon->bits = rel_x > 0 ? + 0x2ba515b7 : /* KEY_RIGHT */ + 0x29a515b7; /* KEY_LEFT */ + } + + if (!imon->stick_keyboard) { + struct lirc_scancode lsc = { + .scancode = imon->bits, + .rc_proto = RC_PROTO_IMON, + }; + + ir_lirc_scancode_event(dev, &lsc); + + input_event(imon->idev, EV_MSC, MSC_SCAN, imon->bits); + + input_report_rel(imon->idev, REL_X, rel_x); + input_report_rel(imon->idev, REL_Y, rel_y); + + input_report_key(imon->idev, BTN_LEFT, + (imon->bits & 0x00010000) != 0); + input_report_key(imon->idev, BTN_RIGHT, + (imon->bits & 0x00040000) != 0); + input_sync(imon->idev); + return; + } + } + + rc_keydown(dev, RC_PROTO_IMON, imon->bits, 0); +} + /** * ir_imon_decode() - Decode one iMON pulse or space * @dev: the struct rc_dev descriptor of the device @@ -56,6 +116,22 @@ static int ir_imon_decode(struct rc_dev *dev, struct ir_raw_event ev) data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse)); + /* + * Since iMON protocol is a series of bits, if at any point + * we encounter an error, make sure that any remaining bits + * aren't parsed as a scancode made up of less bits. + * + * Note that if the stick is held, then the remote repeats + * the scancode with about 12ms between them. So, make sure + * we have at least 10ms of space after an error. That way, + * we're at a new scancode. + */ + if (data->state == STATE_ERROR) { + if (!ev.pulse && ev.duration > MS_TO_NS(10)) + data->state = STATE_INACTIVE; + return 0; + } + for (;;) { if (!geq_margin(ev.duration, IMON_UNIT, IMON_UNIT / 2)) return 0; @@ -95,7 +171,7 @@ static int ir_imon_decode(struct rc_dev *dev, struct ir_raw_event ev) case STATE_FINISHED: if (ev.pulse) goto err_out; - rc_keydown(dev, RC_PROTO_IMON, data->bits, 0); + ir_imon_decode_scancode(dev); data->state = STATE_INACTIVE; break; } @@ -107,7 +183,7 @@ err_out: data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse)); - data->state = STATE_INACTIVE; + data->state = STATE_ERROR; return -EINVAL; } @@ -165,11 +241,64 @@ static int ir_imon_encode(enum rc_proto protocol, u32 scancode, return e - events; } +static int ir_imon_register(struct rc_dev *dev) +{ + struct input_dev *idev; + struct imon_dec *imon = &dev->raw->imon; + int ret; + + idev = input_allocate_device(); + if (!idev) + return -ENOMEM; + + snprintf(imon->name, sizeof(imon->name), + "iMON PAD Stick (%s)", dev->device_name); + idev->name = imon->name; + idev->phys = dev->input_phys; + + /* Mouse bits */ + set_bit(EV_REL, idev->evbit); + set_bit(EV_KEY, idev->evbit); + set_bit(REL_X, idev->relbit); + set_bit(REL_Y, idev->relbit); + set_bit(BTN_LEFT, idev->keybit); + set_bit(BTN_RIGHT, idev->keybit); + + /* Report scancodes too */ + set_bit(EV_MSC, idev->evbit); + set_bit(MSC_SCAN, idev->mscbit); + + input_set_drvdata(idev, imon); + + ret = input_register_device(idev); + if (ret < 0) { + input_free_device(idev); + return -EIO; + } + + imon->idev = idev; + imon->stick_keyboard = false; + + return 0; +} + +static int ir_imon_unregister(struct rc_dev *dev) +{ + struct imon_dec *imon = &dev->raw->imon; + + input_unregister_device(imon->idev); + imon->idev = NULL; + + return 0; +} + static struct ir_raw_handler imon_handler = { .protocols = RC_PROTO_BIT_IMON, .decode = ir_imon_decode, .encode = ir_imon_encode, .carrier = 38000, + .raw_register = ir_imon_register, + .raw_unregister = ir_imon_unregister, .min_timeout = IMON_UNIT * IMON_BITS * 2, }; diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 07ba77f..bbb9a7e 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -126,6 +126,9 @@ struct ir_raw_event_ctrl { int count; int last_chk; unsigned int bits; + bool stick_keyboard; + struct input_dev *idev; + char name[64]; } imon; }; -- cgit v1.1 From 6ba0b22d206888aa524675a69ee796af9118fec2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 20 Apr 2018 13:42:49 -0400 Subject: media: rc: allow build pnp-dependent drivers with COMPILE_TEST The pnp header already provide enough stub to build those drivers with COMPILE_TEST on non-x86 archs. Signed-off-by: Mauro Carvalho Chehab Acked-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index eb2c3b6..9a3b66c 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -149,7 +149,7 @@ config RC_ATI_REMOTE config IR_ENE tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)" - depends on PNP + depends on PNP || COMPILE_TEST depends on RC_CORE ---help--- Say Y here to enable support for integrated infrared receiver @@ -210,7 +210,7 @@ config IR_MCEUSB config IR_ITE_CIR tristate "ITE Tech Inc. IT8712/IT8512 Consumer Infrared Transceiver" - depends on PNP + depends on PNP || COMPILE_TEST depends on RC_CORE ---help--- Say Y here to enable support for integrated infrared receivers @@ -223,7 +223,7 @@ config IR_ITE_CIR config IR_FINTEK tristate "Fintek Consumer Infrared Transceiver" - depends on PNP + depends on PNP || COMPILE_TEST depends on RC_CORE ---help--- Say Y here to enable support for integrated infrared receiver @@ -257,7 +257,7 @@ config IR_MTK config IR_NUVOTON tristate "Nuvoton w836x7hg Consumer Infrared Transceiver" - depends on PNP + depends on PNP || COMPILE_TEST depends on RC_CORE ---help--- Say Y here to enable support for integrated infrared receiver @@ -305,7 +305,7 @@ config IR_STREAMZAP config IR_WINBOND_CIR tristate "Winbond IR remote control" - depends on X86 && PNP + depends on (X86 && PNP) || COMPILE_TEST depends on RC_CORE select NEW_LEDS select LEDS_CLASS -- cgit v1.1 From aec3eadfb642346669c4d9324d82b5844e36a39b Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 9 May 2018 06:11:28 -0400 Subject: media: mceusb: MCE_CMD_SETIRTIMEOUT cause strange behaviour on device If the IR timeout is set on vid 1784 pid 0011, the device starts behaving strangely. Reported-by: Matthias Reichl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 5c0bf61..1619b74 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -181,6 +181,7 @@ enum mceusb_model_type { MCE_GEN2 = 0, /* Most boards */ MCE_GEN1, MCE_GEN3, + MCE_GEN3_BROKEN_IRTIMEOUT, MCE_GEN2_TX_INV, MCE_GEN2_TX_INV_RX_GOOD, POLARIS_EVK, @@ -199,6 +200,7 @@ struct mceusb_model { u32 mce_gen3:1; u32 tx_mask_normal:1; u32 no_tx:1; + u32 broken_irtimeout:1; /* * 2nd IR receiver (short-range, wideband) for learning mode: * 0, absent 2nd receiver (rx2) @@ -242,6 +244,12 @@ static const struct mceusb_model mceusb_model[] = { .tx_mask_normal = 1, .rx2 = 2, }, + [MCE_GEN3_BROKEN_IRTIMEOUT] = { + .mce_gen3 = 1, + .tx_mask_normal = 1, + .rx2 = 2, + .broken_irtimeout = 1 + }, [POLARIS_EVK] = { /* * In fact, the EVK is shipped without @@ -352,7 +360,7 @@ static const struct usb_device_id mceusb_dev_table[] = { .driver_info = MCE_GEN2_TX_INV }, /* Topseed eHome Infrared Transceiver */ { USB_DEVICE(VENDOR_TOPSEED, 0x0011), - .driver_info = MCE_GEN3 }, + .driver_info = MCE_GEN3_BROKEN_IRTIMEOUT }, /* Ricavision internal Infrared Transceiver */ { USB_DEVICE(VENDOR_RICAVISION, 0x0010) }, /* Itron ione Libra Q-11 */ @@ -1441,8 +1449,16 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rc->min_timeout = US_TO_NS(MCE_TIME_UNIT); rc->timeout = MS_TO_NS(100); - rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; - rc->s_timeout = mceusb_set_timeout; + if (!mceusb_model[ir->model].broken_irtimeout) { + rc->s_timeout = mceusb_set_timeout; + rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; + } else { + /* + * If we can't set the timeout using CMD_SETIRTIMEOUT, we can + * rely on software timeouts for timeouts < 100ms. + */ + rc->max_timeout = rc->timeout; + } if (!ir->flags.no_tx) { rc->s_tx_mask = mceusb_set_tx_mask; rc->s_tx_carrier = mceusb_set_tx_carrier; -- cgit v1.1 From d4589935ebab0f75bbb191ce2cb14c5f8f4f9429 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 10 May 2018 07:37:51 -0400 Subject: media: mceusb: filter out bogus timing irdata of duration 0 A mceusb device has been observed producing invalid irdata. Proactively guard against this. Suggested-by: Matthias Reichl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 1619b74..1ca49491 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1177,6 +1177,11 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) init_ir_raw_event(&rawir); rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK); + if (unlikely(!rawir.duration)) { + dev_warn(ir->dev, "nonsensical irdata %02x with duration 0", + ir->buf_in[i]); + break; + } if (rawir.pulse) { ir->pulse_tunit += rawir.duration; ir->pulse_count++; -- cgit v1.1 From e708e5a44d59b4da83706bc952ba39f1ecb6cc5d Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 10 May 2018 07:49:49 -0400 Subject: media: mceusb: add missing break Fallthrough is not intended here. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 1ca49491..4c0c800 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -572,6 +572,7 @@ static int mceusb_cmd_datasize(u8 cmd, u8 subcmd) datasize = 1; break; } + break; case MCE_CMD_PORT_IR: switch (subcmd) { case MCE_CMD_UNKNOWN: -- cgit v1.1 From e0d51e6ceff818c5d7a812c26bbd1bb84348a71a Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 10 May 2018 16:41:15 -0400 Subject: media: rc: default to idle on at startup or after reset Any spaces events received after a reset or startup should be discarded, so ensure the rc device is in idle mode. This also makes it much easier to detect incorrect raw events, as we will do in a following commit. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-ir-raw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 2ab8a2b..2e50104 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -611,6 +611,7 @@ int ir_raw_event_prepare(struct rc_dev *dev) dev->raw->dev = dev; dev->change_protocol = change_protocol; + dev->idle = true; spin_lock_init(&dev->raw->edge_spinlock); timer_setup(&dev->raw->edge_handle, ir_raw_edge_handle, 0); INIT_KFIFO(dev->raw->kfifo); -- cgit v1.1 From 48231f289e52b21cdae621a4ff3211b86080cf5a Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 10 May 2018 06:11:47 -0400 Subject: media: rc: drivers should produce alternate pulse and space timing events Report an error if this is not the case or any problem with the generated raw events. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-ir-raw.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 2e50104..49c56da 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -22,16 +22,27 @@ static int ir_raw_event_thread(void *data) { struct ir_raw_event ev; struct ir_raw_handler *handler; - struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data; + struct ir_raw_event_ctrl *raw = data; + struct rc_dev *dev = raw->dev; while (1) { mutex_lock(&ir_raw_handler_lock); while (kfifo_out(&raw->kfifo, &ev, 1)) { + if (is_timing_event(ev)) { + if (ev.duration == 0) + dev_err(&dev->dev, "nonsensical timing event of duration 0"); + if (is_timing_event(raw->prev_ev) && + !is_transition(&ev, &raw->prev_ev)) + dev_err(&dev->dev, "two consecutive events of type %s", + TO_STR(ev.pulse)); + if (raw->prev_ev.reset && ev.pulse == 0) + dev_err(&dev->dev, "timing event after reset should be pulse"); + } list_for_each_entry(handler, &ir_raw_handler_list, list) - if (raw->dev->enabled_protocols & + if (dev->enabled_protocols & handler->protocols || !handler->protocols) - handler->decode(raw->dev, ev); - ir_lirc_raw_event(raw->dev, ev); + handler->decode(dev, ev); + ir_lirc_raw_event(dev, ev); raw->prev_ev = ev; } mutex_unlock(&ir_raw_handler_lock); -- cgit v1.1 From 09161a05528005b061f07f4e55b42ad558118b9f Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 10 May 2018 06:14:38 -0400 Subject: media: rc: decoders do not need to check for transitions Drivers should never produce consecutive pulse or space raw events. Should that occur, we would have bigger problems than this code is trying to guard against. Note that we already log an error should a driver misbehave. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-mce_kbd-decoder.c | 6 ------ drivers/media/rc/ir-rc5-decoder.c | 3 --- drivers/media/rc/ir-rc6-decoder.c | 10 ---------- 3 files changed, 19 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 9574c3d..64ea429 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -274,9 +274,6 @@ again: return 0; case STATE_HEADER_BIT_END: - if (!is_transition(&ev, &dev->raw->prev_ev)) - break; - decrease_duration(&ev, MCIR2_BIT_END); if (data->count != MCIR2_HEADER_NBITS) { @@ -313,9 +310,6 @@ again: return 0; case STATE_BODY_BIT_END: - if (!is_transition(&ev, &dev->raw->prev_ev)) - break; - if (data->count == data->wanted_bits) data->state = STATE_FINISHED; else diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index cbfaadb..6362465 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -88,9 +88,6 @@ again: return 0; case STATE_BIT_END: - if (!is_transition(&ev, &dev->raw->prev_ev)) - break; - if (data->count == CHECK_RC5X_NBITS) data->state = STATE_CHECK_RC5X; else diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index 66e0710..68487ce 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -145,9 +145,6 @@ again: return 0; case STATE_HEADER_BIT_END: - if (!is_transition(&ev, &dev->raw->prev_ev)) - break; - if (data->count == RC6_HEADER_NBITS) data->state = STATE_TOGGLE_START; else @@ -165,10 +162,6 @@ again: return 0; case STATE_TOGGLE_END: - if (!is_transition(&ev, &dev->raw->prev_ev) || - !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2)) - break; - if (!(data->header & RC6_STARTBIT_MASK)) { dev_dbg(&dev->dev, "RC6 invalid start bit\n"); break; @@ -210,9 +203,6 @@ again: break; case STATE_BODY_BIT_END: - if (!is_transition(&ev, &dev->raw->prev_ev)) - break; - if (data->count == data->wanted_bits) data->state = STATE_FINISHED; else -- cgit v1.1 From 5dae9cea2a72b6de84fd834358d8af21cc255513 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 11 May 2018 05:36:26 -0400 Subject: media: rc: winbond: do not send reset and timeout raw events on startup ir_raw_event_set_idle() sends a timeout event which is not needed, and on startup no reset event is needed either. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/winbond-cir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 0adf099..851acba 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -989,8 +989,7 @@ wbcir_init_hw(struct wbcir_data *data) /* Clear RX state */ data->rxstate = WBCIR_RXSTATE_INACTIVE; - ir_raw_event_reset(data->dev); - ir_raw_event_set_idle(data->dev, true); + wbcir_idle_rx(data->dev, true); /* Clear TX state */ if (data->txstate == WBCIR_TXSTATE_ACTIVE) { @@ -1009,6 +1008,7 @@ wbcir_resume(struct pnp_dev *device) struct wbcir_data *data = pnp_get_drvdata(device); wbcir_init_hw(data); + ir_raw_event_reset(data->dev); enable_irq(data->irq); led_classdev_resume(&data->led); -- cgit v1.1 From 0630efeee8538ae30d81d6e42c9ffb299a3e67b3 Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Sun, 13 May 2018 07:24:31 -0400 Subject: media: rc: ite-cir: lower timeout and extend allowed timeout range The minimum possible timeout of ite-cir is 8 samples, which is typically about 70us. The driver however changes the FIFO trigger level from the hardware's default of 1 byte to 17 bytes, so the minimum usable timeout value is 17 * 8 samples, which is typically about 1.2ms. Tests showed that using timeouts down to 1.2ms actually work fine. The current default timeout of 200ms is much longer than necessary and the maximum timeout of 1s seems to have been chosen a bit arbitrarily. So change the minimum timeout to the driver's limit of 17 * 8 samples and bring timeout and maximum timeout in line with the settings of many other receivers. Signed-off-by: Matthias Reichl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ite-cir.c | 8 +++++--- drivers/media/rc/ite-cir.h | 7 ------- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 65e104c..de77d22 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1561,9 +1561,11 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id rdev->close = ite_close; rdev->s_idle = ite_s_idle; rdev->s_rx_carrier_range = ite_set_rx_carrier_range; - rdev->min_timeout = ITE_MIN_IDLE_TIMEOUT; - rdev->max_timeout = ITE_MAX_IDLE_TIMEOUT; - rdev->timeout = ITE_IDLE_TIMEOUT; + /* FIFO threshold is 17 bytes, so 17 * 8 samples minimum */ + rdev->min_timeout = 17 * 8 * ITE_BAUDRATE_DIVISOR * + itdev->params.sample_period; + rdev->timeout = IR_DEFAULT_TIMEOUT; + rdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; rdev->rx_resolution = ITE_BAUDRATE_DIVISOR * itdev->params.sample_period; rdev->tx_resolution = ITE_BAUDRATE_DIVISOR * diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h index 0e8ebc8..9cb24ac 100644 --- a/drivers/media/rc/ite-cir.h +++ b/drivers/media/rc/ite-cir.h @@ -154,13 +154,6 @@ struct ite_dev { /* default carrier freq for when demodulator is off (Hz) */ #define ITE_DEFAULT_CARRIER_FREQ 38000 -/* default idling timeout in ns (0.2 seconds) */ -#define ITE_IDLE_TIMEOUT 200000000UL - -/* limit timeout values */ -#define ITE_MIN_IDLE_TIMEOUT 100000000UL -#define ITE_MAX_IDLE_TIMEOUT 1000000000UL - /* convert bits to us */ #define ITE_BITS_TO_NS(bits, sample_period) \ ((u32) ((bits) * ITE_BAUDRATE_DIVISOR * sample_period)) -- cgit v1.1 From 70c30b1ea706affcb117e3cd3065690abca5ba69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 21 May 2018 10:38:01 -0400 Subject: media: rc: nuvoton: Tweak the interrupt enabling dance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It appears that we need to enable CIR device before attempting to touch some of the registers. Previously, this was not a big issue, since we were rarely seeing nvt_close() getting called. Unfortunately, since commit cb84343fced1 ("media: lirc: do not call close() or open() on unregistered devices") the initial open() during probe from rc_setup_rx_device() is no longer successful, which means that userspace clients will actually end up calling nvt_open()/nvt_close(). Since nvt_open() is broken, the device doesn't seem to work as expected. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=199597 Signed-off-by: Michał Winiarski Cc: Jarod Wilson Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/nuvoton-cir.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 5e1d866..ce8949b 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -922,6 +922,9 @@ static int nvt_open(struct rc_dev *dev) struct nvt_dev *nvt = dev->priv; unsigned long flags; + /* enable the CIR logical device */ + nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR); + spin_lock_irqsave(&nvt->lock, flags); /* set function enable flags */ @@ -937,9 +940,6 @@ static int nvt_open(struct rc_dev *dev) spin_unlock_irqrestore(&nvt->lock, flags); - /* enable the CIR logical device */ - nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR); - return 0; } -- cgit v1.1 From adbe6cfe5966dbc08d591d0e3771a270ef6e459d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 21 May 2018 10:38:02 -0400 Subject: media: rc: nuvoton: Keep track of users on CIR enable/disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Core rc keeps track of the users - let's use it to tweak the code and use the common code path on suspend/resume. Signed-off-by: Michał Winiarski Cc: Jarod Wilson Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/nuvoton-cir.c | 82 +++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 46 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index ce8949b..eebd6fe 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -543,27 +543,9 @@ static void nvt_cir_regs_init(struct nvt_dev *nvt) nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV | CIR_FIFOCON_RX_TRIGGER_LEV, CIR_FIFOCON); - /* - * Enable TX and RX, specify carrier on = low, off = high, and set - * sample period (currently 50us) - */ - nvt_cir_reg_write(nvt, - CIR_IRCON_TXEN | CIR_IRCON_RXEN | - CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, - CIR_IRCON); - /* clear hardware rx and tx fifos */ nvt_clear_cir_fifo(nvt); nvt_clear_tx_fifo(nvt); - - /* clear any and all stray interrupts */ - nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); - - /* and finally, enable interrupts */ - nvt_set_cir_iren(nvt); - - /* enable the CIR logical device */ - nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR); } static void nvt_cir_wake_regs_init(struct nvt_dev *nvt) @@ -892,6 +874,32 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) return IRQ_HANDLED; } +static void nvt_enable_cir(struct nvt_dev *nvt) +{ + unsigned long flags; + + /* enable the CIR logical device */ + nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR); + + spin_lock_irqsave(&nvt->lock, flags); + + /* + * Enable TX and RX, specify carrier on = low, off = high, and set + * sample period (currently 50us) + */ + nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN | + CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, + CIR_IRCON); + + /* clear all pending interrupts */ + nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); + + /* enable interrupts */ + nvt_set_cir_iren(nvt); + + spin_unlock_irqrestore(&nvt->lock, flags); +} + static void nvt_disable_cir(struct nvt_dev *nvt) { unsigned long flags; @@ -920,25 +928,8 @@ static void nvt_disable_cir(struct nvt_dev *nvt) static int nvt_open(struct rc_dev *dev) { struct nvt_dev *nvt = dev->priv; - unsigned long flags; - /* enable the CIR logical device */ - nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR); - - spin_lock_irqsave(&nvt->lock, flags); - - /* set function enable flags */ - nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN | - CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, - CIR_IRCON); - - /* clear all pending interrupts */ - nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); - - /* enable interrupts */ - nvt_set_cir_iren(nvt); - - spin_unlock_irqrestore(&nvt->lock, flags); + nvt_enable_cir(nvt); return 0; } @@ -1093,19 +1084,13 @@ static void nvt_remove(struct pnp_dev *pdev) static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state) { struct nvt_dev *nvt = pnp_get_drvdata(pdev); - unsigned long flags; nvt_dbg("%s called", __func__); - spin_lock_irqsave(&nvt->lock, flags); - - /* disable all CIR interrupts */ - nvt_cir_reg_write(nvt, 0, CIR_IREN); - - spin_unlock_irqrestore(&nvt->lock, flags); - - /* disable cir logical dev */ - nvt_disable_logical_dev(nvt, LOGICAL_DEV_CIR); + mutex_lock(&nvt->rdev->lock); + if (nvt->rdev->users) + nvt_disable_cir(nvt); + mutex_unlock(&nvt->rdev->lock); /* make sure wake is enabled */ nvt_enable_wake(nvt); @@ -1122,6 +1107,11 @@ static int nvt_resume(struct pnp_dev *pdev) nvt_cir_regs_init(nvt); nvt_cir_wake_regs_init(nvt); + mutex_lock(&nvt->rdev->lock); + if (nvt->rdev->users) + nvt_enable_cir(nvt); + mutex_unlock(&nvt->rdev->lock); + return 0; } -- cgit v1.1 From d24e56f6fbfbce79ae1da3ef7a790942e48676ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Fri, 25 May 2018 10:28:17 -0400 Subject: media: rc: nuvoton: Keep device enabled during reg init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Doing writes when the device is disabled seems to be a NOOP. For CIR device, we should enable it, initialize it, and then disable it until it's opened. CIR_WAKE should always be enabled. Signed-off-by: Michał Winiarski Cc: Jarod Wilson Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/nuvoton-cir.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index eebd6fe..b8299c9 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -535,6 +535,8 @@ static void nvt_set_cir_iren(struct nvt_dev *nvt) static void nvt_cir_regs_init(struct nvt_dev *nvt) { + nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR); + /* set sample limit count (PE interrupt raised when reached) */ nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_SLCH); nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_SLCL); @@ -546,10 +548,14 @@ static void nvt_cir_regs_init(struct nvt_dev *nvt) /* clear hardware rx and tx fifos */ nvt_clear_cir_fifo(nvt); nvt_clear_tx_fifo(nvt); + + nvt_disable_logical_dev(nvt, LOGICAL_DEV_CIR); } static void nvt_cir_wake_regs_init(struct nvt_dev *nvt) { + nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); + /* * Disable RX, set specific carrier on = low, off = high, * and sample period (currently 50us) @@ -561,9 +567,6 @@ static void nvt_cir_wake_regs_init(struct nvt_dev *nvt) /* clear any and all stray interrupts */ nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS); - - /* enable the CIR WAKE logical device */ - nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); } static void nvt_enable_wake(struct nvt_dev *nvt) -- cgit v1.1 From d7832cd2a3c87eb6ae1e802c88b6fc56c5823f6d Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 24 May 2018 05:47:17 -0400 Subject: media: rc: ensure input/lirc device can be opened after register Since commit cb84343fced1 ("media: lirc: do not call close() or open() on unregistered devices") rc_open() will return -ENODEV if rcdev->registered is false. Ensure this is set before we register the input device and the lirc device, else we have a short window where the neither the lirc or input device can be opened. Fixes: cb84343fced1 ("media: lirc: do not call close() or open() on unregistered devices") Cc: stable@vger.kernel.org # v4.16+ Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index b7071bd..2e222d9 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1862,6 +1862,8 @@ int rc_register_device(struct rc_dev *dev) dev->device_name ?: "Unspecified device", path ?: "N/A"); kfree(path); + dev->registered = true; + if (dev->driver_type != RC_DRIVER_IR_RAW_TX) { rc = rc_setup_rx_device(dev); if (rc) @@ -1881,8 +1883,6 @@ int rc_register_device(struct rc_dev *dev) goto out_lirc; } - dev->registered = true; - dev_dbg(&dev->dev, "Registered rc%u (driver: %s)\n", dev->minor, dev->driver_name ? dev->driver_name : "unknown"); -- cgit v1.1