Commit 1a811edf authored by Benjamin Tissoires's avatar Benjamin Tissoires
Browse files

Merge branch 'for-6.12/wacom' into for-linus

Various Wacom fixes (Jason Gerecke):
- Support for high-resolution wheel scrolling
- Support touchrings with relative motion
- Support devices with two touchrings
- Support sequence numbers smaller than 16-bit
parents 8357632e 84aecf2d
Loading
Loading
Loading
Loading
+81 −6
Original line number Diff line number Diff line
@@ -1906,11 +1906,12 @@ static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage,
		if ((code == ABS_X || code == ABS_Y) && !resolution) {
			resolution = WACOM_INTUOS_RES;
			hid_warn(input,
				 "Wacom usage (%d) missing resolution \n",
				 code);
				 "Using default resolution for axis type 0x%x code 0x%x\n",
				 type, code);
		}
		input_abs_set_res(input, code, resolution);
		break;
	case EV_REL:
	case EV_KEY:
	case EV_MSC:
	case EV_SW:
@@ -2047,7 +2048,23 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
		features->device_type |= WACOM_DEVICETYPE_PAD;
		break;
	case WACOM_HID_WD_TOUCHRING:
		if (field->flags & HID_MAIN_ITEM_RELATIVE) {
			wacom_wac->relring_count++;
			if (wacom_wac->relring_count == 1) {
				wacom_map_usage(input, usage, field, EV_REL, REL_WHEEL_HI_RES, 0);
				set_bit(REL_WHEEL, input->relbit);
			}
			else if (wacom_wac->relring_count == 2) {
				wacom_map_usage(input, usage, field, EV_REL, REL_HWHEEL_HI_RES, 0);
				set_bit(REL_HWHEEL, input->relbit);
			}
		} else {
			wacom_wac->absring_count++;
			if (wacom_wac->absring_count == 1)
				wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
			else if (wacom_wac->absring_count == 2)
				wacom_map_usage(input, usage, field, EV_ABS, ABS_THROTTLE, 0);
		}
		features->device_type |= WACOM_DEVICETYPE_PAD;
		break;
	case WACOM_HID_WD_TOUCHRINGSTATUS:
@@ -2112,7 +2129,10 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
		return;

	if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) {
		if (usage->hid != WACOM_HID_WD_TOUCHRING)
		bool is_abs_touchring = usage->hid == WACOM_HID_WD_TOUCHRING &&
					!(field->flags & HID_MAIN_ITEM_RELATIVE);

		if (!is_abs_touchring)
			wacom_wac->hid_data.inrange_state |= value;
	}

@@ -2165,6 +2185,52 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
				 hdev->product == 0x3AA)
				value = wacom_offset_rotation(input, usage, value, 1, 2);
		}
		else if (field->flags & HID_MAIN_ITEM_RELATIVE) {
			int hires_value = value * 120 / usage->resolution_multiplier;
			int *ring_value;
			int lowres_code;

			if (usage->code == REL_WHEEL_HI_RES) {
				/* We must invert the sign for vertical
				 * relative scrolling. Clockwise
				 * rotation produces positive values
				 * from HW, but userspace treats
				 * positive REL_WHEEL as a scroll *up*!
				 */
				hires_value = -hires_value;
				ring_value = &wacom_wac->hid_data.ring_value;
				lowres_code = REL_WHEEL;
			}
			else if (usage->code == REL_HWHEEL_HI_RES) {
				/* No need to invert the sign for
				 * horizontal relative scrolling.
				 * Clockwise rotation produces positive
				 * values from HW and userspace treats
				 * positive REL_HWHEEL as a scroll
				 * right.
				 */
				ring_value = &wacom_wac->hid_data.ring2_value;
				lowres_code = REL_HWHEEL;
			}
			else {
				hid_err(wacom->hdev, "unrecognized relative wheel with code %d\n",
					usage->code);
				break;
			}

			value = hires_value;
			*ring_value += hires_value;

			/* Emulate a legacy wheel click for every 120
			 * units of hi-res travel.
			 */
			if (*ring_value >= 120 || *ring_value <= -120) {
				int clicks = *ring_value / 120;

				input_event(input, usage->type, lowres_code, clicks);
				*ring_value -= clicks * 120;
			}
		}
		else {
			value = wacom_offset_rotation(input, usage, value, 1, 4);
		}
@@ -2322,6 +2388,9 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
		wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS3, 0);
		features->quirks &= ~WACOM_QUIRK_PEN_BUTTON3;
		break;
	case WACOM_HID_WD_SEQUENCENUMBER:
		wacom_wac->hid_data.sequence_number = -1;
		break;
	}
}

@@ -2446,9 +2515,15 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
		wacom_wac->hid_data.barrelswitch3 = value;
		return;
	case WACOM_HID_WD_SEQUENCENUMBER:
		if (wacom_wac->hid_data.sequence_number != value)
			hid_warn(hdev, "Dropped %hu packets", (unsigned short)(value - wacom_wac->hid_data.sequence_number));
		if (wacom_wac->hid_data.sequence_number != value &&
		    wacom_wac->hid_data.sequence_number >= 0) {
			int sequence_size = field->logical_maximum - field->logical_minimum + 1;
			int drop_count = (value - wacom_wac->hid_data.sequence_number) % sequence_size;
			hid_warn(hdev, "Dropped %d packets", drop_count);
		}
		wacom_wac->hid_data.sequence_number = value + 1;
		if (wacom_wac->hid_data.sequence_number > field->logical_maximum)
			wacom_wac->hid_data.sequence_number = field->logical_minimum;
		return;
	}

+5 −1
Original line number Diff line number Diff line
@@ -312,6 +312,8 @@ struct hid_data {
	int width;
	int height;
	int id;
	int ring_value;
	int ring2_value;
	int cc_report;
	int cc_index;
	int cc_value_index;
@@ -324,7 +326,7 @@ struct hid_data {
	int bat_connected;
	int ps_connected;
	bool pad_input_event_flag;
	unsigned short sequence_number;
	int sequence_number;
	ktime_t time_delayed;
};

@@ -355,6 +357,8 @@ struct wacom_wac {
	int num_contacts_left;
	u8 bt_features;
	u8 bt_high_speed;
	u8 absring_count;
	u8 relring_count;
	int mode_report;
	int mode_value;
	struct hid_data hid_data;