aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrant Grundler <grundler@parisc-linux.org>2006-10-10 17:42:51 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-10-17 17:46:33 -0400
commit4550718f6c75c9abe8b987fa4c625fd041aa95a2 (patch)
tree199876339655e70fdab7f72ea69d5d344a13843e
parent0e185b7922ac81516c5c4653dcf6aacbf6341e73 (diff)
USB: input: extract() and implement() are bit field manipulation routines
extract() and implement() have brain damaged attempts to handle 32-bit wide "fields". The problem is the index math in the original code didn't clear all the relevant bits. (offset >> 5) only compensated for 32-bit index. We need (offset >> 6) if we want to use 64-bit loads. But it was also wrong in that it tried to use quasi-aligned loads. Ie "report" was only incremented in multiples of 4 bytes and then the offset was masked off for values greater than 4 bytes. The right way is to pretend "report" points at a byte array. And offset is then only minor adjustment for < 8 bits of offset. "n" (field width) can then be as big as 24 (assuming 32-bit loads) since "offset" will never be bigger than 7. If someone needs either function to handle more than 24-bits, please document why - point at a specification or specific USB hid device - in comments in the code. extract/implement() are also an eyesore to read. Please banish whoever wrote it to read CodingStyle 3 times in a row to a classroom full of 1st graders armed with rubberbands. Or just flame them. Whatever. Globbing all the code together on two lines does NOT make it faster and is Just Wrong. I've tested this patch on j6000 (dual 750Mhz PA-RISC, 32-bit 2.6.12-rc5). Kyle McMartin tested on c3000 (up 400Mhz PA-RISC, same kernel). "p2-mate" (Peter De Schrijver?) tested on sb1250 (dual core Mips, broadcom "swarm" eval board). Signed-off-by: Grant Grundler <grundler@parisc-linux.org> Signed-off-by: Matthew Wilcox <matthew@wil.cx> Cc: Vojtech Pavlik <vojtech@suse.cz> Cc: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/input/hid-core.c24
1 files changed, 17 insertions, 7 deletions
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index a6738a83ff5b..feabda73a6f9 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -750,21 +750,31 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n)
750} 750}
751 751
752/* 752/*
753 * Extract/implement a data field from/to a report. 753 * Extract/implement a data field from/to a little endian report (bit array).
754 */ 754 */
755 755
756static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) 756static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
757{ 757{
758 report += (offset >> 5) << 2; offset &= 31; 758 u32 x;
759 return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1); 759
760 report += offset >> 3; /* adjust byte index */
761 offset &= 8 - 1;
762 x = get_unaligned((u32 *) report);
763 x = le32_to_cpu(x);
764 x = (x >> offset) & ((1 << n) - 1);
765 return x;
760} 766}
761 767
762static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) 768static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
763{ 769{
764 report += (offset >> 5) << 2; offset &= 31; 770 u32 x;
765 put_unaligned((get_unaligned((__le64*)report) 771
766 & cpu_to_le64(~((((__u64) 1 << n) - 1) << offset))) 772 report += offset >> 3;
767 | cpu_to_le64((__u64)value << offset), (__le64*)report); 773 offset &= 8 - 1;
774 x = get_unaligned((u32 *)report);
775 x &= cpu_to_le32(~((((__u32) 1 << n) - 1) << offset));
776 x |= cpu_to_le32(value << offset);
777 put_unaligned(x,(u32 *)report);
768} 778}
769 779
770/* 780/*