Skip to contentSkip to conversation

Use sysfs filter for winbond & nuvoton wakeup

PATCH Superseded Sean Young 2 participants 22 messages Dec 12, 2016 – Dec 13, 2016

Subsystems (17)

v5 of 6 Superseded Latest is v6 →

lore
Share & tools
lore

Sean Young

author maintainer
#0 lore raw

v5 cover Use sysfs filter for winbond & nuvoton wakeup

This series introduces IR encoders and also makes winbond-cir and nuvoton-cir use the sysfs filter wakeup interface for programmable IR wakeup.

Changes since v4:
- ImgTec now also uses wakeup_protocols; all rc drivers which do wakeup now use the same sysfs interface
- Implemented all IR encoders except for xmp for which I cannot find useful documentation
- ir_raw_encode_scancode() now takes u32 scancode, rather than a rc_scancode_filter, since it cannot encode a mask.
- All encoders have been tested extensively by round-tripping over rc-loopback and generating random scancodes. No problems found other than known nec32 issue[1].
- winbond-cir has seen more testing

[1] https://www.mail-archive.com/[email protected]/msg104623.html

Antti Seppälä (3):
[media] rc: rc-ir-raw: Add Manchester encoder (phase encoder) helper [media] rc: ir-rc6-decoder: Add encode capability
[media] rc: nuvoton-cir: Add support wakeup via sysfs filter callback

James Hogan (6):
[media] rc: rc-ir-raw: Add scancode encoder callback [media] rc: rc-ir-raw: Add pulse-distance modulation helper [media] rc: ir-rc5-decoder: Add encode capability [media] rc: ir-nec-decoder: Add encode capability [media] rc: rc-core: Add support for encode_wakeup drivers [media] rc: rc-loopback: Add loopback of filter scancodes

Sean Young (9):
[media] rc: change wakeup_protocols to list all protocol variants [media] img-ir: use new wakeup_protocols sysfs mechanism [media] rc: Add scancode validation
[media] winbond-cir: use sysfs wakeup filter
[media] rc: raw IR drivers cannot handle cec, unknown or other [media] rc: ir-jvc-decoder: Add encode capability [media] rc: ir-sanyo-decoder: Add encode capability [media] rc: ir-sharp-decoder: Add encode capability [media] rc: ir-sony-decoder: Add encode capability

 Documentation/ABI/testing/sysfs-class-rc       |  14 +-
 Documentation/media/uapi/rc/rc-sysfs-nodes.rst |  13 +-
 drivers/hid/hid-picolcd_cir.c                  |   2 +-
 drivers/media/common/siano/smsir.c             |   2 +-
 drivers/media/pci/cx23885/cx23885-input.c      |  14 +-
 drivers/media/rc/ene_ir.c                      |   2 +-
 drivers/media/rc/fintek-cir.c                  |   2 +-
 drivers/media/rc/gpio-ir-recv.c                |   2 +-
 drivers/media/rc/igorplugusb.c                 |   4 +-
 drivers/media/rc/iguanair.c                    |   2 +-
 drivers/media/rc/img-ir/img-ir-hw.c            |   5 +-
 drivers/media/rc/img-ir/img-ir-hw.h            |   2 +-
 drivers/media/rc/img-ir/img-ir-jvc.c           |   2 +-
 drivers/media/rc/img-ir/img-ir-nec.c           |   6 +-
 drivers/media/rc/img-ir/img-ir-rc5.c           |   2 +-
 drivers/media/rc/img-ir/img-ir-rc6.c           |   2 +-
 drivers/media/rc/img-ir/img-ir-sanyo.c         |   2 +-
 drivers/media/rc/img-ir/img-ir-sharp.c         |   2 +-
 drivers/media/rc/img-ir/img-ir-sony.c          |  11 +-
 drivers/media/rc/ir-hix5hd2.c                  |   2 +-
 drivers/media/rc/ir-jvc-decoder.c              |  39 +++
 drivers/media/rc/ir-nec-decoder.c              |  81 ++++++
 drivers/media/rc/ir-rc5-decoder.c              |  97 ++++++++
 drivers/media/rc/ir-rc6-decoder.c              | 117 +++++++++
 drivers/media/rc/ir-sanyo-decoder.c            |  43 ++++
 drivers/media/rc/ir-sharp-decoder.c            |  50 ++++
 drivers/media/rc/ir-sony-decoder.c             |  48 ++++
 drivers/media/rc/ite-cir.c                     |   2 +-
 drivers/media/rc/mceusb.c                      |   2 +-
 drivers/media/rc/meson-ir.c                    |   2 +-
 drivers/media/rc/nuvoton-cir.c                 | 122 +++++++--
 drivers/media/rc/rc-core-priv.h                | 107 ++++++++
 drivers/media/rc/rc-ir-raw.c                   | 245 +++++++++++++++++-
 drivers/media/rc/rc-loopback.c                 |  41 ++-
 drivers/media/rc/rc-main.c                     | 330 +++++++++++++++++++++----
 drivers/media/rc/redrat3.c                     |   2 +-
 drivers/media/rc/serial_ir.c                   |   2 +-
 drivers/media/rc/st_rc.c                       |   2 +-
 drivers/media/rc/streamzap.c                   |   2 +-
 drivers/media/rc/sunxi-cir.c                   |   2 +-
 drivers/media/rc/ttusbir.c                     |   2 +-
 drivers/media/rc/winbond-cir.c                 | 259 +++++++++----------
 drivers/media/usb/dvb-usb-v2/rtl28xxu.c        |   2 +-
 drivers/media/usb/dvb-usb/technisat-usb2.c     |   2 +-
 include/media/rc-core.h                        |  13 +-
 include/media/rc-map.h                         |  19 ++
 46 files changed, 1456 insertions(+), 270 deletions(-)
Signature · 1 line
2.9.3
author maintainer
#1 lore raw

PATCH v5 1/18 rc: change wakeup_protocols to list all protocol variants

No driver has ever created a wakeup_protocol sysfs file since no rc_dev driver implemented change_wakeup_protocol, so we are free to change it.

For IR wakeup, a driver has to program the hardware to wakeup at a specific IR sequence, so it makes no sense to allow multiple wakeup protocols to be selected. In the same manner the sysfs interface only allows one scancode to be provided.

In addition we need to know the specific variant of the protocol.

Note that the ImgTec IR only ever set enabled_wakeup_protocols, it never used it.

---
 Documentation/ABI/testing/sysfs-class-rc       |  14 +-
 Documentation/media/uapi/rc/rc-sysfs-nodes.rst |  13 +-
 drivers/media/rc/img-ir/img-ir-hw.c            |   3 +-
 drivers/media/rc/rc-ir-raw.c                   |   1 -
 drivers/media/rc/rc-main.c                     | 247 ++++++++++++++++++++-----
 include/media/rc-core.h                        |   8 +-
 6 files changed, 215 insertions(+), 71 deletions(-)
Documentation/ABI/testing/sysfs-class-rc +7 -7
index b65674d..cd47235 100644
@@ -62,18 +62,18 @@ Description:
 		This value may be reset to 0 if the current protocol is altered.
 
 What:		/sys/class/rc/rcN/wakeup_protocols
-Date:		Feb 2014
-KernelVersion:	3.15
+Date:		Feb 2017
+KernelVersion:	4.12
 Contact:	Mauro Carvalho Chehab <[email protected]>
 Description:
 		Reading this file returns a list of available protocols to use
 		for the wakeup filter, something like:
-		    "rc5 rc6 nec jvc [sony]"
+		    "rc-5 nec nec-x rc-6-0 rc-6-6a-24 [rc-6-6a-32] rc-6-mce"
+		Note that protocol variants are listed, so "nec", "sony",
+		"rc-5", "rc-6" have their different bit length encodings
+		listed if available.
 		The enabled wakeup protocol is shown in [] brackets.
-		Writing "+proto" will add a protocol to the list of enabled
-		wakeup protocols.
-		Writing "-proto" will remove a protocol from the list of enabled
-		wakeup protocols.
+		Only one protocol can be selected at a time.
 		Writing "proto" will use "proto" for wakeup events.
 		Writing "none" will disable wakeup.
 		Write fails with EINVAL if an invalid protocol combination or
Documentation/media/uapi/rc/rc-sysfs-nodes.rst +7 -6
index 6fb944f..3476ae2 100644
@@ -92,15 +92,16 @@ This value may be reset to 0 if the current protocol is altered.
 Reading this file returns a list of available protocols to use for the
 wakeup filter, something like:
 
-``rc5 rc6 nec jvc [sony]``
+``rc-5 nec nec-x rc-6-0 rc-6-6a-24 [rc-6-6a-32] rc-6-mce``
 
-The enabled wakeup protocol is shown in [] brackets.
+Note that protocol variants are listed, so "nec", "sony", "rc-5", "rc-6"
+have their different bit length encodings listed if available.
 
-Writing "+proto" will add a protocol to the list of enabled wakeup
-protocols.
+Note that all protocol variants are listed.
 
-Writing "-proto" will remove a protocol from the list of enabled wakeup
-protocols.
+The enabled wakeup protocol is shown in [] brackets.
+
+Only one protocol can be selected at a time.
 
 Writing "proto" will use "proto" for wakeup events.
 
drivers/media/rc/img-ir/img-ir-hw.c +1 -2
index 7bb71bc..1a0811d 100644
@@ -581,6 +581,7 @@ static void img_ir_set_decoder(struct img_ir_priv *priv,
 	/* clear the wakeup scancode filter */
 	rdev->scancode_wakeup_filter.data = 0;
 	rdev->scancode_wakeup_filter.mask = 0;
+	rdev->wakeup_protocol = RC_TYPE_UNKNOWN;
 
 	/* clear raw filters */
 	_img_ir_set_filter(priv, NULL);
@@ -685,7 +686,6 @@ static int img_ir_change_protocol(struct rc_dev *dev, u64 *ir_type)
 	if (!hw->decoder || !hw->decoder->filter)
 		wakeup_protocols = 0;
 	rdev->allowed_wakeup_protocols = wakeup_protocols;
-	rdev->enabled_wakeup_protocols = wakeup_protocols;
 	return 0;
 }
 
@@ -701,7 +701,6 @@ static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto)
 	mutex_lock(&rdev->lock);
 	rdev->enabled_protocols = proto;
 	rdev->allowed_wakeup_protocols = proto;
-	rdev->enabled_wakeup_protocols = proto;
 	mutex_unlock(&rdev->lock);
 }
 
drivers/media/rc/rc-ir-raw.c +0 -1
index 1c42a9f..171bdba 100644
@@ -246,7 +246,6 @@ static void ir_raw_disable_protocols(struct rc_dev *dev, u64 protocols)
 {
 	mutex_lock(&dev->lock);
 	dev->enabled_protocols &= ~protocols;
-	dev->enabled_wakeup_protocols &= ~protocols;
 	mutex_unlock(&dev->lock);
 }
 
drivers/media/rc/rc-main.c +197 -50

363 lines not on this page · raw message

