diff options
Diffstat (limited to 'drivers/media/rc/rc-main.c')
-rw-r--r-- | drivers/media/rc/rc-main.c | 98 |
1 files changed, 63 insertions, 35 deletions
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 99697aae92ff..970b93d6f399 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c | |||
@@ -633,19 +633,13 @@ EXPORT_SYMBOL_GPL(rc_repeat); | |||
633 | static void ir_do_keydown(struct rc_dev *dev, int scancode, | 633 | static void ir_do_keydown(struct rc_dev *dev, int scancode, |
634 | u32 keycode, u8 toggle) | 634 | u32 keycode, u8 toggle) |
635 | { | 635 | { |
636 | struct rc_scancode_filter *filter; | 636 | bool new_event = (!dev->keypressed || |
637 | bool new_event = !dev->keypressed || | 637 | dev->last_scancode != scancode || |
638 | dev->last_scancode != scancode || | 638 | dev->last_toggle != toggle); |
639 | dev->last_toggle != toggle; | ||
640 | 639 | ||
641 | if (new_event && dev->keypressed) | 640 | if (new_event && dev->keypressed) |
642 | ir_do_keyup(dev, false); | 641 | ir_do_keyup(dev, false); |
643 | 642 | ||
644 | /* Generic scancode filtering */ | ||
645 | filter = &dev->scancode_filters[RC_FILTER_NORMAL]; | ||
646 | if (filter->mask && ((scancode ^ filter->data) & filter->mask)) | ||
647 | return; | ||
648 | |||
649 | input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); | 643 | input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); |
650 | 644 | ||
651 | if (new_event && keycode != KEY_RESERVED) { | 645 | if (new_event && keycode != KEY_RESERVED) { |
@@ -923,6 +917,7 @@ static ssize_t store_protocols(struct device *device, | |||
923 | int rc, i, count = 0; | 917 | int rc, i, count = 0; |
924 | ssize_t ret; | 918 | ssize_t ret; |
925 | int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); | 919 | int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); |
920 | int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter); | ||
926 | struct rc_scancode_filter local_filter, *filter; | 921 | struct rc_scancode_filter local_filter, *filter; |
927 | 922 | ||
928 | /* Device is being removed */ | 923 | /* Device is being removed */ |
@@ -1007,24 +1002,23 @@ static ssize_t store_protocols(struct device *device, | |||
1007 | * Fall back to clearing the filter. | 1002 | * Fall back to clearing the filter. |
1008 | */ | 1003 | */ |
1009 | filter = &dev->scancode_filters[fattr->type]; | 1004 | filter = &dev->scancode_filters[fattr->type]; |
1010 | if (old_type != type && filter->mask) { | 1005 | set_filter = (fattr->type == RC_FILTER_NORMAL) |
1006 | ? dev->s_filter : dev->s_wakeup_filter; | ||
1007 | |||
1008 | if (set_filter && old_type != type && filter->mask) { | ||
1011 | local_filter = *filter; | 1009 | local_filter = *filter; |
1012 | if (!type) { | 1010 | if (!type) { |
1013 | /* no protocol => clear filter */ | 1011 | /* no protocol => clear filter */ |
1014 | ret = -1; | 1012 | ret = -1; |
1015 | } else if (!dev->s_filter) { | ||
1016 | /* generic filtering => accept any filter */ | ||
1017 | ret = 0; | ||
1018 | } else { | 1013 | } else { |
1019 | /* hardware filtering => try setting, otherwise clear */ | 1014 | /* hardware filtering => try setting, otherwise clear */ |
1020 | ret = dev->s_filter(dev, fattr->type, &local_filter); | 1015 | ret = set_filter(dev, &local_filter); |
1021 | } | 1016 | } |
1022 | if (ret < 0) { | 1017 | if (ret < 0) { |
1023 | /* clear the filter */ | 1018 | /* clear the filter */ |
1024 | local_filter.data = 0; | 1019 | local_filter.data = 0; |
1025 | local_filter.mask = 0; | 1020 | local_filter.mask = 0; |
1026 | if (dev->s_filter) | 1021 | set_filter(dev, &local_filter); |
1027 | dev->s_filter(dev, fattr->type, &local_filter); | ||
1028 | } | 1022 | } |
1029 | 1023 | ||
1030 | /* commit the new filter */ | 1024 | /* commit the new filter */ |
@@ -1068,7 +1062,10 @@ static ssize_t show_filter(struct device *device, | |||
1068 | return -EINVAL; | 1062 | return -EINVAL; |
1069 | 1063 | ||
1070 | mutex_lock(&dev->lock); | 1064 | mutex_lock(&dev->lock); |
1071 | if (fattr->mask) | 1065 | if ((fattr->type == RC_FILTER_NORMAL && !dev->s_filter) || |
1066 | (fattr->type == RC_FILTER_WAKEUP && !dev->s_wakeup_filter)) | ||
1067 | val = 0; | ||
1068 | else if (fattr->mask) | ||
1072 | val = dev->scancode_filters[fattr->type].mask; | 1069 | val = dev->scancode_filters[fattr->type].mask; |
1073 | else | 1070 | else |
1074 | val = dev->scancode_filters[fattr->type].data; | 1071 | val = dev->scancode_filters[fattr->type].data; |
@@ -1106,6 +1103,7 @@ static ssize_t store_filter(struct device *device, | |||
1106 | struct rc_scancode_filter local_filter, *filter; | 1103 | struct rc_scancode_filter local_filter, *filter; |
1107 | int ret; | 1104 | int ret; |
1108 | unsigned long val; | 1105 | unsigned long val; |
1106 | int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter); | ||
1109 | 1107 | ||
1110 | /* Device is being removed */ | 1108 | /* Device is being removed */ |
1111 | if (!dev) | 1109 | if (!dev) |
@@ -1115,9 +1113,11 @@ static ssize_t store_filter(struct device *device, | |||
1115 | if (ret < 0) | 1113 | if (ret < 0) |
1116 | return ret; | 1114 | return ret; |
1117 | 1115 | ||
1118 | /* Scancode filter not supported (but still accept 0) */ | 1116 | /* Can the scancode filter be set? */ |
1119 | if (!dev->s_filter && fattr->type != RC_FILTER_NORMAL) | 1117 | set_filter = (fattr->type == RC_FILTER_NORMAL) ? dev->s_filter : |
1120 | return val ? -EINVAL : count; | 1118 | dev->s_wakeup_filter; |
1119 | if (!set_filter) | ||
1120 | return -EINVAL; | ||
1121 | 1121 | ||
1122 | mutex_lock(&dev->lock); | 1122 | mutex_lock(&dev->lock); |
1123 | 1123 | ||
@@ -1128,16 +1128,16 @@ static ssize_t store_filter(struct device *device, | |||
1128 | local_filter.mask = val; | 1128 | local_filter.mask = val; |
1129 | else | 1129 | else |
1130 | local_filter.data = val; | 1130 | local_filter.data = val; |
1131 | |||
1131 | if (!dev->enabled_protocols[fattr->type] && local_filter.mask) { | 1132 | if (!dev->enabled_protocols[fattr->type] && local_filter.mask) { |
1132 | /* refuse to set a filter unless a protocol is enabled */ | 1133 | /* refuse to set a filter unless a protocol is enabled */ |
1133 | ret = -EINVAL; | 1134 | ret = -EINVAL; |
1134 | goto unlock; | 1135 | goto unlock; |
1135 | } | 1136 | } |
1136 | if (dev->s_filter) { | 1137 | |
1137 | ret = dev->s_filter(dev, fattr->type, &local_filter); | 1138 | ret = set_filter(dev, &local_filter); |
1138 | if (ret < 0) | 1139 | if (ret < 0) |
1139 | goto unlock; | 1140 | goto unlock; |
1140 | } | ||
1141 | 1141 | ||
1142 | /* Success, commit the new filter */ | 1142 | /* Success, commit the new filter */ |
1143 | *filter = local_filter; | 1143 | *filter = local_filter; |
@@ -1189,27 +1189,45 @@ static RC_FILTER_ATTR(wakeup_filter, S_IRUGO|S_IWUSR, | |||
1189 | static RC_FILTER_ATTR(wakeup_filter_mask, S_IRUGO|S_IWUSR, | 1189 | static RC_FILTER_ATTR(wakeup_filter_mask, S_IRUGO|S_IWUSR, |
1190 | show_filter, store_filter, RC_FILTER_WAKEUP, true); | 1190 | show_filter, store_filter, RC_FILTER_WAKEUP, true); |
1191 | 1191 | ||
1192 | static struct attribute *rc_dev_attrs[] = { | 1192 | static struct attribute *rc_dev_protocol_attrs[] = { |
1193 | &dev_attr_protocols.attr.attr, | 1193 | &dev_attr_protocols.attr.attr, |
1194 | NULL, | ||
1195 | }; | ||
1196 | |||
1197 | static struct attribute_group rc_dev_protocol_attr_grp = { | ||
1198 | .attrs = rc_dev_protocol_attrs, | ||
1199 | }; | ||
1200 | |||
1201 | static struct attribute *rc_dev_wakeup_protocol_attrs[] = { | ||
1194 | &dev_attr_wakeup_protocols.attr.attr, | 1202 | &dev_attr_wakeup_protocols.attr.attr, |
1203 | NULL, | ||
1204 | }; | ||
1205 | |||
1206 | static struct attribute_group rc_dev_wakeup_protocol_attr_grp = { | ||
1207 | .attrs = rc_dev_wakeup_protocol_attrs, | ||
1208 | }; | ||
1209 | |||
1210 | static struct attribute *rc_dev_filter_attrs[] = { | ||
1195 | &dev_attr_filter.attr.attr, | 1211 | &dev_attr_filter.attr.attr, |
1196 | &dev_attr_filter_mask.attr.attr, | 1212 | &dev_attr_filter_mask.attr.attr, |
1197 | &dev_attr_wakeup_filter.attr.attr, | ||
1198 | &dev_attr_wakeup_filter_mask.attr.attr, | ||
1199 | NULL, | 1213 | NULL, |
1200 | }; | 1214 | }; |
1201 | 1215 | ||
1202 | static struct attribute_group rc_dev_attr_grp = { | 1216 | static struct attribute_group rc_dev_filter_attr_grp = { |
1203 | .attrs = rc_dev_attrs, | 1217 | .attrs = rc_dev_filter_attrs, |
1204 | }; | 1218 | }; |
1205 | 1219 | ||
1206 | static const struct attribute_group *rc_dev_attr_groups[] = { | 1220 | static struct attribute *rc_dev_wakeup_filter_attrs[] = { |
1207 | &rc_dev_attr_grp, | 1221 | &dev_attr_wakeup_filter.attr.attr, |
1208 | NULL | 1222 | &dev_attr_wakeup_filter_mask.attr.attr, |
1223 | NULL, | ||
1224 | }; | ||
1225 | |||
1226 | static struct attribute_group rc_dev_wakeup_filter_attr_grp = { | ||
1227 | .attrs = rc_dev_wakeup_filter_attrs, | ||
1209 | }; | 1228 | }; |
1210 | 1229 | ||
1211 | static struct device_type rc_dev_type = { | 1230 | static struct device_type rc_dev_type = { |
1212 | .groups = rc_dev_attr_groups, | ||
1213 | .release = rc_dev_release, | 1231 | .release = rc_dev_release, |
1214 | .uevent = rc_dev_uevent, | 1232 | .uevent = rc_dev_uevent, |
1215 | }; | 1233 | }; |
@@ -1266,7 +1284,7 @@ int rc_register_device(struct rc_dev *dev) | |||
1266 | static bool raw_init = false; /* raw decoders loaded? */ | 1284 | static bool raw_init = false; /* raw decoders loaded? */ |
1267 | struct rc_map *rc_map; | 1285 | struct rc_map *rc_map; |
1268 | const char *path; | 1286 | const char *path; |
1269 | int rc, devno; | 1287 | int rc, devno, attr = 0; |
1270 | 1288 | ||
1271 | if (!dev || !dev->map_name) | 1289 | if (!dev || !dev->map_name) |
1272 | return -EINVAL; | 1290 | return -EINVAL; |
@@ -1294,6 +1312,16 @@ int rc_register_device(struct rc_dev *dev) | |||
1294 | return -ENOMEM; | 1312 | return -ENOMEM; |
1295 | } while (test_and_set_bit(devno, ir_core_dev_number)); | 1313 | } while (test_and_set_bit(devno, ir_core_dev_number)); |
1296 | 1314 | ||
1315 | dev->dev.groups = dev->sysfs_groups; | ||
1316 | dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp; | ||
1317 | if (dev->s_filter) | ||
1318 | dev->sysfs_groups[attr++] = &rc_dev_filter_attr_grp; | ||
1319 | if (dev->s_wakeup_filter) | ||
1320 | dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp; | ||
1321 | if (dev->change_wakeup_protocol) | ||
1322 | dev->sysfs_groups[attr++] = &rc_dev_wakeup_protocol_attr_grp; | ||
1323 | dev->sysfs_groups[attr++] = NULL; | ||
1324 | |||
1297 | /* | 1325 | /* |
1298 | * Take the lock here, as the device sysfs node will appear | 1326 | * Take the lock here, as the device sysfs node will appear |
1299 | * when device_add() is called, which may trigger an ir-keytable udev | 1327 | * when device_add() is called, which may trigger an ir-keytable udev |