Skip to content

Commit 88ebed4

Browse files
marcanjannau
authored andcommitted
HID: magicmouse: Query device dimensions via HID report
For SPI/MTP trackpads, query the dimensions via HID report instead of hardcoding values. TODO: Does this work for the USB/BT devices? Maybe we can get rid of the hardcoded sizes everywhere? Signed-off-by: Hector Martin <marcan@marcan.st>
1 parent c7c2889 commit 88ebed4

1 file changed

Lines changed: 81 additions & 21 deletions

File tree

drivers/hid/hid-magicmouse.c

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
6262
#define SPI_REPORT_ID 0x02
6363
#define SPI_RESET_REPORT_ID 0x60
6464
#define MTP_REPORT_ID 0x75
65+
#define SENSOR_DIMENSIONS_REPORT_ID 0xd9
6566
#define USB_BATTERY_TIMEOUT_MS 60000
6667

6768
#define MAX_CONTACTS 16
@@ -116,6 +117,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
116117
#define TRACKPAD2_RES_Y \
117118
((TRACKPAD2_MAX_Y - TRACKPAD2_MIN_Y) / (TRACKPAD2_DIMENSION_Y / 100))
118119

120+
/* These are fallback values, since the real values will be queried from the device. */
119121
#define J314_TP_DIMENSION_X (float)13000
120122
#define J314_TP_MIN_X -5900
121123
#define J314_TP_MAX_X 6500
@@ -139,6 +141,7 @@ struct magicmouse_input_ops {
139141
* struct magicmouse_sc - Tracks Magic Mouse-specific data.
140142
* @input: Input device through which we report events.
141143
* @quirks: Currently unused.
144+
* @query_dimensions: Whether to query and update dimensions on first open
142145
* @ntouches: Number of touches in most recent touch report.
143146
* @scroll_accel: Number of consecutive scroll motions.
144147
* @scroll_jiffies: Time of last scroll motion.
@@ -151,6 +154,7 @@ struct magicmouse_input_ops {
151154
struct magicmouse_sc {
152155
struct input_dev *input;
153156
unsigned long quirks;
157+
bool query_dimensions;
154158

155159
int ntouches;
156160
int scroll_accel;
@@ -174,6 +178,11 @@ struct magicmouse_sc {
174178
struct magicmouse_input_ops input_ops;
175179
};
176180

181+
static inline int le16_to_int(__le16 x)
182+
{
183+
return (signed short)le16_to_cpu(x);
184+
}
185+
177186
static int magicmouse_enable_multitouch(struct hid_device *hdev)
178187
{
179188
const u8 *feature;
@@ -242,19 +251,71 @@ static int magicmouse_open(struct input_dev *dev)
242251
* This results in -EIO from the _raw low-level transport callback,
243252
* but there seems to be no other way of switching the mode.
244253
* Thus the super-ugly hacky success check below.
254+
*
255+
* MTP devices do not need this.
245256
*/
246-
ret = magicmouse_enable_multitouch(hdev);
247-
if (ret == -EIO && hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
248-
schedule_delayed_work(&msc->work, msecs_to_jiffies(500));
249-
return 0;
257+
if (hdev->bus != BUS_HOST) {
258+
ret = magicmouse_enable_multitouch(hdev);
259+
if (ret == -EIO && hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
260+
schedule_delayed_work(&msc->work, msecs_to_jiffies(500));
261+
return 0;
262+
}
263+
if (ret < 0)
264+
hid_err(hdev, "unable to request touch data (%d)\n", ret);
250265
}
251-
if (ret < 0)
252-
hid_err(hdev, "unable to request touch data (%d)\n", ret);
253-
254266
/*
255267
* MT enable is usually not required after the first time, so don't
256268
* consider it fatal.
257269
*/
270+
271+
/*
272+
* For Apple Silicon trackpads, we want to query the dimensions on
273+
* device open. This is because doing so requires the firmware, but
274+
* we don't want to force a firmware load until the device is opened
275+
* for the first time. So do that here and update the input properties
276+
* just in time before userspace queries them.
277+
*/
278+
if (msc->query_dimensions) {
279+
struct input_dev *input = msc->input;
280+
u8 buf[32];
281+
struct {
282+
__le32 width;
283+
__le32 height;
284+
__le16 min_x;
285+
__le16 min_y;
286+
__le16 max_x;
287+
__le16 max_y;
288+
} dim;
289+
uint32_t x_span, y_span;
290+
291+
ret = hid_hw_raw_request(hdev, SENSOR_DIMENSIONS_REPORT_ID, buf, sizeof(buf), HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
292+
if (ret < (int)(1 + sizeof(dim))) {
293+
hid_err(hdev, "unable to request dimensions (%d)\n", ret);
294+
return ret;
295+
}
296+
297+
memcpy(&dim, buf + 1, sizeof(dim));
298+
299+
/* finger position */
300+
input_set_abs_params(input, ABS_MT_POSITION_X,
301+
le16_to_int(dim.min_x), le16_to_int(dim.max_x), 0, 0);
302+
/* Y axis is inverted */
303+
input_set_abs_params(input, ABS_MT_POSITION_Y,
304+
-le16_to_int(dim.max_y), -le16_to_int(dim.min_y), 0, 0);
305+
x_span = le16_to_int(dim.max_x) - le16_to_int(dim.min_x);
306+
y_span = le16_to_int(dim.max_y) - le16_to_int(dim.min_y);
307+
308+
/* X/Y resolution */
309+
input_abs_set_res(input, ABS_MT_POSITION_X, 100 * x_span / le32_to_cpu(dim.width) );
310+
input_abs_set_res(input, ABS_MT_POSITION_Y, 100 * y_span / le32_to_cpu(dim.height) );
311+
312+
/* copy info, as input_mt_init_slots() does */
313+
dev->absinfo[ABS_X] = dev->absinfo[ABS_MT_POSITION_X];
314+
dev->absinfo[ABS_Y] = dev->absinfo[ABS_MT_POSITION_Y];
315+
316+
msc->query_dimensions = false;
317+
}
318+
258319
return 0;
259320
}
260321

@@ -695,11 +756,6 @@ struct tp_mouse_report {
695756
u8 padding[4];
696757
};
697758

698-
static inline int le16_to_int(__le16 x)
699-
{
700-
return (signed short)le16_to_cpu(x);
701-
}
702-
703759
static void report_finger_data(struct input_dev *input, int slot,
704760
const struct input_mt_pos *pos,
705761
const struct tp_finger *f)
@@ -995,6 +1051,7 @@ static int magicmouse_setup_input_mtp(struct input_dev *input,
9951051
{
9961052
int error;
9971053
int mt_flags = 0;
1054+
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
9981055

9991056
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
10001057
__clear_bit(BTN_0, input->keybit);
@@ -1060,6 +1117,18 @@ static int magicmouse_setup_input_mtp(struct input_dev *input,
10601117
if (error)
10611118
return error;
10621119

1120+
/*
1121+
* Override the default input->open function to send the MT
1122+
* enable every time the device is opened. This ensures it works
1123+
* even if we missed a reset event due to the device being closed.
1124+
* input->close is overridden for symmetry.
1125+
*
1126+
* This also takes care of the dimensions query.
1127+
*/
1128+
input->open = magicmouse_open;
1129+
input->close = magicmouse_close;
1130+
msc->query_dimensions = true;
1131+
10631132
return 0;
10641133
}
10651134

@@ -1070,15 +1139,6 @@ static int magicmouse_setup_input_spi(struct input_dev *input,
10701139
if (ret)
10711140
return ret;
10721141

1073-
/*
1074-
* Override the default input->open function to send the MT
1075-
* enable every time the device is opened. This ensures it works
1076-
* even if we missed a reset event due to the device being closed.
1077-
* input->close is overridden for symmetry.
1078-
*/
1079-
input->open = magicmouse_open;
1080-
input->close = magicmouse_close;
1081-
10821142
return 0;
10831143
}
10841144

0 commit comments

Comments
 (0)