summaryrefslogtreecommitdiff
path: root/drivers/media/rc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/rc')
-rw-r--r--drivers/media/rc/Kconfig2
-rw-r--r--drivers/media/rc/ene_ir.c2
-rw-r--r--drivers/media/rc/iguanair.c2
-rw-r--r--drivers/media/rc/ir-lirc-codec.c5
-rw-r--r--drivers/media/rc/ir-rx51.c229
-rw-r--r--drivers/media/rc/keymaps/Makefile2
-rw-r--r--drivers/media/rc/keymaps/rc-cec.c182
-rw-r--r--drivers/media/rc/keymaps/rc-dtt200u.c59
-rw-r--r--drivers/media/rc/lirc_dev.c299
-rw-r--r--drivers/media/rc/mceusb.c8
-rw-r--r--drivers/media/rc/nuvoton-cir.c137
-rw-r--r--drivers/media/rc/nuvoton-cir.h25
-rw-r--r--drivers/media/rc/rc-main.c11
-rw-r--r--drivers/media/rc/redrat3.c84
-rw-r--r--drivers/media/rc/winbond-cir.c4
15 files changed, 548 insertions, 503 deletions
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index bd4d68500..370e16e07 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -336,7 +336,7 @@ config IR_TTUSBIR
config IR_RX51
tristate "Nokia N900 IR transmitter diode"
- depends on OMAP_DM_TIMER && ARCH_OMAP2PLUS && LIRC && !ARCH_MULTIPLATFORM
+ depends on OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS && LIRC
---help---
Say Y or M here if you want to enable support for the IR
transmitter diode built in the Nokia N900 (RX51) device.
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index 8d77e1c4a..d1c61cd03 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -904,7 +904,7 @@ static int ene_set_tx_carrier(struct rc_dev *rdev, u32 carrier)
dbg("TX: out of range %d-%d kHz carrier",
2000 / ENE_CIRMOD_PRD_MIN, 2000 / ENE_CIRMOD_PRD_MAX);
- return -1;
+ return -EINVAL;
}
dev->tx_period = period;
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index ee60e17fb..5f634545d 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -330,7 +330,7 @@ static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier)
mutex_unlock(&ir->lock);
- return carrier;
+ return 0;
}
static int iguanair_set_tx_mask(struct rc_dev *dev, uint32_t mask)
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 5effc65d2..c3277308a 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -292,7 +292,10 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
tmp > dev->max_timeout)
return -EINVAL;
- dev->timeout = tmp;
+ if (dev->s_timeout)
+ ret = dev->s_timeout(dev, tmp);
+ if (!ret)
+ dev->timeout = tmp;
break;
case LIRC_SET_REC_TIMEOUT_REPORTS:
diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c
index 4e1711a40..82fb6f2ca 100644
--- a/drivers/media/rc/ir-rx51.c
+++ b/drivers/media/rc/ir-rx51.c
@@ -12,22 +12,17 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
-
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/wait.h>
-
-#include <plat/dmtimer.h>
-#include <plat/clock.h>
+#include <linux/pwm.h>
+#include <linux/of.h>
+#include <linux/hrtimer.h>
#include <media/lirc.h>
#include <media/lirc_dev.h>
@@ -41,100 +36,51 @@
#define WBUF_LEN 256
-#define TIMER_MAX_VALUE 0xffffffff
-
struct lirc_rx51 {
- struct omap_dm_timer *pwm_timer;
- struct omap_dm_timer *pulse_timer;
+ struct pwm_device *pwm;
+ struct hrtimer timer;
struct device *dev;
struct lirc_rx51_platform_data *pdata;
wait_queue_head_t wqueue;
- unsigned long fclk_khz;
unsigned int freq; /* carrier frequency */
unsigned int duty_cycle; /* carrier duty cycle */
- unsigned int irq_num;
- unsigned int match;
int wbuf[WBUF_LEN];
int wbuf_index;
unsigned long device_is_open;
- int pwm_timer_num;
};
-static void lirc_rx51_on(struct lirc_rx51 *lirc_rx51)
+static inline void lirc_rx51_on(struct lirc_rx51 *lirc_rx51)
{
- omap_dm_timer_set_pwm(lirc_rx51->pwm_timer, 0, 1,
- OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+ pwm_enable(lirc_rx51->pwm);
}
-static void lirc_rx51_off(struct lirc_rx51 *lirc_rx51)
+static inline void lirc_rx51_off(struct lirc_rx51 *lirc_rx51)
{
- omap_dm_timer_set_pwm(lirc_rx51->pwm_timer, 0, 1,
- OMAP_TIMER_TRIGGER_NONE);
+ pwm_disable(lirc_rx51->pwm);
}
static int init_timing_params(struct lirc_rx51 *lirc_rx51)
{
- u32 load, match;
+ struct pwm_device *pwm = lirc_rx51->pwm;
+ int duty, period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, lirc_rx51->freq);
- load = -(lirc_rx51->fclk_khz * 1000 / lirc_rx51->freq);
- match = -(lirc_rx51->duty_cycle * -load / 100);
- omap_dm_timer_set_load(lirc_rx51->pwm_timer, 1, load);
- omap_dm_timer_set_match(lirc_rx51->pwm_timer, 1, match);
- omap_dm_timer_write_counter(lirc_rx51->pwm_timer, TIMER_MAX_VALUE - 2);
- omap_dm_timer_start(lirc_rx51->pwm_timer);
- omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
- omap_dm_timer_start(lirc_rx51->pulse_timer);
+ duty = DIV_ROUND_CLOSEST(lirc_rx51->duty_cycle * period, 100);
- lirc_rx51->match = 0;
+ pwm_config(pwm, duty, period);
return 0;
}
-#define tics_after(a, b) ((long)(b) - (long)(a) < 0)
-
-static int pulse_timer_set_timeout(struct lirc_rx51 *lirc_rx51, int usec)
+static enum hrtimer_restart lirc_rx51_timer_cb(struct hrtimer *timer)
{
- int counter;
-
- BUG_ON(usec < 0);
-
- if (lirc_rx51->match == 0)
- counter = omap_dm_timer_read_counter(lirc_rx51->pulse_timer);
- else
- counter = lirc_rx51->match;
-
- counter += (u32)(lirc_rx51->fclk_khz * usec / (1000));
- omap_dm_timer_set_match(lirc_rx51->pulse_timer, 1, counter);
- omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer,
- OMAP_TIMER_INT_MATCH);
- if (tics_after(omap_dm_timer_read_counter(lirc_rx51->pulse_timer),
- counter)) {
- return 1;
- }
- return 0;
-}
-
-static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr)
-{
- unsigned int retval;
- struct lirc_rx51 *lirc_rx51 = ptr;
-
- retval = omap_dm_timer_read_status(lirc_rx51->pulse_timer);
- if (!retval)
- return IRQ_NONE;
+ struct lirc_rx51 *lirc_rx51 =
+ container_of(timer, struct lirc_rx51, timer);
+ ktime_t now;
- if (retval & ~OMAP_TIMER_INT_MATCH)
- dev_err_ratelimited(lirc_rx51->dev,
- ": Unexpected interrupt source: %x\n", retval);
-
- omap_dm_timer_write_status(lirc_rx51->pulse_timer,
- OMAP_TIMER_INT_MATCH |
- OMAP_TIMER_INT_OVERFLOW |
- OMAP_TIMER_INT_CAPTURE);
if (lirc_rx51->wbuf_index < 0) {
dev_err_ratelimited(lirc_rx51->dev,
- ": BUG wbuf_index has value of %i\n",
+ "BUG wbuf_index has value of %i\n",
lirc_rx51->wbuf_index);
goto end;
}
@@ -144,6 +90,8 @@ static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr)
* pulses until we catch up.
*/
do {
+ u64 ns;
+
if (lirc_rx51->wbuf_index >= WBUF_LEN)
goto end;
if (lirc_rx51->wbuf[lirc_rx51->wbuf_index] == -1)
@@ -154,84 +102,24 @@ static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr)
else
lirc_rx51_on(lirc_rx51);
- retval = pulse_timer_set_timeout(lirc_rx51,
- lirc_rx51->wbuf[lirc_rx51->wbuf_index]);
+ ns = 1000 * lirc_rx51->wbuf[lirc_rx51->wbuf_index];
+ hrtimer_add_expires_ns(timer, ns);
+
lirc_rx51->wbuf_index++;
- } while (retval);
+ now = timer->base->get_time();
+
+ } while (hrtimer_get_expires_tv64(timer) < now.tv64);
- return IRQ_HANDLED;
+ return HRTIMER_RESTART;
end:
/* Stop TX here */
lirc_rx51_off(lirc_rx51);
lirc_rx51->wbuf_index = -1;
- omap_dm_timer_stop(lirc_rx51->pwm_timer);
- omap_dm_timer_stop(lirc_rx51->pulse_timer);
- omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
- wake_up_interruptible(&lirc_rx51->wqueue);
-
- return IRQ_HANDLED;
-}
-
-static int lirc_rx51_init_port(struct lirc_rx51 *lirc_rx51)
-{
- struct clk *clk_fclk;
- int retval, pwm_timer = lirc_rx51->pwm_timer_num;
-
- lirc_rx51->pwm_timer = omap_dm_timer_request_specific(pwm_timer);
- if (lirc_rx51->pwm_timer == NULL) {
- dev_err(lirc_rx51->dev, ": Error requesting GPT%d timer\n",
- pwm_timer);
- return -EBUSY;
- }
-
- lirc_rx51->pulse_timer = omap_dm_timer_request();
- if (lirc_rx51->pulse_timer == NULL) {
- dev_err(lirc_rx51->dev, ": Error requesting pulse timer\n");
- retval = -EBUSY;
- goto err1;
- }
-
- omap_dm_timer_set_source(lirc_rx51->pwm_timer, OMAP_TIMER_SRC_SYS_CLK);
- omap_dm_timer_set_source(lirc_rx51->pulse_timer,
- OMAP_TIMER_SRC_SYS_CLK);
-
- omap_dm_timer_enable(lirc_rx51->pwm_timer);
- omap_dm_timer_enable(lirc_rx51->pulse_timer);
-
- lirc_rx51->irq_num = omap_dm_timer_get_irq(lirc_rx51->pulse_timer);
- retval = request_irq(lirc_rx51->irq_num, lirc_rx51_interrupt_handler,
- IRQF_SHARED, "lirc_pulse_timer", lirc_rx51);
- if (retval) {
- dev_err(lirc_rx51->dev, ": Failed to request interrupt line\n");
- goto err2;
- }
-
- clk_fclk = omap_dm_timer_get_fclk(lirc_rx51->pwm_timer);
- lirc_rx51->fclk_khz = clk_fclk->rate / 1000;
-
- return 0;
-err2:
- omap_dm_timer_free(lirc_rx51->pulse_timer);
-err1:
- omap_dm_timer_free(lirc_rx51->pwm_timer);
-
- return retval;
-}
-
-static int lirc_rx51_free_port(struct lirc_rx51 *lirc_rx51)
-{
- omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
- free_irq(lirc_rx51->irq_num, lirc_rx51);
- lirc_rx51_off(lirc_rx51);
- omap_dm_timer_disable(lirc_rx51->pwm_timer);
- omap_dm_timer_disable(lirc_rx51->pulse_timer);
- omap_dm_timer_free(lirc_rx51->pwm_timer);
- omap_dm_timer_free(lirc_rx51->pulse_timer);
- lirc_rx51->wbuf_index = -1;
+ wake_up_interruptible(&lirc_rx51->wqueue);
- return 0;
+ return HRTIMER_NORESTART;
}
static ssize_t lirc_rx51_write(struct file *file, const char *buf,
@@ -270,8 +158,9 @@ static ssize_t lirc_rx51_write(struct file *file, const char *buf,
lirc_rx51_on(lirc_rx51);
lirc_rx51->wbuf_index = 1;
- pulse_timer_set_timeout(lirc_rx51, lirc_rx51->wbuf[0]);
-
+ hrtimer_start(&lirc_rx51->timer,
+ ns_to_ktime(1000 * lirc_rx51->wbuf[0]),
+ HRTIMER_MODE_REL);
/*
* Don't return back to the userspace until the transfer has
* finished
@@ -371,14 +260,24 @@ static int lirc_rx51_open(struct inode *inode, struct file *file)
if (test_and_set_bit(1, &lirc_rx51->device_is_open))
return -EBUSY;
- return lirc_rx51_init_port(lirc_rx51);
+ lirc_rx51->pwm = pwm_get(lirc_rx51->dev, NULL);
+ if (IS_ERR(lirc_rx51->pwm)) {
+ int res = PTR_ERR(lirc_rx51->pwm);
+
+ dev_err(lirc_rx51->dev, "pwm_get failed: %d\n", res);
+ return res;
+ }
+
+ return 0;
}
static int lirc_rx51_release(struct inode *inode, struct file *file)
{
struct lirc_rx51 *lirc_rx51 = file->private_data;
- lirc_rx51_free_port(lirc_rx51);
+ hrtimer_cancel(&lirc_rx51->timer);
+ lirc_rx51_off(lirc_rx51);
+ pwm_put(lirc_rx51->pwm);
clear_bit(1, &lirc_rx51->device_is_open);
@@ -386,7 +285,6 @@ static int lirc_rx51_release(struct inode *inode, struct file *file)
}
static struct lirc_rx51 lirc_rx51 = {
- .freq = 38000,
.duty_cycle = 50,
.wbuf_index = -1,
};
@@ -444,9 +342,32 @@ static int lirc_rx51_resume(struct platform_device *dev)
static int lirc_rx51_probe(struct platform_device *dev)
{
+ struct pwm_device *pwm;
+
lirc_rx51_driver.features = LIRC_RX51_DRIVER_FEATURES;
lirc_rx51.pdata = dev->dev.platform_data;
- lirc_rx51.pwm_timer_num = lirc_rx51.pdata->pwm_timer;
+
+ if (!lirc_rx51.pdata) {
+ dev_err(&dev->dev, "Platform Data is missing\n");
+ return -ENXIO;
+ }
+
+ pwm = pwm_get(&dev->dev, NULL);
+ if (IS_ERR(pwm)) {
+ int err = PTR_ERR(pwm);
+
+ if (err != -EPROBE_DEFER)
+ dev_err(&dev->dev, "pwm_get failed: %d\n", err);
+ return err;
+ }
+
+ /* Use default, in case userspace does not set the carrier */
+ lirc_rx51.freq = DIV_ROUND_CLOSEST(pwm_get_period(pwm), NSEC_PER_SEC);
+ pwm_put(pwm);
+
+ hrtimer_init(&lirc_rx51.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ lirc_rx51.timer.function = lirc_rx51_timer_cb;
+
lirc_rx51.dev = &dev->dev;
lirc_rx51_driver.dev = &dev->dev;
lirc_rx51_driver.minor = lirc_register_driver(&lirc_rx51_driver);
@@ -457,8 +378,6 @@ static int lirc_rx51_probe(struct platform_device *dev)
lirc_rx51_driver.minor);
return lirc_rx51_driver.minor;
}
- dev_info(lirc_rx51.dev, "registration ok, minor: %d, pwm: %d\n",
- lirc_rx51_driver.minor, lirc_rx51.pwm_timer_num);
return 0;
}
@@ -468,6 +387,14 @@ static int lirc_rx51_remove(struct platform_device *dev)
return lirc_unregister_driver(lirc_rx51_driver.minor);
}
+static const struct of_device_id lirc_rx51_match[] = {
+ {
+ .compatible = "nokia,n900-ir",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, lirc_rx51_match);
+
struct platform_driver lirc_rx51_platform_driver = {
.probe = lirc_rx51_probe,
.remove = lirc_rx51_remove,
@@ -475,7 +402,7 @@ struct platform_driver lirc_rx51_platform_driver = {
.resume = lirc_rx51_resume,
.driver = {
.name = DRIVER_NAME,
- .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lirc_rx51_match),
},
};
module_platform_driver(lirc_rx51_platform_driver);
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index fbbd3bbcd..d7b13fae1 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-behold.o \
rc-behold-columbus.o \
rc-budget-ci-old.o \
+ rc-cec.o \
rc-cinergy-1400.o \
rc-cinergy.o \
rc-delock-61959.o \
@@ -28,6 +29,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-dm1105-nec.o \
rc-dntv-live-dvb-t.o \
rc-dntv-live-dvbt-pro.o \
+ rc-dtt200u.o \
rc-dvbsky.o \
rc-em-terratec.o \
rc-encore-enltv2.o \
diff --git a/drivers/media/rc/keymaps/rc-cec.c b/drivers/media/rc/keymaps/rc-cec.c
new file mode 100644
index 000000000..354c8e724
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-cec.c
@@ -0,0 +1,182 @@
+/* Keytable for the CEC remote control
+ *
+ * Copyright (c) 2015 by Kamil Debski
+ *
+ * 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 <media/rc-map.h>
+#include <linux/module.h>
+
+/*
+ * CEC Spec "High-Definition Multimedia Interface Specification" can be obtained
+ * here: http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf
+ * The list of control codes is listed in Table 27: User Control Codes p. 95
+ */
+
+static struct rc_map_table cec[] = {
+ { 0x00, KEY_OK },
+ { 0x01, KEY_UP },
+ { 0x02, KEY_DOWN },
+ { 0x03, KEY_LEFT },
+ { 0x04, KEY_RIGHT },
+ { 0x05, KEY_RIGHT_UP },
+ { 0x06, KEY_RIGHT_DOWN },
+ { 0x07, KEY_LEFT_UP },
+ { 0x08, KEY_LEFT_DOWN },
+ { 0x09, KEY_ROOT_MENU }, /* CEC Spec: Device Root Menu - see Note 2 */
+ /*
+ * Note 2: This is the initial display that a device shows. It is
+ * device-dependent and can be, for example, a contents menu, setup
+ * menu, favorite menu or other menu. The actual menu displayed
+ * may also depend on the device's current state.
+ */
+ { 0x0a, KEY_SETUP },
+ { 0x0b, KEY_MENU }, /* CEC Spec: Contents Menu */
+ { 0x0c, KEY_FAVORITES }, /* CEC Spec: Favorite Menu */
+ { 0x0d, KEY_EXIT },
+ /* 0x0e-0x0f: Reserved */
+ { 0x10, KEY_MEDIA_TOP_MENU },
+ { 0x11, KEY_CONTEXT_MENU },
+ /* 0x12-0x1c: Reserved */
+ { 0x1d, KEY_DIGITS }, /* CEC Spec: select/toggle a Number Entry Mode */
+ { 0x1e, KEY_NUMERIC_11 },
+ { 0x1f, KEY_NUMERIC_12 },
+ /* 0x20-0x29: Keys 0 to 9 */
+ { 0x20, KEY_NUMERIC_0 },
+ { 0x21, KEY_NUMERIC_1 },
+ { 0x22, KEY_NUMERIC_2 },
+ { 0x23, KEY_NUMERIC_3 },
+ { 0x24, KEY_NUMERIC_4 },
+ { 0x25, KEY_NUMERIC_5 },
+ { 0x26, KEY_NUMERIC_6 },
+ { 0x27, KEY_NUMERIC_7 },
+ { 0x28, KEY_NUMERIC_8 },
+ { 0x29, KEY_NUMERIC_9 },
+ { 0x2a, KEY_DOT },
+ { 0x2b, KEY_ENTER },
+ { 0x2c, KEY_CLEAR },
+ /* 0x2d-0x2e: Reserved */
+ { 0x2f, KEY_NEXT_FAVORITE }, /* CEC Spec: Next Favorite */
+ { 0x30, KEY_CHANNELUP },
+ { 0x31, KEY_CHANNELDOWN },
+ { 0x32, KEY_PREVIOUS }, /* CEC Spec: Previous Channel */
+ { 0x33, KEY_SOUND }, /* CEC Spec: Sound Select */
+ { 0x34, KEY_VIDEO }, /* 0x34: CEC Spec: Input Select */
+ { 0x35, KEY_INFO }, /* CEC Spec: Display Information */
+ { 0x36, KEY_HELP },
+ { 0x37, KEY_PAGEUP },
+ { 0x38, KEY_PAGEDOWN },
+ /* 0x39-0x3f: Reserved */
+ { 0x40, KEY_POWER },
+ { 0x41, KEY_VOLUMEUP },
+ { 0x42, KEY_VOLUMEDOWN },
+ { 0x43, KEY_MUTE },
+ { 0x44, KEY_PLAYCD },
+ { 0x45, KEY_STOPCD },
+ { 0x46, KEY_PAUSECD },
+ { 0x47, KEY_RECORD },
+ { 0x48, KEY_REWIND },
+ { 0x49, KEY_FASTFORWARD },
+ { 0x4a, KEY_EJECTCD }, /* CEC Spec: Eject */
+ { 0x4b, KEY_FORWARD },
+ { 0x4c, KEY_BACK },
+ { 0x4d, KEY_STOP_RECORD }, /* CEC Spec: Stop-Record */
+ { 0x4e, KEY_PAUSE_RECORD }, /* CEC Spec: Pause-Record */
+ /* 0x4f: Reserved */
+ { 0x50, KEY_ANGLE },
+ { 0x51, KEY_TV2 },
+ { 0x52, KEY_VOD }, /* CEC Spec: Video on Demand */
+ { 0x53, KEY_EPG },
+ { 0x54, KEY_TIME }, /* CEC Spec: Timer */
+ { 0x55, KEY_CONFIG },
+ /*
+ * The following codes are hard to implement at this moment, as they
+ * carry an additional additional argument. Most likely changes to RC
+ * framework are necessary.
+ * For now they are interpreted by the CEC framework as non keycodes
+ * and are passed as messages enabling user application to parse them.
+ */
+ /* 0x56: CEC Spec: Select Broadcast Type */
+ /* 0x57: CEC Spec: Select Sound presentation */
+ { 0x58, KEY_AUDIO_DESC }, /* CEC 2.0 and up */
+ { 0x59, KEY_WWW }, /* CEC 2.0 and up */
+ { 0x5a, KEY_3D_MODE }, /* CEC 2.0 and up */
+ /* 0x5b-0x5f: Reserved */
+ { 0x60, KEY_PLAYCD }, /* CEC Spec: Play Function */
+ { 0x6005, KEY_FASTFORWARD },
+ { 0x6006, KEY_FASTFORWARD },
+ { 0x6007, KEY_FASTFORWARD },
+ { 0x6015, KEY_SLOW },
+ { 0x6016, KEY_SLOW },
+ { 0x6017, KEY_SLOW },
+ { 0x6009, KEY_FASTREVERSE },
+ { 0x600a, KEY_FASTREVERSE },
+ { 0x600b, KEY_FASTREVERSE },
+ { 0x6019, KEY_SLOWREVERSE },
+ { 0x601a, KEY_SLOWREVERSE },
+ { 0x601b, KEY_SLOWREVERSE },
+ { 0x6020, KEY_REWIND },
+ { 0x6024, KEY_PLAYCD },
+ { 0x6025, KEY_PAUSECD },
+ { 0x61, KEY_PLAYPAUSE }, /* CEC Spec: Pause-Play Function */
+ { 0x62, KEY_RECORD }, /* Spec: Record Function */
+ { 0x63, KEY_PAUSE_RECORD }, /* CEC Spec: Pause-Record Function */
+ { 0x64, KEY_STOPCD }, /* CEC Spec: Stop Function */
+ { 0x65, KEY_MUTE }, /* CEC Spec: Mute Function */
+ { 0x66, KEY_UNMUTE }, /* CEC Spec: Restore the volume */
+ /*
+ * The following codes are hard to implement at this moment, as they
+ * carry an additional additional argument. Most likely changes to RC
+ * framework are necessary.
+ * For now they are interpreted by the CEC framework as non keycodes
+ * and are passed as messages enabling user application to parse them.
+ */
+ /* 0x67: CEC Spec: Tune Function */
+ /* 0x68: CEC Spec: Seleect Media Function */
+ /* 0x69: CEC Spec: Select A/V Input Function */
+ /* 0x6a: CEC Spec: Select Audio Input Function */
+ { 0x6b, KEY_POWER }, /* CEC Spec: Power Toggle Function */
+ { 0x6c, KEY_SLEEP }, /* CEC Spec: Power Off Function */
+ { 0x6d, KEY_WAKEUP }, /* CEC Spec: Power On Function */
+ /* 0x6e-0x70: Reserved */
+ { 0x71, KEY_BLUE }, /* CEC Spec: F1 (Blue) */
+ { 0x72, KEY_RED }, /* CEC Spec: F2 (Red) */
+ { 0x73, KEY_GREEN }, /* CEC Spec: F3 (Green) */
+ { 0x74, KEY_YELLOW }, /* CEC Spec: F4 (Yellow) */
+ { 0x75, KEY_F5 },
+ { 0x76, KEY_DATA }, /* CEC Spec: Data - see Note 3 */
+ /*
+ * Note 3: This is used, for example, to enter or leave a digital TV
+ * data broadcast application.
+ */
+ /* 0x77-0xff: Reserved */
+};
+
+static struct rc_map_list cec_map = {
+ .map = {
+ .scan = cec,
+ .size = ARRAY_SIZE(cec),
+ .rc_type = RC_TYPE_CEC,
+ .name = RC_MAP_CEC,
+ }
+};
+
+static int __init init_rc_map_cec(void)
+{
+ return rc_map_register(&cec_map);
+}
+
+static void __exit exit_rc_map_cec(void)
+{
+ rc_map_unregister(&cec_map);
+}
+
+module_init(init_rc_map_cec);
+module_exit(exit_rc_map_cec);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kamil Debski");
diff --git a/drivers/media/rc/keymaps/rc-dtt200u.c b/drivers/media/rc/keymaps/rc-dtt200u.c
new file mode 100644
index 000000000..25650e9e4
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-dtt200u.c
@@ -0,0 +1,59 @@
+/* Keytable for Wideview WT-220U.
+ *
+ * Copyright (c) 2016 Jonathan McDowell <noodles@earth.li>
+ *
+ * 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 <media/rc-map.h>
+#include <linux/module.h>
+
+/* key list for the tiny remote control (Yakumo, don't know about the others) */
+static struct rc_map_table dtt200u_table[] = {
+ { 0x8001, KEY_MUTE },
+ { 0x8002, KEY_CHANNELDOWN },
+ { 0x8003, KEY_VOLUMEDOWN },
+ { 0x8004, KEY_1 },
+ { 0x8005, KEY_2 },
+ { 0x8006, KEY_3 },
+ { 0x8007, KEY_4 },
+ { 0x8008, KEY_5 },
+ { 0x8009, KEY_6 },
+ { 0x800a, KEY_7 },
+ { 0x800c, KEY_ZOOM },
+ { 0x800d, KEY_0 },
+ { 0x800e, KEY_SELECT },
+ { 0x8012, KEY_POWER },
+ { 0x801a, KEY_CHANNELUP },
+ { 0x801b, KEY_8 },
+ { 0x801e, KEY_VOLUMEUP },
+ { 0x801f, KEY_9 },
+};
+
+static struct rc_map_list dtt200u_map = {
+ .map = {
+ .scan = dtt200u_table,
+ .size = ARRAY_SIZE(dtt200u_table),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_DTT200U,
+ }
+};
+
+static int __init init_rc_map_dtt200u(void)
+{
+ return rc_map_register(&dtt200u_map);
+}
+
+static void __exit exit_rc_map_dtt200u(void)
+{
+ rc_map_unregister(&dtt200u_map);
+}
+
+module_init(init_rc_map_dtt200u)
+module_exit(exit_rc_map_dtt200u)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 92ae1903c..91f9bb87c 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -19,6 +19,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -80,8 +82,6 @@ static void lirc_irctl_init(struct irctl *ir)
static void lirc_irctl_cleanup(struct irctl *ir)
{
- dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor);
-
device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
if (ir->buf != ir->d.rbuf) {
@@ -97,28 +97,25 @@ static void lirc_irctl_cleanup(struct irctl *ir)
*/
static int lirc_add_to_buf(struct irctl *ir)
{
- if (ir->d.add_to_buf) {
- int res = -ENODATA;
- int got_data = 0;
+ int res;
+ int got_data = -1;
- /*
- * service the device as long as it is returning
- * data and we have space
- */
-get_data:
- res = ir->d.add_to_buf(ir->d.data, ir->buf);
- if (res == 0) {
- got_data++;
- goto get_data;
- }
+ if (!ir->d.add_to_buf)
+ return 0;
- if (res == -ENODEV)
- kthread_stop(ir->task);
+ /*
+ * service the device as long as it is returning
+ * data and we have space
+ */
+ do {
+ got_data++;
+ res = ir->d.add_to_buf(ir->d.data, ir->buf);
+ } while (!res);
- return got_data ? 0 : res;
- }
+ if (res == -ENODEV)
+ kthread_stop(ir->task);
- return 0;
+ return got_data ? 0 : res;
}
/* main function of the polling thread
@@ -127,9 +124,6 @@ static int lirc_thread(void *irctl)
{
struct irctl *ir = irctl;
- dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n",
- ir->d.name, ir->d.minor);
-
do {
if (ir->open) {
if (ir->jiffies_to_wait) {
@@ -146,9 +140,6 @@ static int lirc_thread(void *irctl)
}
} while (!kthread_should_stop());
- dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n",
- ir->d.name, ir->d.minor);
-
return 0;
}
@@ -203,74 +194,86 @@ err_out:
return retval;
}
-int lirc_register_driver(struct lirc_driver *d)
+static int lirc_allocate_buffer(struct irctl *ir)
{
- struct irctl *ir;
- int minor;
+ int err = 0;
int bytes_in_key;
unsigned int chunk_size;
unsigned int buffer_size;
+ struct lirc_driver *d = &ir->d;
+
+ mutex_lock(&lirc_dev_lock);
+
+ bytes_in_key = BITS_TO_LONGS(d->code_length) +
+ (d->code_length % 8 ? 1 : 0);
+ buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key;
+ chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key;
+
+ if (d->rbuf) {
+ ir->buf = d->rbuf;
+ } else {
+ ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+ if (!ir->buf) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = lirc_buffer_init(ir->buf, chunk_size, buffer_size);
+ if (err) {
+ kfree(ir->buf);
+ goto out;
+ }
+ }
+ ir->chunk_size = ir->buf->chunk_size;
+
+out:
+ mutex_unlock(&lirc_dev_lock);
+
+ return err;
+}
+
+static int lirc_allocate_driver(struct lirc_driver *d)
+{
+ struct irctl *ir;
+ int minor;
int err;
if (!d) {
- printk(KERN_ERR "lirc_dev: lirc_register_driver: "
- "driver pointer must be not NULL!\n");
- err = -EBADRQC;
- goto out;
+ pr_err("driver pointer must be not NULL!\n");
+ return -EBADRQC;
}
if (!d->dev) {
- printk(KERN_ERR "%s: dev pointer not filled in!\n", __func__);
- err = -EINVAL;
- goto out;
+ pr_err("dev pointer not filled in!\n");
+ return -EINVAL;
}
- if (MAX_IRCTL_DEVICES <= d->minor) {
- dev_err(d->dev, "lirc_dev: lirc_register_driver: "
- "\"minor\" must be between 0 and %d (%d)!\n",
- MAX_IRCTL_DEVICES - 1, d->minor);
- err = -EBADRQC;
- goto out;
+ if (d->minor >= MAX_IRCTL_DEVICES) {
+ dev_err(d->dev, "minor must be between 0 and %d!\n",
+ MAX_IRCTL_DEVICES - 1);
+ return -EBADRQC;
}
- if (1 > d->code_length || (BUFLEN * 8) < d->code_length) {
- dev_err(d->dev, "lirc_dev: lirc_register_driver: "
- "code length in bits for minor (%d) "
- "must be less than %d!\n",
- d->minor, BUFLEN * 8);
- err = -EBADRQC;
- goto out;
+ if (d->code_length < 1 || d->code_length > (BUFLEN * 8)) {
+ dev_err(d->dev, "code length must be less than %d bits\n",
+ BUFLEN * 8);
+ return -EBADRQC;
}
- dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n",
- d->sample_rate);
if (d->sample_rate) {
if (2 > d->sample_rate || HZ < d->sample_rate) {
- dev_err(d->dev, "lirc_dev: lirc_register_driver: "
- "sample_rate must be between 2 and %d!\n", HZ);
- err = -EBADRQC;
- goto out;
+ dev_err(d->dev, "invalid %d sample rate\n",
+ d->sample_rate);
+ return -EBADRQC;
}
if (!d->add_to_buf) {
- dev_err(d->dev, "lirc_dev: lirc_register_driver: "
- "add_to_buf cannot be NULL when "
- "sample_rate is set\n");
- err = -EBADRQC;
- goto out;
- }
- } else if (!(d->fops && d->fops->read) && !d->rbuf) {
- dev_err(d->dev, "lirc_dev: lirc_register_driver: "
- "fops->read and rbuf cannot all be NULL!\n");
- err = -EBADRQC;
- goto out;
- } else if (!d->rbuf) {
- if (!(d->fops && d->fops->read && d->fops->poll &&
- d->fops->unlocked_ioctl)) {
- dev_err(d->dev, "lirc_dev: lirc_register_driver: "
- "neither read, poll nor unlocked_ioctl can be NULL!\n");
- err = -EBADRQC;
- goto out;
+ dev_err(d->dev, "add_to_buf not set\n");
+ return -EBADRQC;
}
+ } else if (!d->rbuf && !(d->fops && d->fops->read &&
+ d->fops->poll && d->fops->unlocked_ioctl)) {
+ dev_err(d->dev, "undefined read, poll, ioctl\n");
+ return -EBADRQC;
}
mutex_lock(&lirc_dev_lock);
@@ -282,15 +285,13 @@ int lirc_register_driver(struct lirc_driver *d)
for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++)
if (!irctls[minor])
break;
- if (MAX_IRCTL_DEVICES == minor) {
- dev_err(d->dev, "lirc_dev: lirc_register_driver: "
- "no free slots for drivers!\n");
+ if (minor == MAX_IRCTL_DEVICES) {
+ dev_err(d->dev, "no free slots for drivers!\n");
err = -ENOMEM;
goto out_lock;
}
} else if (irctls[minor]) {
- dev_err(d->dev, "lirc_dev: lirc_register_driver: "
- "minor (%d) just registered!\n", minor);
+ dev_err(d->dev, "minor (%d) just registered!\n", minor);
err = -EBUSY;
goto out_lock;
}
@@ -304,37 +305,9 @@ int lirc_register_driver(struct lirc_driver *d)
irctls[minor] = ir;
d->minor = minor;
- if (d->sample_rate) {
- ir->jiffies_to_wait = HZ / d->sample_rate;
- } else {
- /* it means - wait for external event in task queue */
- ir->jiffies_to_wait = 0;
- }
-
/* some safety check 8-) */
d->name[sizeof(d->name)-1] = '\0';
- bytes_in_key = BITS_TO_LONGS(d->code_length) +
- (d->code_length % 8 ? 1 : 0);
- buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key;
- chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key;
-
- if (d->rbuf) {
- ir->buf = d->rbuf;
- } else {
- ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
- if (!ir->buf) {
- err = -ENOMEM;
- goto out_lock;
- }
- err = lirc_buffer_init(ir->buf, chunk_size, buffer_size);
- if (err) {
- kfree(ir->buf);
- goto out_lock;
- }
- }
- ir->chunk_size = ir->buf->chunk_size;
-
if (d->features == 0)
d->features = LIRC_CAN_REC_LIRCCODE;
@@ -345,15 +318,19 @@ int lirc_register_driver(struct lirc_driver *d)
"lirc%u", ir->d.minor);
if (d->sample_rate) {
+ ir->jiffies_to_wait = HZ / d->sample_rate;
+
/* try to fire up polling thread */
ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev");
if (IS_ERR(ir->task)) {
- dev_err(d->dev, "lirc_dev: lirc_register_driver: "
- "cannot run poll thread for minor = %d\n",
- d->minor);
+ dev_err(d->dev, "cannot run thread for minor = %d\n",
+ d->minor);
err = -ECHILD;
goto out_sysfs;
}
+ } else {
+ /* it means - wait for external event in task queue */
+ ir->jiffies_to_wait = 0;
}
err = lirc_cdev_add(ir);
@@ -371,9 +348,26 @@ out_sysfs:
device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
out_lock:
mutex_unlock(&lirc_dev_lock);
-out:
+
return err;
}
+
+int lirc_register_driver(struct lirc_driver *d)
+{
+ int minor, err = 0;
+
+ minor = lirc_allocate_driver(d);
+ if (minor < 0)
+ return minor;
+
+ if (LIRC_CAN_REC(d->features)) {
+ err = lirc_allocate_buffer(irctls[minor]);
+ if (err)
+ lirc_unregister_driver(minor);
+ }
+
+ return err ? err : minor;
+}
EXPORT_SYMBOL(lirc_register_driver);
int lirc_unregister_driver(int minor)
@@ -382,15 +376,14 @@ int lirc_unregister_driver(int minor)
struct cdev *cdev;
if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
- printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between "
- "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES - 1);
+ pr_err("minor (%d) must be between 0 and %d!\n",
+ minor, MAX_IRCTL_DEVICES - 1);
return -EBADRQC;
}
ir = irctls[minor];
if (!ir) {
- printk(KERN_ERR "lirc_dev: %s: failed to get irctl struct "
- "for minor %d!\n", __func__, minor);
+ pr_err("failed to get irctl\n");
return -ENOENT;
}
@@ -399,8 +392,8 @@ int lirc_unregister_driver(int minor)
mutex_lock(&lirc_dev_lock);
if (ir->d.minor != minor) {
- printk(KERN_ERR "lirc_dev: %s: minor (%d) device not "
- "registered!\n", __func__, minor);
+ dev_err(ir->d.dev, "lirc_dev: minor %d device not registered\n",
+ minor);
mutex_unlock(&lirc_dev_lock);
return -ENOENT;
}
@@ -418,7 +411,10 @@ int lirc_unregister_driver(int minor)
ir->d.name, ir->d.minor);
wake_up_interruptible(&ir->buf->wait_poll);
mutex_lock(&ir->irctl_lock);
- ir->d.set_use_dec(ir->d.data);
+
+ if (ir->d.set_use_dec)
+ ir->d.set_use_dec(ir->d.data);
+
module_put(cdev->owner);
mutex_unlock(&ir->irctl_lock);
} else {
@@ -442,8 +438,7 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
int retval = 0;
if (iminor(inode) >= MAX_IRCTL_DEVICES) {
- printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n",
- iminor(inode));
+ pr_err("open result for %d is -ENODEV\n", iminor(inode));
return -ENODEV;
}
@@ -477,7 +472,8 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
cdev = ir->cdev;
if (try_module_get(cdev->owner)) {
ir->open++;
- retval = ir->d.set_use_inc(ir->d.data);
+ if (ir->d.set_use_inc)
+ retval = ir->d.set_use_inc(ir->d.data);
if (retval) {
module_put(cdev->owner);
@@ -490,10 +486,6 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
}
error:
- if (ir)
- dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n",
- ir->d.name, ir->d.minor, retval);
-
mutex_unlock(&lirc_dev_lock);
nonseekable_open(inode, file);
@@ -509,14 +501,12 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
int ret;
if (!ir) {
- printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+ pr_err("called with invalid irctl\n");
return -EINVAL;
}
cdev = ir->cdev;
- dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
-
ret = mutex_lock_killable(&lirc_dev_lock);
WARN_ON(ret);
@@ -524,7 +514,8 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
ir->open--;
if (ir->attached) {
- ir->d.set_use_dec(ir->d.data);
+ if (ir->d.set_use_dec)
+ ir->d.set_use_dec(ir->d.data);
module_put(cdev->owner);
} else {
lirc_irctl_cleanup(ir);
@@ -547,12 +538,10 @@ unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
unsigned int ret;
if (!ir) {
- printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+ pr_err("called with invalid irctl\n");
return POLLERR;
}
- dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor);
-
if (!ir->attached)
return POLLERR;
@@ -580,7 +569,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct irctl *ir = irctls[iminor(file_inode(file))];
if (!ir) {
- printk(KERN_ERR "lirc_dev: %s: no irctl found!\n", __func__);
+ pr_err("no irctl found!\n");
return -ENODEV;
}
@@ -588,7 +577,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ir->d.name, ir->d.minor, cmd);
if (ir->d.minor == NOPLUG || !ir->attached) {
- dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n",
+ dev_err(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n",
ir->d.name, ir->d.minor);
return -ENODEV;
}
@@ -600,8 +589,8 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
result = put_user(ir->d.features, (__u32 __user *)arg);
break;
case LIRC_GET_REC_MODE:
- if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
- result = -ENOSYS;
+ if (LIRC_CAN_REC(ir->d.features)) {
+ result = -ENOTTY;
break;
}
@@ -610,8 +599,8 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
(__u32 __user *)arg);
break;
case LIRC_SET_REC_MODE:
- if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
- result = -ENOSYS;
+ if (LIRC_CAN_REC(ir->d.features)) {
+ result = -ENOTTY;
break;
}
@@ -629,7 +618,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case LIRC_GET_MIN_TIMEOUT:
if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
ir->d.min_timeout == 0) {
- result = -ENOSYS;
+ result = -ENOTTY;
break;
}
@@ -638,7 +627,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case LIRC_GET_MAX_TIMEOUT:
if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
ir->d.max_timeout == 0) {
- result = -ENOSYS;
+ result = -ENOTTY;
break;
}
@@ -648,9 +637,6 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
result = -EINVAL;
}
- dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n",
- ir->d.name, ir->d.minor, result);
-
mutex_unlock(&ir->irctl_lock);
return result;
@@ -668,7 +654,7 @@ ssize_t lirc_dev_fop_read(struct file *file,
DECLARE_WAITQUEUE(wait, current);
if (!ir) {
- printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+ pr_err("called with invalid irctl\n");
return -ENODEV;
}
@@ -709,7 +695,8 @@ ssize_t lirc_dev_fop_read(struct file *file,
/* According to the read(2) man page, 'written' can be
* returned as less than 'length', instead of blocking
* again, returning -EWOULDBLOCK, or returning
- * -ERESTARTSYS */
+ * -ERESTARTSYS
+ */
if (written)
break;
if (file->f_flags & O_NONBLOCK) {
@@ -755,8 +742,6 @@ out_locked:
out_unlocked:
kfree(buf);
- dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n",
- ir->d.name, ir->d.minor, ret ? "<fail>" : "<ok>", ret);
return ret ? ret : written;
}
@@ -775,12 +760,10 @@ ssize_t lirc_dev_fop_write(struct file *file, const char __user *buffer,
struct irctl *ir = irctls[iminor(file_inode(file))];
if (!ir) {
- printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+ pr_err("called with invalid irctl\n");
return -ENODEV;
}
- dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor);
-
if (!ir->attached)
return -ENODEV;
@@ -795,25 +778,23 @@ static int __init lirc_dev_init(void)
lirc_class = class_create(THIS_MODULE, "lirc");
if (IS_ERR(lirc_class)) {
- retval = PTR_ERR(lirc_class);
- printk(KERN_ERR "lirc_dev: class_create failed\n");
- goto error;
+ pr_err("class_create failed\n");
+ return PTR_ERR(lirc_class);
}
retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES,
IRCTL_DEV_NAME);
if (retval) {
class_destroy(lirc_class);
- printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n");
- goto error;
+ pr_err("alloc_chrdev_region failed\n");
+ return retval;
}
- printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, "
- "major %d \n", MAJOR(lirc_base_dev));
+ pr_info("IR Remote Control driver registered, major %d\n",
+ MAJOR(lirc_base_dev));
-error:
- return retval;
+ return 0;
}
@@ -822,7 +803,7 @@ static void __exit lirc_dev_exit(void)
{
class_destroy(lirc_class);
unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES);
- printk(KERN_INFO "lirc_dev: module unloaded\n");
+ pr_info("module unloaded\n");
}
module_init(lirc_dev_init);
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 5cf2e749b..4f8c7effd 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -887,6 +887,12 @@ static int mceusb_set_tx_mask(struct rc_dev *dev, u32 mask)
{
struct mceusb_dev *ir = dev->priv;
+ /* return number of transmitters */
+ int emitters = ir->num_txports ? ir->num_txports : 2;
+
+ if (mask >= (1 << emitters))
+ return emitters;
+
if (ir->flags.tx_mask_normal)
ir->tx_mask = mask;
else
@@ -936,7 +942,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
}
- return carrier;
+ return 0;
}
/*
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index e8ceb0e2f..00215f343 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -139,11 +139,7 @@ static inline void nvt_cir_reg_write(struct nvt_dev *nvt, u8 val, u8 offset)
/* read val from cir config register */
static u8 nvt_cir_reg_read(struct nvt_dev *nvt, u8 offset)
{
- u8 val;
-
- val = inb(nvt->cir_addr + offset);
-
- return val;
+ return inb(nvt->cir_addr + offset);
}
/* write val to cir wake register */
@@ -156,11 +152,7 @@ static inline void nvt_cir_wake_reg_write(struct nvt_dev *nvt,
/* read val from cir wake config register */
static u8 nvt_cir_wake_reg_read(struct nvt_dev *nvt, u8 offset)
{
- u8 val;
-
- val = inb(nvt->cir_wake_addr + offset);
-
- return val;
+ return inb(nvt->cir_wake_addr + offset);
}
/* don't override io address if one is set already */
@@ -481,18 +473,14 @@ static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt)
nvt_set_ioaddr(nvt, &nvt->cir_wake_addr);
- nvt_cr_write(nvt, nvt->cir_wake_irq, CR_CIR_IRQ_RSRC);
-
- nvt_dbg("CIR Wake initialized, base io port address: 0x%lx, irq: %d",
- nvt->cir_wake_addr, nvt->cir_wake_irq);
+ nvt_dbg("CIR Wake initialized, base io port address: 0x%lx",
+ nvt->cir_wake_addr);
}
/* clear out the hardware's cir rx fifo */
static void nvt_clear_cir_fifo(struct nvt_dev *nvt)
{
- u8 val;
-
- val = nvt_cir_reg_read(nvt, CIR_FIFOCON);
+ u8 val = nvt_cir_reg_read(nvt, CIR_FIFOCON);
nvt_cir_reg_write(nvt, val | CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON);
}
@@ -528,7 +516,7 @@ static void nvt_set_cir_iren(struct nvt_dev *nvt)
{
u8 iren;
- iren = CIR_IREN_RTR | CIR_IREN_PE;
+ iren = CIR_IREN_RTR | CIR_IREN_PE | CIR_IREN_RFO;
nvt_cir_reg_write(nvt, iren, CIR_IREN);
}
@@ -567,34 +555,15 @@ static void nvt_cir_regs_init(struct nvt_dev *nvt)
static void nvt_cir_wake_regs_init(struct nvt_dev *nvt)
{
- /* set number of bytes needed for wake from s3 (default 65) */
- nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFO_CMP_BYTES,
- CIR_WAKE_FIFO_CMP_DEEP);
-
- /* set tolerance/variance allowed per byte during wake compare */
- nvt_cir_wake_reg_write(nvt, CIR_WAKE_CMP_TOLERANCE,
- CIR_WAKE_FIFO_CMP_TOL);
-
- /* set sample limit count (PE interrupt raised when reached) */
- nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_WAKE_SLCH);
- nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_WAKE_SLCL);
-
- /* set cir wake fifo rx trigger level (currently 67) */
- nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFOCON_RX_TRIGGER_LEV,
- CIR_WAKE_FIFOCON);
-
/*
- * Enable TX and RX, specific carrier on = low, off = high, and set
- * sample period (currently 50us)
+ * Disable RX, set specific carrier on = low, off = high,
+ * and sample period (currently 50us)
*/
- nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN |
+ nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 |
CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV |
CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL,
CIR_WAKE_IRCON);
- /* clear cir wake rx fifo */
- nvt_clear_cir_wake_fifo(nvt);
-
/* clear any and all stray interrupts */
nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS);
@@ -789,8 +758,6 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
nvt_dbg_verbose("Processing buffer of len %d", nvt->pkts);
- init_ir_raw_event(&rawir);
-
for (i = 0; i < nvt->pkts; i++) {
sample = nvt->buf[i];
@@ -836,19 +803,10 @@ static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
{
u8 fifocount, val;
unsigned int b_idx;
- bool overrun = false;
int i;
/* Get count of how many bytes to read from RX FIFO */
fifocount = nvt_cir_reg_read(nvt, CIR_RXFCONT);
- /* if we get 0xff, probably means the logical dev is disabled */
- if (fifocount == 0xff)
- return;
- /* watch out for a fifo overrun condition */
- else if (fifocount > RX_BUF_LEN) {
- overrun = true;
- fifocount = RX_BUF_LEN;
- }
nvt_dbg("attempting to fetch %u bytes from hw rx fifo", fifocount);
@@ -870,9 +828,6 @@ static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
nvt_dbg("%s: pkts now %d", __func__, nvt->pkts);
nvt_process_rx_ir_data(nvt);
-
- if (overrun)
- nvt_handle_rx_fifo_overrun(nvt);
}
static void nvt_cir_log_irqs(u8 status, u8 iren)
@@ -908,7 +863,7 @@ static bool nvt_cir_tx_inactive(struct nvt_dev *nvt)
static irqreturn_t nvt_cir_isr(int irq, void *data)
{
struct nvt_dev *nvt = data;
- u8 status, iren, cur_state;
+ u8 status, iren;
unsigned long flags;
nvt_dbg_verbose("%s firing", __func__);
@@ -946,23 +901,15 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
nvt_cir_log_irqs(status, iren);
- if (status & CIR_IRSTS_RTR) {
- /* FIXME: add code for study/learn mode */
+ if (status & CIR_IRSTS_RFO)
+ nvt_handle_rx_fifo_overrun(nvt);
+
+ else if (status & (CIR_IRSTS_RTR | CIR_IRSTS_PE)) {
/* We only do rx if not tx'ing */
if (nvt_cir_tx_inactive(nvt))
nvt_get_rx_ir_data(nvt);
}
- if (status & CIR_IRSTS_PE) {
- if (nvt_cir_tx_inactive(nvt))
- nvt_get_rx_ir_data(nvt);
-
- cur_state = nvt->study_state;
-
- if (cur_state == ST_STUDY_NONE)
- nvt_clear_cir_fifo(nvt);
- }
-
spin_unlock_irqrestore(&nvt->nvt_lock, flags);
if (status & CIR_IRSTS_TE)
@@ -1004,51 +951,6 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
return IRQ_HANDLED;
}
-/* Interrupt service routine for CIR Wake */
-static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
-{
- u8 status, iren, val;
- struct nvt_dev *nvt = data;
- unsigned long flags;
-
- nvt_dbg_wake("%s firing", __func__);
-
- spin_lock_irqsave(&nvt->nvt_lock, flags);
-
- status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS);
- iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN);
-
- /* IRQ may be shared with CIR, therefore check for each
- * status bit whether the related interrupt source is enabled
- */
- if (!(status & iren)) {
- spin_unlock_irqrestore(&nvt->nvt_lock, flags);
- return IRQ_NONE;
- }
-
- if (status & CIR_WAKE_IRSTS_IR_PENDING)
- nvt_clear_cir_wake_fifo(nvt);
-
- nvt_cir_wake_reg_write(nvt, status, CIR_WAKE_IRSTS);
- nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IRSTS);
-
- if ((status & CIR_WAKE_IRSTS_PE) &&
- (nvt->wake_state == ST_WAKE_START)) {
- while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) {
- val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY);
- nvt_dbg("setting wake up key: 0x%x", val);
- }
-
- nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN);
- nvt->wake_state = ST_WAKE_FINISH;
- }
-
- spin_unlock_irqrestore(&nvt->nvt_lock, flags);
-
- nvt_dbg_wake("%s done", __func__);
- return IRQ_HANDLED;
-}
-
static void nvt_disable_cir(struct nvt_dev *nvt)
{
unsigned long flags;
@@ -1152,8 +1054,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
nvt->cir_irq = pnp_irq(pdev, 0);
nvt->cir_wake_addr = pnp_port_start(pdev, 1);
- /* irq is always shared between cir and cir wake */
- nvt->cir_wake_irq = nvt->cir_irq;
nvt->cr_efir = CR_EFIR;
nvt->cr_efdr = CR_EFDR;
@@ -1229,11 +1129,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
CIR_IOREG_LENGTH, NVT_DRIVER_NAME "-wake"))
goto exit_unregister_device;
- if (devm_request_irq(&pdev->dev, nvt->cir_wake_irq,
- nvt_cir_wake_isr, IRQF_SHARED,
- NVT_DRIVER_NAME "-wake", (void *)nvt))
- goto exit_unregister_device;
-
ret = device_create_file(&rdev->dev, &dev_attr_wakeup_data);
if (ret)
goto exit_unregister_device;
@@ -1284,10 +1179,6 @@ static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state)
spin_lock_irqsave(&nvt->nvt_lock, flags);
- /* zero out misc state tracking */
- nvt->study_state = ST_STUDY_NONE;
- nvt->wake_state = ST_WAKE_NONE;
-
/* disable all CIR interrupts */
nvt_cir_reg_write(nvt, 0, CIR_IREN);
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index c9c98ebb1..acf735fc7 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -104,7 +104,6 @@ struct nvt_dev {
unsigned long cir_addr;
unsigned long cir_wake_addr;
int cir_irq;
- int cir_wake_irq;
enum nvt_chip_ver chip_ver;
/* hardware id */
@@ -112,36 +111,12 @@ struct nvt_dev {
u8 chip_minor;
/* hardware features */
- bool hw_learning_capable;
bool hw_tx_capable;
- /* rx settings */
- bool learning_enabled;
-
- /* track cir wake state */
- u8 wake_state;
- /* for study */
- u8 study_state;
/* carrier period = 1 / frequency */
u32 carrier;
};
-/* study states */
-#define ST_STUDY_NONE 0x0
-#define ST_STUDY_START 0x1
-#define ST_STUDY_CARRIER 0x2
-#define ST_STUDY_ALL_RECV 0x4
-
-/* wake states */
-#define ST_WAKE_NONE 0x0
-#define ST_WAKE_START 0x1
-#define ST_WAKE_FINISH 0x2
-
-/* receive states */
-#define ST_RX_WAIT_7F 0x1
-#define ST_RX_WAIT_HEAD 0x2
-#define ST_RX_WAIT_SILENT_END 0x4
-
/* send states */
#define ST_TX_NONE 0x0
#define ST_TX_REQUEST 0x2
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 7dfc7c218..8e7f2929f 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -130,13 +130,18 @@ static struct rc_map_list empty_map = {
static int ir_create_table(struct rc_map *rc_map,
const char *name, u64 rc_type, size_t size)
{
- rc_map->name = name;
+ rc_map->name = kstrdup(name, GFP_KERNEL);
+ if (!rc_map->name)
+ return -ENOMEM;
rc_map->rc_type = rc_type;
rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
- if (!rc_map->scan)
+ if (!rc_map->scan) {
+ kfree(rc_map->name);
+ rc_map->name = NULL;
return -ENOMEM;
+ }
IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
rc_map->size, rc_map->alloc);
@@ -153,6 +158,7 @@ static int ir_create_table(struct rc_map *rc_map,
static void ir_free_table(struct rc_map *rc_map)
{
rc_map->size = 0;
+ kfree(rc_map->name);
kfree(rc_map->scan);
rc_map->scan = NULL;
}
@@ -804,6 +810,7 @@ static const struct {
{ RC_BIT_SHARP, "sharp", "ir-sharp-decoder" },
{ RC_BIT_MCE_KBD, "mce_kbd", "ir-mce_kbd-decoder" },
{ RC_BIT_XMP, "xmp", "ir-xmp-decoder" },
+ { RC_BIT_CEC, "cec", NULL },
};
/**
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index ec74244a3..399f44d89 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -188,8 +188,7 @@ struct redrat3_dev {
/* usb dma */
dma_addr_t dma_in;
- /* rx signal timeout timer */
- struct timer_list rx_timeout;
+ /* rx signal timeout */
u32 hw_timeout;
/* Is the device currently transmitting?*/
@@ -330,22 +329,11 @@ static u32 redrat3_us_to_len(u32 microsec)
return result ? result : 1;
}
-/* timer callback to send reset event */
-static void redrat3_rx_timeout(unsigned long data)
-{
- struct redrat3_dev *rr3 = (struct redrat3_dev *)data;
-
- dev_dbg(rr3->dev, "calling ir_raw_event_reset\n");
- ir_raw_event_reset(rr3->rc);
-}
-
static void redrat3_process_ir_data(struct redrat3_dev *rr3)
{
DEFINE_IR_RAW_EVENT(rawir);
struct device *dev;
- unsigned i, trailer = 0;
- unsigned sig_size, single_len, offset, val;
- unsigned long delay;
+ unsigned int i, sig_size, single_len, offset, val;
u32 mod_freq;
if (!rr3) {
@@ -355,10 +343,6 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
dev = rr3->dev;
- /* Make sure we reset the IR kfifo after a bit of inactivity */
- delay = usecs_to_jiffies(rr3->hw_timeout);
- mod_timer(&rr3->rx_timeout, jiffies + delay);
-
mod_freq = redrat3_val_to_mod_freq(&rr3->irdata);
dev_dbg(dev, "Got mod_freq of %u\n", mod_freq);
@@ -376,9 +360,6 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
rawir.pulse = true;
rawir.duration = US_TO_NS(single_len);
- /* Save initial pulse length to fudge trailer */
- if (i == 0)
- trailer = rawir.duration;
/* cap the value to IR_MAX_DURATION */
rawir.duration = (rawir.duration > IR_MAX_DURATION) ?
IR_MAX_DURATION : rawir.duration;
@@ -388,18 +369,13 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
ir_raw_event_store_with_filter(rr3->rc, &rawir);
}
- /* add a trailing space, if need be */
- if (i % 2) {
- rawir.pulse = false;
- /* this duration is made up, and may not be ideal... */
- if (trailer < US_TO_NS(1000))
- rawir.duration = US_TO_NS(2800);
- else
- rawir.duration = trailer;
- dev_dbg(dev, "storing trailing space with duration %d\n",
- rawir.duration);
- ir_raw_event_store_with_filter(rr3->rc, &rawir);
- }
+ /* add a trailing space */
+ rawir.pulse = false;
+ rawir.timeout = true;
+ rawir.duration = US_TO_NS(rr3->hw_timeout);
+ dev_dbg(dev, "storing trailing timeout with duration %d\n",
+ rawir.duration);
+ ir_raw_event_store_with_filter(rr3->rc, &rawir);
dev_dbg(dev, "calling ir_raw_event_handle\n");
ir_raw_event_handle(rr3->rc);
@@ -499,6 +475,37 @@ static u32 redrat3_get_timeout(struct redrat3_dev *rr3)
return timeout;
}
+static int redrat3_set_timeout(struct rc_dev *rc_dev, unsigned int timeoutns)
+{
+ struct redrat3_dev *rr3 = rc_dev->priv;
+ struct usb_device *udev = rr3->udev;
+ struct device *dev = rr3->dev;
+ u32 *timeout;
+ int ret;
+
+ timeout = kmalloc(sizeof(*timeout), GFP_KERNEL);
+ if (!timeout)
+ return -ENOMEM;
+
+ *timeout = cpu_to_be32(redrat3_us_to_len(timeoutns / 1000));
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), RR3_SET_IR_PARAM,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ RR3_IR_IO_SIG_TIMEOUT, 0, timeout, sizeof(*timeout),
+ HZ * 25);
+ dev_dbg(dev, "set ir parm timeout %d ret 0x%02x\n",
+ be32_to_cpu(*timeout), ret);
+
+ if (ret == sizeof(*timeout)) {
+ rr3->hw_timeout = timeoutns / 1000;
+ ret = 0;
+ } else if (ret >= 0)
+ ret = -EIO;
+
+ kfree(timeout);
+
+ return ret;
+}
+
static void redrat3_reset(struct redrat3_dev *rr3)
{
struct usb_device *udev = rr3->udev;
@@ -708,7 +715,7 @@ static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier)
rr3->carrier = carrier;
- return carrier;
+ return 0;
}
static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
@@ -880,7 +887,10 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
rc->priv = rr3;
rc->driver_type = RC_DRIVER_IR_RAW;
rc->allowed_protocols = RC_BIT_ALL;
- rc->timeout = US_TO_NS(2750);
+ rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT);
+ rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT);
+ rc->timeout = US_TO_NS(rr3->hw_timeout);
+ rc->s_timeout = redrat3_set_timeout;
rc->tx_ir = redrat3_transmit_ir;
rc->s_tx_carrier = redrat3_set_tx_carrier;
rc->driver_name = DRIVER_NAME;
@@ -990,7 +1000,7 @@ static int redrat3_dev_probe(struct usb_interface *intf,
if (retval < 0)
goto error;
- /* store current hardware timeout, in us, will use for kfifo resets */
+ /* store current hardware timeout, in µs */
rr3->hw_timeout = redrat3_get_timeout(rr3);
/* default.. will get overridden by any sends with a freq defined */
@@ -1026,7 +1036,6 @@ static int redrat3_dev_probe(struct usb_interface *intf,
retval = -ENOMEM;
goto led_free_error;
}
- setup_timer(&rr3->rx_timeout, redrat3_rx_timeout, (unsigned long)rr3);
/* we can register the device now, as it is ready */
usb_set_intfdata(intf, rr3);
@@ -1055,7 +1064,6 @@ static void redrat3_dev_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);
rc_unregister_device(rr3->rc);
led_classdev_unregister(&rr3->led);
- del_timer_sync(&rr3->rx_timeout);
redrat3_delete(rr3, udev);
}
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index d839f73f6..95ae60e65 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -615,6 +615,10 @@ wbcir_txmask(struct rc_dev *dev, u32 mask)
unsigned long flags;
u8 val;
+ /* return the number of transmitters */
+ if (mask > 15)
+ return 4;
+
/* Four outputs, only one output can be enabled at a time */
switch (mask) {
case 0x1: