Commit 4d189053 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid

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
......@@ -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
......
......@@ -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);
}
}
......
......@@ -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) {
......
......@@ -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;
......
......@@ -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]));
......
......@@ -516,6 +516,12 @@ enum hid_type {
HID_TYPE_USBNONE
};
enum hid_battery_status {
HID_BATTERY_UNKNOWN = 0,
HID_BATTERY_QUERIED, /* Kernel explicitly queried battery strength */
HID_BATTERY_REPORTED, /* Device sent unsolicited battery strength report */
};
struct hid_driver;
struct hid_ll_driver;
......@@ -558,7 +564,8 @@ struct hid_device { /* device report descriptor */
__s32 battery_max;
__s32 battery_report_type;
__s32 battery_report_id;
bool battery_reported;
enum hid_battery_status battery_status;
bool battery_avoid_query;
#endif
unsigned int status; /* see STAT flags above */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment