* [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup
@ 2016-12-06 10:19 Sean Young
2016-12-06 10:19 ` [PATCH v4 01/13] [media] rc: change wakeup_protocols to list all protocol variants Sean Young
` (13 more replies)
0 siblings, 14 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media
This patch series resurrects an earlier series with a new approach.
I've modified wakeup_protocols so that only one protocol variant can
be selected, and the ir_raw_encode_scancode() now takes an enum rc_type
rather than a protocol bitmask.
These changes make it possible for the winbond-cir to use the wakeup
filter, and I've tested this.
For the nuvoton I have merged the v3 code forward and otherwise it is
largely untouched. I do not have the hardware to test this, although
v3 reportedly worked.
It would be relatively easy to add encoders for the remaining protocols
which can be done in follow-on work.
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 (4):
[media] rc: change wakeup_protocols to list all protocol variants
[media] rc: Add scancode validation
[media] winbond-cir: use sysfs wakeup filter
[media] rc: raw IR drivers cannot handle cec, unknown or other
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 | 2 -
drivers/media/rc/ir-hix5hd2.c | 2 +-
drivers/media/rc/ir-nec-decoder.c | 94 +++++++
drivers/media/rc/ir-rc5-decoder.c | 116 +++++++++
drivers/media/rc/ir-rc6-decoder.c | 120 +++++++++
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 | 128 +++++++++-
drivers/media/rc/nuvoton-cir.h | 1 +
drivers/media/rc/rc-core-priv.h | 89 +++++++
drivers/media/rc/rc-ir-raw.c | 191 +++++++++++++-
drivers/media/rc/rc-loopback.c | 40 ++-
drivers/media/rc/rc-main.c | 334 +++++++++++++++++++++----
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 | 254 ++++++++++---------
drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 2 +-
drivers/media/usb/dvb-usb/technisat-usb2.c | 2 +-
include/media/rc-core.h | 14 +-
include/media/rc-map.h | 10 +
35 files changed, 1249 insertions(+), 225 deletions(-)
--
2.9.3
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v4 01/13] [media] rc: change wakeup_protocols to list all protocol variants
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
@ 2016-12-06 10:19 ` Sean Young
2016-12-06 10:19 ` [PATCH v4 02/13] [media] rc: Add scancode validation Sean Young
` (12 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media
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.
Signed-off-by: Sean Young <sean@mess.org>
---
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 | 2 -
drivers/media/rc/rc-ir-raw.c | 1 -
drivers/media/rc/rc-main.c | 266 ++++++++++++++++++++-----
include/media/rc-core.h | 7 +-
6 files changed, 236 insertions(+), 67 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-class-rc b/Documentation/ABI/testing/sysfs-class-rc
index b65674d..cd47235 100644
--- a/Documentation/ABI/testing/sysfs-class-rc
+++ b/Documentation/ABI/testing/sysfs-class-rc
@@ -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 <m.chehab@samsung.com>
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
diff --git a/Documentation/media/uapi/rc/rc-sysfs-nodes.rst b/Documentation/media/uapi/rc/rc-sysfs-nodes.rst
index 6fb944f..3476ae2 100644
--- a/Documentation/media/uapi/rc/rc-sysfs-nodes.rst
+++ b/Documentation/media/uapi/rc/rc-sysfs-nodes.rst
@@ -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.
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index 7bb71bc..08f7c9b 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -685,7 +685,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 +700,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);
}
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 1c42a9f..171bdba 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -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);
}
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index dedaf38..60229e9 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -830,11 +830,6 @@ struct rc_filter_attribute {
};
#define to_rc_filter_attr(a) container_of(a, struct rc_filter_attribute, attr)
-#define RC_PROTO_ATTR(_name, _mode, _show, _store, _type) \
- struct rc_filter_attribute dev_attr_##_name = { \
- .attr = __ATTR(_name, _mode, _show, _store), \
- .type = (_type), \
- }
#define RC_FILTER_ATTR(_name, _mode, _show, _store, _type, _mask) \
struct rc_filter_attribute dev_attr_##_name = { \
.attr = __ATTR(_name, _mode, _show, _store), \
@@ -860,13 +855,13 @@ static bool lirc_is_present(void)
}
/**
- * show_protocols() - shows the current/wakeup IR protocol(s)
+ * show_protocols() - shows the current IR protocol(s)
* @device: the device descriptor
* @mattr: the device attribute struct
* @buf: a pointer to the output buffer
*
* This routine is a callback routine for input read the IR protocol type(s).
- * it is trigged by reading /sys/class/rc/rc?/[wakeup_]protocols.
+ * it is trigged by reading /sys/class/rc/rc?/protocols.
* It returns the protocol names of supported protocols.
* Enabled protocols are printed in brackets.
*
@@ -877,7 +872,6 @@ static ssize_t show_protocols(struct device *device,
struct device_attribute *mattr, char *buf)
{
struct rc_dev *dev = to_rc_dev(device);
- struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr);
u64 allowed, enabled;
char *tmp = buf;
int i;
@@ -891,15 +885,10 @@ static ssize_t show_protocols(struct device *device,
mutex_lock(&dev->lock);
- if (fattr->type == RC_FILTER_NORMAL) {
- enabled = dev->enabled_protocols;
- allowed = dev->allowed_protocols;
- if (dev->raw && !allowed)
- allowed = ir_raw_get_allowed_protocols();
- } else {
- enabled = dev->enabled_wakeup_protocols;
- allowed = dev->allowed_wakeup_protocols;
- }
+ enabled = dev->enabled_protocols;
+ allowed = dev->allowed_protocols;
+ if (dev->raw && !allowed)
+ allowed = ir_raw_get_allowed_protocols();
mutex_unlock(&dev->lock);
@@ -1058,11 +1047,8 @@ static ssize_t store_protocols(struct device *device,
const char *buf, size_t len)
{
struct rc_dev *dev = to_rc_dev(device);
- struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr);
u64 *current_protocols;
- int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
struct rc_scancode_filter *filter;
- int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
u64 old_protocols, new_protocols;
ssize_t rc;
@@ -1073,21 +1059,11 @@ static ssize_t store_protocols(struct device *device,
if (!atomic_read(&dev->initialized))
return -ERESTARTSYS;
- if (fattr->type == RC_FILTER_NORMAL) {
- IR_dprintk(1, "Normal protocol change requested\n");
- current_protocols = &dev->enabled_protocols;
- change_protocol = dev->change_protocol;
- filter = &dev->scancode_filter;
- set_filter = dev->s_filter;
- } else {
- IR_dprintk(1, "Wakeup protocol change requested\n");
- current_protocols = &dev->enabled_wakeup_protocols;
- change_protocol = dev->change_wakeup_protocol;
- filter = &dev->scancode_wakeup_filter;
- set_filter = dev->s_wakeup_filter;
- }
+ IR_dprintk(1, "Normal protocol change requested\n");
+ current_protocols = &dev->enabled_protocols;
+ filter = &dev->scancode_filter;
- if (!change_protocol) {
+ if (!dev->change_protocol) {
IR_dprintk(1, "Protocol switching not supported\n");
return -EINVAL;
}
@@ -1100,7 +1076,7 @@ static ssize_t store_protocols(struct device *device,
if (rc < 0)
goto out;
- rc = change_protocol(dev, &new_protocols);
+ rc = dev->change_protocol(dev, &new_protocols);
if (rc < 0) {
IR_dprintk(1, "Error setting protocols to 0x%llx\n",
(long long)new_protocols);
@@ -1123,16 +1099,16 @@ static ssize_t store_protocols(struct device *device,
* Try setting the same filter with the new protocol (if any).
* Fall back to clearing the filter.
*/
- if (set_filter && filter->mask) {
+ if (dev->s_filter && filter->mask) {
if (new_protocols)
- rc = set_filter(dev, filter);
+ rc = dev->s_filter(dev, filter);
else
rc = -1;
if (rc < 0) {
filter->data = 0;
filter->mask = 0;
- set_filter(dev, filter);
+ dev->s_filter(dev, filter);
}
}
@@ -1221,7 +1197,6 @@ static ssize_t store_filter(struct device *device,
int ret;
unsigned long val;
int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
- u64 *enabled_protocols;
/* Device is being removed */
if (!dev)
@@ -1236,11 +1211,9 @@ static ssize_t store_filter(struct device *device,
if (fattr->type == RC_FILTER_NORMAL) {
set_filter = dev->s_filter;
- enabled_protocols = &dev->enabled_protocols;
filter = &dev->scancode_filter;
} else {
set_filter = dev->s_wakeup_filter;
- enabled_protocols = &dev->enabled_wakeup_protocols;
filter = &dev->scancode_wakeup_filter;
}
@@ -1255,7 +1228,16 @@ static ssize_t store_filter(struct device *device,
else
new_filter.data = val;
- if (!*enabled_protocols && val) {
+ if (fattr->type == RC_FILTER_WAKEUP) {
+ /* refuse to set a filter unless a protocol is enabled */
+ if (dev->wakeup_protocol == RC_TYPE_UNKNOWN && val) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+ }
+
+ if (fattr->type == RC_FILTER_NORMAL && !dev->enabled_protocols
+ && val) {
/* refuse to set a filter unless a protocol is enabled */
ret = -EINVAL;
goto unlock;
@@ -1272,6 +1254,195 @@ static ssize_t store_filter(struct device *device,
return (ret < 0) ? ret : len;
}
+/*
+ * This is the list of all variants of all protocols, which is used by
+ * the wakeup_protocols sysfs entry. In the protocols sysfs entry some
+ * some protocols are grouped together (e.g. nec = nec + necx + nec32).
+ *
+ * For wakeup we need to know the exact protocol variant so the hardware
+ * can be programmed exactly what to expect.
+ */
+static const char * const proto_variant_names[] = {
+ [RC_TYPE_UNKNOWN] = "unknown",
+ [RC_TYPE_OTHER] = "other",
+ [RC_TYPE_RC5] = "rc-5",
+ [RC_TYPE_RC5X] = "rc-5x",
+ [RC_TYPE_RC5_SZ] = "rc-5-sz",
+ [RC_TYPE_JVC] = "jvc",
+ [RC_TYPE_SONY12] = "sony-12",
+ [RC_TYPE_SONY15] = "sony-15",
+ [RC_TYPE_SONY20] = "sony-20",
+ [RC_TYPE_NEC] = "nec",
+ [RC_TYPE_NECX] = "nec-x",
+ [RC_TYPE_NEC32] = "nec-32",
+ [RC_TYPE_SANYO] = "sanyo",
+ [RC_TYPE_MCE_KBD] = "mce_kbd",
+ [RC_TYPE_RC6_0] = "rc-6-0",
+ [RC_TYPE_RC6_6A_20] = "rc-6-6a-20",
+ [RC_TYPE_RC6_6A_24] = "rc-6-6a-24",
+ [RC_TYPE_RC6_6A_32] = "rc-6-6a-32",
+ [RC_TYPE_RC6_MCE] = "rc-6-mce",
+ [RC_TYPE_SHARP] = "sharp",
+ [RC_TYPE_XMP] = "xmp",
+ [RC_TYPE_CEC] = "cec",
+};
+
+/**
+ * show_wakeup_protocols() - shows the wakeup IR protocol
+ * @device: the device descriptor
+ * @mattr: the device attribute struct
+ * @buf: a pointer to the output buffer
+ *
+ * This routine is a callback routine for input read the IR protocol type(s).
+ * it is trigged by reading /sys/class/rc/rc?/wakeup_protocols.
+ * It returns the protocol names of supported protocols.
+ * The enabled protocols are printed in brackets.
+ *
+ * dev->lock is taken to guard against races between device
+ * registration, store_protocols and show_protocols.
+ */
+static ssize_t show_wakeup_protocols(struct device *device,
+ struct device_attribute *mattr,
+ char *buf)
+{
+ struct rc_dev *dev = to_rc_dev(device);
+ u64 allowed;
+ enum rc_type enabled;
+ char *tmp = buf;
+ int i;
+
+ /* Device is being removed */
+ if (!dev)
+ return -EINVAL;
+
+ if (!atomic_read(&dev->initialized))
+ return -ERESTARTSYS;
+
+ mutex_lock(&dev->lock);
+
+ allowed = dev->allowed_wakeup_protocols;
+ enabled = dev->wakeup_protocol;
+
+ mutex_unlock(&dev->lock);
+
+ IR_dprintk(1, "%s: allowed - 0x%llx, enabled - %d\n",
+ __func__, (long long)allowed, enabled);
+
+ for (i = 0; i < ARRAY_SIZE(proto_variant_names); i++) {
+ if (allowed & (1 << i)) {
+ if (i == enabled)
+ tmp += sprintf(tmp, "[%s] ",
+ proto_variant_names[i]);
+ else
+ tmp += sprintf(tmp, "%s ",
+ proto_variant_names[i]);
+ }
+ }
+
+ if (tmp != buf)
+ tmp--;
+ *tmp = '\n';
+
+ return tmp + 1 - buf;
+}
+
+/**
+ * store_wakeup_protocols() - changes the wakeup IR protocol(s)
+ * @device: the device descriptor
+ * @mattr: the device attribute struct
+ * @buf: a pointer to the input buffer
+ * @len: length of the input buffer
+ *
+ * This routine is for changing the IR protocol type.
+ * It is trigged by writing to /sys/class/rc/rc?/wakeup_protocols.
+ * Returns @len on success or a negative error code.
+ *
+ * dev->lock is taken to guard against races between device
+ * registration, store_protocols and show_protocols.
+ */
+static ssize_t store_wakeup_protocols(struct device *device,
+ struct device_attribute *mattr,
+ const char *buf, size_t len)
+{
+ struct rc_dev *dev = to_rc_dev(device);
+ enum rc_type old_protocol, new_protocol;
+ struct rc_scancode_filter *filter;
+ ssize_t rc;
+ u64 allowed;
+ int i;
+
+ /* Device is being removed */
+ if (!dev)
+ return -EINVAL;
+
+ if (!atomic_read(&dev->initialized))
+ return -ERESTARTSYS;
+
+ filter = &dev->scancode_wakeup_filter;
+
+ if (!dev->change_wakeup_protocol) {
+ IR_dprintk(1, "Protocol switching not supported\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev->lock);
+
+ allowed = dev->allowed_wakeup_protocols;
+ old_protocol = dev->wakeup_protocol;
+
+ if (sysfs_streq(buf, "none")) {
+ new_protocol = RC_TYPE_UNKNOWN;
+ } else {
+ for (i = 0; i < ARRAY_SIZE(proto_variant_names); i++) {
+ if ((allowed & (1 << i)) && sysfs_streq(buf,
+ proto_variant_names[i])) {
+ new_protocol = i;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(proto_variant_names)) {
+ rc = -EINVAL;
+ goto out;
+ }
+ }
+
+ if (old_protocol != new_protocol) {
+ rc = dev->change_wakeup_protocol(dev, new_protocol);
+ if (rc < 0) {
+ IR_dprintk(1, "Error setting protocols to %d\n",
+ new_protocol);
+ goto out;
+ }
+
+ dev->wakeup_protocol = new_protocol;
+ IR_dprintk(1, "Protocols changed to %d\n", new_protocol);
+ }
+
+ /*
+ * If a protocol change was attempted the filter may need updating, even
+ * if the actual protocol mask hasn't changed (since the driver may have
+ * cleared the filter).
+ * Try setting the same filter with the new protocol (if any).
+ * Fall back to clearing the filter.
+ */
+ if (dev->s_wakeup_filter && filter->mask) {
+ rc = dev->s_wakeup_filter(dev, filter);
+ if (rc < 0) {
+ filter->data = 0;
+ filter->mask = 0;
+ dev->s_wakeup_filter(dev, filter);
+ }
+ }
+
+ rc = len;
+
+out:
+ mutex_unlock(&dev->lock);
+ return rc;
+}
+
+
static void rc_dev_release(struct device *device)
{
struct rc_dev *dev = to_rc_dev(device);
@@ -1301,10 +1472,9 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
/*
* Static device attribute struct with the sysfs attributes for IR's
*/
-static RC_PROTO_ATTR(protocols, S_IRUGO | S_IWUSR,
- show_protocols, store_protocols, RC_FILTER_NORMAL);
-static RC_PROTO_ATTR(wakeup_protocols, S_IRUGO | S_IWUSR,
- show_protocols, store_protocols, RC_FILTER_WAKEUP);
+static DEVICE_ATTR(protocols, 0644, show_protocols, store_protocols);
+static DEVICE_ATTR(wakeup_protocols, 0644, show_wakeup_protocols,
+ store_wakeup_protocols);
static RC_FILTER_ATTR(filter, S_IRUGO|S_IWUSR,
show_filter, store_filter, RC_FILTER_NORMAL, false);
static RC_FILTER_ATTR(filter_mask, S_IRUGO|S_IWUSR,
@@ -1315,7 +1485,7 @@ static RC_FILTER_ATTR(wakeup_filter_mask, S_IRUGO|S_IWUSR,
show_filter, store_filter, RC_FILTER_WAKEUP, true);
static struct attribute *rc_dev_protocol_attrs[] = {
- &dev_attr_protocols.attr.attr,
+ &dev_attr_protocols.attr,
NULL,
};
@@ -1324,7 +1494,7 @@ static struct attribute_group rc_dev_protocol_attr_grp = {
};
static struct attribute *rc_dev_wakeup_protocol_attrs[] = {
- &dev_attr_wakeup_protocols.attr.attr,
+ &dev_attr_wakeup_protocols.attr,
NULL,
};
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 55281b9..3c34cac 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -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
@@ -149,7 +150,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 +170,7 @@ 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 (*change_wakeup_protocol)(struct rc_dev *dev, enum rc_type protocol);
int (*open)(struct rc_dev *dev);
void (*close)(struct rc_dev *dev);
int (*s_tx_mask)(struct rc_dev *dev, u32 mask);
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 02/13] [media] rc: Add scancode validation
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
2016-12-06 10:19 ` [PATCH v4 01/13] [media] rc: change wakeup_protocols to list all protocol variants Sean Young
@ 2016-12-06 10:19 ` Sean Young
2016-12-06 10:19 ` [PATCH v4 03/13] [media] winbond-cir: use sysfs wakeup filter Sean Young
` (11 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media
We need to valdiate that scancodes are valid for their protocol; an
incorrect necx scancode could actually be a nec scancode, for example.
Signed-off-by: Sean Young <sean@mess.org>
---
drivers/media/rc/rc-main.c | 66 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 65 insertions(+), 1 deletion(-)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 60229e9..4d8a984 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -724,6 +724,66 @@ 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
+ */
+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;
+ }
+
+ if (filter->mask == 0)
+ filter->mask = masks[protocol];
+ filter->data &= masks[protocol];
+ filter->mask &= masks[protocol];
+
+ return 0;
+}
+
int rc_open(struct rc_dev *rdev)
{
int rval = 0;
@@ -1232,8 +1292,12 @@ static ssize_t store_filter(struct device *device,
/* refuse to set a filter unless a protocol is enabled */
if (dev->wakeup_protocol == RC_TYPE_UNKNOWN && val) {
ret = -EINVAL;
- goto unlock;
+ } else if (dev->wakeup_protocol != RC_TYPE_UNKNOWN) {
+ ret = rc_validate_filter(dev->wakeup_protocol,
+ &new_filter);
}
+ if (ret != 0)
+ goto unlock;
}
if (fattr->type == RC_FILTER_NORMAL && !dev->enabled_protocols
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 03/13] [media] winbond-cir: use sysfs wakeup filter
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
2016-12-06 10:19 ` [PATCH v4 01/13] [media] rc: change wakeup_protocols to list all protocol variants Sean Young
2016-12-06 10:19 ` [PATCH v4 02/13] [media] rc: Add scancode validation Sean Young
@ 2016-12-06 10:19 ` Sean Young
2016-12-06 10:19 ` [PATCH v4 04/13] [media] rc: raw IR drivers cannot handle cec, unknown or other Sean Young
` (10 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media
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.
Signed-off-by: Sean Young <sean@mess.org>
---
drivers/media/rc/winbond-cir.c | 252 ++++++++++++++++++++---------------------
1 file changed, 125 insertions(+), 127 deletions(-)
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 78491ed..ce1e8c2 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -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,135 @@ 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 || rc->wakeup_protocol == RC_TYPE_UNKNOWN ||
+ !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;
- }
+ case RC_TYPE_NEC:
+ mask[1] = bitrev8(mask_sc);
+ mask[0] = ~mask[1];
+ mask[3] = bitrev8(mask_sc >> 8);
+ mask[2] = ~mask[3];
- mask[0] = mask[1] = mask[2] = mask[3] = 0xFF;
+ match[1] = bitrev8(wake_sc);
+ match[0] = ~mask[1];
+ match[3] = bitrev8(wake_sc >> 8);
+ match[2] = ~mask[3];
- match[1] = bitrev8((wake_sc & 0xFF));
- match[0] = ~match[1];
+ proto = IR_PROTOCOL_NEC;
+ break;
- match[3] = bitrev8((wake_sc & 0xFF00) >> 8);
- if (wake_sc > 0xFFFF)
- match[2] = bitrev8((wake_sc & 0xFF0000) >> 16);
- else
- match[2] = ~match[3];
+ case RC_TYPE_NECX:
+ mask[1] = bitrev8(mask_sc);
+ mask[0] = ~mask[1];
+ mask[3] = bitrev8(mask_sc >> 8);
+ mask[2] = bitrev8(mask_sc >> 16);
+ match[1] = bitrev8(wake_sc);
+ match[0] = ~mask[1];
+ match[3] = bitrev8(wake_sc >> 8);
+ match[2] = bitrev8(mask_sc >> 16);
+
+ proto = IR_PROTOCOL_NEC;
break;
- case IR_PROTOCOL_RC6:
-
- if (wake_rc6mode == 0) {
- if (wake_sc > 0xFFFF) {
- do_wake = false;
- dev_err(dev, "RC6 - Invalid wake scancode\n");
- 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;
- match[i] = wbcir_to_rc6cells(wake_sc >> 20);
- mask[i++] = 0xFF;
-
- if (wake_sc & 0x80000000) {
- /* Customer range bit and bits 15 - 8 */
- match[i] = wbcir_to_rc6cells(wake_sc >> 24);
- mask[i++] = 0xFF;
- match[i] = wbcir_to_rc6cells(wake_sc >> 28);
- mask[i++] = 0xFF;
- 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;
+ 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;
+ 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);
+ match[i] = wbcir_to_rc6cells(wake_sc >> 20);
+ mask[i++] = wbcir_to_rc6cells(mask_sc >> 20);
+
+ if (rc->wakeup_protocol == RC_TYPE_RC6_6A_24) {
+ rc6_csl = 60;
} else {
- do_wake = false;
- dev_err(dev, "RC6 - Invalid wake mode\n");
+ /* Customer range bit and bits 15 - 8 */
+ match[i] = wbcir_to_rc6cells(wake_sc >> 24);
+ mask[i++] = wbcir_to_rc6cells(mask_sc >> 24);
+ match[i] = wbcir_to_rc6cells(wake_sc >> 28);
+ mask[i++] = wbcir_to_rc6cells(mask_sc >> 28);
+ rc6_csl = 76;
}
+ /* 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 +838,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 +859,21 @@ wbcir_shutdown(struct pnp_dev *device)
disable_irq(data->irq);
}
+/*
+ * Wakeup handling is done on shutdown.
+ */
+static int
+wbcir_change_wakeup_protocol(struct rc_dev *rc, enum rc_type protocol)
+{
+ return 0;
+}
+
+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)
{
@@ -893,7 +892,7 @@ wbcir_init_hw(struct wbcir_data *data)
wbcir_set_irqmask(data, WBCIR_IRQ_NONE);
/* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */
- tmp = protocol << 4;
+ tmp = 0;
if (invert)
tmp |= 0x08;
outb(tmp, data->wbase + WBCIR_REG_WCEIR_CTL);
@@ -1084,6 +1083,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_RC5 | RC_BIT_RC6_0 | 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->change_wakeup_protocol = wbcir_change_wakeup_protocol;
+ data->dev->s_wakeup_filter = wbcir_set_wakeup_filter;
err = rc_register_device(data->dev);
if (err)
@@ -1199,15 +1206,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");
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 04/13] [media] rc: raw IR drivers cannot handle cec, unknown or other
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
` (2 preceding siblings ...)
2016-12-06 10:19 ` [PATCH v4 03/13] [media] winbond-cir: use sysfs wakeup filter Sean Young
@ 2016-12-06 10:19 ` Sean Young
2016-12-06 10:19 ` [PATCH v4 05/13] [media] rc: rc-ir-raw: Add scancode encoder callback Sean Young
` (9 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media
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.
Signed-off-by: Sean Young <sean@mess.org>
---
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(-)
diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c
index 9628651..90add97 100644
--- a/drivers/hid/hid-picolcd_cir.c
+++ b/drivers/hid/hid-picolcd_cir.c
@@ -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;
diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
index 41f2a39..480d8bf 100644
--- a/drivers/media/common/siano/smsir.c
+++ b/drivers/media/common/siano/smsir.c
@@ -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;
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index 1f092fe..2d4e703 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -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:
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index bd5512e..b7ce051 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -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;
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index ecab69e..3de5e82 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -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;
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 5b63b1f..0b5aec4 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -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;
diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c
index 5cf983b..4c4827c 100644
--- a/drivers/media/rc/igorplugusb.c
+++ b/drivers/media/rc/igorplugusb.c
@@ -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);
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index 5f63454..e2fff1f 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -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;
diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c
index d26907e..d95056a 100644
--- a/drivers/media/rc/ir-hix5hd2.c
+++ b/drivers/media/rc/ir-hix5hd2.c
@@ -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;
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 367b28b..01f6929 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -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;
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 9bf6917..9fd8d44 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -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;
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
index 7eb3f4f..3e96e6f 100644
--- a/drivers/media/rc/meson-ir.c
+++ b/drivers/media/rc/meson-ir.c
@@ -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;
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 4b78c89..9e04f41 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -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;
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 63dace8..4bc3f01 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -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;
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 2784f5d..ca878ac 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -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));
diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c
index 436bd58..1faa1ae 100644
--- a/drivers/media/rc/serial_ir.c
+++ b/drivers/media/rc/serial_ir.c
@@ -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;
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c
index 1fa0c9d..80a46e7 100644
--- a/drivers/media/rc/st_rc.c
+++ b/drivers/media/rc/st_rc.c
@@ -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);
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index 53f9b0a..359f928 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -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;
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index eaadc08..42bca8d 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -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;
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
index bc214e2..322e947 100644
--- a/drivers/media/rc/ttusbir.c
+++ b/drivers/media/rc/ttusbir.c
@@ -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;
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index ce1e8c2..0fcaf04 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -1082,7 +1082,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_RC5 | RC_BIT_RC6_0 | RC_BIT_RC6_6A_24 |
RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE;
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index c583c63..e16ca07 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -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;
diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
index 02c3bee..1b21f1b 100644
--- a/drivers/media/usb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -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,
}
};
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index e1cc14c..b2af45d 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -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)
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 05/13] [media] rc: rc-ir-raw: Add scancode encoder callback
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
` (3 preceding siblings ...)
2016-12-06 10:19 ` [PATCH v4 04/13] [media] rc: raw IR drivers cannot handle cec, unknown or other Sean Young
@ 2016-12-06 10:19 ` Sean Young
2016-12-06 10:19 ` [PATCH v4 06/13] [media] rc: rc-ir-raw: Add Manchester encoder (phase encoder) helper Sean Young
` (8 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media; +Cc: James Hogan, Antti Seppälä, David Härdeman
From: James Hogan <james@albanarts.com>
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 filter to a form that is more suitable for
raw hardware wake up filters.
Signed-off-by: James Hogan <james@albanarts.com>
Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
Signed-off-by: Sean Young <sean@mess.org>
Cc: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-core-priv.h | 3 +++
drivers/media/rc/rc-ir-raw.c | 37 +++++++++++++++++++++++++++++++++++++
include/media/rc-core.h | 3 +++
3 files changed, 43 insertions(+)
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 585d5e5..98cc0cf 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -28,6 +28,9 @@ 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,
+ const struct rc_scancode_filter *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);
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 171bdba..1b229ef 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -249,6 +249,43 @@ 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,
+ const struct rc_scancode_filter *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
*/
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 3c34cac..0a72e17 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -307,6 +307,9 @@ 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,
+ const struct rc_scancode_filter *scancode,
+ struct ir_raw_event *events, unsigned int max);
static inline void ir_raw_event_reset(struct rc_dev *dev)
{
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 06/13] [media] rc: rc-ir-raw: Add Manchester encoder (phase encoder) helper
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
` (4 preceding siblings ...)
2016-12-06 10:19 ` [PATCH v4 05/13] [media] rc: rc-ir-raw: Add scancode encoder callback Sean Young
@ 2016-12-06 10:19 ` Sean Young
2016-12-06 10:19 ` [PATCH v4 07/13] [media] rc: rc-ir-raw: Add pulse-distance modulation helper Sean Young
` (7 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media; +Cc: Antti Seppälä, James Hogan, David Härdeman
From: Antti Seppälä <a.seppala@gmail.com>
Adding a simple Manchester encoder to rc-core.
Manchester coding is used by at least RC-5 and RC-6 protocols and their
variants.
Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
Signed-off-by: James Hogan <james@albanarts.com>
Signed-off-by: Sean Young <sean@mess.org>
Cc: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-core-priv.h | 33 ++++++++++++++++
drivers/media/rc/rc-ir-raw.c | 85 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 118 insertions(+)
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 98cc0cf..b175bf3 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -157,6 +157,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
*/
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 1b229ef..072b4bd 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -250,6 +250,91 @@ static void ir_raw_disable_protocols(struct rc_dev *dev, u64 protocols)
}
/**
+ * ir_raw_gen_manchester() - Encode data with Manchester (bi-phase) modulation.
+ * @ev: Pointer to pointer to next free event. *@ev is incremented for
+ * each raw event filled.
+ * @max: Maximum number of raw events to fill.
+ * @timings: Manchester modulation timings.
+ * @n: Number of bits of data.
+ * @data: Data bits to encode.
+ *
+ * Encodes the @n least significant bits of @data using Manchester (bi-phase)
+ * modulation with the timing characteristics described by @timings, writing up
+ * to @max raw IR events using the *@ev pointer.
+ *
+ * Returns: 0 on success.
+ * -ENOBUFS if there isn't enough space in the array to fit the
+ * full encoded data. In this case all @max events will have been
+ * written.
+ */
+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)
+{
+ bool need_pulse;
+ unsigned int i;
+ int ret = -ENOBUFS;
+
+ i = 1 << (n - 1);
+
+ if (timings->leader) {
+ if (!max--)
+ return ret;
+ if (timings->pulse_space_start) {
+ init_ir_raw_event_duration((*ev)++, 1, timings->leader);
+
+ if (!max--)
+ return ret;
+ init_ir_raw_event_duration((*ev), 0, timings->leader);
+ } else {
+ init_ir_raw_event_duration((*ev), 1, timings->leader);
+ }
+ i >>= 1;
+ } else {
+ /* continue existing signal */
+ --(*ev);
+ }
+ /* from here on *ev will point to the last event rather than the next */
+
+ while (n && i > 0) {
+ need_pulse = !(data & i);
+ if (timings->invert)
+ need_pulse = !need_pulse;
+ if (need_pulse == !!(*ev)->pulse) {
+ (*ev)->duration += timings->clock;
+ } else {
+ if (!max--)
+ goto nobufs;
+ init_ir_raw_event_duration(++(*ev), need_pulse,
+ timings->clock);
+ }
+
+ if (!max--)
+ goto nobufs;
+ init_ir_raw_event_duration(++(*ev), !need_pulse,
+ timings->clock);
+ i >>= 1;
+ }
+
+ if (timings->trailer_space) {
+ if (!(*ev)->pulse)
+ (*ev)->duration += timings->trailer_space;
+ else if (!max--)
+ goto nobufs;
+ else
+ init_ir_raw_event_duration(++(*ev), 0,
+ timings->trailer_space);
+ }
+
+ ret = 0;
+nobufs:
+ /* point to the next event rather than last event before returning */
+ ++(*ev);
+ return ret;
+}
+EXPORT_SYMBOL(ir_raw_gen_manchester);
+
+/**
* ir_raw_encode_scancode() - Encode a scancode as raw events
*
* @protocol: protocol
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 07/13] [media] rc: rc-ir-raw: Add pulse-distance modulation helper
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
` (5 preceding siblings ...)
2016-12-06 10:19 ` [PATCH v4 06/13] [media] rc: rc-ir-raw: Add Manchester encoder (phase encoder) helper Sean Young
@ 2016-12-06 10:19 ` Sean Young
2016-12-06 10:19 ` [PATCH v4 08/13] [media] rc: ir-rc5-decoder: Add encode capability Sean Young
` (6 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media; +Cc: James Hogan, Antti Seppälä, David Härdeman
From: James Hogan <james@albanarts.com>
Add IR encoding helper for pulse-distance modulation as used by the NEC
protocol.
Signed-off-by: James Hogan <james@albanarts.com>
Signed-off-by: Sean Young <sean@mess.org>
Cc: Antti Seppälä <a.seppala@gmail.com>
Cc: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-core-priv.h | 52 ++++++++++++++++++++++++++++++++++++++
drivers/media/rc/rc-ir-raw.c | 56 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 108 insertions(+)
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index b175bf3..0680e10 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -190,6 +190,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, unsigned int data);
+
/*
* Routines from rc-raw.c to be used internally and by decoders
*/
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 072b4bd..5d299f6 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -335,6 +335,62 @@ int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
EXPORT_SYMBOL(ir_raw_gen_manchester);
/**
+ * ir_raw_gen_pd() - Encode data to raw events with pulse-distance modulation.
+ * @ev: Pointer to pointer to next free event. *@ev is incremented for
+ * each raw event filled.
+ * @max: Maximum number of raw events to fill.
+ * @timings: Pulse distance modulation timings.
+ * @n: Number of bits of data.
+ * @data: Data bits to encode.
+ *
+ * Encodes the @n least significant bits of @data using pulse-distance
+ * modulation with the timing characteristics described by @timings, writing up
+ * to @max raw IR events using the *@ev pointer.
+ *
+ * Returns: 0 on success.
+ * -ENOBUFS if there isn't enough space in the array to fit the
+ * full encoded data. In this case all @max events will have been
+ * written.
+ */
+int ir_raw_gen_pd(struct ir_raw_event **ev, unsigned int max,
+ const struct ir_raw_timings_pd *timings,
+ unsigned int n, unsigned int data)
+{
+ int i;
+ int ret;
+
+ if (timings->header_pulse) {
+ ret = ir_raw_gen_pulse_space(ev, &max, timings->header_pulse,
+ timings->header_space);
+ if (ret)
+ return ret;
+ }
+
+ if (timings->msb_first) {
+ for (i = n - 1; i >= 0; --i) {
+ ret = ir_raw_gen_pulse_space(ev, &max,
+ timings->bit_pulse,
+ timings->bit_space[(data >> i) & 1]);
+ if (ret)
+ return ret;
+ }
+ } else {
+ for (i = 0; i < n; ++i, data >>= 1) {
+ ret = ir_raw_gen_pulse_space(ev, &max,
+ timings->bit_pulse,
+ timings->bit_space[data & 1]);
+ if (ret)
+ return ret;
+ }
+ }
+
+ ret = ir_raw_gen_pulse_space(ev, &max, timings->trailer_pulse,
+ timings->trailer_space);
+ return ret;
+}
+EXPORT_SYMBOL(ir_raw_gen_pd);
+
+/**
* ir_raw_encode_scancode() - Encode a scancode as raw events
*
* @protocol: protocol
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 08/13] [media] rc: ir-rc5-decoder: Add encode capability
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
` (6 preceding siblings ...)
2016-12-06 10:19 ` [PATCH v4 07/13] [media] rc: rc-ir-raw: Add pulse-distance modulation helper Sean Young
@ 2016-12-06 10:19 ` Sean Young
2016-12-06 10:19 ` [PATCH v4 09/13] [media] rc: ir-rc6-decoder: " Sean Young
` (5 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media; +Cc: James Hogan, Antti Seppälä, David Härdeman
From: James Hogan <james@albanarts.com>
Add the capability to encode RC-5, RC-5X and RC-5-SZ scancodes as raw
events. The protocol is chosen based on the specified protocol mask,
and whether all the required bits are set in the scancode mask, and
none of the unused bits are set in the scancode data. For example a
scancode filter with bit 16 set in both data and mask is unambiguously
RC-5X.
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.
Signed-off-by: James Hogan <james@albanarts.com>
Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
Signed-off-by: Sean Young <sean@mess.org>
Cc: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/ir-rc5-decoder.c | 116 ++++++++++++++++++++++++++++++++++++++
1 file changed, 116 insertions(+)
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index a0fd4e6..c405459 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -181,9 +181,125 @@ 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,
+};
+
+static int ir_rc5_validate_filter(const struct rc_scancode_filter *scancode,
+ unsigned int important_bits)
+{
+ /* all important bits of scancode should be set in mask */
+ if (~scancode->mask & important_bits)
+ return -EINVAL;
+ /* extra bits in mask should be zero in data */
+ if (scancode->mask & scancode->data & ~important_bits)
+ return -EINVAL;
+ return 0;
+}
+
+/**
+ * ir_rc5_encode() - Encode a scancode as a stream of raw events
+ *
+ * @protocol: protocol variant to encode
+ * @scancode: scancode filter describing scancode (helps distinguish between
+ * protocol subtypes when scancode is ambiguous)
+ * @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,
+ const struct rc_scancode_filter *scancode,
+ struct ir_raw_event *events, unsigned int max)
+{
+ int ret;
+ struct ir_raw_event *e = events;
+ unsigned int data, xdata, command, commandx, system;
+
+ /* Detect protocol and convert scancode to raw data */
+ if (protocol == RC_TYPE_RC5 &&
+ !ir_rc5_validate_filter(scancode, 0x1f7f)) {
+ /* decode scancode */
+ command = (scancode->data & 0x003f) >> 0;
+ commandx = (scancode->data & 0x0040) >> 6;
+ system = (scancode->data & 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 &&
+ !ir_rc5_validate_filter(scancode, 0x1f7f3f)) {
+ /* decode scancode */
+ xdata = (scancode->data & 0x00003f) >> 0;
+ command = (scancode->data & 0x003f00) >> 8;
+ commandx = (scancode->data & 0x004000) >> 14;
+ system = (scancode->data & 0x1f0000) >> 16;
+ /* commandx and system overlap, bits must match when encoded */
+ if (commandx == (system & 0x1))
+ return -EINVAL;
+ /* encode data */
+ data = 1 << 18 | system << 12 | command << 6 | xdata;
+
+ /* Modulate the data */
+ ret = ir_raw_gen_manchester(&e, max, &ir_rc5x_timings[0],
+ CHECK_RC5X_NBITS,
+ data >> (RC5X_NBITS-CHECK_RC5X_NBITS));
+ 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 &&
+ !ir_rc5_validate_filter(scancode, 0x2fff)) {
+ /* 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->data & 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)
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 09/13] [media] rc: ir-rc6-decoder: Add encode capability
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
` (7 preceding siblings ...)
2016-12-06 10:19 ` [PATCH v4 08/13] [media] rc: ir-rc5-decoder: Add encode capability Sean Young
@ 2016-12-06 10:19 ` Sean Young
2016-12-06 10:19 ` [PATCH v4 10/13] [media] rc: ir-nec-decoder: " Sean Young
` (4 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media; +Cc: Antti Seppälä, James Hogan, David Härdeman
From: Antti Seppälä <a.seppala@gmail.com>
Add the capability to encode RC-6 and RC-6A scancodes as raw events.
The protocol is chosen based on the specified protocol mask, and
whether all the required bits are set in the scancode mask, and none of
the unused bits are set in the scancode data.
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.
Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
Signed-off-by: Sean Young <sean@mess.org>
Cc: James Hogan <james@albanarts.com>
Cc: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/ir-rc6-decoder.c | 120 ++++++++++++++++++++++++++++++++++++++
1 file changed, 120 insertions(+)
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index 5cc54c9..3667ca2 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -286,11 +286,131 @@ 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,
+ },
+};
+
+static int ir_rc6_validate_filter(const struct rc_scancode_filter *scancode,
+ unsigned int important_bits)
+{
+ /* all important bits of scancode should be set in mask */
+ if (~scancode->mask & important_bits)
+ return -EINVAL;
+ /* extra bits in mask should be zero in data */
+ if (scancode->mask & scancode->data & ~important_bits)
+ return -EINVAL;
+ return 0;
+}
+
+/**
+ * ir_rc6_encode() - Encode a scancode as a stream of raw events
+ *
+ * @protocol: protocol to encode
+ * @scancode: scancode filter describing scancode (helps distinguish between
+ * protocol subtypes when scancode is ambiguous)
+ * @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,
+ const struct rc_scancode_filter *scancode,
+ struct ir_raw_event *events, unsigned int max)
+{
+ int ret;
+ struct ir_raw_event *e = events;
+
+ if (protocol == RC_TYPE_RC6_0 &&
+ !ir_rc6_validate_filter(scancode, 0xffff)) {
+
+ /* 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->data);
+ if (ret < 0)
+ return ret;
+
+ } else if (!ir_rc6_validate_filter(scancode, 0x8fffffff)) {
+
+ /* 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],
+ fls(scancode->mask),
+ scancode->data);
+ if (ret < 0)
+ return ret;
+
+ } else {
+ return -EINVAL;
+ }
+
+ 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)
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 10/13] [media] rc: ir-nec-decoder: Add encode capability
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
` (8 preceding siblings ...)
2016-12-06 10:19 ` [PATCH v4 09/13] [media] rc: ir-rc6-decoder: " Sean Young
@ 2016-12-06 10:19 ` Sean Young
2016-12-06 10:19 ` [PATCH v4 11/13] [media] rc: rc-core: Add support for encode_wakeup drivers Sean Young
` (3 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media; +Cc: James Hogan, Antti Seppälä, David Härdeman
From: James Hogan <james@albanarts.com>
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.
Signed-off-by: James Hogan <james@albanarts.com>
Signed-off-by: Sean Young <sean@mess.org>
Cc: Antti Seppälä <a.seppala@gmail.com>
Cc: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/ir-nec-decoder.c | 94 +++++++++++++++++++++++++++++++++++++++
1 file changed, 94 insertions(+)
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 2a9d155..898cf65 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -201,9 +201,103 @@ 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
+ * @in: scancode filter describing a single NEC scancode.
+ * @raw: raw data to be modulated.
+ */
+static int ir_nec_scancode_to_raw(enum rc_type protocol,
+ const struct rc_scancode_filter *in, u32 *raw)
+{
+ unsigned int addr, addr_inv, data, data_inv;
+
+ data = in->data & 0xff;
+
+ if (protocol == RC_TYPE_NEC32) {
+ /* 32-bit NEC (used by Apple and TiVo remotes) */
+ /* scan encoding: aaAAddDD */
+ if (in->mask != 0xffffffff)
+ return -EINVAL;
+ addr_inv = (in->data >> 24) & 0xff;
+ addr = (in->data >> 16) & 0xff;
+ data_inv = (in->data >> 8) & 0xff;
+ } else if (protocol == RC_TYPE_NECX) {
+ /* Extended NEC */
+ /* scan encoding AAaaDD */
+ if (in->mask != 0x00ffffff)
+ return -EINVAL;
+ addr = (in->data >> 16) & 0xff;
+ addr_inv = (in->data >> 8) & 0xff;
+ data_inv = data ^ 0xff;
+ } else {
+ /* Normal NEC */
+ /* scan encoding: AADD */
+ if (in->mask != 0x0000ffff)
+ return -EINVAL;
+ addr = (in->data >> 8) & 0xff;
+ addr_inv = addr ^ 0xff;
+ data_inv = data ^ 0xff;
+ }
+
+ /* raw encoding: ddDDaaAA */
+ *raw = data_inv << 24 |
+ data << 16 |
+ addr_inv << 8 |
+ addr;
+ return 0;
+}
+
+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
+ * @scancode: scancode filter describing scancode (helps distinguish between
+ * protocol subtypes when scancode is ambiguous)
+ * @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_nec_encode(enum rc_type protocol,
+ const struct rc_scancode_filter *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 */
+ ret = ir_nec_scancode_to_raw(protocol, scancode, &raw);
+ if (ret < 0)
+ return ret;
+
+ /* 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)
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 11/13] [media] rc: rc-core: Add support for encode_wakeup drivers
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
` (9 preceding siblings ...)
2016-12-06 10:19 ` [PATCH v4 10/13] [media] rc: ir-nec-decoder: " Sean Young
@ 2016-12-06 10:19 ` Sean Young
2016-12-06 10:19 ` [PATCH v4 12/13] [media] rc: rc-loopback: Add loopback of filter scancodes Sean Young
` (2 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media; +Cc: James Hogan, Antti Seppälä, David Härdeman
From: James Hogan <james@albanarts.com>
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 to make the
allowed wakeup protocols the same as the set of raw IR encoders.
As well as updating the sysfs interface to know which wakeup protocols
are allowed for encode_wakeup drivers, also ensure that the IR
decoders/encoders are loaded when an encode_wakeup driver is registered.
Signed-off-by: James Hogan <james@albanarts.com>
Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
Signed-off-by: Sean Young <sean@mess.org>
Cc: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-core-priv.h | 1 +
drivers/media/rc/rc-ir-raw.c | 12 ++++++++++++
drivers/media/rc/rc-main.c | 4 +++-
include/media/rc-core.h | 3 +++
4 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 0680e10..8527cff 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -246,6 +246,7 @@ int ir_raw_gen_pd(struct ir_raw_event **ev, unsigned int max,
* Routines from rc-raw.c to be used internally and by decoders
*/
u64 ir_raw_get_allowed_protocols(void);
+u64 ir_raw_get_encode_protocols(void);
int ir_raw_event_register(struct rc_dev *dev);
void ir_raw_event_unregister(struct rc_dev *dev);
int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 5d299f6..f44b9e2 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -27,6 +27,7 @@ static LIST_HEAD(ir_raw_client_list);
static DEFINE_MUTEX(ir_raw_handler_lock);
static LIST_HEAD(ir_raw_handler_list);
static atomic64_t available_protocols = ATOMIC64_INIT(0);
+static atomic64_t encode_protocols = ATOMIC64_INIT(0);
static int ir_raw_event_thread(void *data)
{
@@ -236,6 +237,13 @@ ir_raw_get_allowed_protocols(void)
return atomic64_read(&available_protocols);
}
+/* used internally by the sysfs interface */
+u64
+ir_raw_get_encode_protocols(void)
+{
+ return atomic64_read(&encode_protocols);
+}
+
static int change_protocol(struct rc_dev *dev, u64 *rc_type)
{
/* the caller will update dev->enabled_protocols */
@@ -504,6 +512,8 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
list_for_each_entry(raw, &ir_raw_client_list, list)
ir_raw_handler->raw_register(raw->dev);
atomic64_or(ir_raw_handler->protocols, &available_protocols);
+ if (ir_raw_handler->encode)
+ atomic64_or(ir_raw_handler->protocols, &encode_protocols);
mutex_unlock(&ir_raw_handler_lock);
return 0;
@@ -523,6 +533,8 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
ir_raw_handler->raw_unregister(raw->dev);
}
atomic64_andnot(protocols, &available_protocols);
+ if (ir_raw_handler->encode)
+ atomic64_andnot(protocols, &encode_protocols);
mutex_unlock(&ir_raw_handler_lock);
}
EXPORT_SYMBOL(ir_raw_handler_unregister);
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 4d8a984..0385616 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1750,11 +1750,13 @@ int rc_register_device(struct rc_dev *dev)
dev->input_name ?: "Unspecified device", path ?: "N/A");
kfree(path);
- if (dev->driver_type == RC_DRIVER_IR_RAW) {
+ if (dev->driver_type == RC_DRIVER_IR_RAW || dev->encode_wakeup) {
+ /* Load raw decoders, if they aren't already */
if (!raw_init) {
request_module_nowait("ir-lirc-codec");
raw_init = true;
}
+
rc = ir_raw_event_register(dev);
if (rc < 0)
goto out_input;
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 0a72e17..acfdaf5 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -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
@@ -147,6 +149,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;
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 12/13] [media] rc: rc-loopback: Add loopback of filter scancodes
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
` (10 preceding siblings ...)
2016-12-06 10:19 ` [PATCH v4 11/13] [media] rc: rc-core: Add support for encode_wakeup drivers Sean Young
@ 2016-12-06 10:19 ` Sean Young
2016-12-06 10:19 ` [PATCH v4 13/13] [media] rc: nuvoton-cir: Add support wakeup via sysfs filter callback Sean Young
2016-12-07 10:45 ` [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media; +Cc: James Hogan, Antti Seppälä, David Härdeman
From: James Hogan <james@albanarts.com>
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.
Signed-off-by: James Hogan <james@albanarts.com>
Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
Signed-off-by: Sean Young <sean@mess.org>
Cc: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-loopback.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 4bc3f01..487214e 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -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_filter)
+{
+ static const unsigned int max = 512;
+ struct ir_raw_event *raw;
+ int ret;
+ int i;
+
+ /* fine to disable filter */
+ if (!sc_filter->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_filter, 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;
@@ -195,6 +231,7 @@ static int __init loop_init(void)
rc->map_name = RC_MAP_EMPTY;
rc->priv = &loopdev;
rc->driver_type = RC_DRIVER_IR_RAW;
+ rc->encode_wakeup = true;
rc->allowed_protocols = RC_BIT_ALL_IR_DECODER;
rc->timeout = 100 * 1000 * 1000; /* 100 ms */
rc->min_timeout = 1;
@@ -209,6 +246,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;
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 13/13] [media] rc: nuvoton-cir: Add support wakeup via sysfs filter callback
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
` (11 preceding siblings ...)
2016-12-06 10:19 ` [PATCH v4 12/13] [media] rc: rc-loopback: Add loopback of filter scancodes Sean Young
@ 2016-12-06 10:19 ` Sean Young
2016-12-07 10:45 ` [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-06 10:19 UTC (permalink / raw)
To: linux-media; +Cc: Antti Seppälä, James Hogan, Jarod Wilson
From: Antti Seppälä <a.seppala@gmail.com>
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.
Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
Signed-off-by: James Hogan <james@albanarts.com>
Signed-off-by: Sean Young <sean@mess.org>
Cc: Jarod Wilson <jarod@redhat.com>
---
drivers/media/rc/nuvoton-cir.c | 126 +++++++++++++++++++++++++++++++++++++++++
drivers/media/rc/nuvoton-cir.h | 1 +
include/media/rc-core.h | 1 +
3 files changed, 128 insertions(+)
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 9e04f41..ec16012 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -662,6 +662,129 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
return 0;
}
+static int nvt_write_wakeup_codes(struct rc_dev *dev,
+ const u8 *wakeup_sample_buf, int count)
+{
+ u8 reg, reg_learn_mode;
+ struct nvt_dev *nvt = dev->priv;
+ int i;
+
+ nvt_dbg_wake("writing wakeup samples");
+
+ reg = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON);
+ reg_learn_mode = reg & ~CIR_WAKE_IRCON_MODE0;
+ reg_learn_mode |= CIR_WAKE_IRCON_MODE1;
+
+ /* Lock the learn area to prevent racing with wake-isr */
+ spin_lock(&nvt->lock);
+
+ /* Enable fifo writes */
+ nvt_cir_wake_reg_write(nvt, reg_learn_mode, CIR_WAKE_IRCON);
+
+ /* Clear cir wake rx fifo */
+ nvt_clear_cir_wake_fifo(nvt);
+
+ if (count > WAKE_FIFO_LEN) {
+ nvt_dbg_wake("HW FIFO too small for all wake samples");
+ count = WAKE_FIFO_LEN;
+ }
+
+ if (count)
+ pr_info("Wake samples (%d) =", count);
+ else
+ pr_info("Wake sample fifo cleared");
+
+ /* Write wake samples to fifo */
+ for (i = 0; i < count; i++) {
+ pr_cont(" %02x", wakeup_sample_buf[i]);
+ nvt_cir_wake_reg_write(nvt, wakeup_sample_buf[i],
+ CIR_WAKE_WR_FIFO_DATA);
+ }
+ pr_cont("\n");
+
+ /* Switch cir to wakeup mode and disable fifo writing */
+ nvt_cir_wake_reg_write(nvt, reg, CIR_WAKE_IRCON);
+
+ /* Set number of bytes needed for wake */
+ nvt_cir_wake_reg_write(nvt, count ? count :
+ CIR_WAKE_FIFO_CMP_BYTES,
+ CIR_WAKE_FIFO_CMP_DEEP);
+
+ spin_unlock(&nvt->lock);
+
+ return 0;
+}
+
+static int nvt_ir_raw_set_wakeup_filter(struct rc_dev *dev,
+ struct rc_scancode_filter *sc_filter)
+{
+ u8 *reg_buf;
+ u8 buf_val;
+ int i, ret, count;
+ unsigned int val;
+ struct ir_raw_event *raw;
+ bool complete;
+
+ /* Require both mask and protocol to be set */
+ if (!sc_filter->mask || dev->wakeup_protocol != RC_TYPE_UNKNOWN)
+ return 0;
+
+ raw = kmalloc_array(WAKE_FIFO_LEN, sizeof(*raw), GFP_KERNEL);
+ if (!raw)
+ return -ENOMEM;
+
+ ret = ir_raw_encode_scancode(dev->wakeup_protocol, sc_filter,
+ raw, WAKE_FIFO_LEN);
+ complete = (ret != -ENOBUFS);
+ if (!complete)
+ ret = WAKE_FIFO_LEN;
+ else if (ret < 0)
+ goto out_raw;
+
+ reg_buf = kmalloc_array(WAKE_FIFO_LEN, sizeof(*reg_buf), GFP_KERNEL);
+ if (!reg_buf) {
+ ret = -ENOMEM;
+ goto out_raw;
+ }
+
+ /* Inspect the ir samples */
+ for (i = 0, count = 0; i < ret && count < WAKE_FIFO_LEN; ++i) {
+ val = NS_TO_US((raw[i]).duration) / SAMPLE_PERIOD;
+
+ /* Split too large values into several smaller ones */
+ while (val > 0 && count < WAKE_FIFO_LEN) {
+
+ /* 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;
+
+ reg_buf[count] = buf_val;
+ val -= buf_val;
+ if ((raw[i]).pulse)
+ reg_buf[count] |= BUF_PULSE_BIT;
+ count++;
+ }
+ }
+
+ ret = nvt_write_wakeup_codes(dev, reg_buf, count);
+
+ kfree(reg_buf);
+out_raw:
+ kfree(raw);
+
+ return ret;
+}
+
+/* Dummy implementation. nuvoton is agnostic to the protocol used */
+static int nvt_ir_raw_change_wakeup_protocol(struct rc_dev *dev,
+ enum rc_type protocol)
+{
+ return 0;
+}
+
/*
* nvt_tx_ir
*
@@ -1062,11 +1185,14 @@ 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->encode_wakeup = true;
rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
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->change_wakeup_protocol = nvt_ir_raw_change_wakeup_protocol;
rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
rdev->input_phys = "nuvoton/cir0";
rdev->input_id.bustype = BUS_HOST;
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index c41c576..de2384a 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -60,6 +60,7 @@ static int debug;
*/
#define TX_BUF_LEN 256
#define RX_BUF_LEN 32
+#define WAKE_FIFO_LEN 67
#define SIO_ID_MASK 0xfff0
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index acfdaf5..0ebf166 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -303,6 +303,7 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev)
#define US_TO_NS(usec) ((usec) * 1000)
#define MS_TO_US(msec) ((msec) * 1000)
#define MS_TO_NS(msec) ((msec) * 1000 * 1000)
+#define NS_TO_US(nsec) DIV_ROUND_UP(nsec, 1000L)
void ir_raw_event_handle(struct rc_dev *dev);
int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
--
2.9.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
` (12 preceding siblings ...)
2016-12-06 10:19 ` [PATCH v4 13/13] [media] rc: nuvoton-cir: Add support wakeup via sysfs filter callback Sean Young
@ 2016-12-07 10:45 ` Sean Young
13 siblings, 0 replies; 15+ messages in thread
From: Sean Young @ 2016-12-07 10:45 UTC (permalink / raw)
To: linux-media
On Tue, Dec 06, 2016 at 10:19:08AM +0000, Sean Young wrote:
> This patch series resurrects an earlier series with a new approach.
I've discovered some bugs in this series. Protocol modules are not
autoloaded and rc-loopback and is missing the wakeup_protocols sysfs file.
Please treat this series as RFC while I fix the issues and do more testing.
Sean
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2016-12-07 10:45 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-12-06 10:19 [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
2016-12-06 10:19 ` [PATCH v4 01/13] [media] rc: change wakeup_protocols to list all protocol variants Sean Young
2016-12-06 10:19 ` [PATCH v4 02/13] [media] rc: Add scancode validation Sean Young
2016-12-06 10:19 ` [PATCH v4 03/13] [media] winbond-cir: use sysfs wakeup filter Sean Young
2016-12-06 10:19 ` [PATCH v4 04/13] [media] rc: raw IR drivers cannot handle cec, unknown or other Sean Young
2016-12-06 10:19 ` [PATCH v4 05/13] [media] rc: rc-ir-raw: Add scancode encoder callback Sean Young
2016-12-06 10:19 ` [PATCH v4 06/13] [media] rc: rc-ir-raw: Add Manchester encoder (phase encoder) helper Sean Young
2016-12-06 10:19 ` [PATCH v4 07/13] [media] rc: rc-ir-raw: Add pulse-distance modulation helper Sean Young
2016-12-06 10:19 ` [PATCH v4 08/13] [media] rc: ir-rc5-decoder: Add encode capability Sean Young
2016-12-06 10:19 ` [PATCH v4 09/13] [media] rc: ir-rc6-decoder: " Sean Young
2016-12-06 10:19 ` [PATCH v4 10/13] [media] rc: ir-nec-decoder: " Sean Young
2016-12-06 10:19 ` [PATCH v4 11/13] [media] rc: rc-core: Add support for encode_wakeup drivers Sean Young
2016-12-06 10:19 ` [PATCH v4 12/13] [media] rc: rc-loopback: Add loopback of filter scancodes Sean Young
2016-12-06 10:19 ` [PATCH v4 13/13] [media] rc: nuvoton-cir: Add support wakeup via sysfs filter callback Sean Young
2016-12-07 10:45 ` [PATCH v4 00/13] Use sysfs filter for winbond & nuvoton wakeup Sean Young
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).