Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 79 additions & 7 deletions drivers/hid/hid-magicmouse.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ struct effect_job {
* @quirks: Currently unused.
* @query_dimensions: Whether to query and update dimensions on first open
* @mtp_c1fe: Whether the MTP trackpad sends the J700 C1FE report layout.
* @mtp_palms: Whether the controller's contact classes are trusted for palms
* on the standard MTP report (T6041).
* @mtp_palm_ids: MTP contact IDs reported as palms until they lift.
* @ntouches: Number of touches in most recent touch report.
* @scroll_accel: Number of consecutive scroll motions.
* @scroll_jiffies: Time of last scroll motion.
Expand All @@ -289,6 +292,8 @@ struct magicmouse_sc {
unsigned long quirks;
bool query_dimensions;
bool mtp_c1fe;
bool mtp_palms;
DECLARE_BITMAP(mtp_palm_ids, U8_MAX + 1);

int ntouches;
int scroll_accel;
Expand Down Expand Up @@ -963,12 +968,55 @@ static void report_c1fe_finger_data(struct input_dev *input, int slot,
static bool magicmouse_haptic_click(struct magicmouse_sc *msc, u32 pressure,
bool firmware_button);

/*
* The T6041 (M4 Max) MTP trackpad's records carry the contact ID and state in
* the first word and the controller's class in the low byte of the second: 1
* for a thumb, 2 and 3 for fingers, 6 and above for palms. Recorded on a J616C:
* moving fingers had a tool area of 830-1010 and class 2 or 3, a resting thumb
* ~1750 and class 1, a resting palm ~2040 and class 7; palms dragged across the
* pad reached 5100. The class flickers while a hand lands, so a contact counts
* as a palm once the controller classes it as one with a tool area no finger
* reaches, or once its tool area passes palm size, and stays a palm until it
* lifts. Thumbs stay touches.
*/
#define MAGICMOUSE_MTP_PALM_CLASS_MIN 6
#define MAGICMOUSE_MTP_CLASSED_PALM_TOOL_MAJOR 1400
#define MAGICMOUSE_MTP_PALM_TOOL_MAJOR 2200

static u8 magicmouse_mtp_contact_id(const struct tp_finger *f)
{
return le16_to_cpu(f->unknown1) & 0xff;
}

static void magicmouse_mtp_update_palms(struct magicmouse_sc *msc,
const u8 *records, int count)
{
DECLARE_BITMAP(palms, U8_MAX + 1);
const struct tp_finger *f;
int i, tool;
u8 id, class;

bitmap_zero(palms, U8_MAX + 1);
for (i = 0; i < count; i++) {
f = (const struct tp_finger *)(records + i * sizeof(*f));
id = magicmouse_mtp_contact_id(f);
class = le16_to_cpu(f->unknown2) & 0xff;
tool = le16_to_int(f->tool_major);
if (tool > MAGICMOUSE_MTP_PALM_TOOL_MAJOR ||
(class >= MAGICMOUSE_MTP_PALM_CLASS_MIN &&
tool > MAGICMOUSE_MTP_CLASSED_PALM_TOOL_MAJOR) ||
test_bit(id, msc->mtp_palm_ids))
__set_bit(id, palms);
}
bitmap_copy(msc->mtp_palm_ids, palms, U8_MAX + 1);
}

static void report_finger_data(struct input_dev *input, int slot,
const struct input_mt_pos *pos,
const struct tp_finger *f)
const struct tp_finger *f, int tool)
{
input_mt_slot(input, slot);
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
input_mt_report_slot_state(input, tool, true);

input_report_abs(input, ABS_MT_TOUCH_MAJOR,
le16_to_int(f->touch_major) << 1);
Expand Down Expand Up @@ -1025,6 +1073,10 @@ static int magicmouse_raw_event_mtp(struct hid_device *hdev,
return 0;
}

if (msc->mtp_palms)
magicmouse_mtp_update_palms(msc, data + hdr_sz,
tp_hdr->num_fingers);

n = 0;
for (i = 0; i < tp_hdr->num_fingers; i++) {
f = (struct tp_finger *)(data + hdr_sz + i * touch_sz);
Expand All @@ -1047,7 +1099,13 @@ static int magicmouse_raw_event_mtp(struct hid_device *hdev,
if (msc->mtp_c1fe) {
report_c1fe_finger_data(input, msc->tracking_ids[i], &msc->pos[i]);
} else {
report_finger_data(input, msc->tracking_ids[i], &msc->pos[i], f);
int tool = MT_TOOL_FINGER;

if (msc->mtp_palms &&
test_bit(magicmouse_mtp_contact_id(f), msc->mtp_palm_ids))
tool = MT_TOOL_PALM;
report_finger_data(input, msc->tracking_ids[i], &msc->pos[i],
f, tool);
pressure += le16_to_int(f->pressure);
}
}
Expand Down Expand Up @@ -1315,13 +1373,20 @@ static int magicmouse_setup_input_mtp(struct input_dev *input,
* nothing that user space would take for a touch size or a pressure.
*/
if (!msc->mtp_c1fe) {
/*
* A palm's tool area on the T6041 trackpad exceeds 5000 once
* scaled, so allow the full range of the record's 16-bit fields
* there.
*/
int area_max = msc->mtp_palms ? 2 * S16_MAX : 5000;

/* finger touch area */
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 5000, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 5000, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, area_max, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, area_max, 0, 0);

/* finger approach area */
input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 5000, 0, 0);
input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 5000, 0, 0);
input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, area_max, 0, 0);
input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, area_max, 0, 0);

input_set_abs_params(input, ABS_MT_PRESSURE, 0, 6000, 0, 0);

Expand All @@ -1338,6 +1403,11 @@ static int magicmouse_setup_input_mtp(struct input_dev *input,
J314_TP_MAX_FINGER_ORIENTATION, 0, 0);
}

/* The T6041 controller classifies palms. */
if (msc->mtp_palms)
input_set_abs_params(input, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX,
0, 0);

/* Note: Touch Y position from the device is inverted relative
* to how pointer motion is reported (and relative to how USB
* HID recommends the coordinates work). This driver keeps
Expand Down Expand Up @@ -2323,6 +2393,8 @@ static int magicmouse_probe(struct hid_device *hdev,
/* The J700 trackpad sends a different report layout. */
np = of_get_child_by_name(dev_of_node(hdev->dev.parent), "multi-touch");
msc->mtp_c1fe = of_device_is_compatible(np, "apple,j700-multitouch");
msc->mtp_palms = !msc->mtp_c1fe &&
of_machine_is_compatible("apple,t6041");
of_node_put(np);

msc->input_ops.raw_event = magicmouse_raw_event_mtp;
Expand Down