[10/13] IR: extend interfaces to support more device settings LIRC: add new IOCTL that enables learning mode (wide band receiver)

Message ID 1280489933-20865-11-git-send-email-maximlevitsky@gmail.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

Maxim Levitsky July 30, 2010, 11:38 a.m. UTC
  Still missing features: carrier report & timeout reports.
Will need to pack these into ir_raw_event


Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/media/IR/ir-core-priv.h  |    1 +
 drivers/media/IR/ir-lirc-codec.c |  112 +++++++++++++++++++++++++++++++-------
 include/media/ir-core.h          |   14 +++++
 include/media/lirc.h             |    5 ++-
 4 files changed, 112 insertions(+), 20 deletions(-)
  

Comments

Christoph Bartelmus July 30, 2010, 9:22 p.m. UTC | #1
Hi!

Maxim Levitsky "maximlevitsky@gmail.com" wrote:

> Still missing features: carrier report & timeout reports.
> Will need to pack these into ir_raw_event


Hm, this patch changes the LIRC interface but I can't see the according  
patch to the documentation.

[...]
>   * @tx_ir: transmit IR
>   * @s_idle: optional: enable/disable hardware idle mode, upon which,
> +<<<<<<< current
>   *	device doesn't interrupt host untill it sees IR data
> +=======

Huh?

> +	device doesn't interrupt host untill it sees IR data
> + * @s_learning_mode: enable wide band receiver used for learning
+>>>>>>>> patched

s/untill/until/

[...]
>  #define LIRC_CAN_MEASURE_CARRIER          0x02000000
> +#define LIRC_CAN_HAVE_WIDEBAND_RECEIVER   0x04000000

LIRC_CAN_USE_WIDEBAND_RECEIVER

