summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/rc/img-ir/img-ir-hw.c13
-rw-r--r--drivers/media/rc/img-ir/img-ir-nec.c21
-rw-r--r--drivers/media/rc/img-ir/img-ir-sony.c26
-rw-r--r--drivers/media/rc/rc-ir-raw.c1
-rw-r--r--drivers/media/rc/rc-main.c253
5 files changed, 242 insertions, 72 deletions
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index 7bb71bc9f534..8e2b64135c39 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -488,7 +488,15 @@ static int img_ir_set_filter(struct rc_dev *dev, enum rc_filter_type type,
/* convert scancode filter to raw filter */
filter.minlen = 0;
filter.maxlen = ~0;
- ret = hw->decoder->filter(sc_filter, &filter, hw->enabled_protocols);
+ if (type == RC_FILTER_NORMAL) {
+ /* guess scancode from protocol */
+ ret = hw->decoder->filter(sc_filter, &filter,
+ dev->enabled_protocols);
+ } else {
+ /* for wakeup user provided exact protocol variant */
+ ret = hw->decoder->filter(sc_filter, &filter,
+ 1ULL << dev->wakeup_protocol);
+ }
if (ret)
goto unlock;
dev_dbg(priv->dev, "IR raw %sfilter=%016llx & %016llx\n",
@@ -581,6 +589,7 @@ static void img_ir_set_decoder(struct img_ir_priv *priv,
/* clear the wakeup scancode filter */
rdev->scancode_wakeup_filter.data = 0;
rdev->scancode_wakeup_filter.mask = 0;
+ rdev->wakeup_protocol = RC_TYPE_UNKNOWN;
/* clear raw filters */
_img_ir_set_filter(priv, NULL);
@@ -685,7 +694,6 @@ success:
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 +709,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/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c
index 09314933ea08..044fd42b22a0 100644
--- a/drivers/media/rc/img-ir/img-ir-nec.c
+++ b/drivers/media/rc/img-ir/img-ir-nec.c
@@ -11,6 +11,7 @@
#include "img-ir-hw.h"
#include <linux/bitrev.h>
+#include <linux/log2.h>
/* Convert NEC data to a scancode */
static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols,
@@ -62,7 +63,23 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in,
data = in->data & 0xff;
data_m = in->mask & 0xff;
- if ((in->data | in->mask) & 0xff000000) {
+ protocols &= RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32;
+
+ /*
+ * If only one bit is set, we were requested to do an exact
+ * protocol. This should be the case for wakeup filters; for
+ * normal filters, guess the protocol from the scancode.
+ */
+ if (!is_power_of_2(protocols)) {
+ if ((in->data | in->mask) & 0xff000000)
+ protocols = RC_BIT_NEC32;
+ else if ((in->data | in->mask) & 0x00ff0000)
+ protocols = RC_BIT_NECX;
+ else
+ protocols = RC_BIT_NEC;
+ }
+
+ if (protocols == RC_BIT_NEC32) {
/* 32-bit NEC (used by Apple and TiVo remotes) */
/* scan encoding: as transmitted, MSBit = first received bit */
addr = bitrev8(in->data >> 24);
@@ -73,7 +90,7 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in,
data_m = bitrev8(in->mask >> 8);
data_inv = bitrev8(in->data >> 0);
data_inv_m = bitrev8(in->mask >> 0);
- } else if ((in->data | in->mask) & 0x00ff0000) {
+ } else if (protocols == RC_BIT_NECX) {
/* Extended NEC */
/* scan encoding AAaaDD */
addr = (in->data >> 16) & 0xff;
diff --git a/drivers/media/rc/img-ir/img-ir-sony.c b/drivers/media/rc/img-ir/img-ir-sony.c
index 7f7375f82ed6..3fcba271a419 100644
--- a/drivers/media/rc/img-ir/img-ir-sony.c
+++ b/drivers/media/rc/img-ir/img-ir-sony.c
@@ -68,19 +68,29 @@ static int img_ir_sony_filter(const struct rc_scancode_filter *in,
func = (in->data >> 0) & 0x7f;
func_m = (in->mask >> 0) & 0x7f;
- if (subdev & subdev_m) {
+ protocols &= RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20;
+
+ /*
+ * If only one bit is set, we were requested to do an exact
+ * protocol. This should be the case for wakeup filters; for
+ * normal filters, guess the protocol from the scancode.
+ */
+ if (!is_power_of_2(protocols)) {
+ if (subdev & subdev_m)
+ protocols = RC_BIT_SONY20;
+ else if (dev & dev_m & 0xe0)
+ protocols = RC_BIT_SONY15;
+ else
+ protocols = RC_BIT_SONY12;
+ }
+
+ if (protocols == RC_BIT_SONY20) {
/* can't encode subdev and higher device bits */
if (dev & dev_m & 0xe0)
return -EINVAL;
- /* subdevice (extended) bits only in 20 bit encoding */
- if (!(protocols & RC_BIT_SONY20))
- return -EINVAL;
len = 20;
dev_m &= 0x1f;
- } else if (dev & dev_m & 0xe0) {
- /* upper device bits only in 15 bit encoding */
- if (!(protocols & RC_BIT_SONY15))
- return -EINVAL;
+ } else if (protocols == RC_BIT_SONY15) {
len = 15;
subdev_m = 0;
} else {
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 0d14410471ba..68dfe8161cea 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -235,7 +235,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 75bdc49eeb3e..a4b12d261eb5 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) {
+ 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,172 @@ unlock:
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_20] = "rc-5x-20",
+ [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 & (1ULL << 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 protocol;
+ ssize_t rc;
+ u64 allowed;
+ 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;
+
+ if (sysfs_streq(buf, "none")) {
+ protocol = RC_TYPE_UNKNOWN;
+ } else {
+ for (i = 0; i < ARRAY_SIZE(proto_variant_names); i++) {
+ if ((allowed & (1ULL << i)) &&
+ sysfs_streq(buf, proto_variant_names[i])) {
+ protocol = i;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(proto_variant_names)) {
+ rc = -EINVAL;
+ goto out;
+ }
+ }
+
+ if (dev->wakeup_protocol != protocol) {
+ dev->wakeup_protocol = protocol;
+ IR_dprintk(1, "Wakeup protocol changed to %d\n", protocol);
+
+ if (protocol == RC_TYPE_RC6_MCE)
+ dev->scancode_wakeup_filter.data = 0x800f0000;
+ else
+ dev->scancode_wakeup_filter.data = 0;
+ dev->scancode_wakeup_filter.mask = 0;
+
+ rc = dev->s_wakeup_filter(dev, &dev->scancode_wakeup_filter);
+ if (rc == 0)
+ rc = len;
+ } else {
+ 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 +1449,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 +1462,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,
};
@@ -1323,15 +1470,6 @@ static struct attribute_group rc_dev_protocol_attr_grp = {
.attrs = rc_dev_protocol_attrs,
};
-static struct attribute *rc_dev_wakeup_protocol_attrs[] = {
- &dev_attr_wakeup_protocols.attr.attr,
- NULL,
-};
-
-static struct attribute_group rc_dev_wakeup_protocol_attr_grp = {
- .attrs = rc_dev_wakeup_protocol_attrs,
-};
-
static struct attribute *rc_dev_filter_attrs[] = {
&dev_attr_filter.attr.attr,
&dev_attr_filter_mask.attr.attr,
@@ -1345,6 +1483,7 @@ static struct attribute_group rc_dev_filter_attr_grp = {
static struct attribute *rc_dev_wakeup_filter_attrs[] = {
&dev_attr_wakeup_filter.attr.attr,
&dev_attr_wakeup_filter_mask.attr.attr,
+ &dev_attr_wakeup_protocols.attr,
NULL,
};
@@ -1475,8 +1614,6 @@ int rc_register_device(struct rc_dev *dev)
dev->sysfs_groups[attr++] = &rc_dev_filter_attr_grp;
if (dev->s_wakeup_filter)
dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp;
- if (dev->change_wakeup_protocol)
- dev->sysfs_groups[attr++] = &rc_dev_wakeup_protocol_attr_grp;
dev->sysfs_groups[attr++] = NULL;
rc = device_add(&dev->dev);