Skip to content

Commit ff47973

Browse files
jigpuJiri Kosina
authored andcommitted
HID: wacom: generic: Treat serial number and related fields as unsigned
The HID descriptors for most Wacom devices oddly declare the serial number and other related fields as signed integers. When these numbers are ingested by the HID subsystem, they are automatically sign-extended into 32-bit integers. We treat the fields as unsigned elsewhere in the kernel and userspace, however, so this sign-extension causes problems. In particular, the sign-extended tool ID sent to userspace as ABS_MISC does not properly match unsigned IDs used by xf86-input-wacom and libwacom. We introduce a function 'wacom_s32tou' that can undo the automatic sign extension performed by 'hid_snto32'. We call this function when processing the serial number and related fields to ensure that we are dealing with and reporting the unsigned form. We opt to use this method rather than adding a descriptor fixup in 'wacom_hid_usage_quirk' since it should be more robust in the face of future devices. Ref: linuxwacom/input-wacom#134 Fixes: f85c9dc ("HID: wacom: generic: Support tool ID and additional tool types") CC: <[email protected]> # v4.10+ Signed-off-by: Jason Gerecke <[email protected]> Reviewed-by: Aaron Armstrong Skomra <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 43b7029 commit ff47973

File tree

2 files changed

+21
-4
lines changed

2 files changed

+21
-4
lines changed

drivers/hid/wacom.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,21 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
202202
}
203203
}
204204

205+
/*
206+
* Convert a signed 32-bit integer to an unsigned n-bit integer. Undoes
207+
* the normally-helpful work of 'hid_snto32' for fields that use signed
208+
* ranges for questionable reasons.
209+
*/
210+
static inline __u32 wacom_s32tou(s32 value, __u8 n)
211+
{
212+
switch (n) {
213+
case 8: return ((__u8)value);
214+
case 16: return ((__u16)value);
215+
case 32: return ((__u32)value);
216+
}
217+
return value & (1 << (n - 1)) ? value & (~(~0U << n)) : value;
218+
}
219+
205220
extern const struct hid_device_id wacom_ids[];
206221

207222
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);

drivers/hid/wacom_wac.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2303,7 +2303,7 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
23032303
case HID_DG_TOOLSERIALNUMBER:
23042304
if (value) {
23052305
wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL);
2306-
wacom_wac->serial[0] |= (__u32)value;
2306+
wacom_wac->serial[0] |= wacom_s32tou(value, field->report_size);
23072307
}
23082308
return;
23092309
case HID_DG_TWIST:
@@ -2319,15 +2319,17 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
23192319
return;
23202320
case WACOM_HID_WD_SERIALHI:
23212321
if (value) {
2322+
__u32 raw_value = wacom_s32tou(value, field->report_size);
2323+
23222324
wacom_wac->serial[0] = (wacom_wac->serial[0] & 0xFFFFFFFF);
2323-
wacom_wac->serial[0] |= ((__u64)value) << 32;
2325+
wacom_wac->serial[0] |= ((__u64)raw_value) << 32;
23242326
/*
23252327
* Non-USI EMR devices may contain additional tool type
23262328
* information here. See WACOM_HID_WD_TOOLTYPE case for
23272329
* more details.
23282330
*/
23292331
if (value >> 20 == 1) {
2330-
wacom_wac->id[0] |= value & 0xFFFFF;
2332+
wacom_wac->id[0] |= raw_value & 0xFFFFF;
23312333
}
23322334
}
23332335
return;
@@ -2339,7 +2341,7 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
23392341
* bitwise OR so the complete value can be built
23402342
* up over time :(
23412343
*/
2342-
wacom_wac->id[0] |= value;
2344+
wacom_wac->id[0] |= wacom_s32tou(value, field->report_size);
23432345
return;
23442346
case WACOM_HID_WD_OFFSETLEFT:
23452347
if (features->offset_left && value != features->offset_left)

0 commit comments

Comments
 (0)