@@ -77,6 +77,8 @@ struct ir_raw_event_ctrl {
struct lirc_codec {
struct ir_input_dev *ir_dev;
struct lirc_driver *drv;
+ int timeout_report;
+ int carrier_low;
} lirc;
};
@@ -40,16 +40,24 @@ 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))
- return 0;
+ if (IS_RESET(ev)) {
+
+ if (ir_dev->raw->lirc.timeout_report)
+ sample = LIRC_TIMEOUT(0);
+ else
+ return 0;
- IR_dprintk(2, "LIRC data transfer started (%uus %s)\n",
- TO_US(ev.duration), TO_STR(ev.pulse));
+ IR_dprintk(2, "LIRC: Sending timeout packet\n");
+ } else {
+ sample = ev.duration / 1000;
+ if (ev.pulse)
+ sample |= PULSE_BIT;
+
+ IR_dprintk(2, "LIRC data transfer started (%uus %s)\n",
+ TO_US(ev.duration), TO_STR(ev.pulse));
+ }
- sample = ev.duration / 1000;
- if (ev.pulse)
- sample |= PULSE_BIT;
lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
(unsigned char *) &sample);
@@ -96,13 +104,13 @@ out:
return ret;
}
-static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long __user arg)
{
struct lirc_codec *lirc;
struct ir_input_dev *ir_dev;
int ret = 0;
void *drv_data;
- unsigned long val;
+ unsigned long val = 0;
lirc = lirc_get_pdata(filep);
if (!lirc)
@@ -114,24 +122,22 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long ar
drv_data = ir_dev->props->priv;
- switch (cmd) {
- case LIRC_SET_TRANSMITTER_MASK:
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
ret = get_user(val, (unsigned long *)arg);
if (ret)
return ret;
+ }
- if (ir_dev->props && ir_dev->props->s_tx_mask)
+ switch (cmd) {
+ case LIRC_SET_TRANSMITTER_MASK:
+ if (ir_dev->props->s_tx_mask)
ret = ir_dev->props->s_tx_mask(drv_data, (u32)val);
else
return -EINVAL;
break;
case LIRC_SET_SEND_CARRIER:
- ret = get_user(val, (unsigned long *)arg);
- if (ret)
- return ret;
-
- if (ir_dev->props && ir_dev->props->s_tx_carrier)
+ if (ir_dev->props->s_tx_carrier)
ir_dev->props->s_tx_carrier(drv_data, (u32)val);
else
return -EINVAL;
@@ -139,22 +145,79 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long ar
case LIRC_GET_SEND_MODE:
val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK;
- ret = put_user(val, (unsigned long *)arg);
break;
case LIRC_SET_SEND_MODE:
- ret = get_user(val, (unsigned long *)arg);
- if (ret)
- return ret;
-
if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK))
return -EINVAL;
break;
+ case LIRC_GET_REC_RESOLUTION:
+ val = ir_dev->props->rx_resolution;
+ 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;
+ break;
+
+ case LIRC_SET_REC_TIMEOUT_REPORTS:
+ ir_dev->raw->lirc.timeout_report = !!val;
+ return 0;
+
+ case LIRC_GET_MIN_TIMEOUT:
+ if (!ir_dev->props->max_timeout)
+ return -ENOSYS;
+ val = ir_dev->props->min_timeout;
+ break;
+ case LIRC_GET_MAX_TIMEOUT:
+ if (!ir_dev->props->max_timeout)
+ return -ENOSYS;
+ val = ir_dev->props->max_timeout;
+ break;
+
+ case LIRC_SET_LEARN_MODE:
+ if (ir_dev->props->s_learning_mode)
+ return ir_dev->props->s_learning_mode(
+ ir_dev->props->priv, !!val);
+ else
+ return -ENOSYS;
+
+ 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
+ return -ENOSYS;
+
+ if (!ret)
+ ir_dev->raw->lirc.carrier_low = 0;
+ break;
+
+ case LIRC_SET_REC_CARRIER_RANGE:
+ if (val >= 0)
+ ir_dev->raw->lirc.carrier_low = val;
+ break;
+
+ case LIRC_SET_SEND_DUTY_CYCLE:
+ if (!ir_dev->props->s_tx_duty_cycle)
+ return -ENOSYS;
+
+ if (val <= 0 || val >= 100)
+ return -EINVAL;
+
+ ir_dev->props->s_tx_duty_cycle(ir_dev->props->priv, val);
+ break;
+
default:
return lirc_dev_fop_ioctl(filep, cmd, arg);
}
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ ret = put_user(val, (unsigned long *)arg);
return ret;
}
@@ -200,13 +263,25 @@ static int ir_lirc_register(struct input_dev *input_dev)
features = LIRC_CAN_REC_MODE2;
if (ir_dev->props->tx_ir) {
+
features |= LIRC_CAN_SEND_PULSE;
if (ir_dev->props->s_tx_mask)
features |= LIRC_CAN_SET_TRANSMITTER_MASK;
if (ir_dev->props->s_tx_carrier)
features |= LIRC_CAN_SET_SEND_CARRIER;
+
+ if (ir_dev->props->s_tx_duty_cycle)
+ features |= LIRC_CAN_SET_REC_DUTY_CYCLE;
}
+ if (ir_dev->props->s_rx_carrier_range)
+ features |= LIRC_CAN_SET_REC_CARRIER |
+ LIRC_CAN_SET_REC_CARRIER_RANGE;
+
+ if (ir_dev->props->s_learning_mode)
+ features |= LIRC_CAN_LEARN_MODE;
+
+
snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)",
ir_dev->driver_name);
drv->minor = -1;
@@ -187,6 +187,9 @@ void ir_raw_event_set_idle(struct input_dev *input_dev, int idle)
if (idle) {
IR_dprintk(2, "enter idle mode\n");
+ ir_raw_event_store(input_dev, &raw->current_sample);
+ ir_raw_event_reset(input_dev);
+ raw->current_sample.duration = 0;
raw->last_event = ktime_get();
} else {
IR_dprintk(2, "exit idle mode\n");
@@ -194,17 +197,11 @@ void ir_raw_event_set_idle(struct input_dev *input_dev, int idle)
now = ktime_get();
delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event));
- WARN_ON(raw->current_sample.pulse);
-
- raw->current_sample.duration =
- min(raw->current_sample.duration + delta,
+ raw->current_sample.duration = min(delta,
(u64)IR_MAX_DURATION);
+ raw->current_sample.pulse = false;
ir_raw_event_store(input_dev, &raw->current_sample);
-
- if (raw->current_sample.duration == IR_MAX_DURATION)
- ir_raw_event_reset(input_dev);
-
raw->current_sample.duration = 0;
}
out:
@@ -44,6 +44,8 @@ enum rc_driver_type {
* @timeout: optional time after which device stops sending data
* @min_timeout: minimum timeout supported by device
* @max_timeout: maximum timeout supported by device
+ * @rx_resolution : resolution (in ns) of input sampler
+ * @tx_resolution: resolution (in ns) of output sampler
* @priv: driver-specific data, to be used on the callbacks
* @change_protocol: allow changing the protocol used on hardware decoders
* @open: callback to allow drivers to enable polling/irq when IR input device
@@ -52,9 +54,12 @@ enum rc_driver_type {
* is opened.
* @s_tx_mask: set transmitter mask (for devices with multiple tx outputs)
* @s_tx_carrier: set transmit carrier frequency
+ * @s_tx_duty_cycle: set transmit duty cycle (0% - 100%)
+ * @s_rx_carrier: inform driver about carrier it is expected to handle
* @tx_ir: transmit IR
* @s_idle: optional: enable/disable hardware idle mode, upon which,
device doesn't interrupt host untill it sees IR data
+ * @s_learning_mode: enable learning mode
*/
struct ir_dev_props {
enum rc_driver_type driver_type;
@@ -65,6 +70,8 @@ struct ir_dev_props {
u64 min_timeout;
u64 max_timeout;
+ u32 rx_resolution;
+ u32 tx_resolution;
void *priv;
int (*change_protocol)(void *priv, u64 ir_type);
@@ -72,8 +79,12 @@ struct ir_dev_props {
void (*close)(void *priv);
int (*s_tx_mask)(void *priv, u32 mask);
int (*s_tx_carrier)(void *priv, u32 carrier);
+ 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);
+ int (*s_learning_mode) (void *priv, int enable);
+
};
struct ir_input_dev {
@@ -76,7 +76,7 @@
#define LIRC_CAN_SET_REC_TIMEOUT 0x10000000
#define LIRC_CAN_SET_REC_FILTER 0x08000000
-#define LIRC_CAN_MEASURE_CARRIER 0x02000000
+#define LIRC_CAN_LEARN_MODE 0x02000000
#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK)
#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK)
@@ -145,7 +145,7 @@
* if enabled from the next key press on the driver will send
* LIRC_MODE2_FREQUENCY packets
*/
-#define LIRC_SET_MEASURE_CARRIER_MODE _IOW('i', 0x0000001d, __u32)
+#define LIRC_SET_LEARN_MODE _IOW('i', 0x0000001d, __u32)
/*
* to set a range use