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
This commit is contained in:
commit
4d18905314
6 changed files with 92 additions and 38 deletions
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue