diff options
Diffstat (limited to 'drivers/media/rc')
-rw-r--r-- | drivers/media/rc/Kconfig | 2 | ||||
-rw-r--r-- | drivers/media/rc/ene_ir.c | 2 | ||||
-rw-r--r-- | drivers/media/rc/iguanair.c | 2 | ||||
-rw-r--r-- | drivers/media/rc/ir-lirc-codec.c | 5 | ||||
-rw-r--r-- | drivers/media/rc/ir-rx51.c | 229 | ||||
-rw-r--r-- | drivers/media/rc/keymaps/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/rc/keymaps/rc-cec.c | 182 | ||||
-rw-r--r-- | drivers/media/rc/keymaps/rc-dtt200u.c | 59 | ||||
-rw-r--r-- | drivers/media/rc/lirc_dev.c | 299 | ||||
-rw-r--r-- | drivers/media/rc/mceusb.c | 8 | ||||
-rw-r--r-- | drivers/media/rc/nuvoton-cir.c | 137 | ||||
-rw-r--r-- | drivers/media/rc/nuvoton-cir.h | 25 | ||||
-rw-r--r-- | drivers/media/rc/rc-main.c | 11 | ||||
-rw-r--r-- | drivers/media/rc/redrat3.c | 84 | ||||
-rw-r--r-- | drivers/media/rc/winbond-cir.c | 4 |
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: |