[media] IR: extend ir_raw_event and do refactoring
authorMaxim Levitsky <maximlevitsky@gmail.com>
Sat, 16 Oct 2010 22:56:28 +0000 (19:56 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 21 Oct 2010 12:59:47 +0000 (10:59 -0200)
Add new event types for timeout & carrier report
Move timeout handling from ir_raw_event_store_with_filter to
ir-lirc-codec, where it is really needed.
Now lirc bridge ensures proper gap handling.
Extend lirc bridge for carrier & timeout reports

Note: all new ir_raw_event variables now should be initialized
like that: DEFINE_IR_RAW_EVENT(ev);

To clean an existing event, use init_ir_raw_event(&ev);

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
Acked-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
14 files changed:
drivers/media/IR/ene_ir.c
drivers/media/IR/ir-core-priv.h
drivers/media/IR/ir-jvc-decoder.c
drivers/media/IR/ir-lirc-codec.c
drivers/media/IR/ir-nec-decoder.c
drivers/media/IR/ir-raw-event.c
drivers/media/IR/ir-rc5-decoder.c
drivers/media/IR/ir-rc5-sz-decoder.c
drivers/media/IR/ir-rc6-decoder.c
drivers/media/IR/ir-sony-decoder.c
drivers/media/IR/mceusb.c
drivers/media/IR/nuvoton-cir.c
drivers/media/IR/streamzap.c
include/media/ir-core.h

index f5beea04906af65b2a3be99935e5be87c7b73e5f..0795872ff5de1a2be0888b18e5ed9a6888fd5d4d 100644 (file)
@@ -697,7 +697,7 @@ static irqreturn_t ene_isr(int irq, void *data)
        unsigned long flags;
        irqreturn_t retval = IRQ_NONE;
        struct ene_device *dev = (struct ene_device *)data;
-       struct ir_raw_event ev;
+       DEFINE_IR_RAW_EVENT(ev);
 
        spin_lock_irqsave(&dev->hw_lock, flags);
 
@@ -898,7 +898,7 @@ static int ene_set_learning_mode(void *data, int enable)
 }
 
 /* outside interface: enable or disable idle mode */
-static void ene_rx_set_idle(void *data, int idle)
+static void ene_rx_set_idle(void *data, bool idle)
 {
        struct ene_device *dev = (struct ene_device *)data;
 
index 6830580ae4db3b523eeae4fedecb7955321aa8ac..81c936bd793f1bf5c7b337c1dfbf09709be24891 100644 (file)
@@ -88,6 +88,12 @@ struct ir_raw_event_ctrl {
                struct ir_input_dev *ir_dev;
                struct lirc_driver *drv;
                int carrier_low;
+
+               ktime_t gap_start;
+               u64 gap_duration;
+               bool gap;
+               bool send_timeout_reports;
+
        } lirc;
 };
 
@@ -115,9 +121,14 @@ static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration)
                ev->duration -= duration;
 }
 
+/* Returns true if event is normal pulse/space event */
+static inline bool is_timing_event(struct ir_raw_event ev)
+{
+       return !ev.carrier_report && !ev.reset;
+}
+
 #define TO_US(duration)                        DIV_ROUND_CLOSEST((duration), 1000)
 #define TO_STR(is_pulse)               ((is_pulse) ? "pulse" : "space")
-#define IS_RESET(ev)                   (ev.duration == 0)
 /*
  * Routines from ir-sysfs.c - Meant to be called only internally inside
  * ir-core
index 77a89c4de0143beba0d01d9ba19ec329ca0dc9b8..63dca6e5458b9100b098c4673a28b7aa1f474cf4 100644 (file)
@@ -50,8 +50,9 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC))
                return 0;
 
-       if (IS_RESET(ev)) {
-               data->state = STATE_INACTIVE;
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
                return 0;
        }
 
index 20ac9a4ce522c8fa620eda2478c740584308f6b7..1d9c6b0fd0eaa1434d8c449ca9ff34d93871d568 100644 (file)
@@ -32,6 +32,7 @@
 static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 {
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       struct lirc_codec *lirc = &ir_dev->raw->lirc;
        int sample;
 
        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC))
@@ -40,21 +41,57 @@ static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf)
                return -EINVAL;
 
-       if (IS_RESET(ev))
+       /* Packet start */
+       if (ev.reset)
                return 0;
 
