From 207c957d9e70d1eb8f98c028524dff3befc07f42 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 4 Feb 2017 17:00:36 -0200 Subject: [media] cxusb: dvico remotes are nec Adjust the keymap to use the correct nec scancodes, and adjust the rc driver to output the correct nec scancodes. Now the keymap can be used with any nec receiver, and the rc device should work with any nec keymap. Tested-by: Vincent McIntyre Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/rc-dvico-mce.c | 92 ++++++++++++++-------------- drivers/media/rc/keymaps/rc-dvico-portable.c | 74 +++++++++++----------- 2 files changed, 83 insertions(+), 83 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/keymaps/rc-dvico-mce.c b/drivers/media/rc/keymaps/rc-dvico-mce.c index e5f098c..d1e861f 100644 --- a/drivers/media/rc/keymaps/rc-dvico-mce.c +++ b/drivers/media/rc/keymaps/rc-dvico-mce.c @@ -12,58 +12,58 @@ #include static struct rc_map_table rc_map_dvico_mce_table[] = { - { 0xfe02, KEY_TV }, - { 0xfe0e, KEY_MP3 }, - { 0xfe1a, KEY_DVD }, - { 0xfe1e, KEY_FAVORITES }, - { 0xfe16, KEY_SETUP }, - { 0xfe46, KEY_POWER2 }, - { 0xfe0a, KEY_EPG }, - { 0xfe49, KEY_BACK }, - { 0xfe4d, KEY_MENU }, - { 0xfe51, KEY_UP }, - { 0xfe5b, KEY_LEFT }, - { 0xfe5f, KEY_RIGHT }, - { 0xfe53, KEY_DOWN }, - { 0xfe5e, KEY_OK }, - { 0xfe59, KEY_INFO }, - { 0xfe55, KEY_TAB }, - { 0xfe0f, KEY_PREVIOUSSONG },/* Replay */ - { 0xfe12, KEY_NEXTSONG }, /* Skip */ - { 0xfe42, KEY_ENTER }, /* Windows/Start */ - { 0xfe15, KEY_VOLUMEUP }, - { 0xfe05, KEY_VOLUMEDOWN }, - { 0xfe11, KEY_CHANNELUP }, - { 0xfe09, KEY_CHANNELDOWN }, - { 0xfe52, KEY_CAMERA }, - { 0xfe5a, KEY_TUNER }, /* Live */ - { 0xfe19, KEY_OPEN }, - { 0xfe0b, KEY_1 }, - { 0xfe17, KEY_2 }, - { 0xfe1b, KEY_3 }, - { 0xfe07, KEY_4 }, - { 0xfe50, KEY_5 }, - { 0xfe54, KEY_6 }, - { 0xfe48, KEY_7 }, - { 0xfe4c, KEY_8 }, - { 0xfe58, KEY_9 }, - { 0xfe13, KEY_ANGLE }, /* Aspect */ - { 0xfe03, KEY_0 }, - { 0xfe1f, KEY_ZOOM }, - { 0xfe43, KEY_REWIND }, - { 0xfe47, KEY_PLAYPAUSE }, - { 0xfe4f, KEY_FASTFORWARD }, - { 0xfe57, KEY_MUTE }, - { 0xfe0d, KEY_STOP }, - { 0xfe01, KEY_RECORD }, - { 0xfe4e, KEY_POWER }, + { 0x0102, KEY_TV }, + { 0x010e, KEY_MP3 }, + { 0x011a, KEY_DVD }, + { 0x011e, KEY_FAVORITES }, + { 0x0116, KEY_SETUP }, + { 0x0146, KEY_POWER2 }, + { 0x010a, KEY_EPG }, + { 0x0149, KEY_BACK }, + { 0x014d, KEY_MENU }, + { 0x0151, KEY_UP }, + { 0x015b, KEY_LEFT }, + { 0x015f, KEY_RIGHT }, + { 0x0153, KEY_DOWN }, + { 0x015e, KEY_OK }, + { 0x0159, KEY_INFO }, + { 0x0155, KEY_TAB }, + { 0x010f, KEY_PREVIOUSSONG },/* Replay */ + { 0x0112, KEY_NEXTSONG }, /* Skip */ + { 0x0142, KEY_ENTER }, /* Windows/Start */ + { 0x0115, KEY_VOLUMEUP }, + { 0x0105, KEY_VOLUMEDOWN }, + { 0x0111, KEY_CHANNELUP }, + { 0x0109, KEY_CHANNELDOWN }, + { 0x0152, KEY_CAMERA }, + { 0x015a, KEY_TUNER }, /* Live */ + { 0x0119, KEY_OPEN }, + { 0x010b, KEY_1 }, + { 0x0117, KEY_2 }, + { 0x011b, KEY_3 }, + { 0x0107, KEY_4 }, + { 0x0150, KEY_5 }, + { 0x0154, KEY_6 }, + { 0x0148, KEY_7 }, + { 0x014c, KEY_8 }, + { 0x0158, KEY_9 }, + { 0x0113, KEY_ANGLE }, /* Aspect */ + { 0x0103, KEY_0 }, + { 0x011f, KEY_ZOOM }, + { 0x0143, KEY_REWIND }, + { 0x0147, KEY_PLAYPAUSE }, + { 0x014f, KEY_FASTFORWARD }, + { 0x0157, KEY_MUTE }, + { 0x010d, KEY_STOP }, + { 0x0101, KEY_RECORD }, + { 0x014e, KEY_POWER }, }; static struct rc_map_list dvico_mce_map = { .map = { .scan = rc_map_dvico_mce_table, .size = ARRAY_SIZE(rc_map_dvico_mce_table), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .rc_type = RC_TYPE_NEC, .name = RC_MAP_DVICO_MCE, } }; diff --git a/drivers/media/rc/keymaps/rc-dvico-portable.c b/drivers/media/rc/keymaps/rc-dvico-portable.c index 94ceeee..ac4cb51 100644 --- a/drivers/media/rc/keymaps/rc-dvico-portable.c +++ b/drivers/media/rc/keymaps/rc-dvico-portable.c @@ -12,49 +12,49 @@ #include static struct rc_map_table rc_map_dvico_portable_table[] = { - { 0xfc02, KEY_SETUP }, /* Profile */ - { 0xfc43, KEY_POWER2 }, - { 0xfc06, KEY_EPG }, - { 0xfc5a, KEY_BACK }, - { 0xfc05, KEY_MENU }, - { 0xfc47, KEY_INFO }, - { 0xfc01, KEY_TAB }, - { 0xfc42, KEY_PREVIOUSSONG },/* Replay */ - { 0xfc49, KEY_VOLUMEUP }, - { 0xfc09, KEY_VOLUMEDOWN }, - { 0xfc54, KEY_CHANNELUP }, - { 0xfc0b, KEY_CHANNELDOWN }, - { 0xfc16, KEY_CAMERA }, - { 0xfc40, KEY_TUNER }, /* ATV/DTV */ - { 0xfc45, KEY_OPEN }, - { 0xfc19, KEY_1 }, - { 0xfc18, KEY_2 }, - { 0xfc1b, KEY_3 }, - { 0xfc1a, KEY_4 }, - { 0xfc58, KEY_5 }, - { 0xfc59, KEY_6 }, - { 0xfc15, KEY_7 }, - { 0xfc14, KEY_8 }, - { 0xfc17, KEY_9 }, - { 0xfc44, KEY_ANGLE }, /* Aspect */ - { 0xfc55, KEY_0 }, - { 0xfc07, KEY_ZOOM }, - { 0xfc0a, KEY_REWIND }, - { 0xfc08, KEY_PLAYPAUSE }, - { 0xfc4b, KEY_FASTFORWARD }, - { 0xfc5b, KEY_MUTE }, - { 0xfc04, KEY_STOP }, - { 0xfc56, KEY_RECORD }, - { 0xfc57, KEY_POWER }, - { 0xfc41, KEY_UNKNOWN }, /* INPUT */ - { 0xfc00, KEY_UNKNOWN }, /* HD */ + { 0x0302, KEY_SETUP }, /* Profile */ + { 0x0343, KEY_POWER2 }, + { 0x0306, KEY_EPG }, + { 0x035a, KEY_BACK }, + { 0x0305, KEY_MENU }, + { 0x0347, KEY_INFO }, + { 0x0301, KEY_TAB }, + { 0x0342, KEY_PREVIOUSSONG },/* Replay */ + { 0x0349, KEY_VOLUMEUP }, + { 0x0309, KEY_VOLUMEDOWN }, + { 0x0354, KEY_CHANNELUP }, + { 0x030b, KEY_CHANNELDOWN }, + { 0x0316, KEY_CAMERA }, + { 0x0340, KEY_TUNER }, /* ATV/DTV */ + { 0x0345, KEY_OPEN }, + { 0x0319, KEY_1 }, + { 0x0318, KEY_2 }, + { 0x031b, KEY_3 }, + { 0x031a, KEY_4 }, + { 0x0358, KEY_5 }, + { 0x0359, KEY_6 }, + { 0x0315, KEY_7 }, + { 0x0314, KEY_8 }, + { 0x0317, KEY_9 }, + { 0x0344, KEY_ANGLE }, /* Aspect */ + { 0x0355, KEY_0 }, + { 0x0307, KEY_ZOOM }, + { 0x030a, KEY_REWIND }, + { 0x0308, KEY_PLAYPAUSE }, + { 0x034b, KEY_FASTFORWARD }, + { 0x035b, KEY_MUTE }, + { 0x0304, KEY_STOP }, + { 0x0356, KEY_RECORD }, + { 0x0357, KEY_POWER }, + { 0x0341, KEY_UNKNOWN }, /* INPUT */ + { 0x0300, KEY_UNKNOWN }, /* HD */ }; static struct rc_map_list dvico_portable_map = { .map = { .scan = rc_map_dvico_portable_table, .size = ARRAY_SIZE(rc_map_dvico_portable_table), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .rc_type = RC_TYPE_NEC, .name = RC_MAP_DVICO_PORTABLE, } }; -- cgit v1.1 From 5c8627586942b0269f81e3296dabe9f049815779 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 26 Jan 2017 15:19:33 -0200 Subject: [media] lirc: return ENOTTY when ioctl is not supported We shouldn't be using ENOSYS when a feature is not available. I've tested lirc; nothing is broken as far as I can make out. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 20 ++++++++++---------- drivers/media/rc/lirc_dev.c | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 8517d51..637b583 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -139,7 +139,7 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, } if (!dev->tx_ir) { - ret = -ENOSYS; + ret = -EINVAL; goto out; } @@ -221,19 +221,19 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, /* TX settings */ case LIRC_SET_TRANSMITTER_MASK: if (!dev->s_tx_mask) - return -ENOSYS; + return -ENOTTY; return dev->s_tx_mask(dev, val); case LIRC_SET_SEND_CARRIER: if (!dev->s_tx_carrier) - return -ENOSYS; + return -ENOTTY; return dev->s_tx_carrier(dev, val); case LIRC_SET_SEND_DUTY_CYCLE: if (!dev->s_tx_duty_cycle) - return -ENOSYS; + return -ENOTTY; if (val <= 0 || val >= 100) return -EINVAL; @@ -243,7 +243,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, /* RX settings */ case LIRC_SET_REC_CARRIER: if (!dev->s_rx_carrier_range) - return -ENOSYS; + return -ENOTTY; if (val <= 0) return -EINVAL; @@ -265,32 +265,32 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, case LIRC_SET_WIDEBAND_RECEIVER: if (!dev->s_learning_mode) - return -ENOSYS; + return -ENOTTY; return dev->s_learning_mode(dev, !!val); case LIRC_SET_MEASURE_CARRIER_MODE: if (!dev->s_carrier_report) - return -ENOSYS; + return -ENOTTY; return dev->s_carrier_report(dev, !!val); /* Generic timeout support */ case LIRC_GET_MIN_TIMEOUT: if (!dev->max_timeout) - return -ENOSYS; + return -ENOTTY; val = DIV_ROUND_UP(dev->min_timeout, 1000); break; case LIRC_GET_MAX_TIMEOUT: if (!dev->max_timeout) - return -ENOSYS; + return -ENOTTY; val = dev->max_timeout / 1000; break; case LIRC_SET_REC_TIMEOUT: if (!dev->max_timeout) - return -ENOSYS; + return -ENOTTY; tmp = val * 1000; diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 393dcca..e930c05 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -623,7 +623,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) result = put_user(ir->d.max_timeout, (__u32 __user *)arg); break; default: - result = -EINVAL; + result = -ENOTTY; } mutex_unlock(&ir->irctl_lock); -- cgit v1.1 From bc989391ab08ef75602a82cacf4fabc9f12095e5 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 8 Feb 2017 20:44:38 -0200 Subject: [media] lirc: return ENOTTY when device does support ioctl If timeouts or carrier range is not supported, return proper error. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 637b583..235d74a 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -253,6 +253,9 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, val); case LIRC_SET_REC_CARRIER_RANGE: + if (!dev->s_rx_carrier_range) + return -ENOTTY; + if (val <= 0) return -EINVAL; @@ -305,6 +308,9 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, break; case LIRC_SET_REC_TIMEOUT_REPORTS: + if (!dev->timeout) + return -ENOTTY; + lirc->send_timeout_reports = !!val; break; -- cgit v1.1 From ea80fb6d08a0015badc9a8b8ab7e95eeeaa578b1 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 26 Jan 2017 14:35:31 -0200 Subject: [media] winbond: allow timeout to be set The drivers sets the hardware to idle when a timeout occurs. This can be any reasonable value. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/winbond-cir.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index dc1c830..5a4d4a6 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -1082,7 +1082,9 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) data->dev->tx_ir = wbcir_tx; data->dev->priv = data; data->dev->dev.parent = &device->dev; - data->dev->timeout = MS_TO_NS(100); + data->dev->min_timeout = 1; + data->dev->timeout = IR_DEFAULT_TIMEOUT; + data->dev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; data->dev->rx_resolution = US_TO_NS(2); data->dev->allowed_protocols = RC_BIT_ALL_IR_DECODER; data->dev->allowed_wakeup_protocols = RC_BIT_NEC | RC_BIT_NECX | -- cgit v1.1 From ee5310e66eab685fb42b3b585b00a92b67fb59d7 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 26 Jan 2017 14:37:33 -0200 Subject: [media] gpio-ir: do not allow a timeout of 0 According to the documentation, a timeout of 0 turns off timeouts, which is not the case. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 4a4895e..b4f773b 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -158,7 +158,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) rcdev->input_id.version = 0x0100; rcdev->dev.parent = &pdev->dev; rcdev->driver_name = GPIO_IR_DRIVER_NAME; - rcdev->min_timeout = 0; + rcdev->min_timeout = 1; rcdev->timeout = IR_DEFAULT_TIMEOUT; rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; if (pdata->allowed_protos) -- cgit v1.1 From 7dc2df1476092e65d765a5a7f077ed4b85897f18 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 9 Feb 2017 20:50:20 -0200 Subject: [media] rc: lirc keymap no longer makes any sense The lirc keymap existed once upon a time to select the lirc protocol. Since '275ddb4 [media] rc-core: remove the LIRC "protocol"', IR is always passed to the lirc decoder so this keymap is no longer needed. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/Makefile | 1 - drivers/media/rc/keymaps/rc-lirc.c | 42 -------------------------------------- drivers/media/rc/st_rc.c | 2 +- 3 files changed, 1 insertion(+), 44 deletions(-) delete mode 100644 drivers/media/rc/keymaps/rc-lirc.c (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index ffe9e61..2945f99 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -57,7 +57,6 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-kworld-pc150u.o \ rc-kworld-plus-tv-analog.o \ rc-leadtek-y04g0051.o \ - rc-lirc.o \ rc-lme2510.o \ rc-manli.o \ rc-medion-x10.o \ diff --git a/drivers/media/rc/keymaps/rc-lirc.c b/drivers/media/rc/keymaps/rc-lirc.c deleted file mode 100644 index e172f5d..0000000 --- a/drivers/media/rc/keymaps/rc-lirc.c +++ /dev/null @@ -1,42 +0,0 @@ -/* rc-lirc.c - Empty dummy keytable, for use when its preferred to pass - * all raw IR data to the lirc userspace decoder. - * - * Copyright (c) 2010 by Jarod Wilson - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include - -static struct rc_map_table lirc[] = { - { }, -}; - -static struct rc_map_list lirc_map = { - .map = { - .scan = lirc, - .size = ARRAY_SIZE(lirc), - .rc_type = RC_TYPE_OTHER, - .name = RC_MAP_LIRC, - } -}; - -static int __init init_rc_map_lirc(void) -{ - return rc_map_register(&lirc_map); -} - -static void __exit exit_rc_map_lirc(void) -{ - rc_map_unregister(&lirc_map); -} - -module_init(init_rc_map_lirc) -module_exit(exit_rc_map_lirc) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jarod Wilson "); diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index f0d7190..6228d93 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -298,7 +298,7 @@ static int st_rc_probe(struct platform_device *pdev) rdev->open = st_rc_open; rdev->close = st_rc_close; rdev->driver_name = IR_ST_NAME; - rdev->map_name = RC_MAP_LIRC; + rdev->map_name = RC_MAP_EMPTY; rdev->input_name = "ST Remote Control Receiver"; ret = rc_register_device(rdev); -- cgit v1.1 From e8f4818895b3d7f34b3e5852bce77b3257a27ecc Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 8 Feb 2017 20:48:17 -0200 Subject: [media] lirc: advertise LIRC_CAN_GET_REC_RESOLUTION and improve This feature was never set. The ioctl should fail if no resolution is set. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 235d74a..de85f1d 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -263,6 +263,9 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, return 0; case LIRC_GET_REC_RESOLUTION: + if (!dev->rx_resolution) + return -ENOTTY; + val = dev->rx_resolution; break; @@ -367,8 +370,11 @@ static int ir_lirc_register(struct rc_dev *dev) if (rc) goto rbuf_init_failed; - if (dev->driver_type != RC_DRIVER_IR_RAW_TX) + if (dev->driver_type != RC_DRIVER_IR_RAW_TX) { features |= LIRC_CAN_REC_MODE2; + if (dev->rx_resolution) + features |= LIRC_CAN_GET_REC_RESOLUTION; + } if (dev->tx_ir) { features |= LIRC_CAN_SEND_PULSE; if (dev->s_tx_mask) -- cgit v1.1 From b73bc16d08d9984c78c08b1b8e1bb17563dc10a9 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 11 Feb 2017 20:33:38 -0200 Subject: [media] mce_kbd: add encoder Split the protocol into two variants, one for keyboard and one for mouse data. Note that the mce_kbd protocol cannot be used on the igorplugusb, since the IR is too long. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/igorplugusb.c | 2 +- drivers/media/rc/ir-mce_kbd-decoder.c | 49 +++++++++++++++++++++++++++++++++-- drivers/media/rc/rc-core-priv.h | 2 +- drivers/media/rc/rc-ir-raw.c | 6 ++--- drivers/media/rc/rc-main.c | 8 ++++-- 5 files changed, 58 insertions(+), 9 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c index 0f0ed4e..cb6d4f1 100644 --- a/drivers/media/rc/igorplugusb.c +++ b/drivers/media/rc/igorplugusb.c @@ -205,7 +205,7 @@ static int igorplugusb_probe(struct usb_interface *intf, rc->allowed_protocols = RC_BIT_ALL_IR_DECODER & ~(RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | - RC_BIT_SONY20 | RC_BIT_MCE_KBD | RC_BIT_SANYO); + RC_BIT_SONY20 | RC_BIT_SANYO); rc->priv = ir; rc->driver_name = DRIVER_NAME; diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 5226d51..6a4d58b 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -23,7 +23,7 @@ * - MCIR-2 29-bit IR signals used for mouse movement and buttons * - MCIR-2 32-bit IR signals used for standard keyboard keys * - * The media keys on the keyboard send RC-6 signals that are inditinguishable + * The media keys on the keyboard send RC-6 signals that are indistinguishable * from the keys of the same name on the stock MCE remote, and will be handled * by the standard RC-6 decoder, and be made available to the system via the * input device for the remote, rather than the keyboard/mouse one. @@ -339,6 +339,7 @@ again: } data->state = STATE_INACTIVE; + input_event(data->idev, EV_MSC, MSC_SCAN, scancode); input_sync(data->idev); return 0; } @@ -418,9 +419,53 @@ static int ir_mce_kbd_unregister(struct rc_dev *dev) return 0; } +static const struct ir_raw_timings_manchester ir_mce_kbd_timings = { + .leader = MCIR2_PREFIX_PULSE, + .invert = 1, + .clock = MCIR2_UNIT, + .trailer_space = MCIR2_UNIT * 10, +}; + +/** + * ir_mce_kbd_encode() - Encode a scancode as a stream of raw events + * + * @protocol: protocol to encode + * @scancode: scancode to encode + * @events: array of raw ir events to write into + * @max: maximum size of @events + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + */ +static int ir_mce_kbd_encode(enum rc_type protocol, u32 scancode, + struct ir_raw_event *events, unsigned int max) +{ + struct ir_raw_event *e = events; + int len, ret; + u64 raw; + + if (protocol == RC_TYPE_MCIR2_KBD) { + raw = scancode | + ((u64)MCIR2_KEYBOARD_HEADER << MCIR2_KEYBOARD_NBITS); + len = MCIR2_KEYBOARD_NBITS + MCIR2_HEADER_NBITS + 1; + } else { + raw = scancode | + ((u64)MCIR2_MOUSE_HEADER << MCIR2_MOUSE_NBITS); + len = MCIR2_MOUSE_NBITS + MCIR2_HEADER_NBITS + 1; + } + + ret = ir_raw_gen_manchester(&e, max, &ir_mce_kbd_timings, len, raw); + if (ret < 0) + return ret; + + return e - events; +} + static struct ir_raw_handler mce_kbd_handler = { - .protocols = RC_BIT_MCE_KBD, + .protocols = RC_BIT_MCIR2_KBD | RC_BIT_MCIR2_MSE, .decode = ir_mce_kbd_decode, + .encode = ir_mce_kbd_encode, .raw_register = ir_mce_kbd_register, .raw_unregister = ir_mce_kbd_unregister, }; diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index a70a5c55..0455b27 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -185,7 +185,7 @@ struct ir_raw_timings_manchester { int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, const struct ir_raw_timings_manchester *timings, - unsigned int n, unsigned int data); + unsigned int n, u64 data); /** * ir_raw_gen_pulse_space() - generate pulse and space raw events. diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 7fa84b6..90f66dc 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -258,13 +258,13 @@ static void ir_raw_disable_protocols(struct rc_dev *dev, u64 protocols) */ int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, const struct ir_raw_timings_manchester *timings, - unsigned int n, unsigned int data) + unsigned int n, u64 data) { bool need_pulse; - unsigned int i; + u64 i; int ret = -ENOBUFS; - i = 1 << (n - 1); + i = BIT_ULL(n - 1); if (timings->leader) { if (!max--) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 2424946..b189f24 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -746,6 +746,8 @@ static int rc_validate_filter(struct rc_dev *dev, [RC_TYPE_NECX] = 0xffffff, [RC_TYPE_NEC32] = 0xffffffff, [RC_TYPE_SANYO] = 0x1fffff, + [RC_TYPE_MCIR2_KBD] = 0xffff, + [RC_TYPE_MCIR2_MSE] = 0x1fffff, [RC_TYPE_RC6_0] = 0xffff, [RC_TYPE_RC6_6A_20] = 0xfffff, [RC_TYPE_RC6_6A_24] = 0xffffff, @@ -878,7 +880,8 @@ static const struct { { RC_BIT_RC5_SZ, "rc-5-sz", "ir-rc5-decoder" }, { RC_BIT_SANYO, "sanyo", "ir-sanyo-decoder" }, { RC_BIT_SHARP, "sharp", "ir-sharp-decoder" }, - { RC_BIT_MCE_KBD, "mce_kbd", "ir-mce_kbd-decoder" }, + { RC_BIT_MCIR2_KBD | + RC_BIT_MCIR2_MSE, "mce_kbd", "ir-mce_kbd-decoder" }, { RC_BIT_XMP, "xmp", "ir-xmp-decoder" }, { RC_BIT_CEC, "cec", NULL }, }; @@ -1346,7 +1349,8 @@ static const char * const proto_variant_names[] = { [RC_TYPE_NECX] = "nec-x", [RC_TYPE_NEC32] = "nec-32", [RC_TYPE_SANYO] = "sanyo", - [RC_TYPE_MCE_KBD] = "mce_kbd", + [RC_TYPE_MCIR2_KBD] = "mcir2-kbd", + [RC_TYPE_MCIR2_MSE] = "mcir2-mse", [RC_TYPE_RC6_0] = "rc-6-0", [RC_TYPE_RC6_6A_20] = "rc-6-6a-20", [RC_TYPE_RC6_6A_24] = "rc-6-6a-24", -- cgit v1.1 From 069f3b10aed966b2da6bb1161af41da0e8880724 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 13 Feb 2017 20:53:23 -0200 Subject: [media] serial_ir: iommap is a memory address, not bool This has been broken for a long time, so presumably it is not used. I have no hardware to test this on. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=61401 Fixes: 90ab5ee ("module_param: make bool parameters really bool") Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/serial_ir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c index 923fb22..7b3a3b5 100644 --- a/drivers/media/rc/serial_ir.c +++ b/drivers/media/rc/serial_ir.c @@ -56,7 +56,7 @@ struct serial_ir_hw { static int type; static int io; static int irq; -static bool iommap; +static ulong iommap; static int ioshift; static bool softcarrier = true; static bool share_irq; @@ -836,7 +836,7 @@ module_param(io, int, 0444); MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); /* some architectures (e.g. intel xscale) have memory mapped registers */ -module_param(iommap, bool, 0444); +module_param(iommap, ulong, 0444); MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O (0 = no memory mapped io)"); /* -- cgit v1.1 From 74c839b2f5544fd77fdb34a99b577965d4812edf Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 30 Jan 2017 13:49:58 -0200 Subject: [media] lirc: use refcounting for lirc devices If a lirc device is unplugged, the struct rc_dev is freed even though userspace can still have a file descriptor open on the lirc chardev. The rc_dev structure can be used in a subsequent, or even currently executing ioctl, read or write. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 120 +++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 69 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index e930c05..c8f8edd 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -54,7 +54,8 @@ struct irctl { struct lirc_buffer *buf; unsigned int chunk_size; - struct cdev *cdev; + struct device dev; + struct cdev cdev; struct task_struct *task; long jiffies_to_wait; @@ -76,15 +77,21 @@ static void lirc_irctl_init(struct irctl *ir) ir->d.minor = NOPLUG; } -static void lirc_irctl_cleanup(struct irctl *ir) +static void lirc_release(struct device *ld) { - device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); + struct irctl *ir = container_of(ld, struct irctl, dev); + + put_device(ir->dev.parent); if (ir->buf != ir->d.rbuf) { lirc_buffer_free(ir->buf); kfree(ir->buf); } - ir->buf = NULL; + + mutex_lock(&lirc_dev_lock); + irctls[ir->d.minor] = NULL; + mutex_unlock(&lirc_dev_lock); + kfree(ir); } /* helper function @@ -157,32 +164,21 @@ static int lirc_cdev_add(struct irctl *ir) struct cdev *cdev; int retval; - cdev = cdev_alloc(); - if (!cdev) - return -ENOMEM; + cdev = &ir->cdev; if (d->fops) { - cdev->ops = d->fops; + cdev_init(cdev, d->fops); cdev->owner = d->owner; } else { - cdev->ops = &lirc_dev_fops; + cdev_init(cdev, &lirc_dev_fops); cdev->owner = THIS_MODULE; } retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor); if (retval) - goto err_out; - - retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); - if (retval) - goto err_out; - - ir->cdev = cdev; - - return 0; + return retval; -err_out: - cdev_del(cdev); - return retval; + cdev->kobj.parent = &ir->dev.kobj; + return cdev_add(cdev, ir->dev.devt, 1); } static int lirc_allocate_buffer(struct irctl *ir) @@ -304,9 +300,12 @@ static int lirc_allocate_driver(struct lirc_driver *d) ir->d = *d; - device_create(lirc_class, ir->d.dev, - MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL, - "lirc%u", ir->d.minor); + ir->dev.devt = MKDEV(MAJOR(lirc_base_dev), ir->d.minor); + ir->dev.class = lirc_class; + ir->dev.parent = d->dev; + ir->dev.release = lirc_release; + dev_set_name(&ir->dev, "lirc%d", ir->d.minor); + device_initialize(&ir->dev); if (d->sample_rate) { ir->jiffies_to_wait = HZ / d->sample_rate; @@ -329,14 +328,22 @@ static int lirc_allocate_driver(struct lirc_driver *d) goto out_sysfs; ir->attached = 1; + + err = device_add(&ir->dev); + if (err) + goto out_cdev; + mutex_unlock(&lirc_dev_lock); + get_device(ir->dev.parent); + dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", ir->d.name, ir->d.minor); return minor; - +out_cdev: + cdev_del(&ir->cdev); out_sysfs: - device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); + put_device(&ir->dev); out_lock: mutex_unlock(&lirc_dev_lock); @@ -364,7 +371,6 @@ EXPORT_SYMBOL(lirc_register_driver); int lirc_unregister_driver(int minor) { struct irctl *ir; - struct cdev *cdev; if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { pr_err("minor (%d) must be between 0 and %d!\n", @@ -378,8 +384,6 @@ int lirc_unregister_driver(int minor) return -ENOENT; } - cdev = ir->cdev; - mutex_lock(&lirc_dev_lock); if (ir->d.minor != minor) { @@ -401,22 +405,20 @@ int lirc_unregister_driver(int minor) dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", ir->d.name, ir->d.minor); wake_up_interruptible(&ir->buf->wait_poll); - mutex_lock(&ir->irctl_lock); + } - if (ir->d.set_use_dec) - ir->d.set_use_dec(ir->d.data); + mutex_lock(&ir->irctl_lock); - module_put(cdev->owner); - mutex_unlock(&ir->irctl_lock); - } else { - lirc_irctl_cleanup(ir); - cdev_del(cdev); - kfree(ir); - irctls[minor] = NULL; - } + if (ir->d.set_use_dec) + ir->d.set_use_dec(ir->d.data); + mutex_unlock(&ir->irctl_lock); mutex_unlock(&lirc_dev_lock); + device_del(&ir->dev); + cdev_del(&ir->cdev); + put_device(&ir->dev); + return 0; } EXPORT_SYMBOL(lirc_unregister_driver); @@ -424,7 +426,6 @@ EXPORT_SYMBOL(lirc_unregister_driver); int lirc_dev_fop_open(struct inode *inode, struct file *file) { struct irctl *ir; - struct cdev *cdev; int retval = 0; if (iminor(inode) >= MAX_IRCTL_DEVICES) { @@ -459,18 +460,14 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) goto error; } - cdev = ir->cdev; - if (try_module_get(cdev->owner)) { - ir->open++; - if (ir->d.set_use_inc) - retval = ir->d.set_use_inc(ir->d.data); - - if (retval) { - module_put(cdev->owner); - ir->open--; - } else if (ir->buf) { + ir->open++; + if (ir->d.set_use_inc) + retval = ir->d.set_use_inc(ir->d.data); + if (retval) { + ir->open--; + } else { + if (ir->buf) lirc_buffer_clear(ir->buf); - } if (ir->task) wake_up_process(ir->task); } @@ -487,7 +484,6 @@ EXPORT_SYMBOL(lirc_dev_fop_open); int lirc_dev_fop_close(struct inode *inode, struct file *file) { struct irctl *ir = irctls[iminor(inode)]; - struct cdev *cdev; int ret; if (!ir) { @@ -495,25 +491,14 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file) return -EINVAL; } - cdev = ir->cdev; - ret = mutex_lock_killable(&lirc_dev_lock); WARN_ON(ret); rc_close(ir->d.rdev); ir->open--; - if (ir->attached) { - if (ir->d.set_use_dec) - ir->d.set_use_dec(ir->d.data); - module_put(cdev->owner); - } else { - lirc_irctl_cleanup(ir); - cdev_del(cdev); - irctls[ir->d.minor] = NULL; - kfree(ir); - } - + if (ir->d.set_use_dec) + ir->d.set_use_dec(ir->d.data); if (!ret) mutex_unlock(&lirc_dev_lock); @@ -780,15 +765,12 @@ static int __init lirc_dev_init(void) return retval; } - pr_info("IR Remote Control driver registered, major %d\n", MAJOR(lirc_base_dev)); return 0; } - - static void __exit lirc_dev_exit(void) { class_destroy(lirc_class); -- cgit v1.1 From 03eb2a557ed552e920a0942b774aaf931596eec1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 7 Mar 2017 15:14:13 -0300 Subject: [media] mceusb: fix NULL-deref at probe Make sure to check for the required out endpoint to avoid dereferencing a NULL-pointer in mce_request_packet should a malicious device lack such an endpoint. Note that this path is hit during probe. Fixes: 66e89522aff7 ("V4L/DVB: IR: add mceusb IR receiver driver") Cc: stable # 2.6.36 Signed-off-by: Johan Hovold Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 238d8ea..93b16fe 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1288,8 +1288,8 @@ static int mceusb_dev_probe(struct usb_interface *intf, } } } - if (ep_in == NULL) { - dev_dbg(&intf->dev, "inbound and/or endpoint not found"); + if (!ep_in || !ep_out) { + dev_dbg(&intf->dev, "required endpoints not found\n"); return -ENODEV; } -- cgit v1.1 From ec6b0bd54e00beabfdf45d1f3aba8dfb79f52b53 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 15 Mar 2017 08:31:36 -0300 Subject: [media] st_rc: simplify optional reset handling As of commit bb475230b8e5 ("reset: make optional functions really optional"), the reset framework API calls use NULL pointers to describe optional, non-present reset controls. This allows to return errors from reset_control_get_optional and to call reset_control_(de)assert unconditionally. Signed-off-by: Philipp Zabel Acked-by: Patrice Chotard Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/st_rc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index 6228d93..a08e1dd 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -165,8 +165,7 @@ static void st_rc_hardware_init(struct st_rc_device *dev) unsigned int rx_sampling_freq_div; /* Enable the IP */ - if (dev->rstc) - reset_control_deassert(dev->rstc); + reset_control_deassert(dev->rstc); clk_prepare_enable(dev->sys_clock); baseclock = clk_get_rate(dev->sys_clock); @@ -281,10 +280,11 @@ static int st_rc_probe(struct platform_device *pdev) else rc_dev->rx_base = rc_dev->base; - rc_dev->rstc = reset_control_get_optional(dev, NULL); - if (IS_ERR(rc_dev->rstc)) - rc_dev->rstc = NULL; + if (IS_ERR(rc_dev->rstc)) { + ret = PTR_ERR(rc_dev->rstc); + goto err; + } rc_dev->dev = dev; platform_set_drvdata(pdev, rc_dev); @@ -352,8 +352,7 @@ static int st_rc_suspend(struct device *dev) writel(0x00, rc_dev->rx_base + IRB_RX_EN); writel(0x00, rc_dev->rx_base + IRB_RX_INT_EN); clk_disable_unprepare(rc_dev->sys_clock); - if (rc_dev->rstc) - reset_control_assert(rc_dev->rstc); + reset_control_assert(rc_dev->rstc); } return 0; -- cgit v1.1 From c3d4fb0fb41f4b5eafeee51173c14e50be12f839 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 15 Mar 2017 08:31:38 -0300 Subject: [media] rc: sunxi-cir: simplify optional reset handling As of commit bb475230b8e5 ("reset: make optional functions really optional"), the reset framework API calls use NULL pointers to describe optional, non-present reset controls. This allows to return errors from devm_reset_control_get_optional and to call reset_control_(de)assert unconditionally. Signed-off-by: Philipp Zabel Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/sunxi-cir.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index 25b0061..4b785dd 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -174,16 +174,11 @@ static int sunxi_ir_probe(struct platform_device *pdev) /* Reset (optional) */ ir->rst = devm_reset_control_get_optional(dev, NULL); - if (IS_ERR(ir->rst)) { - ret = PTR_ERR(ir->rst); - if (ret == -EPROBE_DEFER) - return ret; - ir->rst = NULL; - } else { - ret = reset_control_deassert(ir->rst); - if (ret) - return ret; - } + if (IS_ERR(ir->rst)) + return PTR_ERR(ir->rst); + ret = reset_control_deassert(ir->rst); + if (ret) + return ret; ret = clk_set_rate(ir->clk, SUNXI_IR_BASE_CLK); if (ret) { @@ -291,8 +286,7 @@ exit_clkdisable_clk: exit_clkdisable_apb_clk: clk_disable_unprepare(ir->apb_clk); exit_reset_assert: - if (ir->rst) - reset_control_assert(ir->rst); + reset_control_assert(ir->rst); return ret; } @@ -304,8 +298,7 @@ static int sunxi_ir_remove(struct platform_device *pdev) clk_disable_unprepare(ir->clk); clk_disable_unprepare(ir->apb_clk); - if (ir->rst) - reset_control_assert(ir->rst); + reset_control_assert(ir->rst); spin_lock_irqsave(&ir->ir_lock, flags); /* disable IR IRQ */ -- cgit v1.1 From e66267161971155a8b4756b4e17f2f2f82b9f842 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 7 Mar 2017 17:07:59 -0300 Subject: [media] rc: promote lirc_sir out of staging Rename lirc_sir to sir_ir in the process. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 9 + drivers/media/rc/Makefile | 1 + drivers/media/rc/sir_ir.c | 438 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 448 insertions(+) create mode 100644 drivers/media/rc/sir_ir.c (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index d1d3fd0..e422f3d 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -426,4 +426,13 @@ config IR_SERIAL_TRANSMITTER ---help--- Serial Port Transmitter support +config IR_SIR + tristate "Built-in SIR IrDA port" + depends on RC_CORE + ---help--- + Say Y if you want to use a IrDA SIR port Transceivers. + + To compile this driver as a module, choose M here: the module will + be called sir-ir. + endif #RC_DEVICES diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 679aa0a..245e2c2 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -39,4 +39,5 @@ obj-$(CONFIG_RC_ST) += st_rc.o obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o obj-$(CONFIG_IR_IMG) += img-ir/ obj-$(CONFIG_IR_SERIAL) += serial_ir.o +obj-$(CONFIG_IR_SIR) += sir_ir.o obj-$(CONFIG_IR_MTK) += mtk-cir.o diff --git a/drivers/media/rc/sir_ir.c b/drivers/media/rc/sir_ir.c new file mode 100644 index 0000000..e12ec50 --- /dev/null +++ b/drivers/media/rc/sir_ir.c @@ -0,0 +1,438 @@ +/* + * IR SIR driver, (C) 2000 Milan Pikula + * + * sir_ir - Device driver for use with SIR (serial infra red) + * mode of IrDA on many notebooks. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* SECTION: Definitions */ +#define PULSE '[' + +/* 9bit * 1s/115200bit in milli seconds = 78.125ms*/ +#define TIME_CONST (9000000ul / 115200ul) + +/* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */ +#define SIR_TIMEOUT (HZ * 5 / 100) + +/* onboard sir ports are typically com3 */ +static int io = 0x3e8; +static int irq = 4; +static int threshold = 3; + +static DEFINE_SPINLOCK(timer_lock); +static struct timer_list timerlist; +/* time of last signal change detected */ +static ktime_t last; +/* time of last UART data ready interrupt */ +static ktime_t last_intr_time; +static int last_value; +static struct rc_dev *rcdev; + +static struct platform_device *sir_ir_dev; + +static DEFINE_SPINLOCK(hardware_lock); + +/* SECTION: Prototypes */ + +/* Communication with user-space */ +static void add_read_queue(int flag, unsigned long val); +static int init_chrdev(void); +/* Hardware */ +static irqreturn_t sir_interrupt(int irq, void *dev_id); +static void send_space(unsigned long len); +static void send_pulse(unsigned long len); +static int init_hardware(void); +static void drop_hardware(void); +/* Initialisation */ +static int init_port(void); +static void drop_port(void); + +static inline unsigned int sinp(int offset) +{ + return inb(io + offset); +} + +static inline void soutp(int offset, int value) +{ + outb(value, io + offset); +} + +/* SECTION: Communication with user-space */ +static int sir_tx_ir(struct rc_dev *dev, unsigned int *tx_buf, + unsigned int count) +{ + unsigned long flags; + int i; + + local_irq_save(flags); + for (i = 0; i < count;) { + if (tx_buf[i]) + send_pulse(tx_buf[i]); + i++; + if (i >= count) + break; + if (tx_buf[i]) + send_space(tx_buf[i]); + i++; + } + local_irq_restore(flags); + + return count; +} + +static void add_read_queue(int flag, unsigned long val) +{ + DEFINE_IR_RAW_EVENT(ev); + + pr_debug("add flag %d with val %lu\n", flag, val); + + /* + * statistically, pulses are ~TIME_CONST/2 too long. we could + * maybe make this more exact, but this is good enough + */ + if (flag) { + /* pulse */ + if (val > TIME_CONST / 2) + val -= TIME_CONST / 2; + else /* should not ever happen */ + val = 1; + ev.pulse = true; + } else { + val += TIME_CONST / 2; + } + ev.duration = US_TO_NS(val); + + ir_raw_event_store_with_filter(rcdev, &ev); +} + +static int init_chrdev(void) +{ + rcdev = devm_rc_allocate_device(&sir_ir_dev->dev, RC_DRIVER_IR_RAW); + if (!rcdev) + return -ENOMEM; + + rcdev->input_name = "SIR IrDA port"; + rcdev->input_phys = KBUILD_MODNAME "/input0"; + rcdev->input_id.bustype = BUS_HOST; + rcdev->input_id.vendor = 0x0001; + rcdev->input_id.product = 0x0001; + rcdev->input_id.version = 0x0100; + rcdev->tx_ir = sir_tx_ir; + rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rcdev->driver_name = KBUILD_MODNAME; + rcdev->map_name = RC_MAP_RC6_MCE; + rcdev->timeout = IR_DEFAULT_TIMEOUT; + rcdev->dev.parent = &sir_ir_dev->dev; + + return devm_rc_register_device(&sir_ir_dev->dev, rcdev); +} + +/* SECTION: Hardware */ +static void sir_timeout(unsigned long data) +{ + /* + * if last received signal was a pulse, but receiving stopped + * within the 9 bit frame, we need to finish this pulse and + * simulate a signal change to from pulse to space. Otherwise + * upper layers will receive two sequences next time. + */ + + unsigned long flags; + unsigned long pulse_end; + + /* avoid interference with interrupt */ + spin_lock_irqsave(&timer_lock, flags); + if (last_value) { + /* clear unread bits in UART and restart */ + outb(UART_FCR_CLEAR_RCVR, io + UART_FCR); + /* determine 'virtual' pulse end: */ + pulse_end = min_t(unsigned long, + ktime_us_delta(last, last_intr_time), + IR_MAX_DURATION); + dev_dbg(&sir_ir_dev->dev, "timeout add %d for %lu usec\n", + last_value, pulse_end); + add_read_queue(last_value, pulse_end); + last_value = 0; + last = last_intr_time; + } + spin_unlock_irqrestore(&timer_lock, flags); + ir_raw_event_handle(rcdev); +} + +static irqreturn_t sir_interrupt(int irq, void *dev_id) +{ + unsigned char data; + ktime_t curr_time; + static unsigned long delt; + unsigned long deltintr; + unsigned long flags; + int iir, lsr; + + while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) { + switch (iir & UART_IIR_ID) { /* FIXME toto treba preriedit */ + case UART_IIR_MSI: + (void)inb(io + UART_MSR); + break; + case UART_IIR_RLSI: + case UART_IIR_THRI: + (void)inb(io + UART_LSR); + break; + case UART_IIR_RDI: + /* avoid interference with timer */ + spin_lock_irqsave(&timer_lock, flags); + do { + del_timer(&timerlist); + data = inb(io + UART_RX); + curr_time = ktime_get(); + delt = min_t(unsigned long, + ktime_us_delta(last, curr_time), + IR_MAX_DURATION); + deltintr = min_t(unsigned long, + ktime_us_delta(last_intr_time, + curr_time), + IR_MAX_DURATION); + dev_dbg(&sir_ir_dev->dev, "t %lu, d %d\n", + deltintr, (int)data); + /* + * if nothing came in last X cycles, + * it was gap + */ + if (deltintr > TIME_CONST * threshold) { + if (last_value) { + dev_dbg(&sir_ir_dev->dev, "GAP\n"); + /* simulate signal change */ + add_read_queue(last_value, + delt - + deltintr); + last_value = 0; + last = last_intr_time; + delt = deltintr; + } + } + data = 1; + if (data ^ last_value) { + /* + * deltintr > 2*TIME_CONST, remember? + * the other case is timeout + */ + add_read_queue(last_value, + delt - TIME_CONST); + last_value = data; + last = curr_time; + last = ktime_sub_us(last, + TIME_CONST); + } + last_intr_time = curr_time; + if (data) { + /* + * start timer for end of + * sequence detection + */ + timerlist.expires = jiffies + + SIR_TIMEOUT; + add_timer(&timerlist); + } + + lsr = inb(io + UART_LSR); + } while (lsr & UART_LSR_DR); /* data ready */ + spin_unlock_irqrestore(&timer_lock, flags); + break; + default: + break; + } + } + ir_raw_event_handle(rcdev); + return IRQ_RETVAL(IRQ_HANDLED); +} + +static void send_space(unsigned long len) +{ + usleep_range(len, len + 25); +} + +static void send_pulse(unsigned long len) +{ + long bytes_out = len / TIME_CONST; + + if (bytes_out == 0) + bytes_out++; + + while (bytes_out--) { + outb(PULSE, io + UART_TX); + /* FIXME treba seriozne cakanie z char/serial.c */ + while (!(inb(io + UART_LSR) & UART_LSR_THRE)) + ; + } +} + +static int init_hardware(void) +{ + unsigned long flags; + + spin_lock_irqsave(&hardware_lock, flags); + /* reset UART */ + outb(0, io + UART_MCR); + outb(0, io + UART_IER); + /* init UART */ + /* set DLAB, speed = 115200 */ + outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR); + outb(1, io + UART_DLL); outb(0, io + UART_DLM); + /* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */ + outb(UART_LCR_WLEN7, io + UART_LCR); + /* FIFO operation */ + outb(UART_FCR_ENABLE_FIFO, io + UART_FCR); + /* interrupts */ + /* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */ + outb(UART_IER_RDI, io + UART_IER); + /* turn on UART */ + outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, io + UART_MCR); + spin_unlock_irqrestore(&hardware_lock, flags); + return 0; +} + +static void drop_hardware(void) +{ + unsigned long flags; + + spin_lock_irqsave(&hardware_lock, flags); + + /* turn off interrupts */ + outb(0, io + UART_IER); + + spin_unlock_irqrestore(&hardware_lock, flags); +} + +/* SECTION: Initialisation */ + +static int init_port(void) +{ + int retval; + + setup_timer(&timerlist, sir_timeout, 0); + + /* get I/O port access and IRQ line */ + if (!request_region(io, 8, KBUILD_MODNAME)) { + pr_err("i/o port 0x%.4x already in use.\n", io); + return -EBUSY; + } + retval = request_irq(irq, sir_interrupt, 0, + KBUILD_MODNAME, NULL); + if (retval < 0) { + release_region(io, 8); + pr_err("IRQ %d already in use.\n", irq); + return retval; + } + pr_info("I/O port 0x%.4x, IRQ %d.\n", io, irq); + + return 0; +} + +static void drop_port(void) +{ + free_irq(irq, NULL); + del_timer_sync(&timerlist); + release_region(io, 8); +} + +static int init_sir_ir(void) +{ + int retval; + + retval = init_port(); + if (retval < 0) + return retval; + init_hardware(); + return 0; +} + +static int sir_ir_probe(struct platform_device *dev) +{ + int retval; + + retval = init_chrdev(); + if (retval < 0) + return retval; + + return init_sir_ir(); +} + +static int sir_ir_remove(struct platform_device *dev) +{ + return 0; +} + +static struct platform_driver sir_ir_driver = { + .probe = sir_ir_probe, + .remove = sir_ir_remove, + .driver = { + .name = "sir_ir", + }, +}; + +static int __init sir_ir_init(void) +{ + int retval; + + retval = platform_driver_register(&sir_ir_driver); + if (retval) + return retval; + + sir_ir_dev = platform_device_alloc("sir_ir", 0); + if (!sir_ir_dev) { + retval = -ENOMEM; + goto pdev_alloc_fail; + } + + retval = platform_device_add(sir_ir_dev); + if (retval) + goto pdev_add_fail; + + return 0; + +pdev_add_fail: + platform_device_put(sir_ir_dev); +pdev_alloc_fail: + platform_driver_unregister(&sir_ir_driver); + return retval; +} + +static void __exit sir_ir_exit(void) +{ + drop_hardware(); + drop_port(); + platform_device_unregister(sir_ir_dev); + platform_driver_unregister(&sir_ir_driver); +} + +module_init(sir_ir_init); +module_exit(sir_ir_exit); + +MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports"); +MODULE_AUTHOR("Milan Pikula"); +MODULE_LICENSE("GPL"); + +module_param(io, int, 0444); +MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); + +module_param(irq, int, 0444); +MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); + +module_param(threshold, int, 0444); +MODULE_PARM_DESC(threshold, "space detection threshold (3)"); -- cgit v1.1 From bd742c6586401de18d2009dc891cb75ab7fdd795 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Sat, 8 Apr 2017 22:34:08 -0300 Subject: [media] imon: use setup_timer Use setup_timer() instead of init_timer() to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 89823d2..3489010 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -2412,9 +2412,8 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, mutex_lock(&ictx->lock); if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { - init_timer(&ictx->ttimer); - ictx->ttimer.data = (unsigned long)ictx; - ictx->ttimer.function = imon_touch_display_timeout; + setup_timer(&ictx->ttimer, imon_touch_display_timeout, + (unsigned long)ictx); } ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf)); -- cgit v1.1