aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2010-01-11 03:05:43 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-01-12 12:30:24 -0500
commit15e184afa83a45cf8bafdb9dc906b97a8fbc974f (patch)
tree12207c7afbcd660bdb66f444f5b51d89fff0133f /drivers/input
parente6edbdc52bc0755cbfe0721ca91d4fd87649bc13 (diff)
Input: add compat support for sysfs and /proc capabilities output
Input core displays capabilities bitmasks in form of one or more longs printed in hex form and separated by spaces. Unfortunately it does not work well for 32-bit applications running on 64-bit kernels since applications expect that number is "worth" only 32 bits when kernel advances by 64 bits. Fix that by ensuring that output produced for compat tasks uses 32-bit units. Reported-and-tested-by: Michael Tokarev <mjt@tls.msk.ru> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/input.c86
1 files changed, 71 insertions, 15 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c
index ab060710688f..30b503b8d67b 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -24,6 +24,7 @@
24#include <linux/mutex.h> 24#include <linux/mutex.h>
25#include <linux/rcupdate.h> 25#include <linux/rcupdate.h>
26#include <linux/smp_lock.h> 26#include <linux/smp_lock.h>
27#include "input-compat.h"
27 28
28MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); 29MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
29MODULE_DESCRIPTION("Input core"); 30MODULE_DESCRIPTION("Input core");
@@ -764,6 +765,40 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
764 return error; 765 return error;
765} 766}
766 767
768#ifdef CONFIG_COMPAT
769
770static int input_bits_to_string(char *buf, int buf_size,
771 unsigned long bits, bool skip_empty)
772{
773 int len = 0;
774
775 if (INPUT_COMPAT_TEST) {
776 u32 dword = bits >> 32;
777 if (dword || !skip_empty)
778 len += snprintf(buf, buf_size, "%x ", dword);
779
780 dword = bits & 0xffffffffUL;
781 if (dword || !skip_empty || len)
782 len += snprintf(buf + len, max(buf_size - len, 0),
783 "%x", dword);
784 } else {
785 if (bits || !skip_empty)
786 len += snprintf(buf, buf_size, "%lx", bits);
787 }
788
789 return len;
790}
791
792#else /* !CONFIG_COMPAT */
793
794static int input_bits_to_string(char *buf, int buf_size,
795 unsigned long bits, bool skip_empty)
796{
797 return bits || !skip_empty ?
798 snprintf(buf, buf_size, "%lx", bits) : 0;
799}
800
801#endif
767 802
768#ifdef CONFIG_PROC_FS 803#ifdef CONFIG_PROC_FS
769 804
@@ -832,14 +867,25 @@ static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
832 unsigned long *bitmap, int max) 867 unsigned long *bitmap, int max)
833{ 868{
834 int i; 869 int i;
835 870 bool skip_empty = true;
836 for (i = BITS_TO_LONGS(max) - 1; i > 0; i--) 871 char buf[18];
837 if (bitmap[i])
838 break;
839 872
840 seq_printf(seq, "B: %s=", name); 873 seq_printf(seq, "B: %s=", name);
841 for (; i >= 0; i--) 874
842 seq_printf(seq, "%lx%s", bitmap[i], i > 0 ? " " : ""); 875 for (i = BITS_TO_LONGS(max) - 1; i >= 0; i--) {
876 if (input_bits_to_string(buf, sizeof(buf),
877 bitmap[i], skip_empty)) {
878 skip_empty = false;
879 seq_printf(seq, "%s%s", buf, i > 0 ? " " : "");
880 }
881 }
882
883 /*
884 * If no output was produced print a single 0.
885 */
886 if (skip_empty)
887 seq_puts(seq, "0");
888
843 seq_putc(seq, '\n'); 889 seq_putc(seq, '\n');
844} 890}
845 891
@@ -1128,14 +1174,23 @@ static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
1128{ 1174{
1129 int i; 1175 int i;
1130 int len = 0; 1176 int len = 0;
1177 bool skip_empty = true;
1178
1179 for (i = BITS_TO_LONGS(max) - 1; i >= 0; i--) {
1180 len += input_bits_to_string(buf + len, max(buf_size - len, 0),
1181 bitmap[i], skip_empty);
1182 if (len) {
1183 skip_empty = false;
1184 if (i > 0)
1185 len += snprintf(buf + len, max(buf_size - len, 0), " ");
1186 }
1187 }
1131 1188
1132 for (i = BITS_TO_LONGS(max) - 1; i > 0; i--) 1189 /*
1133 if (bitmap[i]) 1190 * If no output was produced print a single 0.
1134 break; 1191 */
1135 1192 if (len == 0)
1136 for (; i >= 0; i--) 1193 len = snprintf(buf, buf_size, "%d", 0);
1137 len += snprintf(buf + len, max(buf_size - len, 0),
1138 "%lx%s", bitmap[i], i > 0 ? " " : "");
1139 1194
1140 if (add_cr) 1195 if (add_cr)
1141 len += snprintf(buf + len, max(buf_size - len, 0), "\n"); 1196 len += snprintf(buf + len, max(buf_size - len, 0), "\n");
@@ -1150,7 +1205,8 @@ static ssize_t input_dev_show_cap_##bm(struct device *dev, \
1150{ \ 1205{ \
1151 struct input_dev *input_dev = to_input_dev(dev); \ 1206 struct input_dev *input_dev = to_input_dev(dev); \
1152 int len = input_print_bitmap(buf, PAGE_SIZE, \ 1207 int len = input_print_bitmap(buf, PAGE_SIZE, \
1153 input_dev->bm##bit, ev##_MAX, 1); \ 1208 input_dev->bm##bit, ev##_MAX, \
1209 true); \
1154 return min_t(int, len, PAGE_SIZE); \ 1210 return min_t(int, len, PAGE_SIZE); \
1155} \ 1211} \
1156static DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL) 1212static DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL)
@@ -1214,7 +1270,7 @@ static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
1214 1270
1215 len = input_print_bitmap(&env->buf[env->buflen - 1], 1271 len = input_print_bitmap(&env->buf[env->buflen - 1],
1216 sizeof(env->buf) - env->buflen, 1272 sizeof(env->buf) - env->buflen,
1217 bitmap, max, 0); 1273 bitmap, max, false);
1218 if (len >= (sizeof(env->buf) - env->buflen)) 1274 if (len >= (sizeof(env->buf) - env->buflen))
1219 return -ENOMEM; 1275 return -ENOMEM;
1220 1276