-       IR_dprintk(2, "LIRC data transfer started (%uus %s)\n",
-                  TO_US(ev.duration), TO_STR(ev.pulse));
+       /* Carrier reports */
+       if (ev.carrier_report) {
+               sample = LIRC_FREQUENCY(ev.carrier);
+
+       /* Packet end */
+       } else if (ev.timeout) {
+
+               if (lirc->gap)
+                       return 0;
+
+               lirc->gap_start = ktime_get();
+               lirc->gap = true;
+               lirc->gap_duration = ev.duration;
+
+               if (!lirc->send_timeout_reports)
+                       return 0;
+
+               sample = LIRC_TIMEOUT(ev.duration / 1000);
 
-       sample = ev.duration / 1000;
-       if (ev.pulse)
-               sample |= PULSE_BIT;
+       /* Normal sample */
+       } else {
+
+               if (lirc->gap) {
+                       int gap_sample;
+
+                       lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(),
+                               lirc->gap_start));
+
+                       /* Convert to ms and cap by LIRC_VALUE_MASK */
+                       do_div(lirc->gap_duration, 1000);
+                       lirc->gap_duration = min(lirc->gap_duration,
+                                                       (u64)LIRC_VALUE_MASK);
+
+                       gap_sample = LIRC_SPACE(lirc->gap_duration);
+                       lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
+                                               (unsigned char *) &gap_sample);
+                       lirc->gap = false;
+               }
+
+               sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
+                                       LIRC_SPACE(ev.duration / 1000);
+       }
 
        lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
                          (unsigned char *) &sample);
        wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll);
 
-
        return 0;
 }
 
@@ -102,7 +139,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
        struct ir_input_dev *ir_dev;
        int ret = 0;
        void *drv_data;
-       __u32 val = 0;
+       __u32 val = 0, tmp;
 
        lirc = lirc_get_pdata(filep);
        if (!lirc)
@@ -130,22 +167,20 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
        case LIRC_SET_SEND_MODE:
                if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK))
                        return -EINVAL;
-               break;
+               return 0;
 
        /* TX settings */
        case LIRC_SET_TRANSMITTER_MASK:
-               if (ir_dev->props->s_tx_mask)
-                       ret = ir_dev->props->s_tx_mask(drv_data, val);
-               else
+               if (!ir_dev->props->s_tx_mask)
                        return -EINVAL;
-               break;
+
+               return ir_dev->props->s_tx_mask(drv_data, val);
 
        case LIRC_SET_SEND_CARRIER:
-               if (ir_dev->props->s_tx_carrier)
-                       ir_dev->props->s_tx_carrier(drv_data, val);
-               else
+               if (!ir_dev->props->s_tx_carrier)
                        return -EINVAL;
-               break;
+
+               return ir_dev->props->s_tx_carrier(drv_data, val);
 
        case LIRC_SET_SEND_DUTY_CYCLE:
                if (!ir_dev->props->s_tx_duty_cycle)
@@ -154,39 +189,42 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
                if (val <= 0 || val >= 100)
                        return -EINVAL;
 
-               ir_dev->props->s_tx_duty_cycle(ir_dev->props->priv, val);
-               break;
+               return ir_dev->props->s_tx_duty_cycle(drv_data, val);
 
        /* RX settings */
        case LIRC_SET_REC_CARRIER:
-               if (ir_dev->props->s_rx_carrier_range)
-                       ret = ir_dev->props->s_rx_carrier_range(
-                               ir_dev->props->priv,
-                               ir_dev->raw->lirc.carrier_low, val);
-               else
+               if (!ir_dev->props->s_rx_carrier_range)
                        return -ENOSYS;
 
-               if (!ret)
-                       ir_dev->raw->lirc.carrier_low = 0;
-               break;
+               if (val <= 0)
+                       return -EINVAL;
+
+               return ir_dev->props->s_rx_carrier_range(drv_data,
+                       ir_dev->raw->lirc.carrier_low, val);
 
        case LIRC_SET_REC_CARRIER_RANGE:
-               if (val >= 0)
-                       ir_dev->raw->lirc.carrier_low = val;
-               break;
+               if (val <= 0)
+                       return -EINVAL;
 
