hid-core: big-endian fix fix

Adam Kropelin had posted 32-bit fix in June 2005 about two weeks after I
originally had posted my fixes for big endian support. Adam has a UPS
device which reports LINEV using 32-bits.

Added comments to describe the limitations of the code.

extract() is the same version I posted earlier and tested in user space.
Made similar changes to implement() routine. I've written (and will
shortly post) a test for implement(). Code tested on C3600 (parisc) with
USB keyboard/mouse attached.


I've dropped test_implement.c and a few other user space test programs on
http://iou.parisc-linux.org/~grundler/tests/

-rw-r--r-- 1 grundler grundler 1750 Oct 18 09:13 test_extract.c
-rw-r--r-- 1 grundler grundler 561 Jan 25 2006 test_ffs.c
-rw-r--r-- 1 grundler users 7175 Apr 8 2005 test_fls.c
-rw-r--r-- 1 grundler grundler 206 Sep 1 15:52 test_gettimeofday.c
-rw-r--r-- 1 grundler grundler 1886 Oct 19 09:20 test_implement.c
-rw-r--r-- 1 grundler users 2707 Jun 4 2005 test_unaligned.c

I would appreciate if someone else would look at the output of
test_implement.c to make it does The Right Thing.

Signed-off-by: Grant Grundler <grundler@parisc-linux.org>
Cc: Matthew Wilcox <matthew@wil.cx>
Cc: Dmitry Torokhov <dtor@mail.ru>
Acked-By: Adam Kropelin <akropel1@rochester.rr.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>


authored by Grant Grundler and committed by Greg Kroah-Hartman 68717950 bc724b98

+42 -17
+42 -17
drivers/usb/input/hid-core.c
··· 270 * Read data value from item. 271 */ 272 273 - static __inline__ __u32 item_udata(struct hid_item *item) 274 { 275 switch (item->size) { 276 case 1: return item->data.u8; ··· 280 return 0; 281 } 282 283 - static __inline__ __s32 item_sdata(struct hid_item *item) 284 { 285 switch (item->size) { 286 case 1: return item->data.s8; ··· 727 * done by hand. 728 */ 729 730 - static __inline__ __s32 snto32(__u32 value, unsigned n) 731 { 732 switch (n) { 733 case 8: return ((__s8)value); ··· 741 * Convert a signed 32-bit integer to a signed n-bit integer. 742 */ 743 744 - static __inline__ __u32 s32ton(__s32 value, unsigned n) 745 { 746 - __s32 a = value >> (n - 1); 747 if (a && a != -1) 748 return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; 749 return value & ((1 << n) - 1); ··· 751 752 /* 753 * Extract/implement a data field from/to a little endian report (bit array). 754 */ 755 756 static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) 757 { 758 - u32 x; 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; 766 } 767 768 static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) 769 { 770 - u32 x; 771 772 report += offset >> 3; 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); 778 } 779 780 /*
··· 270 * Read data value from item. 271 */ 272 273 + static u32 item_udata(struct hid_item *item) 274 { 275 switch (item->size) { 276 case 1: return item->data.u8; ··· 280 return 0; 281 } 282 283 + static s32 item_sdata(struct hid_item *item) 284 { 285 switch (item->size) { 286 case 1: return item->data.s8; ··· 727 * done by hand. 728 */ 729 730 + static s32 snto32(__u32 value, unsigned n) 731 { 732 switch (n) { 733 case 8: return ((__s8)value); ··· 741 * Convert a signed 32-bit integer to a signed n-bit integer. 742 */ 743 744 + static u32 s32ton(__s32 value, unsigned n) 745 { 746 + s32 a = value >> (n - 1); 747 if (a && a != -1) 748 return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; 749 return value & ((1 << n) - 1); ··· 751 752 /* 753 * Extract/implement a data field from/to a little endian report (bit array). 754 + * 755 + * Code sort-of follows HID spec: 756 + * http://www.usb.org/developers/devclass_docs/HID1_11.pdf 757 + * 758 + * While the USB HID spec allows unlimited length bit fields in "report 759 + * descriptors", most devices never use more than 16 bits. 760 + * One model of UPS is claimed to report "LINEV" as a 32-bit field. 761 + * Search linux-kernel and linux-usb-devel archives for "hid-core extract". 762 */ 763 764 static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) 765 { 766 + u64 x; 767 + 768 + WARN_ON(n > 32); 769 770 report += offset >> 3; /* adjust byte index */ 771 + offset &= 7; /* now only need bit offset into one byte */ 772 + x = get_unaligned((u64 *) report); 773 + x = le64_to_cpu(x); 774 + x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ 775 + return (u32) x; 776 } 777 778 + /* 779 + * "implement" : set bits in a little endian bit stream. 780 + * Same concepts as "extract" (see comments above). 781 + * The data mangled in the bit stream remains in little endian 782 + * order the whole time. It make more sense to talk about 783 + * endianness of register values by considering a register 784 + * a "cached" copy of the little endiad bit stream. 785 + */ 786 static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) 787 { 788 + u64 x; 789 + u64 m = (1ULL << n) - 1; 790 + 791 + WARN_ON(n > 32); 792 + 793 + WARN_ON(value > m); 794 + value &= m; 795 796 report += offset >> 3; 797 + offset &= 7; 798 + 799 + x = get_unaligned((u64 *)report); 800 + x &= cpu_to_le64(~(m << offset)); 801 + x |= cpu_to_le64(((u64) value) << offset); 802 + put_unaligned(x, (u64 *) report); 803 } 804 805 /*