aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-core.c
diff options
context:
space:
mode:
authorPete Zaitcev <zaitcev@redhat.com>2010-04-12 14:16:11 -0400
committerJiri Kosina <jkosina@suse.cz>2010-04-13 09:55:49 -0400
commit75c28df87eb6d8e1389af67f26fbe2394e28385e (patch)
tree1a798db8c77e301508d26e8e10c1b1974bdef749 /drivers/hid/hid-core.c
parent6dec143a50c01ca0cc0afcbf5ea4bb8e87981edf (diff)
HID: non-overlapping zeroing of extra bits
From my review of the way the unused bits of report are being zeroed, it seems like there must be a bug. Currently, the zeroing is done in hid_output_field and it covers any bits between the last used bit and the end of the byte. But in case of, say, my keyboard, NumLock is mask 0x01 and CapsLock is 0x02. Invoking hid_output_field for NumLock definitely zeroes across CapsLock. The only reason this works is that the fields are sorted by the offset. It would be more correct and simpler to zero-fill the buffer into which the fields are set. The patch is tested with an IBM keyboard that is improperly sensitive to out-of-report pad bits, the extra bits are still zeroed and the fields continue to work as expected. It is also tested with good keyboards. In case, a related bug in RHEL 5 is tracked with Red Hat bug 513934. Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-core.c')
-rw-r--r--drivers/hid/hid-core.c6
1 files changed, 1 insertions, 5 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 9f92f629d448..8617aa97a9c8 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -940,13 +940,8 @@ static void hid_output_field(struct hid_field *field, __u8 *data)
940 unsigned count = field->report_count; 940 unsigned count = field->report_count;
941 unsigned offset = field->report_offset; 941 unsigned offset = field->report_offset;
942 unsigned size = field->report_size; 942 unsigned size = field->report_size;
943 unsigned bitsused = offset + count * size;
944 unsigned n; 943 unsigned n;
945 944
946 /* make sure the unused bits in the last byte are zeros */
947 if (count > 0 && size > 0 && (bitsused % 8) != 0)
948 data[(bitsused-1)/8] &= (1 << (bitsused % 8)) - 1;
949
950 for (n = 0; n < count; n++) { 945 for (n = 0; n < count; n++) {
951 if (field->logical_minimum < 0) /* signed values */ 946 if (field->logical_minimum < 0) /* signed values */
952 implement(data, offset + n * size, size, s32ton(field->value[n], size)); 947 implement(data, offset + n * size, size, s32ton(field->value[n], size));
@@ -966,6 +961,7 @@ void hid_output_report(struct hid_report *report, __u8 *data)
966 if (report->id > 0) 961 if (report->id > 0)
967 *data++ = report->id; 962 *data++ = report->id;
968 963
964 memset(data, 0, ((report->size - 1) >> 3) + 1);
969 for (n = 0; n < report->maxfield; n++) 965 for (n = 0; n < report->maxfield; n++)
970 hid_output_field(report->field[n], data); 966 hid_output_field(report->field[n], data);
971} 967}