+               ir_dev->raw->lirc.carrier_low = val;
+               return 0;
 
        case LIRC_GET_REC_RESOLUTION:
                val = ir_dev->props->rx_resolution;
                break;
 
        case LIRC_SET_WIDEBAND_RECEIVER:
-               if (ir_dev->props->s_learning_mode)
-                       return ir_dev->props->s_learning_mode(
-                               ir_dev->props->priv, !!val);
-               else
+               if (!ir_dev->props->s_learning_mode)
                        return -ENOSYS;
 
+               return ir_dev->props->s_learning_mode(drv_data, !!val);
+
+       case LIRC_SET_MEASURE_CARRIER_MODE:
+               if (!ir_dev->props->s_carrier_report)
+                       return -ENOSYS;
+
+               return ir_dev->props->s_carrier_report(drv_data, !!val);
+
        /* Generic timeout support */
        case LIRC_GET_MIN_TIMEOUT:
                if (!ir_dev->props->max_timeout)
@@ -201,10 +239,20 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
                break;
 
        case LIRC_SET_REC_TIMEOUT:
-               if (val < ir_dev->props->min_timeout ||
-                   val > ir_dev->props->max_timeout)
-                       return -EINVAL;
-               ir_dev->props->timeout = val * 1000;
+               if (!ir_dev->props->max_timeout)
+                       return -ENOSYS;
+
+               tmp = val * 1000;
+
+               if (tmp < ir_dev->props->min_timeout ||
+                       tmp > ir_dev->props->max_timeout)
+                               return -EINVAL;
+
+               ir_dev->props->timeout = tmp;
+               break;
+
+       case LIRC_SET_REC_TIMEOUT_REPORTS:
+               lirc->send_timeout_reports = !!val;
                break;
 
        default:
@@ -280,6 +328,10 @@ static int ir_lirc_register(struct input_dev *input_dev)
        if (ir_dev->props->s_learning_mode)
                features |= LIRC_CAN_USE_WIDEBAND_RECEIVER;
 
+       if (ir_dev->props->s_carrier_report)
+               features |= LIRC_CAN_MEASURE_CARRIER;
+
+
        if (ir_dev->props->max_timeout)
                features |= LIRC_CAN_SET_REC_TIMEOUT;
 
index d597421d65470f3ca146a361c06a9aee9b175ed9..70993f79c8a2b9bb2a556f618df782cb59114368 100644 (file)
@@ -54,8 +54,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC))
                return 0;
 
-       if (IS_RESET(ev)) {
-               data->state = STATE_INACTIVE;
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
                return 0;
        }
 
index 119b567feeab2aeec8f0ff03d49a2ccade6fa058..0d59ef7d10145539a9c68b67524dd1dde4edd8d2 100644 (file)
@@ -174,7 +174,7 @@ int ir_raw_event_store_with_filter(struct input_dev *input_dev,
        if (ir->idle && !ev->pulse)
                return 0;
        else if (ir->idle)
-               ir_raw_event_set_idle(input_dev, 0);
+               ir_raw_event_set_idle(input_dev, false);
 
        if (!raw->this_ev.duration) {
                raw->this_ev = *ev;
@@ -187,48 +187,35 @@ int ir_raw_event_store_with_filter(struct input_dev *input_dev,
 
        /* Enter idle mode if nessesary */
        if (!ev->pulse && ir->props->timeout &&
-               raw->this_ev.duration >= ir->props->timeout)
-               ir_raw_event_set_idle(input_dev, 1);
+               raw->this_ev.duration >= ir->props->timeout) {
+               ir_raw_event_set_idle(input_dev, true);
+       }
        return 0;
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
 
-void ir_raw_event_set_idle(struct input_dev *input_dev, int idle)
+/**
+ * ir_raw_event_set_idle() - hint the ir core if device is receiving
+ * IR data or not
+ * @input_dev: the struct input_dev device descriptor
+ * @idle: the hint value
+ */
+void ir_raw_event_set_idle(struct input_dev *input_dev, bool idle)
 {
        struct ir_input_dev *ir = input_get_drvdata(input_dev);
        struct ir_raw_event_ctrl *raw = ir->raw;
-       ktime_t now;
-       u64 delta;
 
-       if (!ir->props)
+       if (!ir->props || !ir->raw)
                return;
 
-       if (!ir->raw)
-               goto out;
+       IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
 
        if (idle) {
-               IR_dprintk(2, "enter idle mode\n");
-               raw->last_event = ktime_get();
-       } else {
-               IR_dprintk(2, "exit idle mode\n");
-
-               now = ktime_get();
-               delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event));
-
-               WARN_ON(raw->this_ev.pulse);
-
-               raw->this_ev.duration =
-                       min(raw->this_ev.duration + delta,
-                                               (u64)IR_MAX_DURATION);
-
+               raw->this_ev.timeout = true;
                ir_raw_event_store(input_dev, &raw->this_ev);
-
-               if (raw->this_ev.duration == IR_MAX_DURATION)
-                       ir_raw_event_reset(input_dev);
-
-               raw->this_ev.duration = 0;
+               init_ir_raw_event(&raw->this_ev);
        }
-out:
+
        if (ir->props->s_idle)
                ir->props->s_idle(ir->props->priv, idle);
        ir->idle = idle;
index df4770d978ad835201ec31341d122f3011db9427..572ed4ca8c6886eac536015f6b928e218e601878 100644 (file)
@@ -55,8 +55,9 @@ static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
         if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5))
                 return 0;
 
