Skip to content

Commit

Permalink
[media] IR: extend ir_raw_event and do refactoring
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Maxim Levitsky authored and Mauro Carvalho Chehab committed Oct 21, 2010
1 parent fb249ca commit 4651918
Show file tree
Hide file tree
Showing 14 changed files with 181 additions and 93 deletions.
4 changes: 2 additions & 2 deletions drivers/media/IR/ene_ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;

Expand Down
13 changes: 12 additions & 1 deletion drivers/media/IR/ir-core-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions drivers/media/IR/ir-jvc-decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
128 changes: 90 additions & 38 deletions drivers/media/IR/ir-lirc-codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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;
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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:
Expand Down Expand Up @@ -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;

Expand Down
5 changes: 3 additions & 2 deletions drivers/media/IR/ir-nec-decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
45 changes: 16 additions & 29 deletions drivers/media/IR/ir-raw-event.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions drivers/media/IR/ir-rc5-decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
5 changes: 3 additions & 2 deletions drivers/media/IR/ir-rc5-sz-decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
5 changes: 3 additions & 2 deletions drivers/media/IR/ir-rc6-decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
5 changes: 3 additions & 2 deletions drivers/media/IR/ir-sony-decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Loading

0 comments on commit 4651918

Please sign in to comment.