diff options
Diffstat (limited to 'drivers/media/rc')
-rw-r--r-- | drivers/media/rc/img-ir/img-ir-core.c | 2 | ||||
-rw-r--r-- | drivers/media/rc/img-ir/img-ir-hw.c | 28 | ||||
-rw-r--r-- | drivers/media/rc/img-ir/img-ir-hw.h | 3 | ||||
-rw-r--r-- | drivers/media/rc/ir-lirc-codec.c | 12 | ||||
-rw-r--r-- | drivers/media/rc/rc-main.c | 14 |
5 files changed, 43 insertions, 16 deletions
diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c index a0cac2f09109..9971dda621f5 100644 --- a/drivers/media/rc/img-ir/img-ir-core.c +++ b/drivers/media/rc/img-ir/img-ir-core.c @@ -146,7 +146,7 @@ static int img_ir_remove(struct platform_device *pdev) { struct img_ir_priv *priv = platform_get_drvdata(pdev); - free_irq(priv->irq, img_ir_isr); + free_irq(priv->irq, priv); img_ir_remove_hw(priv); img_ir_remove_raw(priv); diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index ec49f94425fc..2fd47c9bf5d8 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -530,6 +530,22 @@ static void img_ir_set_decoder(struct img_ir_priv *priv, u32 ir_status, irq_en; spin_lock_irq(&priv->lock); + /* + * First record that the protocol is being stopped so that the end timer + * isn't restarted while we're trying to stop it. + */ + hw->stopping = true; + + /* + * Release the lock to stop the end timer, since the end timer handler + * acquires the lock and we don't want to deadlock waiting for it. + */ + spin_unlock_irq(&priv->lock); + del_timer_sync(&hw->end_timer); + spin_lock_irq(&priv->lock); + + hw->stopping = false; + /* switch off and disable interrupts */ img_ir_write(priv, IMG_IR_CONTROL, 0); irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE); @@ -541,12 +557,13 @@ static void img_ir_set_decoder(struct img_ir_priv *priv, if (ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2)) { ir_status &= ~(IMG_IR_RXDVAL | IMG_IR_RXDVALD2); img_ir_write(priv, IMG_IR_STATUS, ir_status); - img_ir_read(priv, IMG_IR_DATA_LW); - img_ir_read(priv, IMG_IR_DATA_UP); } - /* stop the end timer and switch back to normal mode */ - del_timer_sync(&hw->end_timer); + /* always read data to clear buffer if IR wakes the device */ + img_ir_read(priv, IMG_IR_DATA_LW); + img_ir_read(priv, IMG_IR_DATA_UP); + + /* switch back to normal mode */ hw->mode = IMG_IR_M_NORMAL; /* clear the wakeup scancode filter */ @@ -817,7 +834,8 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw) } - if (dec->repeat) { + /* we mustn't update the end timer while trying to stop it */ + if (dec->repeat && !hw->stopping) { unsigned long interval; img_ir_begin_repeat(priv); diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h index 8fcc16c32c5b..307ddcd1a99e 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.h +++ b/drivers/media/rc/img-ir/img-ir-hw.h @@ -214,6 +214,8 @@ enum img_ir_mode { * @flags: IMG_IR_F_*. * @filters: HW filters (derived from scancode filters). * @mode: Current decode mode. + * @stopping: Indicates that decoder is being taken down and timers + * should not be restarted. * @suspend_irqen: Saved IRQ enable mask over suspend. */ struct img_ir_priv_hw { @@ -229,6 +231,7 @@ struct img_ir_priv_hw { struct img_ir_filter filters[RC_FILTER_MAX]; enum img_ir_mode mode; + bool stopping; u32 suspend_irqen; }; diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index ed2c8a1ed8ca..98893a8332c7 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -42,11 +42,17 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) return -EINVAL; /* Packet start */ - if (ev.reset) - return 0; + if (ev.reset) { + /* Userspace expects a long space event before the start of + * the signal to use as a sync. This may be done with repeat + * packets and normal samples. But if a reset has been sent + * then we assume that a long time has passed, so we send a + * space with the maximum time value. */ + sample = LIRC_SPACE(LIRC_VALUE_MASK); + IR_dprintk(2, "delivering reset sync space to lirc_dev\n"); /* Carrier reports */ - if (ev.carrier_report) { + } else if (ev.carrier_report) { sample = LIRC_FREQUENCY(ev.carrier); IR_dprintk(2, "carrier report (freq: %d)\n", sample); diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 8d3b74c5a717..fc369b033484 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1021,16 +1021,16 @@ static ssize_t store_protocols(struct device *device, goto out; } - if (new_protocols == old_protocols) { - rc = len; - goto out; + if (new_protocols != old_protocols) { + *current_protocols = new_protocols; + IR_dprintk(1, "Protocols changed to 0x%llx\n", + (long long)new_protocols); } - *current_protocols = new_protocols; - IR_dprintk(1, "Protocols changed to 0x%llx\n", (long long)new_protocols); - /* - * If the protocol is changed the filter needs updating. + * If a protocol change was attempted the filter may need updating, even + * if the actual protocol mask hasn't changed (since the driver may have + * cleared the filter). * Try setting the same filter with the new protocol (if any). * Fall back to clearing the filter. */ |