include/media/rc-core.h +3 -5
index 55281b9..19a0ad2 100644
@@ -86,7 +86,8 @@ enum rc_filter_type {
  * @allowed_protocols: bitmask with the supported RC_BIT_* protocols
  * @enabled_protocols: bitmask with the enabled RC_BIT_* protocols
  * @allowed_wakeup_protocols: bitmask with the supported RC_BIT_* wakeup protocols
- * @enabled_wakeup_protocols: bitmask with the enabled RC_BIT_* wakeup protocols
+ * @wakeup_protocol: the enabled RC_TYPE_* wakeup protocol or
+ *	RC_TYPE_UNKNOWN if disabled.
  * @scancode_filter: scancode filter
  * @scancode_wakeup_filter: scancode wakeup filters
  * @scancode_mask: some hardware decoders are not capable of providing the full
@@ -110,8 +111,6 @@ enum rc_filter_type {
  * @rx_resolution : resolution (in ns) of input sampler
  * @tx_resolution: resolution (in ns) of output sampler
  * @change_protocol: allow changing the protocol used on hardware decoders
- * @change_wakeup_protocol: allow changing the protocol used for wakeup
- *	filtering
  * @open: callback to allow drivers to enable polling/irq when IR input device
  *	is opened.
  * @close: callback to allow drivers to disable polling/irq when IR input device
@@ -149,7 +148,7 @@ struct rc_dev {
 	u64				allowed_protocols;
 	u64				enabled_protocols;
 	u64				allowed_wakeup_protocols;
-	u64				enabled_wakeup_protocols;
+	enum rc_type			wakeup_protocol;
 	struct rc_scancode_filter	scancode_filter;
 	struct rc_scancode_filter	scancode_wakeup_filter;
 	u32				scancode_mask;
@@ -169,7 +168,6 @@ struct rc_dev {
 	u32				rx_resolution;
 	u32				tx_resolution;
 	int				(*change_protocol)(struct rc_dev *dev, u64 *rc_type);
-	int				(*change_wakeup_protocol)(struct rc_dev *dev, u64 *rc_type);
 	int				(*open)(struct rc_dev *dev);
 	void				(*close)(struct rc_dev *dev);
 	int				(*s_tx_mask)(struct rc_dev *dev, u32 mask);
Signature · 1 line
2.9.3
author maintainer
#2 lore raw

PATCH v5 2/18 img-ir: use new wakeup_protocols sysfs mechanism

In reply to Sean Young

Rather than guessing what variant a scancode is from its length, use the new wakeup_protocol.

Cc James Hogan <[email protected]>
Cc Sifan Naeem <[email protected]>
---
 drivers/media/rc/img-ir/img-ir-hw.c    |  2 +-
 drivers/media/rc/img-ir/img-ir-hw.h    |  2 +-
 drivers/media/rc/img-ir/img-ir-jvc.c   |  2 +-
 drivers/media/rc/img-ir/img-ir-nec.c   |  6 +++---
 drivers/media/rc/img-ir/img-ir-rc5.c   |  2 +-
 drivers/media/rc/img-ir/img-ir-rc6.c   |  2 +-
 drivers/media/rc/img-ir/img-ir-sanyo.c |  2 +-
 drivers/media/rc/img-ir/img-ir-sharp.c |  2 +-
 drivers/media/rc/img-ir/img-ir-sony.c  | 11 +++--------
 9 files changed, 13 insertions(+), 18 deletions(-)
drivers/media/rc/img-ir/img-ir-hw.c +1 -1
index 1a0811d..841d9d7 100644
@@ -488,7 +488,7 @@ static int img_ir_set_filter(struct rc_dev *dev, enum rc_filter_type type,
 	/* convert scancode filter to raw filter */
 	filter.minlen = 0;
 	filter.maxlen = ~0;
-	ret = hw->decoder->filter(sc_filter, &filter, hw->enabled_protocols);
+	ret = hw->decoder->filter(sc_filter, &filter, dev->wakeup_protocol);
 	if (ret)
 		goto unlock;
 	dev_dbg(priv->dev, "IR raw %sfilter=%016llx & %016llx\n",
drivers/media/rc/img-ir/img-ir-hw.h +1 -1
index 91a2977..e1959ddc 100644
@@ -179,7 +179,7 @@ struct img_ir_decoder {
 	int (*scancode)(int len, u64 raw, u64 enabled_protocols,
 			struct img_ir_scancode_req *request);
 	int (*filter)(const struct rc_scancode_filter *in,
-		      struct img_ir_filter *out, u64 protocols);
+		      struct img_ir_filter *out, enum rc_type protocol);
 };
 
 extern struct img_ir_decoder img_ir_nec;
drivers/media/rc/img-ir/img-ir-jvc.c +1 -1
index d3e2fc0..10b302c 100644
@@ -30,7 +30,7 @@ static int img_ir_jvc_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert JVC scancode to JVC data filter */
 static int img_ir_jvc_filter(const struct rc_scancode_filter *in,
-			     struct img_ir_filter *out, u64 protocols)
+			     struct img_ir_filter *out, enum rc_type protocol)
 {
 	unsigned int cust, data;
 	unsigned int cust_m, data_m;
drivers/media/rc/img-ir/img-ir-nec.c +3 -3
index 0931493..fff00d4 100644
@@ -54,7 +54,7 @@ static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert NEC scancode to NEC data filter */
 static int img_ir_nec_filter(const struct rc_scancode_filter *in,
-			     struct img_ir_filter *out, u64 protocols)
+			     struct img_ir_filter *out, enum rc_type protocol)
 {
 	unsigned int addr, addr_inv, data, data_inv;
 	unsigned int addr_m, addr_inv_m, data_m, data_inv_m;
@@ -62,7 +62,7 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in,
 	data       = in->data & 0xff;
 	data_m     = in->mask & 0xff;
 
-	if ((in->data | in->mask) & 0xff000000) {
+	if (protocol == RC_TYPE_NEC32) {
 		/* 32-bit NEC (used by Apple and TiVo remotes) */
 		/* scan encoding: as transmitted, MSBit = first received bit */
 		addr       = bitrev8(in->data >> 24);
@@ -73,7 +73,7 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in,
 		data_m     = bitrev8(in->mask >>  8);
 		data_inv   = bitrev8(in->data >>  0);
 		data_inv_m = bitrev8(in->mask >>  0);
-	} else if ((in->data | in->mask) & 0x00ff0000) {
+	} else if (protocol == RC_TYPE_NECX) {
 		/* Extended NEC */
 		/* scan encoding AAaaDD */
 		addr       = (in->data >> 16) & 0xff;
drivers/media/rc/img-ir/img-ir-rc5.c +1 -1
index a8a28a3..24a6bcf 100644
@@ -41,7 +41,7 @@ static int img_ir_rc5_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert RC5 scancode to RC5 data filter */
 static int img_ir_rc5_filter(const struct rc_scancode_filter *in,
-				 struct img_ir_filter *out, u64 protocols)
+			     struct img_ir_filter *out, enum rc_type protocol)
 {
 	/* Not supported by the hw. */
 	return -EINVAL;
drivers/media/rc/img-ir/img-ir-rc6.c +1 -1
index de1e275..451e2ef8 100644
@@ -62,7 +62,7 @@ static int img_ir_rc6_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert RC6 scancode to RC6 data filter */
 static int img_ir_rc6_filter(const struct rc_scancode_filter *in,
-				 struct img_ir_filter *out, u64 protocols)
+			     struct img_ir_filter *out, enum rc_type protocol)
 {
 	/* Not supported by the hw. */
 	return -EINVAL;
drivers/media/rc/img-ir/img-ir-sanyo.c +1 -1
index f394994..8f542bd 100644
@@ -51,7 +51,7 @@ static int img_ir_sanyo_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert Sanyo scancode to Sanyo data filter */
 static int img_ir_sanyo_filter(const struct rc_scancode_filter *in,
-			       struct img_ir_filter *out, u64 protocols)
+			       struct img_ir_filter *out, enum rc_type protocol)
 {
 	unsigned int addr, addr_inv, data, data_inv;
 	unsigned int addr_m, data_m;
drivers/media/rc/img-ir/img-ir-sharp.c +1 -1
index fe5acc4..c8b4e9b 100644
@@ -39,7 +39,7 @@ static int img_ir_sharp_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert Sharp scancode to Sharp data filter */
 static int img_ir_sharp_filter(const struct rc_scancode_filter *in,
-			       struct img_ir_filter *out, u64 protocols)
+			       struct img_ir_filter *out, enum rc_type protocol)
 {
 	unsigned int addr, cmd, exp = 0, chk = 0;
 	unsigned int addr_m, cmd_m, exp_m = 0, chk_m = 0;
drivers/media/rc/img-ir/img-ir-sony.c +3 -8
index 7f7375f..ecae41c 100644
@@ -55,7 +55,7 @@ static int img_ir_sony_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert NEC scancode to NEC data filter */
 static int img_ir_sony_filter(const struct rc_scancode_filter *in,
-			      struct img_ir_filter *out, u64 protocols)
+			      struct img_ir_filter *out, enum rc_type protocol)
 {
 	unsigned int dev, subdev, func;
 	unsigned int dev_m, subdev_m, func_m;
@@ -68,19 +68,14 @@ static int img_ir_sony_filter(const struct rc_scancode_filter *in,
 	func     = (in->data >> 0)  & 0x7f;
 	func_m   = (in->mask >> 0)  & 0x7f;
 
-	if (subdev & subdev_m) {
+	if (protocol == RC_TYPE_SONY20) {
 		/* can't encode subdev and higher device bits */
 		if (dev & dev_m & 0xe0)
 			return -EINVAL;
-		/* subdevice (extended) bits only in 20 bit encoding */
-		if (!(protocols & RC_BIT_SONY20))
-			return -EINVAL;
 		len = 20;
 		dev_m &= 0x1f;
-	} else if (dev & dev_m & 0xe0) {
+	} else if (protocol == RC_TYPE_SONY15) {
 		/* upper device bits only in 15 bit encoding */
-		if (!(protocols & RC_BIT_SONY15))
-			return -EINVAL;
 		len = 15;
 		subdev_m = 0;
 	} else {
Signature · 1 line
2.9.3
#3 lore raw

Re: [PATCH v5 02/18] [media] img-ir: use new wakeup_protocols sysfs mechanism

Hi Sean (and Sifan),

Quoted 23 lines · Sean Young

Rather than guessing what variant a scancode is from its length, use the new wakeup_protocol.

Cc James Hogan <[email protected]>
Cc Sifan Naeem <[email protected]>
---
 drivers/media/rc/img-ir/img-ir-hw.c    |  2 +-
 drivers/media/rc/img-ir/img-ir-hw.h    |  2 +-
 drivers/media/rc/img-ir/img-ir-jvc.c   |  2 +-
 drivers/media/rc/img-ir/img-ir-nec.c   |  6 +++---
 drivers/media/rc/img-ir/img-ir-rc5.c   |  2 +-
 drivers/media/rc/img-ir/img-ir-rc6.c   |  2 +-
 drivers/media/rc/img-ir/img-ir-sanyo.c |  2 +-
 drivers/media/rc/img-ir/img-ir-sharp.c |  2 +-
 drivers/media/rc/img-ir/img-ir-sony.c  | 11 +++--------
 9 files changed, 13 insertions(+), 18 deletions(-)
drivers/media/rc/img-ir/img-ir-hw.c +0 -0
index 1a0811d..841d9d7 100644

drivers/media/rc/img-ir/img-ir-hw.c static int img_ir_set_filter(struct rc_dev *dev, enum rc_filter_type type, · line 491

Quoted 5 lines
drivers/media/rc/img-ir/img-ir-hw.c +1 -1
@@ -488,7 +488,7 @@ static int img_ir_set_filter(struct rc_dev *dev, enum rc_filter_type type,
 	/* convert scancode filter to raw filter */
 	filter.minlen = 0;
 	filter.maxlen = ~0;
-	ret = hw->decoder->filter(sc_filter, &filter, hw->enabled_protocols);
+	ret = hw->decoder->filter(sc_filter, &filter, dev->wakeup_protocol);

According to patch 1, wakeup_protocol can always be set to RC_TYPE_UNKNOWN using the protocol "none", but this function is used for the normal filter too. AFAICT that would make it impossible to set a normal filter without first setting the (new) wakeup protocol too. Technically when type == RC_FILTER_NORMAL, the protocol should be based on enabled_protocols, which should be set to a single protocol group.

I'll also note that enforcing that a wakeup protocol is set before setting the wakeup filter (in patch 1 which I'm not Cc'd on) is an incompatible API change. The old API basically meant that a mask of 0 disabled the wakeup filter, and there was no wakeup_protocol to set.

If wakeup filters can be changed to still be writable when wakeup protocol is not set, then I suppose this driver could do something like:

	if (type == RC_TYPE_NORMAL) {
		use hw->enabled_protocols;
	} else if (type == RC_TYPE_WAKEUP) {
		if (dev->wakeup_protocol == RC_TYPE_UNKNOWN)
			use hw->enabled_protocols;
		else
			use 1 << dev->wakeup_protocol;
	}

Clearly allowing a wakeup filter with no protocol is not ideal though.

It probably isn't a big deal from the img-ir point of view for those semantics to change slightly. The TZ1090 SoC I originally wrote the driver for is practically obsolete from my point of view, and the common clk and power management drivers to make this driver/feature functional was never merged into mainline.

Sifan: Does the MIPS pistachio SoC support wake up using img-ir, and does it even support suspend to RAM in mainline yet? If not then its impossible to utilise the wake filters in current kernels and changing the semantics is probably fine.

Cheers
James

Quoted 150 lines
drivers/media/rc/img-ir/img-ir-hw.c +0 -0
 	if (ret)
 		goto unlock;
 	dev_dbg(priv->dev, "IR raw %sfilter=%016llx & %016llx\n",
drivers/media/rc/img-ir/img-ir-hw.h +1 -1
index 91a2977..e1959ddc 100644
@@ -179,7 +179,7 @@ struct img_ir_decoder {
 	int (*scancode)(int len, u64 raw, u64 enabled_protocols,
 			struct img_ir_scancode_req *request);
 	int (*filter)(const struct rc_scancode_filter *in,
-		      struct img_ir_filter *out, u64 protocols);
+		      struct img_ir_filter *out, enum rc_type protocol);
 };
 
 extern struct img_ir_decoder img_ir_nec;
drivers/media/rc/img-ir/img-ir-jvc.c +1 -1
index d3e2fc0..10b302c 100644
@@ -30,7 +30,7 @@ static int img_ir_jvc_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert JVC scancode to JVC data filter */
 static int img_ir_jvc_filter(const struct rc_scancode_filter *in,
-			     struct img_ir_filter *out, u64 protocols)
+			     struct img_ir_filter *out, enum rc_type protocol)
 {
 	unsigned int cust, data;
 	unsigned int cust_m, data_m;
drivers/media/rc/img-ir/img-ir-nec.c +3 -3
index 0931493..fff00d4 100644
@@ -54,7 +54,7 @@ static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert NEC scancode to NEC data filter */
 static int img_ir_nec_filter(const struct rc_scancode_filter *in,
-			     struct img_ir_filter *out, u64 protocols)
+			     struct img_ir_filter *out, enum rc_type protocol)
 {
 	unsigned int addr, addr_inv, data, data_inv;
 	unsigned int addr_m, addr_inv_m, data_m, data_inv_m;
@@ -62,7 +62,7 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in,
 	data       = in->data & 0xff;
 	data_m     = in->mask & 0xff;
 
-	if ((in->data | in->mask) & 0xff000000) {
+	if (protocol == RC_TYPE_NEC32) {
 		/* 32-bit NEC (used by Apple and TiVo remotes) */
 		/* scan encoding: as transmitted, MSBit = first received bit */
 		addr       = bitrev8(in->data >> 24);
@@ -73,7 +73,7 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in,
 		data_m     = bitrev8(in->mask >>  8);
 		data_inv   = bitrev8(in->data >>  0);
 		data_inv_m = bitrev8(in->mask >>  0);
-	} else if ((in->data | in->mask) & 0x00ff0000) {
+	} else if (protocol == RC_TYPE_NECX) {
 		/* Extended NEC */
 		/* scan encoding AAaaDD */
 		addr       = (in->data >> 16) & 0xff;
drivers/media/rc/img-ir/img-ir-rc5.c +1 -1
index a8a28a3..24a6bcf 100644
@@ -41,7 +41,7 @@ static int img_ir_rc5_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert RC5 scancode to RC5 data filter */
 static int img_ir_rc5_filter(const struct rc_scancode_filter *in,
-				 struct img_ir_filter *out, u64 protocols)
+			     struct img_ir_filter *out, enum rc_type protocol)
 {
 	/* Not supported by the hw. */
 	return -EINVAL;
drivers/media/rc/img-ir/img-ir-rc6.c +1 -1
index de1e275..451e2ef8 100644
@@ -62,7 +62,7 @@ static int img_ir_rc6_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert RC6 scancode to RC6 data filter */
 static int img_ir_rc6_filter(const struct rc_scancode_filter *in,
-				 struct img_ir_filter *out, u64 protocols)
+			     struct img_ir_filter *out, enum rc_type protocol)
 {
 	/* Not supported by the hw. */
 	return -EINVAL;
drivers/media/rc/img-ir/img-ir-sanyo.c +1 -1
index f394994..8f542bd 100644
@@ -51,7 +51,7 @@ static int img_ir_sanyo_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert Sanyo scancode to Sanyo data filter */
 static int img_ir_sanyo_filter(const struct rc_scancode_filter *in,
-			       struct img_ir_filter *out, u64 protocols)
+			       struct img_ir_filter *out, enum rc_type protocol)
 {
 	unsigned int addr, addr_inv, data, data_inv;
 	unsigned int addr_m, data_m;
drivers/media/rc/img-ir/img-ir-sharp.c +1 -1
index fe5acc4..c8b4e9b 100644
@@ -39,7 +39,7 @@ static int img_ir_sharp_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert Sharp scancode to Sharp data filter */
 static int img_ir_sharp_filter(const struct rc_scancode_filter *in,
-			       struct img_ir_filter *out, u64 protocols)
+			       struct img_ir_filter *out, enum rc_type protocol)
 {
 	unsigned int addr, cmd, exp = 0, chk = 0;
 	unsigned int addr_m, cmd_m, exp_m = 0, chk_m = 0;
drivers/media/rc/img-ir/img-ir-sony.c +3 -8
index 7f7375f..ecae41c 100644
@@ -55,7 +55,7 @@ static int img_ir_sony_scancode(int len, u64 raw, u64 enabled_protocols,
 
 /* Convert NEC scancode to NEC data filter */
 static int img_ir_sony_filter(const struct rc_scancode_filter *in,
-			      struct img_ir_filter *out, u64 protocols)
+			      struct img_ir_filter *out, enum rc_type protocol)
 {
 	unsigned int dev, subdev, func;
 	unsigned int dev_m, subdev_m, func_m;
@@ -68,19 +68,14 @@ static int img_ir_sony_filter(const struct rc_scancode_filter *in,
 	func     = (in->data >> 0)  & 0x7f;
 	func_m   = (in->mask >> 0)  & 0x7f;
 
-	if (subdev & subdev_m) {
+	if (protocol == RC_TYPE_SONY20) {
 		/* can't encode subdev and higher device bits */
 		if (dev & dev_m & 0xe0)
 			return -EINVAL;
-		/* subdevice (extended) bits only in 20 bit encoding */
-		if (!(protocols & RC_BIT_SONY20))
-			return -EINVAL;
 		len = 20;
 		dev_m &= 0x1f;
-	} else if (dev & dev_m & 0xe0) {
+	} else if (protocol == RC_TYPE_SONY15) {
 		/* upper device bits only in 15 bit encoding */
-		if (!(protocols & RC_BIT_SONY15))
-			return -EINVAL;
 		len = 15;
 		subdev_m = 0;
 	} else {
Signature · 1 line
2.9.3
author maintainer
#4 lore raw

Re: [PATCH v5 02/18] [media] img-ir: use new wakeup_protocols sysfs mechanism

Hi James,

Quoted 28 lines · James Hogan
Quoted 27 lines · Sean Young

Rather than guessing what variant a scancode is from its length, use the new wakeup_protocol.

Cc James Hogan <[email protected]>
Cc Sifan Naeem <[email protected]>
---
 drivers/media/rc/img-ir/img-ir-hw.c    |  2 +-
 drivers/media/rc/img-ir/img-ir-hw.h    |  2 +-
 drivers/media/rc/img-ir/img-ir-jvc.c   |  2 +-
 drivers/media/rc/img-ir/img-ir-nec.c   |  6 +++---
 drivers/media/rc/img-ir/img-ir-rc5.c   |  2 +-
 drivers/media/rc/img-ir/img-ir-rc6.c   |  2 +-
 drivers/media/rc/img-ir/img-ir-sanyo.c |  2 +-
 drivers/media/rc/img-ir/img-ir-sharp.c |  2 +-
 drivers/media/rc/img-ir/img-ir-sony.c  | 11 +++--------
 9 files changed, 13 insertions(+), 18 deletions(-)
drivers/media/rc/img-ir/img-ir-hw.c +0 -1
index 1a0811d..841d9d7 100644
@@ -488,7 +488,7 @@ static int img_ir_set_filter(struct rc_dev *dev, enum rc_filter_type type,
 	/* convert scancode filter to raw filter */
 	filter.minlen = 0;
 	filter.maxlen = ~0;
-	ret = hw->decoder->filter(sc_filter, &filter, hw->enabled_protocols);
Quoted 8 lines

drivers/media/rc/img-ir/img-ir-hw.c static int img_ir_set_filter(struct rc_dev *dev, enum rc_filter_type type, · line 491

Quoted 1 line
drivers/media/rc/img-ir/img-ir-hw.c +1 -0
+	ret = hw->decoder->filter(sc_filter, &filter, dev->wakeup_protocol);

According to patch 1, wakeup_protocol can always be set to RC_TYPE_UNKNOWN using the protocol "none", but this function is used for the normal filter too. AFAICT that would make it impossible to set a normal filter without first setting the (new) wakeup protocol too. Technically when type == RC_FILTER_NORMAL, the protocol should be based on enabled_protocols, which should be set to a single protocol group.

Yes, this change is wrong. For normal filters it should clearly use dev->enabled_protocols.

Quoted 4 lines

I'll also note that enforcing that a wakeup protocol is set before setting the wakeup filter (in patch 1 which I'm not Cc'd on) is an incompatible API change. The old API basically meant that a mask of 0 disabled the wakeup filter, and there was no wakeup_protocol to set.

The "new" API always ensures that the mask is 0 if no protocol is set, no wakeup filter can be set while wakeup_protocol is RC_TYPE_UNKNOWN. This could be documented more clearly, I'll add something for that.

Howver you point out that the "new" API would require setting a wakeup protocol first, which was not required before. That is true, but at the same time, guessing the protocol variant from the scancode is not reliable either (as is done for Sony and NEC).

Quoted 11 lines

If wakeup filters can be changed to still be writable when wakeup protocol is not set, then I suppose this driver could do something like:

	if (type == RC_TYPE_NORMAL) {
		use hw->enabled_protocols;
	} else if (type == RC_TYPE_WAKEUP) {
		if (dev->wakeup_protocol == RC_TYPE_UNKNOWN)
			use hw->enabled_protocols;
		else
			use 1 << dev->wakeup_protocol;
	}

The problem with this solution is that wakeup_filter can not be set until a wakeup_protocol is set, so we would still need to set a wakeup_protocol, so it won't help.

Another solution would be to set the wakeup_protocol automagically whenever the normal protocol is set, much like enabled_wakeup_protocols is done now. We would have to pick a variant though.

So that leaves the question open of whether we want to guess the protocol variant from the scancode for img-ir or if we can live with having to select this using wakeup_protocols. Having to do this does solve the issue of the driver guessing the wrong protocol if the higher bits happen to be 0 in the scancode.

Also note that this is an issue for nec and sony only, the other protocols img-ir supports only have one variant.

Quoted 1 line

Clearly allowing a wakeup filter with no protocol is not ideal though.

Agreed.

Thanks,
Sean

#5 lore raw

Re: [PATCH v5 02/18] [media] img-ir: use new wakeup_protocols sysfs mechanism

Hi Sean,

Quoted 5 lines · Sean Young

So that leaves the question open of whether we want to guess the protocol variant from the scancode for img-ir or if we can live with having to select this using wakeup_protocols. Having to do this does solve the issue of the driver guessing the wrong protocol if the higher bits happen to be 0 in the scancode.

I've received confirmation that pistachio doesn't yet support suspend in mainline, in which case there can never be any real users of the old semantics on current/old mainline kernel versions. So I'm fine with it changing.

Cheers
James

author maintainer
#6 lore raw

PATCH v5 3/18 rc: Add scancode validation

In reply to Sean Young

We need to valdiate that scancodes are valid for their protocol; an incorrect necx scancode could actually be a nec scancode, for example.

---
 drivers/media/rc/rc-main.c | 71 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 68 insertions(+), 3 deletions(-)
drivers/media/rc/rc-main.c +68 -3
index 1ed06a9..33969ab 100644
@@ -724,6 +724,64 @@ void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
 }
 EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
 
+/**
+ * rc_validate_filter() - checks that the scancode and mask are valid and
+ *			  provides sensible defaults
+ * @protocol:	the protocol for the filter
+ * @filter:	the scancode and mask
+ * @return:	0 or -EINVAL if the filter is not valid
+ */
+static int rc_validate_filter(enum rc_type protocol,
+			      struct rc_scancode_filter *filter)
+{
+	static u32 masks[] = {
+		[RC_TYPE_RC5] = 0x1f7f,
+		[RC_TYPE_RC5X] = 0x1f7f3f,
+		[RC_TYPE_RC5_SZ] = 0x2fff,
+		[RC_TYPE_SONY12] = 0x1f007f,
+		[RC_TYPE_SONY15] = 0xff007f,
+		[RC_TYPE_SONY20] = 0x1fff7f,
+		[RC_TYPE_JVC] = 0xffff,
+		[RC_TYPE_NEC] = 0xffff,
+		[RC_TYPE_NECX] = 0xffffff,
+		[RC_TYPE_NEC32] = 0xffffffff,
+		[RC_TYPE_SANYO] = 0x1fffff,
+		[RC_TYPE_RC6_0] = 0xffff,
+		[RC_TYPE_RC6_6A_20] = 0xfffff,
+		[RC_TYPE_RC6_6A_24] = 0xffffff,
+		[RC_TYPE_RC6_6A_32] = 0xffffffff,
+		[RC_TYPE_RC6_MCE] = 0xffffffff,
+		[RC_TYPE_SHARP] = 0x1fff,
+	};
+	u32 s = filter->data;
+
+	switch (protocol) {
+	case RC_TYPE_NECX:
+		if ((((s >> 16) ^ ~(s >> 8)) & 0xff) == 0)
+			return -EINVAL;
+		break;
+	case RC_TYPE_NEC32:
+		if ((((s >> 24) ^ ~(s >> 16)) & 0xff) == 0)
+			return -EINVAL;
+		break;
+	case RC_TYPE_RC6_MCE:
+		if ((s & 0xffff0000) != 0x800f0000)
+			return -EINVAL;
+		break;
+	case RC_TYPE_RC6_6A_32:
+		if ((s & 0xffff0000) == 0x800f0000)
+			return -EINVAL;
+		break;
+	default:
+		break;
+	}
+
+	filter->data &= masks[protocol];
+	filter->mask &= masks[protocol];
+
+	return 0;
+}
+
 int rc_open(struct rc_dev *rdev)
 {
 	int rval = 0;
@@ -1229,11 +1287,18 @@ static ssize_t store_filter(struct device *device,
 		new_filter.data = val;
 
 	if (fattr->type == RC_FILTER_WAKEUP) {
-		/* refuse to set a filter unless a protocol is enabled */
-		if (dev->wakeup_protocol == RC_TYPE_UNKNOWN) {
+		/*
+		 * Refuse to set a filter unless a protocol is enabled
+		 * and the filter is valid for that protocol
+		 */
+		if (dev->wakeup_protocol != RC_TYPE_UNKNOWN)
+			ret = rc_validate_filter(dev->wakeup_protocol,
+						 &new_filter);
+		else
 			ret = -EINVAL;
+
+		if (ret != 0)
 			goto unlock;
-		}
 	}
 
 	if (fattr->type == RC_FILTER_NORMAL && !dev->enabled_protocols &&
Signature · 1 line
2.9.3
author maintainer
#7 lore raw

PATCH v5 4/18 winbond-cir: use sysfs wakeup filter

In reply to Sean Young

Now that we can select the exact variant of the protocol for wakeup filter, the winbond-cir can use the wakeup filter rather than module parameters.

Cc David Härdeman <[email protected]>
---
 drivers/media/rc/winbond-cir.c | 257 +++++++++++++++++++++--------------------
 1 file changed, 131 insertions(+), 126 deletions(-)
drivers/media/rc/winbond-cir.c +131 -126
index 78491ed..08971df 100644
@@ -194,7 +194,6 @@ enum wbcir_txstate {
 #define WBCIR_NAME	"Winbond CIR"
 #define WBCIR_ID_FAMILY          0xF1 /* Family ID for the WPCD376I	*/
 #define	WBCIR_ID_CHIP            0x04 /* Chip ID for the WPCD376I	*/
-#define INVALID_SCANCODE   0x7FFFFFFF /* Invalid with all protos	*/
 #define WAKEUP_IOMEM_LEN         0x10 /* Wake-Up I/O Reg Len		*/
 #define EHFUNC_IOMEM_LEN         0x10 /* Enhanced Func I/O Reg Len	*/
 #define SP_IOMEM_LEN             0x08 /* Serial Port 3 (IR) Reg Len	*/
@@ -225,10 +224,6 @@ struct wbcir_data {
 	u32 txcarrier;
 };
 
-static enum wbcir_protocol protocol = IR_PROTOCOL_RC6;
-module_param(protocol, uint, 0444);
-MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command (0 = RC5, 1 = NEC, 2 = RC6A, default)");
-
 static bool invert; /* default = 0 */
 module_param(invert, bool, 0444);
 MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver");
@@ -237,15 +232,6 @@ static bool txandrx; /* default = 0 */
 module_param(txandrx, bool, 0444);
 MODULE_PARM_DESC(txandrx, "Allow simultaneous TX and RX");
 
-static unsigned int wake_sc = 0x800F040C;
-module_param(wake_sc, uint, 0644);
-MODULE_PARM_DESC(wake_sc, "Scancode of the power-on IR command");
-
-static unsigned int wake_rc6mode = 6;
-module_param(wake_rc6mode, uint, 0644);
-MODULE_PARM_DESC(wake_rc6mode, "RC6 mode for the power-on command (0 = 0, 6 = 6A, default)");
-
-
 
 /*****************************************************************************
  *
@@ -696,138 +682,153 @@ wbcir_shutdown(struct pnp_dev *device)
 {
 	struct device *dev = &device->dev;
 	struct wbcir_data *data = pnp_get_drvdata(device);
+	struct rc_dev *rc = data->dev;
 	bool do_wake = true;
 	u8 match[11];
 	u8 mask[11];
 	u8 rc6_csl = 0;
+	u8 proto;
+	u32 wake_sc = rc->scancode_wakeup_filter.data;
+	u32 mask_sc = rc->scancode_wakeup_filter.mask;
 	int i;
 
 	memset(match, 0, sizeof(match));
 	memset(mask, 0, sizeof(mask));
 
-	if (wake_sc == INVALID_SCANCODE || !device_may_wakeup(dev)) {
+	if (!mask_sc || !device_may_wakeup(dev)) {
 		do_wake = false;
 		goto finish;
 	}
 
-	switch (protocol) {
-	case IR_PROTOCOL_RC5:
-		if (wake_sc > 0xFFF) {
-			do_wake = false;
-			dev_err(dev, "RC5 - Invalid wake scancode\n");
-			break;
-		}
-
+	switch (rc->wakeup_protocol) {
+	case RC_TYPE_RC5:
 		/* Mask = 13 bits, ex toggle */
-		mask[0] = 0xFF;
-		mask[1] = 0x17;
+		mask[0]  = (mask_sc & 0x003f);
+		mask[0] |= (mask_sc & 0x0300) >> 2;
+		mask[1]  = (mask_sc & 0x1c00) >> 10;
+		if (mask_sc & 0x0040)		      /* 2nd start bit  */
+			match[1] |= 0x10;
 
-		match[0]  = (wake_sc & 0x003F);      /* 6 command bits */
-		match[0] |= (wake_sc & 0x0180) >> 1; /* 2 address bits */
-		match[1]  = (wake_sc & 0x0E00) >> 9; /* 3 address bits */
-		if (!(wake_sc & 0x0040))             /* 2nd start bit  */
+		match[0]  = (wake_sc & 0x003F);       /* 6 command bits */
+		match[0] |= (wake_sc & 0x0300) >> 2;  /* 2 address bits */
+		match[1]  = (wake_sc & 0x1c00) >> 10; /* 3 address bits */
+		if (!(wake_sc & 0x0040))	      /* 2nd start bit  */
 			match[1] |= 0x10;
 
+		proto = IR_PROTOCOL_RC5;
 		break;
 
-	case IR_PROTOCOL_NEC:
-		if (wake_sc > 0xFFFFFF) {
-			do_wake = false;
-			dev_err(dev, "NEC - Invalid wake scancode\n");
-			break;
-		}
-
-		mask[0] = mask[1] = mask[2] = mask[3] = 0xFF;
+	case RC_TYPE_NEC:
+		mask[1] = bitrev8(mask_sc);
+		mask[0] = mask[1];
+		mask[3] = bitrev8(mask_sc >> 8);
+		mask[2] = mask[3];
 
-		match[1] = bitrev8((wake_sc & 0xFF));
+		match[1] = bitrev8(wake_sc);
 		match[0] = ~match[1];
+		match[3] = bitrev8(wake_sc >> 8);
+		match[2] = ~match[3];
 
-		match[3] = bitrev8((wake_sc & 0xFF00) >> 8);
-		if (wake_sc > 0xFFFF)
-			match[2] = bitrev8((wake_sc & 0xFF0000) >> 16);
-		else
-			match[2] = ~match[3];
+		proto = IR_PROTOCOL_NEC;
+		break;
 
+	case RC_TYPE_NECX:
+		mask[1] = bitrev8(mask_sc);
+		mask[0] = mask[1];
+		mask[2] = bitrev8(mask_sc >> 8);
+		mask[3] = bitrev8(mask_sc >> 16);
+
+		match[1] = bitrev8(wake_sc);
+		match[0] = ~match[1];
+		match[2] = bitrev8(wake_sc >> 8);
+		match[3] = bitrev8(wake_sc >> 16);
+
+		proto = IR_PROTOCOL_NEC;
 		break;
 
-	case IR_PROTOCOL_RC6:
+	case RC_TYPE_NEC32:
+		mask[0] = bitrev8(mask_sc);
+		mask[1] = bitrev8(mask_sc >> 8);
+		mask[2] = bitrev8(mask_sc >> 16);
+		mask[3] = bitrev8(mask_sc >> 24);
 
-		if (wake_rc6mode == 0) {
-			if (wake_sc > 0xFFFF) {
-				do_wake = false;
-				dev_err(dev, "RC6 - Invalid wake scancode\n");
-				break;
-			}
+		match[0] = bitrev8(wake_sc);
+		match[1] = bitrev8(wake_sc >> 8);
+		match[2] = bitrev8(wake_sc >> 16);
+		match[3] = bitrev8(wake_sc >> 24);
+
+		proto = IR_PROTOCOL_NEC;
+		break;
+
+	case RC_TYPE_RC6_0:
+		/* Command */
+		match[0] = wbcir_to_rc6cells(wake_sc >> 0);
+		mask[0]  = wbcir_to_rc6cells(mask_sc >> 0);
+		match[1] = wbcir_to_rc6cells(wake_sc >> 4);
+		mask[1]  = wbcir_to_rc6cells(mask_sc >> 4);
+
+		/* Address */
+		match[2] = wbcir_to_rc6cells(wake_sc >>  8);
+		mask[2]  = wbcir_to_rc6cells(mask_sc >>  8);
+		match[3] = wbcir_to_rc6cells(wake_sc >> 12);
+		mask[3]  = wbcir_to_rc6cells(mask_sc >> 12);
+
+		/* Header */
+		match[4] = 0x50; /* mode1 = mode0 = 0, ignore toggle */
+		mask[4]  = 0xF0;
+		match[5] = 0x09; /* start bit = 1, mode2 = 0 */
+		mask[5]  = 0x0F;
+
+		rc6_csl = 44;
+		proto = IR_PROTOCOL_RC6;
+		break;
 
-			/* Command */
-			match[0] = wbcir_to_rc6cells(wake_sc >>  0);
-			mask[0]  = 0xFF;
-			match[1] = wbcir_to_rc6cells(wake_sc >>  4);
-			mask[1]  = 0xFF;
-
-			/* Address */
-			match[2] = wbcir_to_rc6cells(wake_sc >>  8);
-			mask[2]  = 0xFF;
-			match[3] = wbcir_to_rc6cells(wake_sc >> 12);
-			mask[3]  = 0xFF;
-
-			/* Header */
-			match[4] = 0x50; /* mode1 = mode0 = 0, ignore toggle */
-			mask[4]  = 0xF0;
-			match[5] = 0x09; /* start bit = 1, mode2 = 0 */
-			mask[5]  = 0x0F;
-
-			rc6_csl = 44;
-
-		} else if (wake_rc6mode == 6) {
-			i = 0;
-
-			/* Command */
-			match[i]  = wbcir_to_rc6cells(wake_sc >>  0);
-			mask[i++] = 0xFF;
-			match[i]  = wbcir_to_rc6cells(wake_sc >>  4);
-			mask[i++] = 0xFF;
-
-			/* Address + Toggle */
-			match[i]  = wbcir_to_rc6cells(wake_sc >>  8);
-			mask[i++] = 0xFF;
-			match[i]  = wbcir_to_rc6cells(wake_sc >> 12);
-			mask[i++] = 0x3F;
-
-			/* Customer bits 7 - 0 */
-			match[i]  = wbcir_to_rc6cells(wake_sc >> 16);
-			mask[i++] = 0xFF;
+	case RC_TYPE_RC6_6A_24:
+	case RC_TYPE_RC6_6A_32:
+	case RC_TYPE_RC6_MCE:
+		i = 0;
+
+		/* Command */
+		match[i]  = wbcir_to_rc6cells(wake_sc >>  0);
+		mask[i++] = wbcir_to_rc6cells(mask_sc >>  0);
+		match[i]  = wbcir_to_rc6cells(wake_sc >>  4);
+		mask[i++] = wbcir_to_rc6cells(mask_sc >>  4);
+
+		/* Address + Toggle */
+		match[i]  = wbcir_to_rc6cells(wake_sc >>  8);
+		mask[i++] = wbcir_to_rc6cells(mask_sc >>  8);
+		match[i]  = wbcir_to_rc6cells(wake_sc >> 12);
+		mask[i++] = wbcir_to_rc6cells(mask_sc >> 12);
+
+		/* Customer bits 7 - 0 */
+		match[i]  = wbcir_to_rc6cells(wake_sc >> 16);
+		mask[i++] = wbcir_to_rc6cells(mask_sc >> 16);
+
+		if (rc->wakeup_protocol == RC_TYPE_RC6_6A_20) {
+			rc6_csl = 52;
+		} else {
 			match[i]  = wbcir_to_rc6cells(wake_sc >> 20);
-			mask[i++] = 0xFF;
+			mask[i++] = wbcir_to_rc6cells(mask_sc >> 20);
 
-			if (wake_sc & 0x80000000) {
+			if (rc->wakeup_protocol == RC_TYPE_RC6_6A_24) {
+				rc6_csl = 60;
+			} else {
 				/* Customer range bit and bits 15 - 8 */
 				match[i]  = wbcir_to_rc6cells(wake_sc >> 24);
-				mask[i++] = 0xFF;
+				mask[i++] = wbcir_to_rc6cells(mask_sc >> 24);
 				match[i]  = wbcir_to_rc6cells(wake_sc >> 28);
-				mask[i++] = 0xFF;
+				mask[i++] = wbcir_to_rc6cells(mask_sc >> 28);
 				rc6_csl = 76;
-			} else if (wake_sc <= 0x007FFFFF) {
-				rc6_csl = 60;
-			} else {
-				do_wake = false;
-				dev_err(dev, "RC6 - Invalid wake scancode\n");
-				break;
 			}
-
-			/* Header */
-			match[i]  = 0x93; /* mode1 = mode0 = 1, submode = 0 */
-			mask[i++] = 0xFF;
-			match[i]  = 0x0A; /* start bit = 1, mode2 = 1 */
-			mask[i++] = 0x0F;
-
-		} else {
-			do_wake = false;
-			dev_err(dev, "RC6 - Invalid wake mode\n");
 		}
 
+		/* Header */
+		match[i]  = 0x93; /* mode1 = mode0 = 1, submode = 0 */
+		mask[i++] = 0xFF;
+		match[i]  = 0x0A; /* start bit = 1, mode2 = 1 */
+		mask[i++] = 0x0F;
+		proto = IR_PROTOCOL_RC6;
 		break;
-
 	default:
 		do_wake = false;
 		break;
@@ -855,7 +856,8 @@ wbcir_shutdown(struct pnp_dev *device)
 		wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x01, 0x07);
 
 		/* Set CEIR_EN */
-		wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x01, 0x01);
+		wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL,
+			       (proto << 4) | 0x01, 0x31);
 
 	} else {
 		/* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */
@@ -875,6 +877,15 @@ wbcir_shutdown(struct pnp_dev *device)
 	disable_irq(data->irq);
 }
 
+/*
+ * Wakeup handling is done on shutdown.
+ */
+static int
+wbcir_set_wakeup_filter(struct rc_dev *rc, struct rc_scancode_filter *filter)
+{
+	return 0;
+}
+
 static int
 wbcir_suspend(struct pnp_dev *device, pm_message_t state)
 {
@@ -887,16 +898,11 @@ wbcir_suspend(struct pnp_dev *device, pm_message_t state)
 static void
 wbcir_init_hw(struct wbcir_data *data)
 {
-	u8 tmp;
-
 	/* Disable interrupts */
 	wbcir_set_irqmask(data, WBCIR_IRQ_NONE);
 
-	/* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */
-	tmp = protocol << 4;
-	if (invert)
-		tmp |= 0x08;
-	outb(tmp, data->wbase + WBCIR_REG_WCEIR_CTL);
+	/* Set RX_INV, Clear CEIR_EN (needed for the led) */
+	wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, invert ? 8 : 0, 0x09);
 
 	/* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */
 	wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17);
@@ -1084,6 +1090,14 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
 	data->dev->timeout = MS_TO_NS(100);
 	data->dev->rx_resolution = US_TO_NS(2);
 	data->dev->allowed_protocols = RC_BIT_ALL;
+	data->dev->allowed_wakeup_protocols = RC_BIT_NEC | RC_BIT_NECX |
+			RC_BIT_NEC32 | RC_BIT_RC5 | RC_BIT_RC6_0 |
+			RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 |
+			RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE;
+	data->dev->wakeup_protocol = RC_TYPE_RC6_MCE;
+	data->dev->scancode_wakeup_filter.data = 0x800F040C;
+	data->dev->scancode_wakeup_filter.mask = ~0;
+	data->dev->s_wakeup_filter = wbcir_set_wakeup_filter;
 
 	err = rc_register_device(data->dev);
 	if (err)
@@ -1199,15 +1213,6 @@ wbcir_init(void)
 {
 	int ret;
 
-	switch (protocol) {
-	case IR_PROTOCOL_RC5:
-	case IR_PROTOCOL_NEC:
-	case IR_PROTOCOL_RC6:
-		break;
-	default:
-		pr_err("Invalid power-on protocol\n");
-	}
-
 	ret = pnp_register_driver(&wbcir_driver);
 	if (ret)
 		pr_err("Unable to register driver\n");
Signature · 1 line
2.9.3
author maintainer
#8 lore raw

PATCH v5 5/18 rc: raw IR drivers cannot handle cec, unknown or other

In reply to Sean Young

unknown and other are for IR protocols for which we have no decoder, so the raw IR drivers have no chance of generating them. cec is not an IR protocol.

Cc Jiri Kosina <[email protected]>
Cc Benjamin Tissoires <[email protected]>
Cc Bruno Prémont <[email protected]>
---
 drivers/hid/hid-picolcd_cir.c              |  2 +-
 drivers/media/common/siano/smsir.c         |  2 +-
 drivers/media/pci/cx23885/cx23885-input.c  | 14 +++++++-------
 drivers/media/rc/ene_ir.c                  |  2 +-
 drivers/media/rc/fintek-cir.c              |  2 +-
 drivers/media/rc/gpio-ir-recv.c            |  2 +-
 drivers/media/rc/igorplugusb.c             |  4 ++--
 drivers/media/rc/iguanair.c                |  2 +-
 drivers/media/rc/ir-hix5hd2.c              |  2 +-
 drivers/media/rc/ite-cir.c                 |  2 +-
 drivers/media/rc/mceusb.c                  |  2 +-
 drivers/media/rc/meson-ir.c                |  2 +-
 drivers/media/rc/nuvoton-cir.c             |  2 +-
 drivers/media/rc/rc-loopback.c             |  2 +-
 drivers/media/rc/redrat3.c                 |  2 +-
 drivers/media/rc/serial_ir.c               |  2 +-
 drivers/media/rc/st_rc.c                   |  2 +-
 drivers/media/rc/streamzap.c               |  2 +-
 drivers/media/rc/sunxi-cir.c               |  2 +-
 drivers/media/rc/ttusbir.c                 |  2 +-
 drivers/media/rc/winbond-cir.c             |  2 +-
 drivers/media/usb/dvb-usb-v2/rtl28xxu.c    |  2 +-
 drivers/media/usb/dvb-usb/technisat-usb2.c |  2 +-
 include/media/rc-map.h                     | 10 ++++++++++
 24 files changed, 40 insertions(+), 30 deletions(-)
drivers/hid/hid-picolcd_cir.c +1 -1
index 9628651..90add97 100644
@@ -114,7 +114,7 @@ int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
 
 	rdev->priv             = data;
 	rdev->driver_type      = RC_DRIVER_IR_RAW;
-	rdev->allowed_protocols = RC_BIT_ALL;
+	rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	rdev->open             = picolcd_cir_open;
 	rdev->close            = picolcd_cir_close;
 	rdev->input_name       = data->hdev->name;
drivers/media/common/siano/smsir.c +1 -1
index 41f2a39..480d8bf 100644
@@ -87,7 +87,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
 
 	dev->priv = coredev;
 	dev->driver_type = RC_DRIVER_IR_RAW;
-	dev->allowed_protocols = RC_BIT_ALL;
+	dev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	dev->map_name = sms_get_board(board_id)->rc_codes;
 	dev->driver_name = MODULE_NAME;
 
drivers/media/pci/cx23885/cx23885-input.c +7 -7
index 1f092fe..2d4e703 100644
@@ -286,28 +286,28 @@ int cx23885_input_init(struct cx23885_dev *dev)
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 		/* Integrated CX2388[58] IR controller */
 		driver_type = RC_DRIVER_IR_RAW;
-		allowed_protos = RC_BIT_ALL;
+		allowed_protos = RC_BIT_ALL_IR_DECODER;
 		/* The grey Hauppauge RC-5 remote */
 		rc_map = RC_MAP_HAUPPAUGE;
 		break;
 	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
 		/* Integrated CX23885 IR controller */
 		driver_type = RC_DRIVER_IR_RAW;
-		allowed_protos = RC_BIT_ALL;
+		allowed_protos = RC_BIT_ALL_IR_DECODER;
 		/* The grey Terratec remote with orange buttons */
 		rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS;
 		break;
 	case CX23885_BOARD_TEVII_S470:
 		/* Integrated CX23885 IR controller */
 		driver_type = RC_DRIVER_IR_RAW;
-		allowed_protos = RC_BIT_ALL;
+		allowed_protos = RC_BIT_ALL_IR_DECODER;
 		/* A guess at the remote */
 		rc_map = RC_MAP_TEVII_NEC;
 		break;
 	case CX23885_BOARD_MYGICA_X8507:
 		/* Integrated CX23885 IR controller */
 		driver_type = RC_DRIVER_IR_RAW;
-		allowed_protos = RC_BIT_ALL;
+		allowed_protos = RC_BIT_ALL_IR_DECODER;
 		/* A guess at the remote */
 		rc_map = RC_MAP_TOTAL_MEDIA_IN_HAND_02;
 		break;
@@ -315,7 +315,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
 	case CX23885_BOARD_TBS_6981:
 		/* Integrated CX23885 IR controller */
 		driver_type = RC_DRIVER_IR_RAW;
-		allowed_protos = RC_BIT_ALL;
+		allowed_protos = RC_BIT_ALL_IR_DECODER;
 		/* A guess at the remote */
 		rc_map = RC_MAP_TBS_NEC;
 		break;
@@ -327,13 +327,13 @@ int cx23885_input_init(struct cx23885_dev *dev)
 	case CX23885_BOARD_DVBSKY_T982:
 		/* Integrated CX23885 IR controller */
 		driver_type = RC_DRIVER_IR_RAW;
-		allowed_protos = RC_BIT_ALL;
+		allowed_protos = RC_BIT_ALL_IR_DECODER;
 		rc_map = RC_MAP_DVBSKY;
 		break;
 	case CX23885_BOARD_TT_CT2_4500_CI:
 		/* Integrated CX23885 IR controller */
 		driver_type = RC_DRIVER_IR_RAW;
-		allowed_protos = RC_BIT_ALL;
+		allowed_protos = RC_BIT_ALL_IR_DECODER;
 		rc_map = RC_MAP_TT_1500;
 		break;
 	default:
drivers/media/rc/ene_ir.c +1 -1
index bd5512e..b7ce051 100644
@@ -1059,7 +1059,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
 		learning_mode_force = false;
 
 	rdev->driver_type = RC_DRIVER_IR_RAW;
-	rdev->allowed_protocols = RC_BIT_ALL;
+	rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	rdev->priv = dev;
 	rdev->open = ene_open;
 	rdev->close = ene_close;
drivers/media/rc/fintek-cir.c +1 -1
index ecab69e..3de5e82 100644
@@ -535,7 +535,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
 	/* Set up the rc device */
 	rdev->priv = fintek;
 	rdev->driver_type = RC_DRIVER_IR_RAW;
-	rdev->allowed_protocols = RC_BIT_ALL;
+	rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	rdev->open = fintek_open;
 	rdev->close = fintek_close;
 	rdev->input_name = FINTEK_DESCRIPTION;
drivers/media/rc/gpio-ir-recv.c +1 -1
index 5b63b1f..0b5aec4 100644
@@ -165,7 +165,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
 	if (pdata->allowed_protos)
 		rcdev->allowed_protocols = pdata->allowed_protos;
 	else
-		rcdev->allowed_protocols = RC_BIT_ALL;
+		rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY;
 
 	gpio_dev->rcdev = rcdev;
drivers/media/rc/igorplugusb.c +2 -2
index 5cf983b..4c4827c 100644
@@ -203,8 +203,8 @@ static int igorplugusb_probe(struct usb_interface *intf,
 	 * This device can only store 36 pulses + spaces, which is not enough
 	 * for the NEC protocol and many others.
 	 */
-	rc->allowed_protocols = RC_BIT_ALL & ~(RC_BIT_NEC | RC_BIT_NECX |
-			RC_BIT_NEC32 | RC_BIT_RC6_6A_20 |
+	rc->allowed_protocols = RC_BIT_ALL_IR_DECODER & ~(RC_BIT_NEC |
+			RC_BIT_NECX | RC_BIT_NEC32 | RC_BIT_RC6_6A_20 |
 			RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE |
 			RC_BIT_SONY20 | RC_BIT_MCE_KBD | RC_BIT_SANYO);
 
drivers/media/rc/iguanair.c +1 -1
index 5f63454..e2fff1f 100644
@@ -495,7 +495,7 @@ static int iguanair_probe(struct usb_interface *intf,
 	usb_to_input_id(ir->udev, &rc->input_id);
 	rc->dev.parent = &intf->dev;
 	rc->driver_type = RC_DRIVER_IR_RAW;
-	rc->allowed_protocols = RC_BIT_ALL;
+	rc->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	rc->priv = ir;
 	rc->open = iguanair_open;
 	rc->close = iguanair_close;
drivers/media/rc/ir-hix5hd2.c +1 -1
index d26907e..d95056a 100644
@@ -243,7 +243,7 @@ static int hix5hd2_ir_probe(struct platform_device *pdev)
 	priv->rate = clk_get_rate(priv->clock);
 
 	rdev->driver_type = RC_DRIVER_IR_RAW;
-	rdev->allowed_protocols = RC_BIT_ALL;
+	rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	rdev->priv = priv;
 	rdev->open = hix5hd2_ir_open;
 	rdev->close = hix5hd2_ir_close;
drivers/media/rc/ite-cir.c +1 -1
index 367b28b..01f6929 100644
@@ -1562,7 +1562,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
 	/* set up ir-core props */
 	rdev->priv = itdev;
 	rdev->driver_type = RC_DRIVER_IR_RAW;
-	rdev->allowed_protocols = RC_BIT_ALL;
+	rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	rdev->open = ite_open;
 	rdev->close = ite_close;
 	rdev->s_idle = ite_s_idle;
drivers/media/rc/mceusb.c +1 -1
index 9bf6917..9fd8d44 100644
@@ -1202,7 +1202,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
 	rc->dev.parent = dev;
 	rc->priv = ir;
 	rc->driver_type = RC_DRIVER_IR_RAW;
-	rc->allowed_protocols = RC_BIT_ALL;
+	rc->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	rc->timeout = MS_TO_NS(100);
 	if (!ir->flags.no_tx) {
 		rc->s_tx_mask = mceusb_set_tx_mask;
drivers/media/rc/meson-ir.c +1 -1
index 7eb3f4f..3e96e6f 100644
@@ -145,7 +145,7 @@ static int meson_ir_probe(struct platform_device *pdev)
 	ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY;
 	ir->rc->dev.parent = dev;
 	ir->rc->driver_type = RC_DRIVER_IR_RAW;
-	ir->rc->allowed_protocols = RC_BIT_ALL;
+	ir->rc->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	ir->rc->rx_resolution = US_TO_NS(MESON_TRATE);
 	ir->rc->timeout = MS_TO_NS(200);
 	ir->rc->driver_name = DRIVER_NAME;
drivers/media/rc/nuvoton-cir.c +1 -1
index 4b78c89..9e04f41 100644
@@ -1062,7 +1062,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 	/* Set up the rc device */
 	rdev->priv = nvt;
 	rdev->driver_type = RC_DRIVER_IR_RAW;
-	rdev->allowed_protocols = RC_BIT_ALL;
+	rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	rdev->open = nvt_open;
 	rdev->close = nvt_close;
 	rdev->tx_ir = nvt_tx_ir;
drivers/media/rc/rc-loopback.c +1 -1
index 63dace8..4bc3f01 100644
@@ -195,7 +195,7 @@ static int __init loop_init(void)
 	rc->map_name		= RC_MAP_EMPTY;
 	rc->priv		= &loopdev;
 	rc->driver_type		= RC_DRIVER_IR_RAW;
-	rc->allowed_protocols	= RC_BIT_ALL;
+	rc->allowed_protocols	= RC_BIT_ALL_IR_DECODER;
 	rc->timeout		= 100 * 1000 * 1000; /* 100 ms */
 	rc->min_timeout		= 1;
 	rc->max_timeout		= UINT_MAX;
drivers/media/rc/redrat3.c +1 -1
index 2784f5d..ca878ac 100644
@@ -961,7 +961,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
 	rc->dev.parent = dev;
 	rc->priv = rr3;
 	rc->driver_type = RC_DRIVER_IR_RAW;
-	rc->allowed_protocols = RC_BIT_ALL;
+	rc->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT);
 	rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT);
 	rc->timeout = US_TO_NS(redrat3_get_timeout(rr3));
drivers/media/rc/serial_ir.c +1 -1
index 436bd58..1faa1ae 100644
@@ -778,7 +778,7 @@ static int __init serial_ir_init_module(void)
 	rcdev->close = serial_ir_close;
 	rcdev->dev.parent = &serial_ir.pdev->dev;
 	rcdev->driver_type = RC_DRIVER_IR_RAW;
-	rcdev->allowed_protocols = RC_BIT_ALL;
+	rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	rcdev->driver_name = KBUILD_MODNAME;
 	rcdev->map_name = RC_MAP_RC6_MCE;
 	rcdev->timeout = IR_DEFAULT_TIMEOUT;
drivers/media/rc/st_rc.c +1 -1
index 1fa0c9d..80a46e7 100644
@@ -291,7 +291,7 @@ static int st_rc_probe(struct platform_device *pdev)
 	st_rc_hardware_init(rc_dev);
 
 	rdev->driver_type = RC_DRIVER_IR_RAW;
-	rdev->allowed_protocols = RC_BIT_ALL;
+	rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	/* rx sampling rate is 10Mhz */
 	rdev->rx_resolution = 100;
 	rdev->timeout = US_TO_NS(MAX_SYMB_TIME);
drivers/media/rc/streamzap.c +1 -1
index 53f9b0a..359f928 100644
@@ -309,7 +309,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
 	rdev->dev.parent = dev;
 	rdev->priv = sz;
 	rdev->driver_type = RC_DRIVER_IR_RAW;
-	rdev->allowed_protocols = RC_BIT_ALL;
+	rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	rdev->driver_name = DRIVER_NAME;
 	rdev->map_name = RC_MAP_STREAMZAP;
 
drivers/media/rc/sunxi-cir.c +1 -1
index eaadc08..42bca8d 100644
@@ -230,7 +230,7 @@ static int sunxi_ir_probe(struct platform_device *pdev)
 	ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY;
 	ir->rc->dev.parent = dev;
 	ir->rc->driver_type = RC_DRIVER_IR_RAW;
-	ir->rc->allowed_protocols = RC_BIT_ALL;
+	ir->rc->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	ir->rc->rx_resolution = SUNXI_IR_SAMPLE;
 	ir->rc->timeout = MS_TO_NS(SUNXI_IR_TIMEOUT);
 	ir->rc->driver_name = SUNXI_IR_DEV;
drivers/media/rc/ttusbir.c +1 -1
index bc214e2..322e947 100644
@@ -318,7 +318,7 @@ static int ttusbir_probe(struct usb_interface *intf,
 	usb_to_input_id(tt->udev, &rc->input_id);
 	rc->dev.parent = &intf->dev;
 	rc->driver_type = RC_DRIVER_IR_RAW;
-	rc->allowed_protocols = RC_BIT_ALL;
+	rc->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	rc->priv = tt;
 	rc->driver_name = DRIVER_NAME;
 	rc->map_name = RC_MAP_TT_1500;
drivers/media/rc/winbond-cir.c +1 -1
index 08971df..f640ece 100644
@@ -1089,7 +1089,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
 	data->dev->dev.parent = &device->dev;
 	data->dev->timeout = MS_TO_NS(100);
 	data->dev->rx_resolution = US_TO_NS(2);
-	data->dev->allowed_protocols = RC_BIT_ALL;
+	data->dev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	data->dev->allowed_wakeup_protocols = RC_BIT_NEC | RC_BIT_NECX |
 			RC_BIT_NEC32 | RC_BIT_RC5 | RC_BIT_RC6_0 |
 			RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 |
drivers/media/usb/dvb-usb-v2/rtl28xxu.c +1 -1
index c583c63..e16ca07 100644
@@ -1778,7 +1778,7 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
 	/* load empty to enable rc */
 	if (!rc->map_name)
 		rc->map_name = RC_MAP_EMPTY;
-	rc->allowed_protos = RC_BIT_ALL;
+	rc->allowed_protos = RC_BIT_ALL_IR_DECODER;
 	rc->driver_type = RC_DRIVER_IR_RAW;
 	rc->query = rtl2832u_rc_query;
 	rc->interval = 200;
drivers/media/usb/dvb-usb/technisat-usb2.c +1 -1
index 02c3bee..1b21f1b 100644
@@ -753,7 +753,7 @@ static struct dvb_usb_device_properties technisat_usb2_devices = {
 		.rc_codes    = RC_MAP_TECHNISAT_USB2,
 		.module_name = "technisat-usb2",
 		.rc_query    = technisat_usb2_rc_query,
-		.allowed_protos = RC_BIT_ALL,
+		.allowed_protos = RC_BIT_ALL_IR_DECODER,
 		.driver_type    = RC_DRIVER_IR_RAW,
 	}
 };
include/media/rc-map.h +10 -0
index e1cc14c..b2af45d 100644
@@ -95,6 +95,16 @@ enum rc_type {
 			 RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
 			 RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | RC_BIT_SHARP | \
 			 RC_BIT_XMP | RC_BIT_CEC)
+/* All rc protocols for which we have decoders */
+#define RC_BIT_ALL_IR_DECODER \
+			(RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \
+			 RC_BIT_JVC | \
+			 RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \
+			 RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 | \
+			 RC_BIT_SANYO | RC_BIT_MCE_KBD | RC_BIT_RC6_0 | \
+			 RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
+			 RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | RC_BIT_SHARP | \
+			 RC_BIT_XMP)
 
 
 #define RC_SCANCODE_UNKNOWN(x)			(x)
Signature · 1 line
2.9.3
author maintainer
#9 lore raw

PATCH v5 6/18 rc: rc-ir-raw: Add scancode encoder callback

From: James Hogan <[email protected]>

Add a callback to raw ir handlers for encoding and modulating a scancode to a set of raw events. This could be used for transmit, or for converting a wakeup scancode to a form that is more suitable for raw hardware wake up filters.

---
 drivers/media/rc/rc-core-priv.h |  2 ++
 drivers/media/rc/rc-ir-raw.c    | 36 ++++++++++++++++++++++++++++++++++++
 include/media/rc-core.h         |  2 ++
 3 files changed, 40 insertions(+)
drivers/media/rc/rc-core-priv.h +2 -0
index 585d5e5..d8be011 100644
@@ -28,6 +28,8 @@ struct ir_raw_handler {
 
 	u64 protocols; /* which are handled by this handler */
 	int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
+	int (*encode)(enum rc_type protocol, u32 scancode,
+		      struct ir_raw_event *events, unsigned int max);
 
 	/* These two should only be used by the lirc decoder */
 	int (*raw_register)(struct rc_dev *dev);
drivers/media/rc/rc-ir-raw.c +36 -0
index 171bdba..c23c877 100644
@@ -249,6 +249,42 @@ static void ir_raw_disable_protocols(struct rc_dev *dev, u64 protocols)
 	mutex_unlock(&dev->lock);
 }
 
+/**
+ * ir_raw_encode_scancode() - Encode a scancode as raw events
+ *
+ * @protocol:		protocol
+ * @scancode:		scancode filter describing a single scancode
+ * @events:		array of raw events to write into
+ * @max:		max number of raw events
+ *
+ * Attempts to encode the scancode as raw events.
+ *
+ * Returns:	The number of events written.
+ *		-ENOBUFS if there isn't enough space in the array to fit the
+ *		encoding. In this case all @max events will have been written.
+ *		-EINVAL if the scancode is ambiguous or invalid, or if no
+ *		compatible encoder was found.
+ */
+int ir_raw_encode_scancode(enum rc_type protocol, u32 scancode,
+			   struct ir_raw_event *events, unsigned int max)
+{
+	struct ir_raw_handler *handler;
+	int ret = -EINVAL;
+
+	mutex_lock(&ir_raw_handler_lock);
+	list_for_each_entry(handler, &ir_raw_handler_list, list) {
+		if (handler->protocols & (1 << protocol) && handler->encode) {
+			ret = handler->encode(protocol, scancode, events, max);
+			if (ret >= 0 || ret == -ENOBUFS)
+				break;
+		}
+	}
+	mutex_unlock(&ir_raw_handler_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(ir_raw_encode_scancode);
+
 /*
  * Used to (un)register raw event clients
  */
include/media/rc-core.h +2 -0
index 19a0ad2..bdf3ff0 100644
@@ -304,6 +304,8 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
 int ir_raw_event_store_with_filter(struct rc_dev *dev,
 				struct ir_raw_event *ev);
 void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
+int ir_raw_encode_scancode(enum rc_type protocol, u32 scancode,
+			   struct ir_raw_event *events, unsigned int max);
 
 static inline void ir_raw_event_reset(struct rc_dev *dev)
 {
Signature · 1 line
2.9.3
author maintainer
#10 lore raw

PATCH v5 7/18 rc: rc-ir-raw: Add Manchester encoder (phase encoder) helper

From: Antti Seppälä <[email protected]>

Adding a simple Manchester encoder to rc-core.
Manchester coding is used by at least RC-5 and RC-6 protocols and their variants.

---
 drivers/media/rc/rc-core-priv.h | 33 ++++++++++++++++
 drivers/media/rc/rc-ir-raw.c    | 85 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 118 insertions(+)
drivers/media/rc/rc-core-priv.h +33 -0
index d8be011..74513c6 100644
@@ -156,6 +156,39 @@ static inline bool is_timing_event(struct ir_raw_event ev)
 #define TO_US(duration)			DIV_ROUND_CLOSEST((duration), 1000)
 #define TO_STR(is_pulse)		((is_pulse) ? "pulse" : "space")
 
+/* functions for IR encoders */
+
+static inline void init_ir_raw_event_duration(struct ir_raw_event *ev,
+					      unsigned int pulse,
+					      u32 duration)
+{
+	init_ir_raw_event(ev);
+	ev->duration = duration;
+	ev->pulse = pulse;
+}
+
+/**
+ * struct ir_raw_timings_manchester - Manchester coding timings
+ * @leader:		duration of leader pulse (if any) 0 if continuing
+ *			existing signal (see @pulse_space_start)
+ * @pulse_space_start:	1 for starting with pulse (0 for starting with space)
+ * @clock:		duration of each pulse/space in ns
+ * @invert:		if set clock logic is inverted
+ *			(0 = space + pulse, 1 = pulse + space)
+ * @trailer_space:	duration of trailer space in ns
+ */
+struct ir_raw_timings_manchester {
+	unsigned int leader;
+	unsigned int pulse_space_start:1;
+	unsigned int clock;
+	unsigned int invert:1;
+	unsigned int trailer_space;
+};
+
+int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
+			  const struct ir_raw_timings_manchester *timings,
+			  unsigned int n, unsigned int data);
+
 /*
  * Routines from rc-raw.c to be used internally and by decoders
  */
drivers/media/rc/rc-ir-raw.c +85 -0

91 lines not on this page · raw message

Signature · 1 line
2.9.3
author maintainer
#11 lore raw

PATCH v5 8/18 rc: rc-ir-raw: Add pulse-distance modulation helper

In reply to Sean Young

From: James Hogan <[email protected]>

Add IR encoding helper for pulse-distance modulation as used by the NEC protocol.

Cc Mauro Carvalho Chehab <[email protected]>
Cc Antti Seppälä <[email protected]>
Cc David Härdeman <[email protected]>
---
 drivers/media/rc/rc-core-priv.h | 52 ++++++++++++++++++++++++++++++++++++
 drivers/media/rc/rc-ir-raw.c    | 59 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+)
drivers/media/rc/rc-core-priv.h +52 -0
index 74513c6..630f33c 100644
@@ -189,6 +189,58 @@ int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
 			  const struct ir_raw_timings_manchester *timings,
 			  unsigned int n, unsigned int data);
 
+/**
+ * ir_raw_gen_pulse_space() - generate pulse and space raw events.
+ * @ev:			Pointer to pointer to next free raw event.
+ *			Will be incremented for each raw event written.
+ * @max:		Pointer to number of raw events available in buffer.
+ *			Will be decremented for each raw event written.
+ * @pulse_width:	Width of pulse in ns.
+ * @space_width:	Width of space in ns.
+ *
+ * Returns:	0 on success.
+ *		-ENOBUFS if there isn't enough buffer space to write both raw
+ *		events. In this case @max events will have been written.
+ */
+static inline int ir_raw_gen_pulse_space(struct ir_raw_event **ev,
+					 unsigned int *max,
+					 unsigned int pulse_width,
+					 unsigned int space_width)
+{
+	if (!*max)
+		return -ENOBUFS;
+	init_ir_raw_event_duration((*ev)++, 1, pulse_width);
+	if (!--*max)
+		return -ENOBUFS;
+	init_ir_raw_event_duration((*ev)++, 0, space_width);
+	--*max;
+	return 0;
+}
+
+/**
+ * struct ir_raw_timings_pd - pulse-distance modulation timings
+ * @header_pulse:	duration of header pulse in ns (0 for none)
+ * @header_space:	duration of header space in ns
+ * @bit_pulse:		duration of bit pulse in ns
+ * @bit_space:		duration of bit space (for logic 0 and 1) in ns
+ * @trailer_pulse:	duration of trailer pulse in ns
+ * @trailer_space:	duration of trailer space in ns
+ * @msb_first:		1 if most significant bit is sent first
+ */
+struct ir_raw_timings_pd {
+	unsigned int header_pulse;
+	unsigned int header_space;
+	unsigned int bit_pulse;
+	unsigned int bit_space[2];
+	unsigned int trailer_pulse;
+	unsigned int trailer_space;
+	unsigned int msb_first:1;
+};
+
+int ir_raw_gen_pd(struct ir_raw_event **ev, unsigned int max,
+		  const struct ir_raw_timings_pd *timings,
+		  unsigned int n, u64 data);
+
 /*
  * Routines from rc-raw.c to be used internally and by decoders
  */
drivers/media/rc/rc-ir-raw.c +59 -0

65 lines not on this page · raw message

Signature · 1 line
2.9.3
author maintainer
#12 lore raw

PATCH v5 9/18 rc: ir-rc5-decoder: Add encode capability

In reply to Sean Young

From: James Hogan <[email protected]>

Add the capability to encode RC-5, RC-5X and RC-5-SZ scancodes as raw events.

The Manchester modulation helper is used, and for RC-5X it is used twice with two sets of timings, the first with a short trailer space for the space in the middle, and the second with no leader so that it can continue the space.

The encoding in RC-5-SZ first inserts a pulse and then simply utilizes the generic Manchester encoder available in rc-core.

---
 drivers/media/rc/ir-rc5-decoder.c | 97 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)
drivers/media/rc/ir-rc5-decoder.c +97 -0
index a95477c..92964bd 100644
@@ -181,9 +181,106 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	return -EINVAL;
 }
 
+static struct ir_raw_timings_manchester ir_rc5_timings = {
+	.leader			= RC5_UNIT,
+	.pulse_space_start	= 0,
+	.clock			= RC5_UNIT,
+	.trailer_space		= RC5_UNIT * 10,
+};
+
+static struct ir_raw_timings_manchester ir_rc5x_timings[2] = {
+	{
+		.leader			= RC5_UNIT,
+		.pulse_space_start	= 0,
+		.clock			= RC5_UNIT,
+		.trailer_space		= RC5X_SPACE,
+	},
+	{
+		.clock			= RC5_UNIT,
+		.trailer_space		= RC5_UNIT * 10,
+	},
+};
+
+static struct ir_raw_timings_manchester ir_rc5_sz_timings = {
+	.leader				= RC5_UNIT,
+	.pulse_space_start		= 0,
+	.clock				= RC5_UNIT,
+	.trailer_space			= RC5_UNIT * 10,
+};
+
+/**
+ * ir_rc5_encode() - Encode a scancode as a stream of raw events
+ *
+ * @protocol:	protocol variant to encode
+ * @scancode:	scancode to encode
+ * @events:	array of raw ir events to write into
+ * @max:	maximum size of @events
+ *
+ * Returns:	The number of events written.
+ *		-ENOBUFS if there isn't enough space in the array to fit the
+ *		encoding. In this case all @max events will have been written.
+ *		-EINVAL if the scancode is ambiguous or invalid.
+ */
+static int ir_rc5_encode(enum rc_type protocol, u32 scancode,
+			 struct ir_raw_event *events, unsigned int max)
+{
+	int ret;
+	struct ir_raw_event *e = events;
+	unsigned int data, xdata, command, commandx, system, pre_space_data;
+
+	/* Detect protocol and convert scancode to raw data */
+	if (protocol == RC_TYPE_RC5) {
+		/* decode scancode */
+		command  = (scancode & 0x003f) >> 0;
+		commandx = (scancode & 0x0040) >> 6;
+		system   = (scancode & 0x1f00) >> 8;
+		/* encode data */
+		data = !commandx << 12 | system << 6 | command;
+
+		/* Modulate the data */
+		ret = ir_raw_gen_manchester(&e, max, &ir_rc5_timings,
+					    RC5_NBITS, data);
+		if (ret < 0)
+			return ret;
+	} else if (protocol == RC_TYPE_RC5X) {
+		/* decode scancode */
+		xdata    = (scancode & 0x00003f) >> 0;
+		command  = (scancode & 0x003f00) >> 8;
+		commandx = !(scancode & 0x004000);
+		system   = (scancode & 0x1f0000) >> 16;
+
+		/* encode data */
+		data = commandx << 18 | system << 12 | command << 6 | xdata;
+
+		/* Modulate the data */
+		pre_space_data = data >> (RC5X_NBITS - CHECK_RC5X_NBITS);
+		ret = ir_raw_gen_manchester(&e, max, &ir_rc5x_timings[0],
+					    CHECK_RC5X_NBITS, pre_space_data);
+		if (ret < 0)
+			return ret;
+		ret = ir_raw_gen_manchester(&e, max - (e - events),
+					    &ir_rc5x_timings[1],
+					    RC5X_NBITS - CHECK_RC5X_NBITS,
+					    data);
+		if (ret < 0)
+			return ret;
+	} else if (protocol == RC_TYPE_RC5_SZ) {
+		/* RC5-SZ scancode is raw enough for Manchester as it is */
+		ret = ir_raw_gen_manchester(&e, max, &ir_rc5_sz_timings,
+					    RC5_SZ_NBITS, scancode & 0x2fff);
+		if (ret < 0)
+			return ret;
+	} else {
+		return -EINVAL;
+	}
+
+	return e - events;
+}
+
 static struct ir_raw_handler rc5_handler = {
 	.protocols	= RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ,
 	.decode		= ir_rc5_decode,
+	.encode		= ir_rc5_encode,
 };
 
 static int __init ir_rc5_decode_init(void)
Signature · 1 line
2.9.3
author maintainer
#13 lore raw

PATCH v5 10/18 rc: ir-rc6-decoder: Add encode capability

In reply to Sean Young

From: Antti Seppälä <[email protected]>

Add the capability to encode RC-6 and RC-6A scancodes as raw events.

The Manchester modulation helper is used several times with various timings so that RC-6 header preamble, the header, header trailing bit and the data itself can be modulated correctly.

---
 drivers/media/rc/ir-rc6-decoder.c | 117 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)
drivers/media/rc/ir-rc6-decoder.c +117 -0
index 5cc54c9..29f9f9a 100644
@@ -286,11 +286,128 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	return -EINVAL;
 }
 
+static struct ir_raw_timings_manchester ir_rc6_timings[4] = {
+	{
+		.leader			= RC6_PREFIX_PULSE,
+		.pulse_space_start	= 0,
+		.clock			= RC6_UNIT,
+		.invert			= 1,
+		.trailer_space		= RC6_PREFIX_SPACE,
+	},
+	{
+		.clock			= RC6_UNIT,
+		.invert			= 1,
+	},
+	{
+		.clock			= RC6_UNIT * 2,
+		.invert			= 1,
+	},
+	{
+		.clock			= RC6_UNIT,
+		.invert			= 1,
+		.trailer_space		= RC6_SUFFIX_SPACE,
+	},
+};
+
+/**
+ * ir_rc6_encode() - Encode a scancode as a stream of raw events
+ *
+ * @protocol:	protocol to encode
+ * @scancode:	scancode to encode
+ * @events:	array of raw ir events to write into
+ * @max:	maximum size of @events
+ *
+ * Returns:	The number of events written.
+ *		-ENOBUFS if there isn't enough space in the array to fit the
+ *		encoding. In this case all @max events will have been written.
+ *		-EINVAL if the scancode is ambiguous or invalid.
+ */
+static int ir_rc6_encode(enum rc_type protocol, u32 scancode,
+			 struct ir_raw_event *events, unsigned int max)
+{
+	int ret;
+	struct ir_raw_event *e = events;
+
+	if (protocol == RC_TYPE_RC6_0) {
+		/* Modulate the preamble */
+		ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0);
+		if (ret < 0)
+			return ret;
+
+		/* Modulate the header (Start Bit & Mode-0) */
+		ret = ir_raw_gen_manchester(&e, max - (e - events),
+					    &ir_rc6_timings[1],
+					    RC6_HEADER_NBITS, (1 << 3));
+		if (ret < 0)
+			return ret;
+
+		/* Modulate Trailer Bit */
+		ret = ir_raw_gen_manchester(&e, max - (e - events),
+					    &ir_rc6_timings[2], 1, 0);
+		if (ret < 0)
+			return ret;
+
+		/* Modulate rest of the data */
+		ret = ir_raw_gen_manchester(&e, max - (e - events),
+					    &ir_rc6_timings[3], RC6_0_NBITS,
+					    scancode);
+		if (ret < 0)
+			return ret;
+
+	} else {
+		int bits;
+
+		switch (protocol) {
+		case RC_TYPE_RC6_MCE:
+		case RC_TYPE_RC6_6A_32:
+			bits = 32;
+			break;
+		case RC_TYPE_RC6_6A_24:
+			bits = 24;
+			break;
+		case RC_TYPE_RC6_6A_20:
+			bits = 20;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		/* Modulate the preamble */
+		ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0);
+		if (ret < 0)
+			return ret;
+
+		/* Modulate the header (Start Bit & Header-version 6 */
+		ret = ir_raw_gen_manchester(&e, max - (e - events),
+					    &ir_rc6_timings[1],
+					    RC6_HEADER_NBITS, (1 << 3 | 6));
+		if (ret < 0)
+			return ret;
+
+		/* Modulate Trailer Bit */
+		ret = ir_raw_gen_manchester(&e, max - (e - events),
+					    &ir_rc6_timings[2], 1, 0);
+		if (ret < 0)
+			return ret;
+
+		/* Modulate rest of the data */
+		ret = ir_raw_gen_manchester(&e, max - (e - events),
+					    &ir_rc6_timings[3],
+					    bits,
+					    scancode);
+		if (ret < 0)
+			return ret;
+	}
+
+	return e - events;
+}
+
 static struct ir_raw_handler rc6_handler = {
 	.protocols	= RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 |
 			  RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 |
 			  RC_BIT_RC6_MCE,
 	.decode		= ir_rc6_decode,
+	.encode		= ir_rc6_encode,
 };
 
 static int __init ir_rc6_decode_init(void)
Signature · 1 line
2.9.3
author maintainer
#14 lore raw

PATCH v5 11/18 rc: ir-nec-decoder: Add encode capability

In reply to Sean Young

From: James Hogan <[email protected]>

Add the capability to encode NEC scancodes as raw events. The scancode_to_raw is pretty much taken from the img-ir NEC filter() callback, and modulation uses the pulse distance helper added in a previous commit.

Cc Mauro Carvalho Chehab <[email protected]>
Cc Antti Seppälä <[email protected]>
Cc David Härdeman <[email protected]>
---
 drivers/media/rc/ir-nec-decoder.c | 81 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)
drivers/media/rc/ir-nec-decoder.c +81 -0
index 2a9d155..22aab8a 100644
@@ -201,9 +201,90 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	return -EINVAL;
 }
 
+/**
+ * ir_nec_scancode_to_raw() - encode an NEC scancode ready for modulation.
+ * @protocol:	specific protocol to use
+ * @scancode:	a single NEC scancode.
+ * @raw:	raw data to be modulated.
+ */
+static u32 ir_nec_scancode_to_raw(enum rc_type protocol, u32 scancode)
+{
+	unsigned int addr, addr_inv, data, data_inv;
+
+	data = scancode & 0xff;
+
+	if (protocol == RC_TYPE_NEC32) {
+		/* 32-bit NEC (used by Apple and TiVo remotes) */
+		/* scan encoding: aaAAddDD */
+		addr_inv   = (scancode >> 24) & 0xff;
+		addr       = (scancode >> 16) & 0xff;
+		data_inv   = (scancode >>  8) & 0xff;
+	} else if (protocol == RC_TYPE_NECX) {
+		/* Extended NEC */
+		/* scan encoding AAaaDD */
+		addr       = (scancode >> 16) & 0xff;
+		addr_inv   = (scancode >>  8) & 0xff;
+		data_inv   = data ^ 0xff;
+	} else {
+		/* Normal NEC */
+		/* scan encoding: AADD */
+		addr       = (scancode >>  8) & 0xff;
+		addr_inv   = addr ^ 0xff;
+		data_inv   = data ^ 0xff;
+	}
+
+	/* raw encoding: ddDDaaAA */
+	return data_inv << 24 |
+	       data     << 16 |
+	       addr_inv <<  8 |
+	       addr;
+}
+
+static struct ir_raw_timings_pd ir_nec_timings = {
+	.header_pulse	= NEC_HEADER_PULSE,
+	.header_space	= NEC_HEADER_SPACE,
+	.bit_pulse	= NEC_BIT_PULSE,
+	.bit_space[0]	= NEC_BIT_0_SPACE,
+	.bit_space[1]	= NEC_BIT_1_SPACE,
+	.trailer_pulse	= NEC_TRAILER_PULSE,
+	.trailer_space	= NEC_TRAILER_SPACE,
+	.msb_first	= 0,
+};
+
+/**
+ * ir_nec_encode() - Encode a scancode as a stream of raw events
+ *
+ * @protocol:	protocol to encode
+ * @scancode:	scancode to encode
+ * @events:	array of raw ir events to write into
+ * @max:	maximum size of @events
+ *
+ * Returns:	The number of events written.
+ *		-ENOBUFS if there isn't enough space in the array to fit the
+ *		encoding. In this case all @max events will have been written.
+ */
+static int ir_nec_encode(enum rc_type protocol, u32 scancode,
+			 struct ir_raw_event *events, unsigned int max)
+{
+	struct ir_raw_event *e = events;
+	int ret;
+	u32 raw;
+
+	/* Convert a NEC scancode to raw NEC data */
+	raw = ir_nec_scancode_to_raw(protocol, scancode);
+
+	/* Modulate the raw data using a pulse distance modulation */
+	ret = ir_raw_gen_pd(&e, max, &ir_nec_timings, NEC_NBITS, raw);
+	if (ret < 0)
+		return ret;
+
+	return e - events;
+}
+
 static struct ir_raw_handler nec_handler = {
 	.protocols	= RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32,
 	.decode		= ir_nec_decode,
+	.encode		= ir_nec_encode,
 };
 
 static int __init ir_nec_decode_init(void)
Signature · 1 line
2.9.3
author maintainer
#15 lore raw

PATCH v5 12/18 rc: ir-jvc-decoder: Add encode capability

In reply to Sean Young

Add the capability to encode JVC scancodes as raw events.

---
 drivers/media/rc/ir-jvc-decoder.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)
drivers/media/rc/ir-jvc-decoder.c +39 -0
index 182402f..584cd43 100644
@@ -170,9 +170,48 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	return -EINVAL;
 }
 
+static struct ir_raw_timings_pd ir_jvc_timings = {
+	.header_pulse  = JVC_HEADER_PULSE,
+	.header_space  = JVC_HEADER_SPACE,
+	.bit_pulse     = JVC_BIT_PULSE,
+	.bit_space[0]  = JVC_BIT_0_SPACE,
+	.bit_space[1]  = JVC_BIT_1_SPACE,
+	.trailer_pulse = JVC_TRAILER_PULSE,
+	.trailer_space = JVC_TRAILER_SPACE,
+	.msb_first     = 1,
+};
+
+/**
+ * ir_jvc_encode() - Encode a scancode as a stream of raw events
+ *
+ * @protocol:	protocol to encode
+ * @scancode:	scancode to encode
+ * @events:	array of raw ir events to write into
+ * @max:	maximum size of @events
+ *
+ * Returns:	The number of events written.
+ *		-ENOBUFS if there isn't enough space in the array to fit the
+ *		encoding. In this case all @max events will have been written.
+ */
+static int ir_jvc_encode(enum rc_type protocol, u32 scancode,
+			 struct ir_raw_event *events, unsigned int max)
+{
+	struct ir_raw_event *e = events;
+	int ret;
+	u32 raw = (bitrev8((scancode >> 8) & 0xff) << 8) |
+		  (bitrev8((scancode >> 0) & 0xff) << 0);
+
+	ret = ir_raw_gen_pd(&e, max, &ir_jvc_timings, JVC_NBITS, raw);
+	if (ret < 0)
+		return ret;
+
+	return e - events;
+}
+
 static struct ir_raw_handler jvc_handler = {
 	.protocols	= RC_BIT_JVC,
 	.decode		= ir_jvc_decode,
+	.encode		= ir_jvc_encode,
 };
 
 static int __init ir_jvc_decode_init(void)
Signature · 1 line
2.9.3
author maintainer
#16 lore raw

PATCH v5 13/18 rc: ir-sanyo-decoder: Add encode capability

In reply to Sean Young

Add the capability to encode Sanyo scancodes as raw events.

---
 drivers/media/rc/ir-sanyo-decoder.c | 43 +++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)
drivers/media/rc/ir-sanyo-decoder.c +43 -0
index b07d9ca..190dd91 100644
@@ -176,9 +176,52 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	return -EINVAL;
 }
 
+static struct ir_raw_timings_pd ir_sanyo_timings = {
+	.header_pulse  = SANYO_HEADER_PULSE,
+	.header_space  = SANYO_HEADER_SPACE,
+	.bit_pulse     = SANYO_BIT_PULSE,
+	.bit_space[0]  = SANYO_BIT_0_SPACE,
+	.bit_space[1]  = SANYO_BIT_1_SPACE,
+	.trailer_pulse = SANYO_TRAILER_PULSE,
+	.trailer_space = SANYO_TRAILER_SPACE,
+	.msb_first     = 1,
+};
+
+/**
+ * ir_sanyo_encode() - Encode a scancode as a stream of raw events
+ *
+ * @protocol:	protocol to encode
+ * @scancode:	scancode to encode
+ * @events:	array of raw ir events to write into
+ * @max:	maximum size of @events
+ *
+ * Returns:	The number of events written.
+ *		-ENOBUFS if there isn't enough space in the array to fit the
+ *		encoding. In this case all @max events will have been written.
+ */
+static int ir_sanyo_encode(enum rc_type protocol, u32 scancode,
+			   struct ir_raw_event *events, unsigned int max)
+{
+	struct ir_raw_event *e = events;
+	int ret;
+	u64 raw;
+
+	raw = ((u64)(bitrev16(scancode >> 8) & 0xfff8) << (8 + 8 + 13 - 3)) |
+	      ((u64)(bitrev16(~scancode >> 8) & 0xfff8) << (8 + 8 +  0 - 3)) |
+	      ((bitrev8(scancode) & 0xff) << 8) |
+	      (bitrev8(~scancode) & 0xff);
+
+	ret = ir_raw_gen_pd(&e, max, &ir_sanyo_timings, SANYO_NBITS, raw);
+	if (ret < 0)
+		return ret;
+
+	return e - events;
+}
+
 static struct ir_raw_handler sanyo_handler = {
 	.protocols	= RC_BIT_SANYO,
 	.decode		= ir_sanyo_decode,
+	.encode		= ir_sanyo_encode,
 };
 
 static int __init ir_sanyo_decode_init(void)
Signature · 1 line
2.9.3
author maintainer
#17 lore raw

PATCH v5 14/18 rc: ir-sharp-decoder: Add encode capability

In reply to Sean Young

Add the capability to encode Sharp scancodes as raw events.

---
 drivers/media/rc/ir-sharp-decoder.c | 50 +++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)
drivers/media/rc/ir-sharp-decoder.c +50 -0
index 317677f..d37af7c 100644
@@ -173,9 +173,59 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	return -EINVAL;
 }
 
+static struct ir_raw_timings_pd ir_sharp_timings = {
+	.header_pulse  = 0,
+	.header_space  = 0,
+	.bit_pulse     = SHARP_BIT_PULSE,
+	.bit_space[0]  = SHARP_BIT_0_PERIOD,
+	.bit_space[1]  = SHARP_BIT_1_PERIOD,
+	.trailer_pulse = SHARP_BIT_PULSE,
+	.trailer_space = SHARP_ECHO_SPACE,
+	.msb_first     = 1,
+};
+
+/**
+ * ir_sharp_encode() - Encode a scancode as a stream of raw events
+ *
+ * @protocol:	protocol to encode
+ * @scancode:	scancode to encode
+ * @events:	array of raw ir events to write into
+ * @max:	maximum size of @events
+ *
+ * Returns:	The number of events written.
+ *		-ENOBUFS if there isn't enough space in the array to fit the
+ *		encoding. In this case all @max events will have been written.
+ */
+static int ir_sharp_encode(enum rc_type protocol, u32 scancode,
+			   struct ir_raw_event *events, unsigned int max)
+{
+	struct ir_raw_event *e = events;
+	int ret;
+	u32 raw;
+
+	raw = (((bitrev8(scancode >> 8) >> 3) << 8) & 0x1f00) |
+		bitrev8(scancode);
+	ret = ir_raw_gen_pd(&e, max, &ir_sharp_timings, SHARP_NBITS,
+			    (raw << 2) | 2);
+	if (ret < 0)
+		return ret;
+
+	max -= ret;
+
+	raw = (((bitrev8(scancode >> 8) >> 3) << 8) & 0x1f00) |
+		bitrev8(~scancode);
+	ret = ir_raw_gen_pd(&e, max, &ir_sharp_timings, SHARP_NBITS,
+			    (raw << 2) | 1);
+	if (ret < 0)
+		return ret;
+
+	return e - events;
+}
+
 static struct ir_raw_handler sharp_handler = {
 	.protocols	= RC_BIT_SHARP,
 	.decode		= ir_sharp_decode,
+	.encode		= ir_sharp_encode,
 };
 
 static int __init ir_sharp_decode_init(void)
Signature · 1 line
2.9.3
author maintainer
#18 lore raw

PATCH v5 15/18 rc: ir-sony-decoder: Add encode capability

In reply to Sean Young

Add the capability to encode Sony scancodes as raw events. Sony uses space distance rather than pulse distance.

---
 drivers/media/rc/ir-sony-decoder.c | 48 ++++++++++++++++++++++++++++
 drivers/media/rc/rc-core-priv.h    | 20 ++++++++++++
 drivers/media/rc/rc-ir-raw.c       | 64 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 132 insertions(+)
drivers/media/rc/ir-sony-decoder.c +48 -0
index baa972c..a1962ae 100644
@@ -169,9 +169,57 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	return 0;
 }
 
+static struct ir_raw_timings_sd ir_sony_timings = {
+	.header_pulse  = SONY_HEADER_PULSE,
+	.bit_space     = SONY_BIT_SPACE,
+	.bit_pulse[0]  = SONY_BIT_0_PULSE,
+	.bit_pulse[1]  = SONY_BIT_1_PULSE,
+	.trailer_space = SONY_TRAILER_SPACE + SONY_BIT_SPACE,
+	.msb_first     = 0,
+};
+
+/**
+ * ir_sony_encode() - Encode a scancode as a stream of raw events
+ *
+ * @protocol:	protocol to encode
+ * @scancode:	scancode to encode
+ * @events:	array of raw ir events to write into
+ * @max:	maximum size of @events
+ *
+ * Returns:	The number of events written.
+ *		-ENOBUFS if there isn't enough space in the array to fit the
+ *		encoding. In this case all @max events will have been written.
+ */
+static int ir_sony_encode(enum rc_type protocol, u32 scancode,
+			  struct ir_raw_event *events, unsigned int max)
+{
+	struct ir_raw_event *e = events;
+	u32 raw, len;
+	int ret;
+
+	if (protocol == RC_TYPE_SONY12) {
+		raw = (scancode & 0x7f) | ((scancode & 0x1f0000) >> 9);
+		len = 12;
+	} else if (protocol == RC_TYPE_SONY15) {
+		raw = (scancode & 0x7f) | ((scancode & 0xff0000) >> 9);
+		len = 15;
+	} else {
+		raw = (scancode & 0x7f) | ((scancode & 0x1f0000) >> 9) |
+		       ((scancode & 0xff00) << 4);
+		len = 20;
+	}
+
+	ret = ir_raw_gen_sd(&e, max, &ir_sony_timings, len, raw);
+	if (ret < 0)
+		return ret;
+
+	return e - events;
+}
+
 static struct ir_raw_handler sony_handler = {
 	.protocols	= RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20,
 	.decode		= ir_sony_decode,
+	.encode		= ir_sony_encode,
 };
 
 static int __init ir_sony_decode_init(void)
drivers/media/rc/rc-core-priv.h +20 -0
index 630f33c..bbe2984 100644
@@ -241,6 +241,26 @@ int ir_raw_gen_pd(struct ir_raw_event **ev, unsigned int max,
 		  const struct ir_raw_timings_pd *timings,
 		  unsigned int n, u64 data);
 
+/**
+ * struct ir_raw_timings_sd - space-distance modulation timings
+ * @header_pulse:	duration of header pulse in ns (0 for none)
+ * @bit_space:		duration of bit space in ns
+ * @bit_pulse:		duration of bit pulse (for logic 0 and 1) in ns
+ * @trailer_space:	duration of trailer space in ns
+ * @msb_first:		1 if most significant bit is sent first
+ */
+struct ir_raw_timings_sd {
+	unsigned int header_pulse;
+	unsigned int bit_space;
+	unsigned int bit_pulse[2];
+	unsigned int trailer_space;
+	unsigned int msb_first:1;
+};
+
+int ir_raw_gen_sd(struct ir_raw_event **ev, unsigned int max,
+		  const struct ir_raw_timings_sd *timings,
+		  unsigned int n, u64 data);
+
 /*
  * Routines from rc-raw.c to be used internally and by decoders
  */
drivers/media/rc/rc-ir-raw.c +64 -0

70 lines not on this page · raw message

Signature · 1 line
2.9.3
author maintainer
#19 lore raw

PATCH v5 16/18 rc: rc-core: Add support for encode_wakeup drivers

In reply to Sean Young

From: James Hogan <[email protected]>

Add support in rc-core for drivers which implement the wakeup scancode filter by encoding the scancode using the raw IR encoders. This is by way of rc_dev::encode_wakeup which should be set to true and rc_dev::allowed_wakeup_protocols should be set to the raw IR encoders.

We also do not permit the mask to be set as we cannot generate IR which would match that.

---
 drivers/media/rc/rc-main.c | 26 +++++++++++++++++++++-----
 include/media/rc-core.h    |  3 +++
 include/media/rc-map.h     |  9 +++++++++
 3 files changed, 33 insertions(+), 5 deletions(-)
drivers/media/rc/rc-main.c +21 -5
index 33969ab..10eed3c 100644
@@ -727,11 +727,11 @@ EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
 /**
  * rc_validate_filter() - checks that the scancode and mask are valid and
  *			  provides sensible defaults
- * @protocol:	the protocol for the filter
+ * @dev:	the struct rc_dev descriptor of the device
  * @filter:	the scancode and mask
  * @return:	0 or -EINVAL if the filter is not valid
  */
-static int rc_validate_filter(enum rc_type protocol,
+static int rc_validate_filter(struct rc_dev *dev,
 			      struct rc_scancode_filter *filter)
 {
 	static u32 masks[] = {
@@ -754,6 +754,7 @@ static int rc_validate_filter(enum rc_type protocol,
 		[RC_TYPE_SHARP] = 0x1fff,
 	};
 	u32 s = filter->data;
+	enum rc_type protocol = dev->wakeup_protocol;
 
 	switch (protocol) {
 	case RC_TYPE_NECX:
@@ -779,6 +780,13 @@ static int rc_validate_filter(enum rc_type protocol,
 	filter->data &= masks[protocol];
 	filter->mask &= masks[protocol];
 
+	/*
+	 * If we have to raw encode the IR for wakeup, we cannot have a mask
+	 */
+	if (dev->encode_wakeup &&
+	    filter->mask != 0 && filter->mask != masks[protocol])
+		return -EINVAL;
+
 	return 0;
 }
 
@@ -1044,7 +1052,6 @@ static int parse_protocol_change(u64 *protocols, const char *buf)
 }
 
 static void ir_raw_load_modules(u64 *protocols)
-
 {
 	u64 available;
 	int i, ret;
@@ -1292,8 +1299,7 @@ static ssize_t store_filter(struct device *device,
 		 * and the filter is valid for that protocol
 		 */
 		if (dev->wakeup_protocol != RC_TYPE_UNKNOWN)
-			ret = rc_validate_filter(dev->wakeup_protocol,
-						 &new_filter);
+			ret = rc_validate_filter(dev, &new_filter);
 		else
 			ret = -EINVAL;
 
@@ -1461,6 +1467,16 @@ static ssize_t store_wakeup_protocols(struct device *device,
 			rc = -EINVAL;
 			goto out;
 		}
+
+		if (dev->encode_wakeup) {
+			u64 mask = 1 << protocol;
+
+			ir_raw_load_modules(&mask);
+			if (!mask) {
+				rc = -EINVAL;
+				goto out;
+			}
+		}
 	}
 
 	if (dev->wakeup_protocol != protocol) {
include/media/rc-core.h +3 -0
index bdf3ff0..9760944 100644
@@ -83,6 +83,8 @@ enum rc_filter_type {
  * @input_dev: the input child device used to communicate events to userspace
  * @driver_type: specifies if protocol decoding is done in hardware or software
  * @idle: used to keep track of RX state
+ * @encode_wakeup: wakeup filtering uses IR encode API, therefore the allowed
+ *	wakeup protocols is the set of all raw encoders
  * @allowed_protocols: bitmask with the supported RC_BIT_* protocols
  * @enabled_protocols: bitmask with the enabled RC_BIT_* protocols
  * @allowed_wakeup_protocols: bitmask with the supported RC_BIT_* wakeup protocols
@@ -145,6 +147,7 @@ struct rc_dev {
 	struct input_dev		*input_dev;
 	enum rc_driver_type		driver_type;
 	bool				idle;
+	bool				encode_wakeup;
 	u64				allowed_protocols;
 	u64				enabled_protocols;
 	u64				allowed_wakeup_protocols;
include/media/rc-map.h +9 -0
index b2af45d..a1289a4 100644
@@ -106,6 +106,15 @@ enum rc_type {
 			 RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | RC_BIT_SHARP | \
 			 RC_BIT_XMP)
 
+#define RC_BIT_ALL_IR_ENCODER \
+			(RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \
+			 RC_BIT_JVC | \
+			 RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \
+			 RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 | \
+			 RC_BIT_SANYO | \
+			 RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
+			 RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | \
+			 RC_BIT_SHARP)
 
 #define RC_SCANCODE_UNKNOWN(x)			(x)
 #define RC_SCANCODE_OTHER(x)			(x)
Signature · 1 line
2.9.3
author maintainer
#20 lore raw

PATCH v5 17/18 rc: rc-loopback: Add loopback of filter scancodes

In reply to Sean Young

From: James Hogan <[email protected]>

Add the s_wakeup_filter callback to the rc-loopback driver, which instead of setting the filter just feeds the scancode back through the input device so that it can be verified.

---
 drivers/media/rc/rc-loopback.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)
drivers/media/rc/rc-loopback.c +39 -0
index 4bc3f01..bd31fb1 100644
@@ -26,6 +26,7 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/slab.h>
 #include <media/rc-core.h>
 
 #define DRIVER_NAME	"rc-loopback"
@@ -176,6 +177,41 @@ static int loop_set_carrier_report(struct rc_dev *dev, int enable)
 	return 0;
 }
 
+static int loop_set_wakeup_filter(struct rc_dev *dev,
+				  struct rc_scancode_filter *sc)
+{
+	static const unsigned int max = 512;
+	struct ir_raw_event *raw;
+	int ret;
+	int i;
+
+	/* fine to disable filter */
+	if (!sc->mask)
+		return 0;
+
+	/* encode the specified filter and loop it back */
+	raw = kmalloc_array(max, sizeof(*raw), GFP_KERNEL);
+	if (!raw)
+		return -ENOMEM;
+
+	ret = ir_raw_encode_scancode(dev->wakeup_protocol, sc->data, raw, max);
+	/* still loop back the partial raw IR even if it's incomplete */
+	if (ret == -ENOBUFS)
+		ret = max;
+	if (ret >= 0) {
+		/* do the loopback */
+		for (i = 0; i < ret; ++i)
+			ir_raw_event_store(dev, &raw[i]);
+		ir_raw_event_handle(dev);
+
+		ret = 0;
+	}
+
+	kfree(raw);
+
+	return ret;
+}
+
 static int __init loop_init(void)
 {
 	struct rc_dev *rc;
@@ -196,6 +232,8 @@ static int __init loop_init(void)
 	rc->priv		= &loopdev;
 	rc->driver_type		= RC_DRIVER_IR_RAW;
 	rc->allowed_protocols	= RC_BIT_ALL_IR_DECODER;
+	rc->allowed_wakeup_protocols = RC_BIT_ALL_IR_ENCODER;
+	rc->encode_wakeup	= true;
 	rc->timeout		= 100 * 1000 * 1000; /* 100 ms */
 	rc->min_timeout		= 1;
 	rc->max_timeout		= UINT_MAX;
@@ -209,6 +247,7 @@ static int __init loop_init(void)
 	rc->s_idle		= loop_set_idle;
 	rc->s_learning_mode	= loop_set_learning_mode;
 	rc->s_carrier_report	= loop_set_carrier_report;
+	rc->s_wakeup_filter	= loop_set_wakeup_filter;
 
 	loopdev.txmask		= RXMASK_REGULAR;
 	loopdev.txcarrier	= 36000;
Signature · 1 line
2.9.3
author maintainer
#21 lore raw

PATCH v5 18/18 rc: nuvoton-cir: Add support wakeup via sysfs filter callback

In reply to Sean Young

From: Antti Seppälä <[email protected]>

Nuvoton-cir utilizes the encoding capabilities of rc-core to convert scancodes from user space to pulse/space format understood by the underlying hardware.

Converted samples are then written to the wakeup fifo along with other necessary configuration to enable wake up functionality.

---
 drivers/media/rc/nuvoton-cir.c | 120 ++++++++++++++++++++++++++++++++---------
 1 file changed, 96 insertions(+), 24 deletions(-)
drivers/media/rc/nuvoton-cir.c +96 -24
index 9e04f41..2e2d981 100644
@@ -176,6 +176,41 @@ static void nvt_set_ioaddr(struct nvt_dev *nvt, unsigned long *ioaddr)
 	}
 }
 
+static void nvt_write_wakeup_codes(struct rc_dev *dev,
+				   const u8 *wbuf, int count)
+{
+	u8 tolerance, config;
+	struct nvt_dev *nvt = dev->priv;
+	int i;
+
+	/* hardcode the tolerance to 10% */
+	tolerance = DIV_ROUND_UP(count, 10);
+
+	spin_lock(&nvt->lock);
+
+	nvt_clear_cir_wake_fifo(nvt);
+	nvt_cir_wake_reg_write(nvt, count, CIR_WAKE_FIFO_CMP_DEEP);
+	nvt_cir_wake_reg_write(nvt, tolerance, CIR_WAKE_FIFO_CMP_TOL);
+
+	config = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON);
+
+	/* enable writes to wake fifo */
+	nvt_cir_wake_reg_write(nvt, config | CIR_WAKE_IRCON_MODE1,
+			       CIR_WAKE_IRCON);
+
+	if (count)
+		pr_info("Wake samples (%d) =", count);
+	else
+		pr_info("Wake sample fifo cleared");
+
+	for (i = 0; i < count; i++)
+		nvt_cir_wake_reg_write(nvt, wbuf[i], CIR_WAKE_WR_FIFO_DATA);
+
+	nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON);
+
+	spin_unlock(&nvt->lock);
+}
+
 static ssize_t wakeup_data_show(struct device *dev,
 				struct device_attribute *attr,
 				char *buf)
@@ -214,9 +249,7 @@ static ssize_t wakeup_data_store(struct device *dev,
 				 const char *buf, size_t len)
 {
 	struct rc_dev *rc_dev = to_rc_dev(dev);
-	struct nvt_dev *nvt = rc_dev->priv;
-	unsigned long flags;
-	u8 tolerance, config, wake_buf[WAKEUP_MAX_SIZE];
+	u8 wake_buf[WAKEUP_MAX_SIZE];
 	char **argv;
 	int i, count;
 	unsigned int val;
@@ -245,27 +278,7 @@ static ssize_t wakeup_data_store(struct device *dev,
 			wake_buf[i] |= BUF_PULSE_BIT;
 	}
 
-	/* hardcode the tolerance to 10% */
-	tolerance = DIV_ROUND_UP(count, 10);
-
-	spin_lock_irqsave(&nvt->lock, flags);
-
-	nvt_clear_cir_wake_fifo(nvt);
-	nvt_cir_wake_reg_write(nvt, count, CIR_WAKE_FIFO_CMP_DEEP);
-	nvt_cir_wake_reg_write(nvt, tolerance, CIR_WAKE_FIFO_CMP_TOL);
-
-	config = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON);
-
-	/* enable writes to wake fifo */
-	nvt_cir_wake_reg_write(nvt, config | CIR_WAKE_IRCON_MODE1,
-			       CIR_WAKE_IRCON);
-
-	for (i = 0; i < count; i++)
-		nvt_cir_wake_reg_write(nvt, wake_buf[i], CIR_WAKE_WR_FIFO_DATA);
-
-	nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON);
-
-	spin_unlock_irqrestore(&nvt->lock, flags);
+	nvt_write_wakeup_codes(rc_dev, wake_buf, count);
 
 	ret = len;
 out:
@@ -662,6 +675,62 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
 	return 0;
 }
 
+static int nvt_ir_raw_set_wakeup_filter(struct rc_dev *dev,
+					struct rc_scancode_filter *sc_filter)
+{
+	u8 buf_val;
+	int i, ret, count;
+	unsigned int val;
+	struct ir_raw_event *raw;
+	u8 wake_buf[WAKEUP_MAX_SIZE];
+	bool complete;
+
+	/* Require mask to be set */
+	if (!sc_filter->mask)
+		return 0;
+
+	raw = kmalloc_array(WAKEUP_MAX_SIZE, sizeof(*raw), GFP_KERNEL);
+	if (!raw)
+		return -ENOMEM;
+
+	ret = ir_raw_encode_scancode(dev->wakeup_protocol, sc_filter->data,
+				     raw, WAKEUP_MAX_SIZE);
+	complete = (ret != -ENOBUFS);
+	if (!complete)
+		ret = WAKEUP_MAX_SIZE;
+	else if (ret < 0)
+		goto out_raw;
+
+	/* Inspect the ir samples */
+	for (i = 0, count = 0; i < ret && count < WAKEUP_MAX_SIZE; ++i) {
+		/* NS to US */
+		val = DIV_ROUND_UP(raw[i].duration, 1000L) / SAMPLE_PERIOD;
+
+		/* Split too large values into several smaller ones */
+		while (val > 0 && count < WAKEUP_MAX_SIZE) {
+			/* Skip last value for better comparison tolerance */
+			if (complete && i == ret - 1 && val < BUF_LEN_MASK)
+				break;
+
+			/* Clamp values to BUF_LEN_MASK at most */
+			buf_val = (val > BUF_LEN_MASK) ? BUF_LEN_MASK : val;
+
+			wake_buf[count] = buf_val;
+			val -= buf_val;
+			if ((raw[i]).pulse)
+				wake_buf[count] |= BUF_PULSE_BIT;
+			count++;
+		}
+	}
+
+	nvt_write_wakeup_codes(dev, wake_buf, count);
+	ret = 0;
+out_raw:
+	kfree(raw);
+
+	return ret;
+}
+
 /*
  * nvt_tx_ir
  *
@@ -1063,10 +1132,13 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 	rdev->priv = nvt;
 	rdev->driver_type = RC_DRIVER_IR_RAW;
 	rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
+	rdev->allowed_wakeup_protocols = RC_BIT_ALL_IR_ENCODER;
+	rdev->encode_wakeup = true;
 	rdev->open = nvt_open;
 	rdev->close = nvt_close;
 	rdev->tx_ir = nvt_tx_ir;
 	rdev->s_tx_carrier = nvt_set_tx_carrier;
+	rdev->s_wakeup_filter = nvt_ir_raw_set_wakeup_filter;
 	rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
 	rdev->input_phys = "nuvoton/cir0";
 	rdev->input_id.bustype = BUS_HOST;
Signature · 1 line
2.9.3