diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/input/hid-core.c | 59 |
1 files changed, 42 insertions, 17 deletions
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 45f44fe33bfe..6d42036c906c 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c | |||
@@ -270,7 +270,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign | |||
270 | * Read data value from item. | 270 | * Read data value from item. |
271 | */ | 271 | */ |
272 | 272 | ||
273 | static __inline__ __u32 item_udata(struct hid_item *item) | 273 | static u32 item_udata(struct hid_item *item) |
274 | { | 274 | { |
275 | switch (item->size) { | 275 | switch (item->size) { |
276 | case 1: return item->data.u8; | 276 | case 1: return item->data.u8; |
@@ -280,7 +280,7 @@ static __inline__ __u32 item_udata(struct hid_item *item) | |||
280 | return 0; | 280 | return 0; |
281 | } | 281 | } |
282 | 282 | ||
283 | static __inline__ __s32 item_sdata(struct hid_item *item) | 283 | static s32 item_sdata(struct hid_item *item) |
284 | { | 284 | { |
285 | switch (item->size) { | 285 | switch (item->size) { |
286 | case 1: return item->data.s8; | 286 | case 1: return item->data.s8; |
@@ -727,7 +727,7 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) | |||
727 | * done by hand. | 727 | * done by hand. |
728 | */ | 728 | */ |
729 | 729 | ||
730 | static __inline__ __s32 snto32(__u32 value, unsigned n) | 730 | static s32 snto32(__u32 value, unsigned n) |
731 | { | 731 | { |
732 | switch (n) { | 732 | switch (n) { |
733 | case 8: return ((__s8)value); | 733 | case 8: return ((__s8)value); |
@@ -741,9 +741,9 @@ static __inline__ __s32 snto32(__u32 value, unsigned n) | |||
741 | * Convert a signed 32-bit integer to a signed n-bit integer. | 741 | * Convert a signed 32-bit integer to a signed n-bit integer. |
742 | */ | 742 | */ |
743 | 743 | ||
744 | static __inline__ __u32 s32ton(__s32 value, unsigned n) | 744 | static u32 s32ton(__s32 value, unsigned n) |
745 | { | 745 | { |
746 | __s32 a = value >> (n - 1); | 746 | s32 a = value >> (n - 1); |
747 | if (a && a != -1) | 747 | if (a && a != -1) |
748 | return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; | 748 | return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; |
749 | return value & ((1 << n) - 1); | 749 | return value & ((1 << n) - 1); |
@@ -751,30 +751,55 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n) | |||
751 | 751 | ||
752 | /* | 752 | /* |
753 | * Extract/implement a data field from/to a little endian report (bit array). | 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". | ||
754 | */ | 762 | */ |
755 | 763 | ||
756 | static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) | 764 | static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) |
757 | { | 765 | { |
758 | u32 x; | 766 | u64 x; |
767 | |||
768 | WARN_ON(n > 32); | ||
759 | 769 | ||
760 | report += offset >> 3; /* adjust byte index */ | 770 | report += offset >> 3; /* adjust byte index */ |
761 | offset &= 8 - 1; | 771 | offset &= 7; /* now only need bit offset into one byte */ |
762 | x = get_unaligned((u32 *) report); | 772 | x = get_unaligned((u64 *) report); |
763 | x = le32_to_cpu(x); | 773 | x = le64_to_cpu(x); |
764 | x = (x >> offset) & ((1 << n) - 1); | 774 | x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ |
765 | return x; | 775 | return (u32) x; |
766 | } | 776 | } |
767 | 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 | */ | ||
768 | static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) | 786 | static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) |
769 | { | 787 | { |
770 | u32 x; | 788 | u64 x; |
789 | u64 m = (1ULL << n) - 1; | ||
790 | |||
791 | WARN_ON(n > 32); | ||
792 | |||
793 | WARN_ON(value > m); | ||
794 | value &= m; | ||
771 | 795 | ||
772 | report += offset >> 3; | 796 | report += offset >> 3; |
773 | offset &= 8 - 1; | 797 | offset &= 7; |
774 | x = get_unaligned((u32 *)report); | 798 | |
775 | x &= cpu_to_le32(~((((__u32) 1 << n) - 1) << offset)); | 799 | x = get_unaligned((u64 *)report); |
776 | x |= cpu_to_le32(value << offset); | 800 | x &= cpu_to_le64(~(m << offset)); |
777 | put_unaligned(x,(u32 *)report); | 801 | x |= cpu_to_le64(((u64) value) << offset); |
802 | put_unaligned(x, (u64 *) report); | ||
778 | } | 803 | } |
779 | 804 | ||
780 | /* | 805 | /* |