From e589333f346b58f8da5bb8152e1219c52d375ccc Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Sat, 31 Jul 2010 11:59:23 -0300 Subject: V4L/DVB: IR: extend interfaces to support more device settings LIRC: add new IOCTL that enables learning mode (wide band receiver) Still missing features: carrier report & timeout reports. Will need to pack these into ir_raw_event Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/IR/ir-core-priv.h | 1 + drivers/media/IR/ir-lirc-codec.c | 112 ++++++++++++++++++++++++++++++++------- 2 files changed, 94 insertions(+), 19 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h index 8053e3b84272..a85a8c7c905a 100644 --- a/drivers/media/IR/ir-core-priv.h +++ b/drivers/media/IR/ir-core-priv.h @@ -79,6 +79,7 @@ struct ir_raw_event_ctrl { struct lirc_codec { struct ir_input_dev *ir_dev; struct lirc_driver *drv; + int carrier_low; } lirc; }; diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c index 8ca01fd67139..77b5946413c0 100644 --- a/drivers/media/IR/ir-lirc-codec.c +++ b/drivers/media/IR/ir-lirc-codec.c @@ -46,7 +46,6 @@ static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev) 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; @@ -96,13 +95,14 @@ 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,47 +114,106 @@ 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; + } + + switch (cmd) { + + /* legacy support */ + case LIRC_GET_SEND_MODE: + val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; + break; + + case LIRC_SET_SEND_MODE: + if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) + return -EINVAL; + break; - if (ir_dev->props && ir_dev->props->s_tx_mask) + /* TX settings */ + 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; break; - case LIRC_GET_SEND_MODE: - val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; - ret = put_user(val, (unsigned long *)arg); + 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; - case LIRC_SET_SEND_MODE: - ret = get_user(val, (unsigned long *)arg); - if (ret) - return ret; + /* 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 + return -ENOSYS; - if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) + 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_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 + return -ENOSYS; + + /* Generic timeout support */ + case LIRC_GET_MIN_TIMEOUT: + if (!ir_dev->props->max_timeout) + return -ENOSYS; + val = ir_dev->props->min_timeout / 1000; + break; + + case LIRC_GET_MAX_TIMEOUT: + if (!ir_dev->props->max_timeout) + return -ENOSYS; + val = ir_dev->props->max_timeout / 1000; + 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; 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 +259,28 @@ 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_USE_WIDEBAND_RECEIVER; + + if (ir_dev->props->max_timeout) + features |= LIRC_CAN_SET_REC_TIMEOUT; + + snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)", ir_dev->driver_name); drv->minor = -1; -- cgit v1.2.3