mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-04 04:06:26 +00:00
Merge branch 'for-6.8/wacom' into for-linus
- functional fix for handling Confidence in Wacom driver (Jason Gerecke) - power management fix for Wacom userspace battery exporting (Tatsunosuke Tobita) Conflicts: tools/testing/selftests/hid/tests/test_wacom_generic.py
This commit is contained in:
commit
0b43615af1
@ -164,6 +164,7 @@ struct wacom {
|
||||
struct work_struct battery_work;
|
||||
struct work_struct remote_work;
|
||||
struct delayed_work init_work;
|
||||
struct delayed_work aes_battery_work;
|
||||
struct wacom_remote *remote;
|
||||
struct work_struct mode_change_work;
|
||||
struct timer_list idleprox_timer;
|
||||
|
@ -1813,6 +1813,13 @@ static void wacom_destroy_battery(struct wacom *wacom)
|
||||
}
|
||||
}
|
||||
|
||||
static void wacom_aes_battery_handler(struct work_struct *work)
|
||||
{
|
||||
struct wacom *wacom = container_of(work, struct wacom, aes_battery_work.work);
|
||||
|
||||
wacom_destroy_battery(wacom);
|
||||
}
|
||||
|
||||
static ssize_t wacom_show_speed(struct device *dev,
|
||||
struct device_attribute
|
||||
*attr, char *buf)
|
||||
@ -2794,6 +2801,7 @@ static int wacom_probe(struct hid_device *hdev,
|
||||
|
||||
mutex_init(&wacom->lock);
|
||||
INIT_DELAYED_WORK(&wacom->init_work, wacom_init_work);
|
||||
INIT_DELAYED_WORK(&wacom->aes_battery_work, wacom_aes_battery_handler);
|
||||
INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
|
||||
INIT_WORK(&wacom->battery_work, wacom_battery_work);
|
||||
INIT_WORK(&wacom->remote_work, wacom_remote_work);
|
||||
|
@ -2528,11 +2528,12 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
|
||||
struct input_dev *input = wacom_wac->pen_input;
|
||||
bool range = wacom_wac->hid_data.inrange_state;
|
||||
bool sense = wacom_wac->hid_data.sense_state;
|
||||
bool entering_range = !wacom_wac->tool[0] && range;
|
||||
|
||||
if (wacom_wac->is_invalid_bt_frame)
|
||||
return;
|
||||
|
||||
if (!wacom_wac->tool[0] && range) { /* first in range */
|
||||
if (entering_range) { /* first in range */
|
||||
/* Going into range select tool */
|
||||
if (wacom_wac->hid_data.invert_state)
|
||||
wacom_wac->tool[0] = BTN_TOOL_RUBBER;
|
||||
@ -2583,6 +2584,15 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
|
||||
input_sync(input);
|
||||
}
|
||||
|
||||
/* Handle AES battery timeout behavior */
|
||||
if (wacom_wac->features.quirks & WACOM_QUIRK_AESPEN) {
|
||||
if (entering_range)
|
||||
cancel_delayed_work(&wacom->aes_battery_work);
|
||||
if (!sense)
|
||||
schedule_delayed_work(&wacom->aes_battery_work,
|
||||
msecs_to_jiffies(WACOM_AES_BATTERY_TIMEOUT));
|
||||
}
|
||||
|
||||
if (!sense) {
|
||||
wacom_wac->tool[0] = 0;
|
||||
wacom_wac->id[0] = 0;
|
||||
@ -2649,8 +2659,8 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
|
||||
{
|
||||
struct hid_data *hid_data = &wacom_wac->hid_data;
|
||||
bool mt = wacom_wac->features.touch_max > 1;
|
||||
bool prox = hid_data->tipswitch &&
|
||||
report_touch_events(wacom_wac);
|
||||
bool touch_down = hid_data->tipswitch && hid_data->confidence;
|
||||
bool prox = touch_down && report_touch_events(wacom_wac);
|
||||
|
||||
if (touch_is_muted(wacom_wac)) {
|
||||
if (!wacom_wac->shared->touch_down)
|
||||
@ -2700,24 +2710,6 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
|
||||
}
|
||||
}
|
||||
|
||||
static bool wacom_wac_slot_is_active(struct input_dev *dev, int key)
|
||||
{
|
||||
struct input_mt *mt = dev->mt;
|
||||
struct input_mt_slot *s;
|
||||
|
||||
if (!mt)
|
||||
return false;
|
||||
|
||||
for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
|
||||
if (s->key == key &&
|
||||
input_mt_get_value(s, ABS_MT_TRACKING_ID) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void wacom_wac_finger_event(struct hid_device *hdev,
|
||||
struct hid_field *field, struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
@ -2768,14 +2760,8 @@ static void wacom_wac_finger_event(struct hid_device *hdev,
|
||||
}
|
||||
|
||||
if (usage->usage_index + 1 == field->report_count) {
|
||||
if (equivalent_usage == wacom_wac->hid_data.last_slot_field) {
|
||||
bool touch_removed = wacom_wac_slot_is_active(wacom_wac->touch_input,
|
||||
wacom_wac->hid_data.id) && !wacom_wac->hid_data.tipswitch;
|
||||
|
||||
if (wacom_wac->hid_data.confidence || touch_removed) {
|
||||
wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
|
||||
}
|
||||
}
|
||||
if (equivalent_usage == wacom_wac->hid_data.last_slot_field)
|
||||
wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#define WACOM_MAX_REMOTES 5
|
||||
#define WACOM_STATUS_UNKNOWN 255
|
||||
#define WACOM_REMOTE_BATTERY_TIMEOUT 21000000000ll
|
||||
#define WACOM_AES_BATTERY_TIMEOUT 1800000
|
||||
|
||||
/* packet length for individual models */
|
||||
#define WACOM_PKGLEN_BBFUN 9
|
||||
|
@ -27,6 +27,7 @@ from .descriptors_wacom import (
|
||||
)
|
||||
|
||||
import attr
|
||||
from collections import namedtuple
|
||||
from enum import Enum
|
||||
from hidtools.hut import HUT
|
||||
from hidtools.hid import HidUnit
|
||||
@ -862,6 +863,8 @@ class TestPTHX60_Pen(TestOpaqueCTLTablet):
|
||||
|
||||
|
||||
class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest):
|
||||
ContactIds = namedtuple("ContactIds", "contact_id, tracking_id, slot_num")
|
||||
|
||||
def create_device(self):
|
||||
return test_multitouch.Digitizer(
|
||||
"DTH 2452",
|
||||
@ -869,6 +872,57 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
|
||||
input_info=(0x3, 0x056A, 0x0383),
|
||||
)
|
||||
|
||||
def make_contact(self, contact_id=0, t=0):
|
||||
"""
|
||||
Make a single touch contact that can move over time.
|
||||
|
||||
Creates a touch object that has a well-known position in space that
|
||||
does not overlap with other contacts. The value of `t` may be
|
||||
incremented over time to move the point along a linear path.
|
||||
"""
|
||||
x = 50 + 10 * contact_id + t
|
||||
y = 100 + 100 * contact_id + t
|
||||
return test_multitouch.Touch(contact_id, x, y)
|
||||
|
||||
def make_contacts(self, n, t=0):
|
||||
"""
|
||||
Make multiple touch contacts that can move over time.
|
||||
|
||||
Returns a list of `n` touch objects that are positioned at well-known
|
||||
locations. The value of `t` may be incremented over time to move the
|
||||
points along a linear path.
|
||||
"""
|
||||
return [ self.make_contact(id, t) for id in range(0, n) ]
|
||||
|
||||
def assert_contact(self, uhdev, evdev, contact_ids, t=0):
|
||||
"""
|
||||
Assert properties of a contact generated by make_contact.
|
||||
"""
|
||||
contact_id = contact_ids.contact_id
|
||||
tracking_id = contact_ids.tracking_id
|
||||
slot_num = contact_ids.slot_num
|
||||
|
||||
x = 50 + 10 * contact_id + t
|
||||
y = 100 + 100 * contact_id + t
|
||||
|
||||
# If the data isn't supposed to be stored in any slots, there is
|
||||
# nothing we can check for in the evdev stream.
|
||||
if slot_num is None:
|
||||
assert tracking_id == -1
|
||||
return
|
||||
|
||||
assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == tracking_id
|
||||
if tracking_id != -1:
|
||||
assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_X] == x
|
||||
assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_Y] == y
|
||||
|
||||
def assert_contacts(self, uhdev, evdev, data, t=0):
|
||||
"""
|
||||
Assert properties of a list of contacts generated by make_contacts.
|
||||
"""
|
||||
for contact_ids in data:
|
||||
self.assert_contact(uhdev, evdev, contact_ids, t)
|
||||
|
||||
def test_contact_id_0(self):
|
||||
"""
|
||||
Bring a finger in contact with the tablet, then hold it down and remove it.
|
||||
@ -920,3 +974,225 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
|
||||
_slot = self.get_slot(uhdev, t0, 0)
|
||||
|
||||
assert not events
|
||||
|
||||
def test_confidence_multitouch(self):
|
||||
"""
|
||||
Bring multiple fingers in contact with the tablet, some with the
|
||||
confidence bit set, and some without.
|
||||
|
||||
Ensure that all confident touches are reported and that all non-
|
||||
confident touches are ignored.
|
||||
"""
|
||||
uhdev = self.uhdev
|
||||
evdev = uhdev.get_evdev()
|
||||
|
||||
touches = self.make_contacts(5)
|
||||
touches[0].confidence = False
|
||||
touches[2].confidence = False
|
||||
touches[4].confidence = False
|
||||
|
||||
r = uhdev.event(touches)
|
||||
events = uhdev.next_sync_events()
|
||||
self.debug_reports(r, uhdev, events)
|
||||
|
||||
assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
|
||||
|
||||
self.assert_contacts(uhdev, evdev,
|
||||
[ self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None),
|
||||
self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0),
|
||||
self.ContactIds(contact_id = 2, tracking_id = -1, slot_num = None),
|
||||
self.ContactIds(contact_id = 3, tracking_id = 1, slot_num = 1),
|
||||
self.ContactIds(contact_id = 4, tracking_id = -1, slot_num = None) ])
|
||||
|
||||
def confidence_change_assert_playback(self, uhdev, evdev, timeline):
|
||||
"""
|
||||
Assert proper behavior of contacts that move and change tipswitch /
|
||||
confidence status over time.
|
||||
|
||||
Given a `timeline` list of touch states to iterate over, verify
|
||||
that the contacts move and are reported as up/down as expected
|
||||
by the state of the tipswitch and confidence bits.
|
||||
"""
|
||||
t = 0
|
||||
|
||||
for state in timeline:
|
||||
touches = self.make_contacts(len(state), t)
|
||||
|
||||
for item in zip(touches, state):
|
||||
item[0].tipswitch = item[1][1]
|
||||
item[0].confidence = item[1][2]
|
||||
|
||||
r = uhdev.event(touches)
|
||||
events = uhdev.next_sync_events()
|
||||
self.debug_reports(r, uhdev, events)
|
||||
|
||||
ids = [ x[0] for x in state ]
|
||||
self.assert_contacts(uhdev, evdev, ids, t)
|
||||
|
||||
t += 1
|
||||
|
||||
def test_confidence_loss_a(self):
|
||||
"""
|
||||
Transition a confident contact to a non-confident contact by
|
||||
first clearing the tipswitch.
|
||||
|
||||
Ensure that the driver reports the transitioned contact as
|
||||
being removed and that other contacts continue to report
|
||||
normally. This mode of confidence loss is used by the
|
||||
DTH-2452.
|
||||
"""
|
||||
uhdev = self.uhdev
|
||||
evdev = uhdev.get_evdev()
|
||||
|
||||
self.confidence_change_assert_playback(uhdev, evdev, [
|
||||
# t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||
# Both fingers confidently in contact
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
||||
|
||||
# t=1: Contact 0 == !Down + confident; Contact 1 == Down + confident
|
||||
# First finger looses confidence and clears only the tipswitch flag
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, True),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
||||
|
||||
# t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||
# First finger has lost confidence and has both flags cleared
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
||||
|
||||
# t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||
# First finger has lost confidence and has both flags cleared
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)]
|
||||
])
|
||||
|
||||
def test_confidence_loss_b(self):
|
||||
"""
|
||||
Transition a confident contact to a non-confident contact by
|
||||
cleraing both tipswitch and confidence bits simultaneously.
|
||||
|
||||
Ensure that the driver reports the transitioned contact as
|
||||
being removed and that other contacts continue to report
|
||||
normally. This mode of confidence loss is used by some
|
||||
AES devices.
|
||||
"""
|
||||
uhdev = self.uhdev
|
||||
evdev = uhdev.get_evdev()
|
||||
|
||||
self.confidence_change_assert_playback(uhdev, evdev, [
|
||||
# t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||
# Both fingers confidently in contact
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
||||
|
||||
# t=1: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||
# First finger looses confidence and has both flags cleared simultaneously
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
||||
|
||||
# t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||
# First finger has lost confidence and has both flags cleared
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
||||
|
||||
# t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||
# First finger has lost confidence and has both flags cleared
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)]
|
||||
])
|
||||
|
||||
def test_confidence_loss_c(self):
|
||||
"""
|
||||
Transition a confident contact to a non-confident contact by
|
||||
clearing only the confidence bit.
|
||||
|
||||
Ensure that the driver reports the transitioned contact as
|
||||
being removed and that other contacts continue to report
|
||||
normally.
|
||||
"""
|
||||
uhdev = self.uhdev
|
||||
evdev = uhdev.get_evdev()
|
||||
|
||||
self.confidence_change_assert_playback(uhdev, evdev, [
|
||||
# t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||
# Both fingers confidently in contact
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
||||
|
||||
# t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident
|
||||
# First finger looses confidence and clears only the confidence flag
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), True, False),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
||||
|
||||
# t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||
# First finger has lost confidence and has both flags cleared
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
||||
|
||||
# t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||
# First finger has lost confidence and has both flags cleared
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)]
|
||||
])
|
||||
|
||||
def test_confidence_gain_a(self):
|
||||
"""
|
||||
Transition a contact that was always non-confident to confident.
|
||||
|
||||
Ensure that the confident contact is reported normally.
|
||||
"""
|
||||
uhdev = self.uhdev
|
||||
evdev = uhdev.get_evdev()
|
||||
|
||||
self.confidence_change_assert_playback(uhdev, evdev, [
|
||||
# t=0: Contact 0 == Down + !confident; Contact 1 == Down + confident
|
||||
# Only second finger is confidently in contact
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None), True, False),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)],
|
||||
|
||||
# t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident
|
||||
# First finger gains confidence
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None), True, False),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)],
|
||||
|
||||
# t=2: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||
# First finger remains confident
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = 1, slot_num = 1), True, True),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)],
|
||||
|
||||
# t=3: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||
# First finger remains confident
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = 1, slot_num = 1), True, True),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)]
|
||||
])
|
||||
|
||||
def test_confidence_gain_b(self):
|
||||
"""
|
||||
Transition a contact from non-confident to confident.
|
||||
|
||||
Ensure that the confident contact is reported normally.
|
||||
"""
|
||||
uhdev = self.uhdev
|
||||
evdev = uhdev.get_evdev()
|
||||
|
||||
self.confidence_change_assert_playback(uhdev, evdev, [
|
||||
# t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||
# First and second finger confidently in contact
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
||||
|
||||
# t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident
|
||||
# Firtst finger looses confidence
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), True, False),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
||||
|
||||
# t=2: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||
# First finger gains confidence
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = 2, slot_num = 0), True, True),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
||||
|
||||
# t=3: Contact 0 == !Down + confident; Contact 1 == Down + confident
|
||||
# First finger goes up
|
||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, True),
|
||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)]
|
||||
])
|
||||
|
Loading…
Reference in New Issue
Block a user