diff options
-rw-r--r-- | drivers/hid/hid-core.c | 33 |
1 files changed, 15 insertions, 18 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index bdb8cc89cacc..9985c0ab7c7f 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -1129,49 +1129,46 @@ EXPORT_SYMBOL_GPL(hid_field_extract); | |||
1129 | static void __implement(u8 *report, unsigned offset, int n, u32 value) | 1129 | static void __implement(u8 *report, unsigned offset, int n, u32 value) |
1130 | { | 1130 | { |
1131 | unsigned int idx = offset / 8; | 1131 | unsigned int idx = offset / 8; |
1132 | unsigned int size = offset + n; | ||
1133 | unsigned int bit_shift = offset % 8; | 1132 | unsigned int bit_shift = offset % 8; |
1134 | int bits_to_set = 8 - bit_shift; | 1133 | int bits_to_set = 8 - bit_shift; |
1135 | u8 bit_mask = 0xff << bit_shift; | ||
1136 | 1134 | ||
1137 | while (n - bits_to_set >= 0) { | 1135 | while (n - bits_to_set >= 0) { |
1138 | report[idx] &= ~bit_mask; | 1136 | report[idx] &= ~(0xff << bit_shift); |
1139 | report[idx] |= value << bit_shift; | 1137 | report[idx] |= value << bit_shift; |
1140 | value >>= bits_to_set; | 1138 | value >>= bits_to_set; |
1141 | n -= bits_to_set; | 1139 | n -= bits_to_set; |
1142 | bits_to_set = 8; | 1140 | bits_to_set = 8; |
1143 | bit_mask = 0xff; | ||
1144 | bit_shift = 0; | 1141 | bit_shift = 0; |
1145 | idx++; | 1142 | idx++; |
1146 | } | 1143 | } |
1147 | 1144 | ||
1148 | /* last nibble */ | 1145 | /* last nibble */ |
1149 | if (n) { | 1146 | if (n) { |
1150 | if (size % 8) | 1147 | u8 bit_mask = ((1U << n) - 1); |
1151 | bit_mask &= (1U << (size % 8)) - 1; | 1148 | report[idx] &= ~(bit_mask << bit_shift); |
1152 | report[idx] &= ~bit_mask; | 1149 | report[idx] |= value << bit_shift; |
1153 | report[idx] |= (value << bit_shift) & bit_mask; | ||
1154 | } | 1150 | } |
1155 | } | 1151 | } |
1156 | 1152 | ||
1157 | static void implement(const struct hid_device *hid, u8 *report, | 1153 | static void implement(const struct hid_device *hid, u8 *report, |
1158 | unsigned offset, unsigned n, u32 value) | 1154 | unsigned offset, unsigned n, u32 value) |
1159 | { | 1155 | { |
1160 | u64 m; | 1156 | if (unlikely(n > 32)) { |
1161 | |||
1162 | if (n > 32) { | ||
1163 | hid_warn(hid, "%s() called with n (%d) > 32! (%s)\n", | 1157 | hid_warn(hid, "%s() called with n (%d) > 32! (%s)\n", |
1164 | __func__, n, current->comm); | 1158 | __func__, n, current->comm); |
1165 | n = 32; | 1159 | n = 32; |
1160 | } else if (n < 32) { | ||
1161 | u32 m = (1U << n) - 1; | ||
1162 | |||
1163 | if (unlikely(value > m)) { | ||
1164 | hid_warn(hid, | ||
1165 | "%s() called with too large value %d (n: %d)! (%s)\n", | ||
1166 | __func__, value, n, current->comm); | ||
1167 | WARN_ON(1); | ||
1168 | value &= m; | ||
1169 | } | ||
1166 | } | 1170 | } |
1167 | 1171 | ||
1168 | m = (1ULL << n) - 1; | ||
1169 | if (value > m) | ||
1170 | hid_warn(hid, "%s() called with too large value %d! (%s)\n", | ||
1171 | __func__, value, current->comm); | ||
1172 | WARN_ON(value > m); | ||
1173 | value &= m; | ||
1174 | |||
1175 | __implement(report, offset, n, value); | 1172 | __implement(report, offset, n, value); |
1176 | } | 1173 | } |
1177 | 1174 | ||