[5/9] IR: extend interfaces to support more device settings

Message ID 1280330051-27732-6-git-send-email-maximlevitsky@gmail.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

Maxim Levitsky July 28, 2010, 3:14 p.m. UTC
  Also reuse LIRC_SET_MEASURE_CARRIER_MODE as LIRC_SET_LEARN_MODE
(LIRC_SET_LEARN_MODE will start carrier reports if possible, and
tune receiver to wide band mode)

This IOCTL isn't yet used by lirc, so this won't break userspace.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/media/IR/ir-core-priv.h  |    2 +
 drivers/media/IR/ir-lirc-codec.c |  100 ++++++++++++++++++++++++++++++++++----
 include/media/ir-core.h          |   11 ++++
 include/media/lirc.h             |    4 +-
 4 files changed, 105 insertions(+), 12 deletions(-)
  

Comments

Mauro Carvalho Chehab July 28, 2010, 5 p.m. UTC | #1
Em 28-07-2010 12:14, Maxim Levitsky escreveu:
> Also reuse LIRC_SET_MEASURE_CARRIER_MODE as LIRC_SET_LEARN_MODE
> (LIRC_SET_LEARN_MODE will start carrier reports if possible, and
> tune receiver to wide band mode)
> 
> This IOCTL isn't yet used by lirc, so this won't break userspace.
> 
> Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> ---
>  drivers/media/IR/ir-core-priv.h  |    2 +
>  drivers/media/IR/ir-lirc-codec.c |  100 ++++++++++++++++++++++++++++++++++----
>  include/media/ir-core.h          |   11 ++++
>  include/media/lirc.h             |    4 +-
>  4 files changed, 105 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
> index 3eafdb7..4ed170d 100644
> --- a/drivers/media/IR/ir-core-priv.h
> +++ b/drivers/media/IR/ir-core-priv.h
> @@ -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;
>  };
>  
> diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c
> index 8ca01fd..0f3969c 100644
> --- a/drivers/media/IR/ir-lirc-codec.c
> +++ b/drivers/media/IR/ir-lirc-codec.c
> @@ -96,13 +96,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)
> @@ -116,10 +116,21 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long ar
>  
>  	switch (cmd) {
>  	case LIRC_SET_TRANSMITTER_MASK:
> +	case LIRC_SET_SEND_CARRIER:
> +	case LIRC_SET_SEND_MODE:
> +	case LIRC_SET_REC_TIMEOUT:
> +	case LIRC_SET_REC_TIMEOUT_REPORTS:
> +	case LIRC_SET_LEARN_MODE:
> +	case LIRC_SET_REC_CARRIER:
> +	case LIRC_SET_REC_CARRIER_RANGE:
> +	case LIRC_SET_SEND_DUTY_CYCLE:
>  		ret = get_user(val, (unsigned long *)arg);
>  		if (ret)
>  			return ret;
> +	}

	As, in all cases, the argument is an __u32, you can just use this, to get 
the arguments for all LIRC_SET_* cases:

	if (_IOC_DIR(cmd) & _IOC_WRITE) {
  		ret = get_user(val, (unsigned long *)arg);
  		if (ret)
  			return ret;
	}

 
> +	switch (cmd) {
> +	case LIRC_SET_TRANSMITTER_MASK:
>  		if (ir_dev->props && ir_dev->props->s_tx_mask)
>  			ret = ir_dev->props->s_tx_mask(drv_data, (u32)val);
>  		else
> @@ -127,10 +138,6 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long ar
>  		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)
>  			ir_dev->props->s_tx_carrier(drv_data, (u32)val);
>  		else
> @@ -143,14 +150,75 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long ar
>  		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;
> +		ret = put_user(val, (unsigned long *)arg);
> +		break;

	You can use something like this, to handle the LIRC_GET* cases:

	switch (cmd) {
	...
	case LIRC_GET_REC_RESOLUTION:
		val = ir_dev->props->rx_resolution;
		break;
	...
	}

	if (_IOC_DIR(cmd) & _IOC_READ) {
  		ret = put_user(val, (unsigned long *)arg);
  		if (ret)
  			return ret;
	}