-       if (IS_RESET(ev)) {
-               data->state = STATE_INACTIVE;
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
                return 0;
        }
 
index 68f11d6acd5ba992f8fc975245043170e8241137..7c413501a3f776361d96c9094850182cdc4c075c 100644 (file)
@@ -51,8 +51,9 @@ static int ir_rc5_sz_decode(struct input_dev *input_dev, struct ir_raw_event ev)
         if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5_SZ))
                 return 0;
 
-       if (IS_RESET(ev)) {
-               data->state = STATE_INACTIVE;
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
                return 0;
        }
 
index f1624b8279bcce2d581c567cf0840b38ebfc4bc2..d25da91f44ff4fdbbd1fb24fa6c8c9305690e711 100644 (file)
@@ -85,8 +85,9 @@ static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6))
                return 0;
 
-       if (IS_RESET(ev)) {
-               data->state = STATE_INACTIVE;
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
                return 0;
        }
 
index b9074f07c7a0570293e46eebb8981900da862035..2d15730822bc78931c3e4c9c0aad33211563ed70 100644 (file)
@@ -48,8 +48,9 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY))
                return 0;
 
-       if (IS_RESET(ev)) {
-               data->state = STATE_INACTIVE;
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
                return 0;
        }
 
index bc620e10ef77e46149f57bdf278cc8bf79d150b3..6825da5771f6d5dbd6abf84fa01e5673c546e282 100644 (file)
@@ -660,7 +660,7 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier)
 
 static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
 {
-       struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
+       DEFINE_IR_RAW_EVENT(rawir);
        int i, start_index = 0;
        u8 hdr = MCE_CONTROL_HEADER;
 
@@ -997,6 +997,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
        ir->len_in = maxp;
        ir->flags.microsoft_gen1 = is_microsoft_gen1;
        ir->flags.tx_mask_inverted = tx_mask_inverted;
+       init_ir_raw_event(&ir->rawir);
 
        /* Saving usb interface data for use by the transmitter routine */
        ir->usb_ep_in = ep_in;
index 2f0f78078b57a1de52fa7dc7b4730fedde32a630..301be53aee857298c43855df887a90ece26a2d8c 100644 (file)
@@ -586,7 +586,7 @@ static void nvt_dump_rx_buf(struct nvt_dev *nvt)
  */
 static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
 {
-       struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
+       DEFINE_IR_RAW_EVENT(rawir);
        unsigned int count;
        u32 carrier;
        u8 sample;
@@ -622,6 +622,8 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
                }
 
                rawir.duration += nvt->rawir.duration;
+
+               init_ir_raw_event(&nvt->rawir);
                nvt->rawir.duration = 0;
                nvt->rawir.pulse = rawir.pulse;
 
@@ -1016,6 +1018,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 
        spin_lock_init(&nvt->nvt_lock);
        spin_lock_init(&nvt->tx.lock);
+       init_ir_raw_event(&nvt->rawir);
 
        ret = -EBUSY;
        /* now claim resources */
index 86a4f68feea4b563f75f72c634bc1393c0717865..548381c35bfd1573bf5886b648100e0d06a63f11 100644 (file)
@@ -146,7 +146,7 @@ static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
 static void sz_push_full_pulse(struct streamzap_ir *sz,
                               unsigned char value)
 {
-       struct ir_raw_event rawir;
+       DEFINE_IR_RAW_EVENT(rawir);
 
        if (sz->idle) {
                long deltv;
@@ -193,7 +193,7 @@ static void sz_push_half_pulse(struct streamzap_ir *sz,
 static void sz_push_full_space(struct streamzap_ir *sz,
                               unsigned char value)
 {
-       struct ir_raw_event rawir;
+       DEFINE_IR_RAW_EVENT(rawir);
 
        rawir.pulse = false;
        rawir.duration = ((int) value) * SZ_RESOLUTION;
@@ -270,7 +270,7 @@ static void streamzap_callback(struct urb *urb)
                        break;
                case FullSpace:
                        if (sz->buf_in[i] == SZ_TIMEOUT) {
-                               struct ir_raw_event rawir;
+                               DEFINE_IR_RAW_EVENT(rawir);
 
                                rawir.pulse = false;
                                rawir.duration = timeout;
index 4dd43d44ec5e58b8215317b2c90880f5dd437954..6dc37fae660609e278b4dd1977120a29ee28f636 100644 (file)
@@ -60,6 +60,7 @@ enum rc_driver_type {
  * @s_idle: optional: enable/disable hardware idle mode, upon which,
        device doesn't interrupt host until it sees IR pulses
  * @s_learning_mode: enable wide band receiver used for learning
+ * @s_carrier_report: enable carrier reports
  */
 struct ir_dev_props {
        enum rc_driver_type     driver_type;
@@ -82,8 +83,9 @@ struct ir_dev_props {
        int                     (*s_tx_duty_cycle)(void *priv, u32 duty_cycle);
        int                     (*s_rx_carrier_range)(void *priv, u32 min, u32 max);
        int                     (*tx_ir)(void *priv, int *txbuf, u32 n);
-       void                    (*s_idle)(void *priv, int enable);
+       void                    (*s_idle)(void *priv, bool enable);
        int                     (*s_learning_mode)(void *priv, int enable);
+       int                     (*s_carrier_report) (void *priv, int enable);
 };
 
 struct ir_input_dev {
@@ -163,22 +165,48 @@ u32 ir_g_keycode_from_table(struct input_dev *input_dev, u32 scancode);
 /* From ir-raw-event.c */
 
 struct ir_raw_event {
-       unsigned                        pulse:1;
-       unsigned                        duration:31;
+       union {
+               u32             duration;
+
+               struct {
+                       u32     carrier;
+                       u8      duty_cycle;
+               };
+       };
+
+       unsigned                pulse:1;
+       unsigned                reset:1;
+       unsigned                timeout:1;
+       unsigned                carrier_report:1;
 };
 
-#define IR_MAX_DURATION                 0x7FFFFFFF      /* a bit more than 2 seconds */
+#define DEFINE_IR_RAW_EVENT(event) \
+       struct ir_raw_event event = { \
+               { .duration = 0 } , \
+               .pulse = 0, \
+               .reset = 0, \
+               .timeout = 0, \
+               .carrier_report = 0 }
+
+static inline void init_ir_raw_event(struct ir_raw_event *ev)
+{
+       memset(ev, 0, sizeof(*ev));
+}
+
+#define IR_MAX_DURATION         0xFFFFFFFF      /* a bit more than 4 seconds */
 
 void ir_raw_event_handle(struct input_dev *input_dev);
 int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev);
 int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type);
 int ir_raw_event_store_with_filter(struct input_dev *input_dev,
                                struct ir_raw_event *ev);
-void ir_raw_event_set_idle(struct input_dev *input_dev, int idle);
+void ir_raw_event_set_idle(struct input_dev *input_dev, bool idle);
 
 static inline void ir_raw_event_reset(struct input_dev *input_dev)
 {
-       struct ir_raw_event ev = { .pulse = false, .duration = 0 };
+       DEFINE_IR_RAW_EVENT(ev);
+       ev.reset = true;
+
        ir_raw_event_store(input_dev, &ev);
        ir_raw_event_handle(input_dev);
 }