[...]
> @@ -145,7 +146,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_MEASURE_CARRIER_MODE	_IOW('i', 0x0000001d, __u32)
>
>  /*
>   * to set a range use
> @@ -162,4 +163,6 @@
>  #define LIRC_SETUP_START               _IO('i', 0x00000021)
>  #define LIRC_SETUP_END                 _IO('i', 0x00000022)
>
> +#define LIRC_SET_WIDEBAND_RECEIVER     _IOW('i', 0x00000023, __u32)

If you really want this new ioctl, then it should be clarified how it  
behaves in relation to LIRC_SET_MEASURE_CARRIER_MODE.

Do you have to enable the wide-band receiver explicitly before you can  
enable carrier reports or does enabling carrier reports implicitly switch  
to the wide-band receiver?

What happens if carrier mode is enabled and you explicitly turn off the  
wide-band receiver?

And while we're at interface stuff:
Do we really need LIRC_SETUP_START and LIRC_SETUP_END? It is only used  
once in lircd during startup.

Christoph
--
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
  
Maxim Levitsky July 30, 2010, 10:01 p.m. UTC | #2
On Fri, 2010-07-30 at 23:22 +0200, Christoph Bartelmus wrote: 
> Hi!
> 
> Maxim Levitsky "maximlevitsky@gmail.com" wrote:
> 
> > Still missing features: carrier report & timeout reports.
> > Will need to pack these into ir_raw_event
> 
> 
> Hm, this patch changes the LIRC interface but I can't see the according  
> patch to the documentation.
> 
> [...]
> >   * @tx_ir: transmit IR
> >   * @s_idle: optional: enable/disable hardware idle mode, upon which,
> > +<<<<<<< current
> >   *	device doesn't interrupt host untill it sees IR data
> > +=======
> 
> Huh?
:-)


> 
> > +	device doesn't interrupt host untill it sees IR data
> > + * @s_learning_mode: enable wide band receiver used for learning
> +>>>>>>>> patched
> 
> s/untill/until/
> 
> [...]
> >  #define LIRC_CAN_MEASURE_CARRIER          0x02000000
> > +#define LIRC_CAN_HAVE_WIDEBAND_RECEIVER   0x04000000
> 
> LIRC_CAN_USE_WIDEBAND_RECEIVER

OK. 
> 
> [...]
> > @@ -145,7 +146,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_MEASURE_CARRIER_MODE	_IOW('i', 0x0000001d, __u32)
> >
> >  /*
> >   * to set a range use
> > @@ -162,4 +163,6 @@
> >  #define LIRC_SETUP_START               _IO('i', 0x00000021)
> >  #define LIRC_SETUP_END                 _IO('i', 0x00000022)
> >
> > +#define LIRC_SET_WIDEBAND_RECEIVER     _IOW('i', 0x00000023, __u32)
> 
> If you really want this new ioctl, then it should be clarified how it  
> behaves in relation to LIRC_SET_MEASURE_CARRIER_MODE.

In my opinion, I won't need the LIRC_SET_MEASURE_CARRIER_MODE,
I would just optionally turn that on in learning mode.
You disagree, and since that is not important (besides TX and learning
features are present only at fraction of ENE devices. The only user I
did the debugging with, doesn't seem to want to help debug that code
anymore...)

But anyway, in current state I want these features to be independent.
Driver will enable learning mode if it have to.

I'll add the documentation.



> 
> Do you have to enable the wide-band receiver explicitly before you can  
> enable carrier reports or does enabling carrier reports implicitly switch  
> to the wide-band receiver?
I would implicitly switch the learning mode on, untill user turns off
the carrier reports.

> 
> What happens if carrier mode is enabled and you explicitly turn off the  
> wide-band receiver?
Wouldn't it be better to have one ioctl for both after all?

> 
> And while we're at interface stuff:
> Do we really need LIRC_SETUP_START and LIRC_SETUP_END? It is only used  
> once in lircd during startup.
I don't think so.

Best regards,
Maxim Levitsky

--
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
  
Christoph Bartelmus July 31, 2010, 8:10 a.m. UTC | #3
Hi Maxim,

on 31 Jul 10 at 01:01, Maxim Levitsky wrote:
> On Fri, 2010-07-30 at 23:22 +0200, Christoph Bartelmus wrote:
[...]
>>> +#define LIRC_SET_WIDEBAND_RECEIVER     _IOW('i', 0x00000023, __u32)
>>
>> If you really want this new ioctl, then it should be clarified how it
>> behaves in relation to LIRC_SET_MEASURE_CARRIER_MODE.

> In my opinion, I won't need the LIRC_SET_MEASURE_CARRIER_MODE,
> I would just optionally turn that on in learning mode.
> You disagree, and since that is not important (besides TX and learning
> features are present only at fraction of ENE devices. The only user I
> did the debugging with, doesn't seem to want to help debug that code
> anymore...)
>
> But anyway, in current state I want these features to be independent.
> Driver will enable learning mode if it have to.

Please avoid the term "learning mode" as to you it probably means  
something different than to me.

>
> I'll add the documentation.

>>
>> Do you have to enable the wide-band receiver explicitly before you can
>> enable carrier reports or does enabling carrier reports implicitly switch
>> to the wide-band receiver?
> I would implicitly switch the learning mode on, untill user turns off
> the carrier reports.

You mean that you'll implicitly switch on the wide-band receiver. Ok.

>>
>> What happens if carrier mode is enabled and you explicitly turn off the
>> wide-band receiver?
> Wouldn't it be better to have one ioctl for both after all?

There may be hardware that allows carrier measurement but does not have a  
wide-band receiver. And there may be hardware that does have a wide-band  
receiver but does not allow carrier measurement. irrecord needs to be able  
to distinguish these cases, so we need separate ioctls.

I'd say: carrier reports may switch on the wide-band reciever implicitly.  
In that case the wide-band receiver cannot be switched off explicitly  
until carrier reports are disabled again. It just needs to be documented.

>>
>> And while we're at interface stuff:
>> Do we really need LIRC_SETUP_START and LIRC_SETUP_END? It is only used
>> once in lircd during startup.
> I don't think so.
>

Christoph
--
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
  
Maxim Levitsky July 31, 2010, 9:35 a.m. UTC | #4
On Sat, 2010-07-31 at 10:10 +0200, Christoph Bartelmus wrote: 
> Hi Maxim,
> 
> on 31 Jul 10 at 01:01, Maxim Levitsky wrote:
> > On Fri, 2010-07-30 at 23:22 +0200, Christoph Bartelmus wrote:
> [...]
> >>> +#define LIRC_SET_WIDEBAND_RECEIVER     _IOW('i', 0x00000023, __u32)
> >>
> >> If you really want this new ioctl, then it should be clarified how it
> >> behaves in relation to LIRC_SET_MEASURE_CARRIER_MODE.
> 
> > In my opinion, I won't need the LIRC_SET_MEASURE_CARRIER_MODE,
> > I would just optionally turn that on in learning mode.
> > You disagree, and since that is not important (besides TX and learning
> > features are present only at fraction of ENE devices. The only user I
> > did the debugging with, doesn't seem to want to help debug that code
> > anymore...)
> >
> > But anyway, in current state I want these features to be independent.
> > Driver will enable learning mode if it have to.
> 
> Please avoid the term "learning mode" as to you it probably means  
> something different than to me.
> 
> >
> > I'll add the documentation.
> 
> >>
> >> Do you have to enable the wide-band receiver explicitly before you can
> >> enable carrier reports or does enabling carrier reports implicitly switch
> >> to the wide-band receiver?
> > I would implicitly switch the learning mode on, untill user turns off
> > the carrier reports.
> 
> You mean that you'll implicitly switch on the wide-band receiver. Ok.
> 
> >>
> >> What happens if carrier mode is enabled and you explicitly turn off the
> >> wide-band receiver?
> > Wouldn't it be better to have one ioctl for both after all?
> 
> There may be hardware that allows carrier measurement but does not have a  
> wide-band receiver. And there may be hardware that does have a wide-band  
> receiver but does not allow carrier measurement. irrecord needs to be able  
> to distinguish these cases, so we need separate ioctls.
> 
> I'd say: carrier reports may switch on the wide-band reciever implicitly.  
> In that case the wide-band receiver cannot be switched off explicitly  
> until carrier reports are disabled again. It just needs to be documented.

No problem.

Best regards,
Maxim Levitsky

--
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
  

Patch

diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
index 30ff52c..52253b4 100644
--- a/drivers/media/IR/ir-core-priv.h
+++ b/drivers/media/IR/ir-core-priv.h
@@ -78,6 +78,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 8ca01fd..5d5150f 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_HAVE_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;
diff --git a/include/media/ir-core.h b/include/media/ir-core.h
index 7ad39fe..ed9c1cb 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,16 @@  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,
+<<<<<<< current
  *	device doesn't interrupt host untill it sees IR data
+=======
+	device doesn't interrupt host untill it sees IR data
+ * @s_learning_mode: enable wide band receiver used for learning
+>>>>>>> patched
  */
 struct ir_dev_props {
 	enum rc_driver_type	driver_type;
@@ -65,6 +74,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 +83,11 @@  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..bda3d03 100644
--- a/include/media/lirc.h
+++ b/include/media/lirc.h
@@ -77,6 +77,7 @@ 
 #define LIRC_CAN_SET_REC_FILTER           0x08000000
 
 #define LIRC_CAN_MEASURE_CARRIER          0x02000000
+#define LIRC_CAN_HAVE_WIDEBAND_RECEIVER   0x04000000
 
 #define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK)
 #define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK)
@@ -145,7 +146,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_MEASURE_CARRIER_MODE	_IOW('i', 0x0000001d, __u32)
 
 /*
  * to set a range use
@@ -162,4 +163,6 @@ 
 #define LIRC_SETUP_START               _IO('i', 0x00000021)
 #define LIRC_SETUP_END                 _IO('i', 0x00000022)
 
+#define LIRC_SET_WIDEBAND_RECEIVER     _IOW('i', 0x00000023, __u32)
+
 #endif