diff options
Diffstat (limited to 'drivers/media/rc')
-rw-r--r-- | drivers/media/rc/ati_remote.c | 47 | ||||
-rw-r--r-- | drivers/media/rc/igorplugusb.c | 17 | ||||
-rw-r--r-- | drivers/media/rc/keymaps/rc-avermedia-rm-ks.c | 56 | ||||
-rw-r--r-- | drivers/media/rc/lirc_dev.c | 7 | ||||
-rw-r--r-- | drivers/media/rc/mceusb.c | 5 | ||||
-rw-r--r-- | drivers/media/rc/nuvoton-cir.c | 106 | ||||
-rw-r--r-- | drivers/media/rc/nuvoton-cir.h | 3 | ||||
-rw-r--r-- | drivers/media/rc/rc-main.c | 47 | ||||
-rw-r--r-- | drivers/media/rc/sunxi-cir.c | 1 |
9 files changed, 205 insertions, 84 deletions
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index a35631891cc0..3f61d77d4147 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -443,6 +443,21 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, return retval; } +struct accel_times { + const char value; + unsigned int msecs; +}; + +static const struct accel_times accel[] = { + { 1, 125 }, + { 2, 250 }, + { 4, 500 }, + { 6, 1000 }, + { 9, 1500 }, + { 13, 2000 }, + { 20, 0 }, +}; + /* * ati_remote_compute_accel * @@ -454,30 +469,22 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, */ static int ati_remote_compute_accel(struct ati_remote *ati_remote) { - static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; - unsigned long now = jiffies; - int acc; + unsigned long now = jiffies, reset_time; + int i; + + reset_time = msecs_to_jiffies(250); - if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) { - acc = 1; + if (time_after(now, ati_remote->old_jiffies + reset_time)) { ati_remote->acc_jiffies = now; + return 1; } - else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125))) - acc = accel[0]; - else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250))) - acc = accel[1]; - else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500))) - acc = accel[2]; - else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000))) - acc = accel[3]; - else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500))) - acc = accel[4]; - else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000))) - acc = accel[5]; - else - acc = accel[6]; + for (i = 0; i < ARRAY_SIZE(accel) - 1; i++) { + unsigned long timeout = msecs_to_jiffies(accel[i].msecs); - return acc; + if (time_before(now, ati_remote->acc_jiffies + timeout)) + return accel[i].value; + } + return accel[i].value; } /* diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c index b36e51576f8e..e0c531fa01da 100644 --- a/drivers/media/rc/igorplugusb.c +++ b/drivers/media/rc/igorplugusb.c @@ -152,7 +152,7 @@ static int igorplugusb_probe(struct usb_interface *intf, struct usb_endpoint_descriptor *ep; struct igorplugusb *ir; struct rc_dev *rc; - int ret; + int ret = -ENOMEM; udev = interface_to_usbdev(intf); idesc = intf->cur_altsetting; @@ -182,7 +182,7 @@ static int igorplugusb_probe(struct usb_interface *intf, ir->urb = usb_alloc_urb(0, GFP_KERNEL); if (!ir->urb) - return -ENOMEM; + goto fail; usb_fill_control_urb(ir->urb, udev, usb_rcvctrlpipe(udev, 0), (uint8_t *)&ir->request, @@ -191,6 +191,9 @@ static int igorplugusb_probe(struct usb_interface *intf, usb_make_path(udev, ir->phys, sizeof(ir->phys)); rc = rc_allocate_device(); + if (!rc) + goto fail; + rc->input_name = DRIVER_DESC; rc->input_phys = ir->phys; usb_to_input_id(udev, &rc->input_id); @@ -214,9 +217,7 @@ static int igorplugusb_probe(struct usb_interface *intf, ret = rc_register_device(rc); if (ret) { dev_err(&intf->dev, "failed to register rc device: %d", ret); - rc_free_device(rc); - usb_free_urb(ir->urb); - return ret; + goto fail; } usb_set_intfdata(intf, ir); @@ -224,6 +225,12 @@ static int igorplugusb_probe(struct usb_interface *intf, igorplugusb_cmd(ir, SET_INFRABUFFER_EMPTY); return 0; +fail: + rc_free_device(ir->rc); + usb_free_urb(ir->urb); + del_timer(&ir->timer); + + return ret; } static void igorplugusb_disconnect(struct usb_interface *intf) diff --git a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c index 8344bcc595be..2583400ca1b4 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c +++ b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c @@ -23,35 +23,35 @@ /* Initial keytable is from Jose Alberto Reguero <jareguero@telefonica.net> and Felipe Morales Moreno <felipe.morales.moreno@gmail.com> */ -/* FIXME: mappings are not 100% correct? */ +/* Keytable fixed by Philippe Valembois <lephilousophe@users.sourceforge.net> */ static struct rc_map_table avermedia_rm_ks[] = { - { 0x0501, KEY_POWER2 }, - { 0x0502, KEY_CHANNELUP }, - { 0x0503, KEY_CHANNELDOWN }, - { 0x0504, KEY_VOLUMEUP }, - { 0x0505, KEY_VOLUMEDOWN }, - { 0x0506, KEY_MUTE }, - { 0x0507, KEY_RIGHT }, - { 0x0508, KEY_RED }, - { 0x0509, KEY_1 }, - { 0x050a, KEY_2 }, - { 0x050b, KEY_3 }, - { 0x050c, KEY_4 }, - { 0x050d, KEY_5 }, - { 0x050e, KEY_6 }, - { 0x050f, KEY_7 }, - { 0x0510, KEY_8 }, - { 0x0511, KEY_9 }, - { 0x0512, KEY_0 }, - { 0x0513, KEY_AUDIO }, - { 0x0515, KEY_EPG }, - { 0x0516, KEY_PLAY }, - { 0x0517, KEY_RECORD }, - { 0x0518, KEY_STOP }, - { 0x051c, KEY_BACK }, - { 0x051d, KEY_FORWARD }, - { 0x054d, KEY_LEFT }, - { 0x0556, KEY_ZOOM }, + { 0x0501, KEY_POWER2 }, /* Power (RED POWER BUTTON) */ + { 0x0502, KEY_CHANNELUP }, /* Channel+ */ + { 0x0503, KEY_CHANNELDOWN }, /* Channel- */ + { 0x0504, KEY_VOLUMEUP }, /* Volume+ */ + { 0x0505, KEY_VOLUMEDOWN }, /* Volume- */ + { 0x0506, KEY_MUTE }, /* Mute */ + { 0x0507, KEY_AGAIN }, /* Recall */ + { 0x0508, KEY_VIDEO }, /* Source */ + { 0x0509, KEY_1 }, /* 1 */ + { 0x050a, KEY_2 }, /* 2 */ + { 0x050b, KEY_3 }, /* 3 */ + { 0x050c, KEY_4 }, /* 4 */ + { 0x050d, KEY_5 }, /* 5 */ + { 0x050e, KEY_6 }, /* 6 */ + { 0x050f, KEY_7 }, /* 7 */ + { 0x0510, KEY_8 }, /* 8 */ + { 0x0511, KEY_9 }, /* 9 */ + { 0x0512, KEY_0 }, /* 0 */ + { 0x0513, KEY_AUDIO }, /* Audio */ + { 0x0515, KEY_EPG }, /* EPG */ + { 0x0516, KEY_PLAYPAUSE }, /* Play/Pause */ + { 0x0517, KEY_RECORD }, /* Record */ + { 0x0518, KEY_STOP }, /* Stop */ + { 0x051c, KEY_BACK }, /* << */ + { 0x051d, KEY_FORWARD }, /* >> */ + { 0x054d, KEY_INFO }, /* Display information */ + { 0x0556, KEY_ZOOM }, /* Fullscreen */ }; static struct rc_map_list avermedia_rm_ks_map = { diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 4de0e85af805..92ae1903c010 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -506,6 +506,7 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file) { struct irctl *ir = irctls[iminor(inode)]; struct cdev *cdev; + int ret; if (!ir) { printk(KERN_ERR "%s: called with invalid irctl\n", __func__); @@ -516,7 +517,8 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file) dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor); - WARN_ON(mutex_lock_killable(&lirc_dev_lock)); + ret = mutex_lock_killable(&lirc_dev_lock); + WARN_ON(ret); rc_close(ir->d.rdev); @@ -532,7 +534,8 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file) kfree(ir); } - mutex_unlock(&lirc_dev_lock); + if (!ret) + mutex_unlock(&lirc_dev_lock); return 0; } diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 2cdb740cde48..35155ae500c7 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -587,9 +587,8 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, if (len == 2) dev_dbg(dev, "Get hw/sw rev?"); else - dev_dbg(dev, "hw/sw rev 0x%02x 0x%02x 0x%02x 0x%02x", - data1, data2, - buf[start + 4], buf[start + 5]); + dev_dbg(dev, "hw/sw rev %*ph", + 4, &buf[start + 2]); break; case MCE_CMD_RESUME: dev_dbg(dev, "Device resume requested"); diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index c96da3aaf00b..99b303b702ac 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -39,6 +39,8 @@ #include "nuvoton-cir.h" +static void nvt_clear_cir_wake_fifo(struct nvt_dev *nvt); + static const struct nvt_chip nvt_chips[] = { { "w83667hg", NVT_W83667HG }, { "NCT6775F", NVT_6775F }, @@ -177,6 +179,104 @@ static void nvt_set_ioaddr(struct nvt_dev *nvt, unsigned long *ioaddr) } } +static ssize_t wakeup_data_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rc_dev *rc_dev = to_rc_dev(dev); + struct nvt_dev *nvt = rc_dev->priv; + int fifo_len, duration; + unsigned long flags; + ssize_t buf_len = 0; + int i; + + spin_lock_irqsave(&nvt->nvt_lock, flags); + + fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT); + fifo_len = min(fifo_len, WAKEUP_MAX_SIZE); + + /* go to first element to be read */ + while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) + nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY); + + for (i = 0; i < fifo_len; i++) { + duration = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY); + duration = (duration & BUF_LEN_MASK) * SAMPLE_PERIOD; + buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len, + "%d ", duration); + } + buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len, "\n"); + + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + + return buf_len; +} + +static ssize_t wakeup_data_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct rc_dev *rc_dev = to_rc_dev(dev); + struct nvt_dev *nvt = rc_dev->priv; + unsigned long flags; + u8 tolerance, config, wake_buf[WAKEUP_MAX_SIZE]; + char **argv; + int i, count; + unsigned int val; + ssize_t ret; + + argv = argv_split(GFP_KERNEL, buf, &count); + if (!argv) + return -ENOMEM; + if (!count || count > WAKEUP_MAX_SIZE) { + ret = -EINVAL; + goto out; + } + + for (i = 0; i < count; i++) { + ret = kstrtouint(argv[i], 10, &val); + if (ret) + goto out; + val = DIV_ROUND_CLOSEST(val, SAMPLE_PERIOD); + if (!val || val > 0x7f) { + ret = -EINVAL; + goto out; + } + wake_buf[i] = val; + /* sequence must start with a pulse */ + if (i % 2 == 0) + wake_buf[i] |= BUF_PULSE_BIT; + } + + /* hardcode the tolerance to 10% */ + tolerance = DIV_ROUND_UP(count, 10); + + spin_lock_irqsave(&nvt->nvt_lock, flags); + + nvt_clear_cir_wake_fifo(nvt); + nvt_cir_wake_reg_write(nvt, count, CIR_WAKE_FIFO_CMP_DEEP); + nvt_cir_wake_reg_write(nvt, tolerance, CIR_WAKE_FIFO_CMP_TOL); + + config = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON); + + /* enable writes to wake fifo */ + nvt_cir_wake_reg_write(nvt, config | CIR_WAKE_IRCON_MODE1, + CIR_WAKE_IRCON); + + for (i = 0; i < count; i++) + nvt_cir_wake_reg_write(nvt, wake_buf[i], CIR_WAKE_WR_FIFO_DATA); + + nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON); + + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + + ret = len; +out: + argv_free(argv); + return ret; +} +static DEVICE_ATTR_RW(wakeup_data); + /* dump current cir register contents */ static void cir_dump_regs(struct nvt_dev *nvt) { @@ -1133,6 +1233,10 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) 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; + device_init_wakeup(&pdev->dev, true); dev_notice(&pdev->dev, "driver has been successfully loaded\n"); @@ -1156,6 +1260,8 @@ static void nvt_remove(struct pnp_dev *pdev) { struct nvt_dev *nvt = pnp_get_drvdata(pdev); + device_remove_file(&nvt->rdev->dev, &dev_attr_wakeup_data); + nvt_disable_cir(nvt); /* enable CIR Wake (for IR power-on) */ diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index 4a5650dffa29..c9c98ebb19ee 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -417,3 +417,6 @@ struct nvt_dev { /* as VISTA MCE definition, valid carrier value */ #define MAX_CARRIER 60000 #define MIN_CARRIER 30000 + +/* max wakeup sequence length */ +#define WAKEUP_MAX_SIZE 65 diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index dcf20d9cbe09..4e9bbe735ae9 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -13,6 +13,7 @@ */ #include <media/rc-core.h> +#include <linux/atomic.h> #include <linux/spinlock.h> #include <linux/delay.h> #include <linux/input.h> @@ -723,10 +724,6 @@ int rc_open(struct rc_dev *rdev) return -EINVAL; mutex_lock(&rdev->lock); - if (!rdev->initialized) { - rval = -EINVAL; - goto unlock; - } if (!rdev->users++ && rdev->open != NULL) rval = rdev->open(rdev); @@ -734,7 +731,6 @@ int rc_open(struct rc_dev *rdev) if (rval) rdev->users--; -unlock: mutex_unlock(&rdev->lock); return rval; @@ -879,11 +875,10 @@ static ssize_t show_protocols(struct device *device, if (!dev) return -EINVAL; + if (!atomic_read(&dev->initialized)) + return -ERESTARTSYS; + mutex_lock(&dev->lock); - if (!dev->initialized) { - mutex_unlock(&dev->lock); - return -EINVAL; - } if (fattr->type == RC_FILTER_NORMAL) { enabled = dev->enabled_protocols; @@ -1064,6 +1059,9 @@ static ssize_t store_protocols(struct device *device, if (!dev) return -EINVAL; + if (!atomic_read(&dev->initialized)) + return -ERESTARTSYS; + if (fattr->type == RC_FILTER_NORMAL) { IR_dprintk(1, "Normal protocol change requested\n"); current_protocols = &dev->enabled_protocols; @@ -1084,10 +1082,6 @@ static ssize_t store_protocols(struct device *device, } mutex_lock(&dev->lock); - if (!dev->initialized) { - rc = -EINVAL; - goto out; - } old_protocols = *current_protocols; new_protocols = old_protocols; @@ -1168,11 +1162,10 @@ static ssize_t show_filter(struct device *device, if (!dev) return -EINVAL; + if (!atomic_read(&dev->initialized)) + return -ERESTARTSYS; + mutex_lock(&dev->lock); - if (!dev->initialized) { - mutex_unlock(&dev->lock); - return -EINVAL; - } if (fattr->type == RC_FILTER_NORMAL) filter = &dev->scancode_filter; @@ -1223,6 +1216,9 @@ static ssize_t store_filter(struct device *device, if (!dev) return -EINVAL; + if (!atomic_read(&dev->initialized)) + return -ERESTARTSYS; + ret = kstrtoul(buf, 0, &val); if (ret < 0) return ret; @@ -1241,10 +1237,6 @@ static ssize_t store_filter(struct device *device, return -EINVAL; mutex_lock(&dev->lock); - if (!dev->initialized) { - ret = -EINVAL; - goto unlock; - } new_filter = *filter; if (fattr->mask) @@ -1431,6 +1423,7 @@ int rc_register_device(struct rc_dev *dev) dev->minor = minor; dev_set_name(&dev->dev, "rc%u", dev->minor); dev_set_drvdata(&dev->dev, dev); + atomic_set(&dev->initialized, 0); dev->dev.groups = dev->sysfs_groups; dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp; @@ -1455,10 +1448,6 @@ int rc_register_device(struct rc_dev *dev) dev->input_dev->phys = dev->input_phys; dev->input_dev->name = dev->input_name; - rc = input_register_device(dev->input_dev); - if (rc) - goto out_table; - /* * Default delay of 250ms is too short for some protocols, especially * since the timeout is currently set to 250ms. Increase it to 500ms, @@ -1474,6 +1463,11 @@ int rc_register_device(struct rc_dev *dev) */ dev->input_dev->rep[REP_PERIOD] = 125; + /* rc_open will be called here */ + rc = input_register_device(dev->input_dev); + if (rc) + goto out_table; + path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); dev_info(&dev->dev, "%s as %s\n", dev->input_name ?: "Unspecified device", path ?: "N/A"); @@ -1497,8 +1491,9 @@ int rc_register_device(struct rc_dev *dev) dev->enabled_protocols = rc_type; } + /* Allow the RC sysfs nodes to be accessible */ mutex_lock(&dev->lock); - dev->initialized = true; + atomic_set(&dev->initialized, 1); mutex_unlock(&dev->lock); IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n", diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index 40f77685cc4a..eaadc081760a 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -326,6 +326,7 @@ static const struct of_device_id sunxi_ir_match[] = { { .compatible = "allwinner,sun5i-a13-ir", }, {}, }; +MODULE_DEVICE_TABLE(of, sunxi_ir_match); static struct platform_driver sunxi_ir_driver = { .probe = sunxi_ir_probe, |