> +
> +	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;
> +
> +		ret = put_user(ir_dev->props->min_timeout, (unsigned long *)arg);
> +		break;
> +	case LIRC_GET_MAX_TIMEOUT:
> +		if (!ir_dev->props->max_timeout)
> +			return -ENOSYS;
> +
> +		ret = put_user(ir_dev->props->max_timeout, (unsigned long *)arg);
> +		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);
>  	}
> @@ -200,13 +268,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;
> diff --git a/include/media/ir-core.h b/include/media/ir-core.h
> index 53ce966..46cc6c5 100644
> --- a/include/media/ir-core.h
> +++ b/include/media/ir-core.h
> @@ -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 {
> diff --git a/include/media/lirc.h b/include/media/lirc.h
> index 42c467c..09a9753 100644
> --- a/include/media/lirc.h
> +++ b/include/media/lirc.h
> @@ -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

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
  
Jarod Wilson July 28, 2010, 8:47 p.m. UTC | #2
On Wed, Jul 28, 2010 at 06:14:07PM +0300, Maxim Levitsky wrote:
> Also reuse LIRC_SET_MEASURE_CARRIER_MODE as LIRC_SET_LEARN_MODE
> (LIRC_SET_LEARN_MODE will start carrier reports if possible, and
> tune receiver to wide band mode)
> 
> This IOCTL isn't yet used by lirc, so this won't break userspace.

Plus, once lirc 0.8.7 is released (Real Soon Now), we'll start working on
lirc 0.9.0 with the express goal of it being built against lirc.h as
provided by the kernel.

These all generally look good and sane to me, and I'll make use of the
LEARN_MODE bits for mceusb after something along these lines is committed.

I like the simplifications Mauro suggested for the ioctl handling. In
addition to those, there's a bit of whitespace damage in lirc.h that I'd
like to see cleaned up for v2.
  

Patch

diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
index 3eafdb7..4ed170d 100644
--- a/drivers/media/IR/ir-core-priv.h
+++ b/drivers/media/IR/ir-core-priv.h
@@ -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;
 };
 
diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c
index 8ca01fd..0f3969c 100644
--- a/drivers/media/IR/ir-lirc-codec.c
+++ b/drivers/media/IR/ir-lirc-codec.c
@@ -96,13 +96,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)
@@ -116,10 +116,21 @@  static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long ar
 
 	switch (cmd) {
 	case LIRC_SET_TRANSMITTER_MASK:
+	case LIRC_SET_SEND_CARRIER:
+	case LIRC_SET_SEND_MODE:
+	case LIRC_SET_REC_TIMEOUT:
+	case LIRC_SET_REC_TIMEOUT_REPORTS:
+	case LIRC_SET_LEARN_MODE:
+	case LIRC_SET_REC_CARRIER:
+	case LIRC_SET_REC_CARRIER_RANGE:
+	case LIRC_SET_SEND_DUTY_CYCLE:
 		ret = get_user(val, (unsigned long *)arg);
 		if (ret)
 			return ret;
+	}
 
+	switch (cmd) {
+	case LIRC_SET_TRANSMITTER_MASK:
 		if (ir_dev->props && ir_dev->props->s_tx_mask)
 			ret = ir_dev->props->s_tx_mask(drv_data, (u32)val);
 		else
@@ -127,10 +138,6 @@  static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long ar
 		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)
 			ir_dev->props->s_tx_carrier(drv_data, (u32)val);
 		else
@@ -143,14 +150,75 @@  static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long ar
 		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;
+		ret = put_user(val, (unsigned long *)arg);
+		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;
+
+		ret = put_user(ir_dev->props->min_timeout, (unsigned long *)arg);
+		break;
+	case LIRC_GET_MAX_TIMEOUT:
+		if (!ir_dev->props->max_timeout)
+			return -ENOSYS;
+
+		ret = put_user(ir_dev->props->max_timeout, (unsigned long *)arg);
+		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);
 	}
@@ -200,13 +268,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;
diff --git a/include/media/ir-core.h b/include/media/ir-core.h
index 53ce966..46cc6c5 100644
--- a/include/media/ir-core.h
+++ b/include/media/ir-core.h
@@ -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 {
diff --git a/include/media/lirc.h b/include/media/lirc.h
index 42c467c..09a9753 100644
--- a/include/media/lirc.h
+++ b/include/media/lirc.h
@@ -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