aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/rc
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2014-01-17 08:58:49 -0500
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-02-06 06:18:57 -0500
commit00942d1a1bd93ac108c1b92d504c568a37be1833 (patch)
tree34c0e172aac0ec1ebbb5bb27cf33703c96c44262 /drivers/media/rc
parent324a6673a8635f050b68d78066ba25a2a17c2817 (diff)
[media] media: rc: add sysfs scancode filtering interface
Add and document a generic sysfs based scancode filtering interface for making use of IR data matching hardware to filter out uninteresting scancodes. Two filters exist, one for normal operation and one for filtering scancodes which are permitted to wake the system from suspend. The following files are added to /sys/class/rc/rc?/: - filter: normal scancode filter value - filter_mask: normal scancode filter mask - wakeup_filter: wakeup scancode filter value - wakeup_filter_mask: wakeup scancode filter mask A new s_filter() driver callback is added which must arrange for the specified filter to be applied at the right time. Drivers can convert the scancode filter into a raw IR data filter, which can be applied immediately or later (for wake up filters). Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Mauro Carvalho Chehab <m.chehab@samsung.com> Cc: linux-media@vger.kernel.org Cc: Rob Landley <rob@landley.net> Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/rc')
-rw-r--r--drivers/media/rc/rc-main.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index f1b67db45e78..fa8b9575a84c 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -969,6 +969,130 @@ out:
969 return ret; 969 return ret;
970} 970}
971 971
972/**
973 * struct rc_filter_attribute - Device attribute relating to a filter type.
974 * @attr: Device attribute.
975 * @type: Filter type.
976 * @mask: false for filter value, true for filter mask.
977 */
978struct rc_filter_attribute {
979 struct device_attribute attr;
980 enum rc_filter_type type;
981 bool mask;
982};
983#define to_rc_filter_attr(a) container_of(a, struct rc_filter_attribute, attr)
984
985#define RC_FILTER_ATTR(_name, _mode, _show, _store, _type, _mask) \
986 struct rc_filter_attribute dev_attr_##_name = { \
987 .attr = __ATTR(_name, _mode, _show, _store), \
988 .type = (_type), \
989 .mask = (_mask), \
990 }
991
992/**
993 * show_filter() - shows the current scancode filter value or mask
994 * @device: the device descriptor
995 * @attr: the device attribute struct
996 * @buf: a pointer to the output buffer
997 *
998 * This routine is a callback routine to read a scancode filter value or mask.
999 * It is trigged by reading /sys/class/rc/rc?/[wakeup_]filter[_mask].
1000 * It prints the current scancode filter value or mask of the appropriate filter
1001 * type in hexadecimal into @buf and returns the size of the buffer.
1002 *
1003 * Bits of the filter value corresponding to set bits in the filter mask are
1004 * compared against input scancodes and non-matching scancodes are discarded.
1005 *
1006 * dev->lock is taken to guard against races between device registration,
1007 * store_filter and show_filter.
1008 */
1009static ssize_t show_filter(struct device *device,
1010 struct device_attribute *attr,
1011 char *buf)
1012{
1013 struct rc_dev *dev = to_rc_dev(device);
1014 struct rc_filter_attribute *fattr = to_rc_filter_attr(attr);
1015 u32 val;
1016
1017 /* Device is being removed */
1018 if (!dev)
1019 return -EINVAL;
1020
1021 mutex_lock(&dev->lock);
1022 if (!dev->s_filter)
1023 val = 0;
1024 else if (fattr->mask)
1025 val = dev->scancode_filters[fattr->type].mask;
1026 else
1027 val = dev->scancode_filters[fattr->type].data;
1028 mutex_unlock(&dev->lock);
1029
1030 return sprintf(buf, "%#x\n", val);
1031}
1032
1033/**
1034 * store_filter() - changes the scancode filter value
1035 * @device: the device descriptor
1036 * @attr: the device attribute struct
1037 * @buf: a pointer to the input buffer
1038 * @len: length of the input buffer
1039 *
1040 * This routine is for changing a scancode filter value or mask.
1041 * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]filter[_mask].
1042 * Returns -EINVAL if an invalid filter value for the current protocol was
1043 * specified or if scancode filtering is not supported by the driver, otherwise
1044 * returns @len.
1045 *
1046 * Bits of the filter value corresponding to set bits in the filter mask are
1047 * compared against input scancodes and non-matching scancodes are discarded.
1048 *
1049 * dev->lock is taken to guard against races between device registration,
1050 * store_filter and show_filter.
1051 */
1052static ssize_t store_filter(struct device *device,
1053 struct device_attribute *attr,
1054 const char *buf,
1055 size_t count)
1056{
1057 struct rc_dev *dev = to_rc_dev(device);
1058 struct rc_filter_attribute *fattr = to_rc_filter_attr(attr);
1059 struct rc_scancode_filter local_filter, *filter;
1060 int ret;
1061 unsigned long val;
1062
1063 /* Device is being removed */
1064 if (!dev)
1065 return -EINVAL;
1066
1067 ret = kstrtoul(buf, 0, &val);
1068 if (ret < 0)
1069 return ret;
1070
1071 /* Scancode filter not supported (but still accept 0) */
1072 if (!dev->s_filter)
1073 return val ? -EINVAL : count;
1074
1075 mutex_lock(&dev->lock);
1076
1077 /* Tell the driver about the new filter */
1078 filter = &dev->scancode_filters[fattr->type];
1079 local_filter = *filter;
1080 if (fattr->mask)
1081 local_filter.mask = val;
1082 else
1083 local_filter.data = val;
1084 ret = dev->s_filter(dev, fattr->type, &local_filter);
1085 if (ret < 0)
1086 goto unlock;
1087
1088 /* Success, commit the new filter */
1089 *filter = local_filter;
1090
1091unlock:
1092 mutex_unlock(&dev->lock);
1093 return count;
1094}
1095
972static void rc_dev_release(struct device *device) 1096static void rc_dev_release(struct device *device)
973{ 1097{
974} 1098}
@@ -1000,9 +1124,21 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
1000 */ 1124 */
1001static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR, 1125static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR,
1002 show_protocols, store_protocols); 1126 show_protocols, store_protocols);
1127static RC_FILTER_ATTR(filter, S_IRUGO|S_IWUSR,
1128 show_filter, store_filter, RC_FILTER_NORMAL, false);
1129static RC_FILTER_ATTR(filter_mask, S_IRUGO|S_IWUSR,
1130 show_filter, store_filter, RC_FILTER_NORMAL, true);
1131static RC_FILTER_ATTR(wakeup_filter, S_IRUGO|S_IWUSR,
1132 show_filter, store_filter, RC_FILTER_WAKEUP, false);
1133static RC_FILTER_ATTR(wakeup_filter_mask, S_IRUGO|S_IWUSR,
1134 show_filter, store_filter, RC_FILTER_WAKEUP, true);
1003 1135
1004static struct attribute *rc_dev_attrs[] = { 1136static struct attribute *rc_dev_attrs[] = {
1005 &dev_attr_protocols.attr, 1137 &dev_attr_protocols.attr,
1138 &dev_attr_filter.attr.attr,
1139 &dev_attr_filter_mask.attr.attr,
1140 &dev_attr_wakeup_filter.attr.attr,
1141 &dev_attr_wakeup_filter_mask.attr.attr,
1006 NULL, 1142 NULL,
1007}; 1143};
1008 1144