diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h index 203d27d198b8..3f8b24a57014 100644 --- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h @@ -91,6 +91,7 @@ #include #include #include +#include #include /* @@ -167,6 +168,7 @@ struct wacom { struct delayed_work init_work; struct wacom_remote *remote; struct work_struct mode_change_work; + struct timer_list idleprox_timer; bool generic_has_leds; struct wacom_leds { struct wacom_group_leds *groups; @@ -239,4 +241,5 @@ struct wacom_led *wacom_led_find(struct wacom *wacom, unsigned int group, struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur); int wacom_equivalent_usage(int usage); int wacom_initialize_leds(struct wacom *wacom); +void wacom_idleprox_timeout(struct timer_list *list); #endif diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 98384b911288..194a2e327591 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -2781,6 +2781,7 @@ static int wacom_probe(struct hid_device *hdev, INIT_WORK(&wacom->battery_work, wacom_battery_work); INIT_WORK(&wacom->remote_work, wacom_remote_work); INIT_WORK(&wacom->mode_change_work, wacom_mode_change_work); + timer_setup(&wacom->idleprox_timer, &wacom_idleprox_timeout, TIMER_DEFERRABLE); /* ask for the report descriptor to be loaded by HID */ error = hid_parse(hdev); @@ -2821,6 +2822,7 @@ static void wacom_remove(struct hid_device *hdev) cancel_work_sync(&wacom->battery_work); cancel_work_sync(&wacom->remote_work); cancel_work_sync(&wacom->mode_change_work); + del_timer_sync(&wacom->idleprox_timer); if (hdev->bus == BUS_BLUETOOTH) device_remove_file(&hdev->dev, &dev_attr_speed); diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index f8cc4bb3e3a7..d049239256a2 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -11,6 +11,7 @@ #include "wacom_wac.h" #include "wacom.h" #include +#include /* resolution for penabled devices */ #define WACOM_PL_RES 20 @@ -41,6 +42,43 @@ static int wacom_numbered_button_to_key(int n); static void wacom_update_led(struct wacom *wacom, int button_count, int mask, int group); + +static void wacom_force_proxout(struct wacom_wac *wacom_wac) +{ + struct input_dev *input = wacom_wac->pen_input; + + wacom_wac->shared->stylus_in_proximity = 0; + + input_report_key(input, BTN_TOUCH, 0); + input_report_key(input, BTN_STYLUS, 0); + input_report_key(input, BTN_STYLUS2, 0); + input_report_key(input, BTN_STYLUS3, 0); + input_report_key(input, wacom_wac->tool[0], 0); + if (wacom_wac->serial[0]) { + input_report_abs(input, ABS_MISC, 0); + } + input_report_abs(input, ABS_PRESSURE, 0); + + wacom_wac->tool[0] = 0; + wacom_wac->id[0] = 0; + wacom_wac->serial[0] = 0; + + input_sync(input); +} + +void wacom_idleprox_timeout(struct timer_list *list) +{ + struct wacom *wacom = from_timer(wacom, list, idleprox_timer); + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + + if (!wacom_wac->hid_data.sense_state) { + return; + } + + hid_warn(wacom->hdev, "%s: tool appears to be hung in-prox. forcing it out.\n", __func__); + wacom_force_proxout(wacom_wac); +} + /* * Percent of battery capacity for Graphire. * 8th value means AC online and show 100% capacity. @@ -2329,6 +2367,7 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field value = field->logical_maximum - value; break; case HID_DG_INRANGE: + mod_timer(&wacom->idleprox_timer, jiffies + msecs_to_jiffies(100)); wacom_wac->hid_data.inrange_state = value; if (!(features->quirks & WACOM_QUIRK_SENSE)) wacom_wac->hid_data.sense_state = value;