Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d189053 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull HID updates from Jiri Kosina:

 - suspend/resume handling fix for Raydium I2C-connected touchscreen
   from Aaron Ma

 - protocol fixup for certain BT-connected Wacoms from Aaron Armstrong
   Skomra

 - battery level reporting fix on BT-connected mice from Dmitry Torokhov

 - hidraw race condition fix from Rodrigo Rivas Costa

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid:
  HID: i2c-hid: fix inverted return value from i2c_hid_command()
  HID: i2c-hid: Fix resume issue on Raydium touchscreen device
  HID: wacom: bluetooth: send exit report for recent Bluetooth devices
  HID: hidraw: Fix crash on HIDIOCGFEATURE with a destroyed device
  HID: input: fix battery level reporting on BT mice
parents 41e3bef5 b658912c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -525,6 +525,9 @@
#define I2C_VENDOR_ID_HANTICK		0x0911
#define I2C_PRODUCT_ID_HANTICK_5288	0x5288

#define I2C_VENDOR_ID_RAYD		0x2386
#define I2C_PRODUCT_ID_RAYD_3118	0x3118

#define USB_VENDOR_ID_HANWANG		0x0b57
#define USB_DEVICE_ID_HANWANG_TABLET_FIRST	0x5000
#define USB_DEVICE_ID_HANWANG_TABLET_LAST	0x8fff
+17 −7
Original line number Diff line number Diff line
@@ -387,7 +387,8 @@ static int hidinput_get_battery_property(struct power_supply *psy,
		break;

	case POWER_SUPPLY_PROP_CAPACITY:
		if (dev->battery_report_type == HID_FEATURE_REPORT) {
		if (dev->battery_status != HID_BATTERY_REPORTED &&
		    !dev->battery_avoid_query) {
			value = hidinput_query_battery_capacity(dev);
			if (value < 0)
				return value;
@@ -403,17 +404,17 @@ static int hidinput_get_battery_property(struct power_supply *psy,
		break;

	case POWER_SUPPLY_PROP_STATUS:
		if (!dev->battery_reported &&
		    dev->battery_report_type == HID_FEATURE_REPORT) {
		if (dev->battery_status != HID_BATTERY_REPORTED &&
		    !dev->battery_avoid_query) {
			value = hidinput_query_battery_capacity(dev);
			if (value < 0)
				return value;

			dev->battery_capacity = value;
			dev->battery_reported = true;
			dev->battery_status = HID_BATTERY_QUERIED;
		}

		if (!dev->battery_reported)
		if (dev->battery_status == HID_BATTERY_UNKNOWN)
			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
		else if (dev->battery_capacity == 100)
			val->intval = POWER_SUPPLY_STATUS_FULL;
@@ -486,6 +487,14 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
	dev->battery_report_type = report_type;
	dev->battery_report_id = field->report->id;

	/*
	 * Stylus is normally not connected to the device and thus we
	 * can't query the device and get meaningful battery strength.
	 * We have to wait for the device to report it on its own.
	 */
	dev->battery_avoid_query = report_type == HID_INPUT_REPORT &&
				   field->physical == HID_DG_STYLUS;

	dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg);
	if (IS_ERR(dev->battery)) {
		error = PTR_ERR(dev->battery);
@@ -530,9 +539,10 @@ static void hidinput_update_battery(struct hid_device *dev, int value)

	capacity = hidinput_scale_battery_capacity(dev, value);

	if (!dev->battery_reported || capacity != dev->battery_capacity) {
	if (dev->battery_status != HID_BATTERY_REPORTED ||
	    capacity != dev->battery_capacity) {
		dev->battery_capacity = capacity;
		dev->battery_reported = true;
		dev->battery_status = HID_BATTERY_REPORTED;
		power_supply_changed(dev->battery);
	}
}
+5 −0
Original line number Diff line number Diff line
@@ -192,6 +192,11 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
	int ret = 0, len;
	unsigned char report_number;

	if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
		ret = -ENODEV;
		goto out;
	}

	dev = hidraw_table[minor]->hid;

	if (!dev->ll_driver->raw_request) {
+13 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@
/* quirks to control the device */
#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV	BIT(0)
#define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET	BIT(1)
#define I2C_HID_QUIRK_RESEND_REPORT_DESCR	BIT(2)

/* flags */
#define I2C_HID_STARTED		0
@@ -171,6 +172,8 @@ static const struct i2c_hid_quirks {
		I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
	{ I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
		I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
	{ I2C_VENDOR_ID_RAYD, I2C_PRODUCT_ID_RAYD_3118,
		I2C_HID_QUIRK_RESEND_REPORT_DESCR },
	{ 0, 0 }
};

@@ -1220,6 +1223,16 @@ static int i2c_hid_resume(struct device *dev)
	if (ret)
		return ret;

	/* RAYDIUM device (2386:3118) need to re-send report descr cmd
	 * after resume, after this it will be back normal.
	 * otherwise it issues too many incomplete reports.
	 */
	if (ihid->quirks & I2C_HID_QUIRK_RESEND_REPORT_DESCR) {
		ret = i2c_hid_command(client, &hid_report_descr_cmd, NULL, 0);
		if (ret)
			return ret;
	}

	if (hid->driver && hid->driver->reset_resume) {
		ret = hid->driver->reset_resume(hid);
		return ret;
+46 −30
Original line number Diff line number Diff line
@@ -689,6 +689,45 @@ static int wacom_intuos_get_tool_type(int tool_id)
	return tool_type;
}

static void wacom_exit_report(struct wacom_wac *wacom)
{
	struct input_dev *input = wacom->pen_input;
	struct wacom_features *features = &wacom->features;
	unsigned char *data = wacom->data;
	int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0;

	/*
	 * Reset all states otherwise we lose the initial states
	 * when in-prox next time
	 */
	input_report_abs(input, ABS_X, 0);
	input_report_abs(input, ABS_Y, 0);
	input_report_abs(input, ABS_DISTANCE, 0);
	input_report_abs(input, ABS_TILT_X, 0);
	input_report_abs(input, ABS_TILT_Y, 0);
	if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
		input_report_key(input, BTN_LEFT, 0);
		input_report_key(input, BTN_MIDDLE, 0);
		input_report_key(input, BTN_RIGHT, 0);
		input_report_key(input, BTN_SIDE, 0);
		input_report_key(input, BTN_EXTRA, 0);
		input_report_abs(input, ABS_THROTTLE, 0);
		input_report_abs(input, ABS_RZ, 0);
	} else {
		input_report_abs(input, ABS_PRESSURE, 0);
		input_report_key(input, BTN_STYLUS, 0);
		input_report_key(input, BTN_STYLUS2, 0);
		input_report_key(input, BTN_TOUCH, 0);
		input_report_abs(input, ABS_WHEEL, 0);
		if (features->type >= INTUOS3S)
			input_report_abs(input, ABS_Z, 0);
	}
	input_report_key(input, wacom->tool[idx], 0);
	input_report_abs(input, ABS_MISC, 0); /* reset tool id */
	input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
	wacom->id[idx] = 0;
}

static int wacom_intuos_inout(struct wacom_wac *wacom)
{
	struct wacom_features *features = &wacom->features;
@@ -741,36 +780,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
		if (!wacom->id[idx])
			return 1;

		/*
		 * Reset all states otherwise we lose the initial states
		 * when in-prox next time
		 */
		input_report_abs(input, ABS_X, 0);
		input_report_abs(input, ABS_Y, 0);
		input_report_abs(input, ABS_DISTANCE, 0);
		input_report_abs(input, ABS_TILT_X, 0);
		input_report_abs(input, ABS_TILT_Y, 0);
		if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
			input_report_key(input, BTN_LEFT, 0);
			input_report_key(input, BTN_MIDDLE, 0);
			input_report_key(input, BTN_RIGHT, 0);
			input_report_key(input, BTN_SIDE, 0);
			input_report_key(input, BTN_EXTRA, 0);
			input_report_abs(input, ABS_THROTTLE, 0);
			input_report_abs(input, ABS_RZ, 0);
		} else {
			input_report_abs(input, ABS_PRESSURE, 0);
			input_report_key(input, BTN_STYLUS, 0);
			input_report_key(input, BTN_STYLUS2, 0);
			input_report_key(input, BTN_TOUCH, 0);
			input_report_abs(input, ABS_WHEEL, 0);
			if (features->type >= INTUOS3S)
				input_report_abs(input, ABS_Z, 0);
		}
		input_report_key(input, wacom->tool[idx], 0);
		input_report_abs(input, ABS_MISC, 0); /* reset tool id */
		input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
		wacom->id[idx] = 0;
		wacom_exit_report(wacom);
		return 2;
	}

@@ -1235,6 +1245,12 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
		if (!valid)
			continue;

		if (!prox) {
			wacom->shared->stylus_in_proximity = false;
			wacom_exit_report(wacom);
			input_sync(pen_input);
			return;
		}
		if (range) {
			input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
			input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
Loading