Skip to content

Commit 3b2fcb0

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 261daa2 commit 3b2fcb0

1 file changed

Lines changed: 80 additions & 24 deletions

File tree

drivers/hid/hid-magicmouse.c

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
6363
#define SPI_REPORT_ID 0x02
6464
#define SPI_RESET_REPORT_ID 0x60
6565
#define MTP_REPORT_ID 0x75
66+
#define SENSOR_DIMENSIONS_REPORT_ID 0xd9
6667
#define USB_BATTERY_TIMEOUT_SEC 60
6768

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

121+
/* These are fallback values, since the real values will be queried from the device. */
120122
#define J314_TP_DIMENSION_X (float)13000
121123
#define J314_TP_MIN_X -5900
122124
#define J314_TP_MAX_X 6500
@@ -140,6 +142,7 @@ struct magicmouse_input_ops {
140142
* struct magicmouse_sc - Tracks Magic Mouse-specific data.
141143
* @input: Input device through which we report events.
142144
* @quirks: Currently unused.
145+
* @query_dimensions: Whether to query and update dimensions on first open
143146
* @ntouches: Number of touches in most recent touch report.
144147
* @scroll_accel: Number of consecutive scroll motions.
145148
* @scroll_jiffies: Time of last scroll motion.
@@ -154,6 +157,7 @@ struct magicmouse_input_ops {
154157
struct magicmouse_sc {
155158
struct input_dev *input;
156159
unsigned long quirks;
160+
bool query_dimensions;
157161

158162
int ntouches;
159163
int scroll_accel;
@@ -179,6 +183,11 @@ struct magicmouse_sc {
179183

180184
static int magicmouse_enable_multitouch(struct hid_device *hdev);
181185

186+
static inline int le16_to_int(__le16 x)
187+
{
188+
return (signed short)le16_to_cpu(x);
189+
}
190+
182191
static int magicmouse_open(struct input_dev *dev)
183192
{
184193
struct hid_device *hdev = input_get_drvdata(dev);
@@ -196,21 +205,69 @@ static int magicmouse_open(struct input_dev *dev)
196205
* This results in -EIO from the _raw low-level transport callback,
197206
* but there seems to be no other way of switching the mode.
198207
* Thus the super-ugly hacky success check below.
208+
*
209+
* MTP devices do not need this.
199210
*/
200-
ret = magicmouse_enable_multitouch(hdev);
201-
if (ret != -EIO && ret < 0) {
202-
hid_err(hdev, "unable to request touch data (%d)\n", ret);
203-
return ret;
204-
}
205-
if (ret == -EIO && (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
206-
hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2_USBC)) {
207-
schedule_delayed_work(&msc->work, msecs_to_jiffies(500));
211+
if (hdev->bus != BUS_HOST) {
212+
ret = magicmouse_enable_multitouch(hdev);
213+
if (ret != -EIO && ret < 0) {
214+
hid_err(hdev, "unable to request touch data (%d)\n", ret);
215+
return ret;
216+
}
217+
if (ret == -EIO && (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
218+
hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2_USBC)) {
219+
schedule_delayed_work(&msc->work, msecs_to_jiffies(500));
220+
}
208221
}
209222

210223
/*
211-
* MT enable is usually not required after the first time, so don't
212-
* consider it fatal.
224+
* For Apple Silicon trackpads, we want to query the dimensions on
225+
* device open. This is because doing so requires the firmware, but
226+
* we don't want to force a firmware load until the device is opened
227+
* for the first time. So do that here and update the input properties
228+
* just in time before userspace queries them.
213229
*/
230+
if (msc->query_dimensions) {
231+
struct input_dev *input = msc->input;
232+
u8 buf[32];
233+
struct {
234+
__le32 width;
235+
__le32 height;
236+
__le16 min_x;
237+
__le16 min_y;
238+
__le16 max_x;
239+
__le16 max_y;
240+
} dim;
241+
uint32_t x_span, y_span;
242+
243+
ret = hid_hw_raw_request(hdev, SENSOR_DIMENSIONS_REPORT_ID, buf, sizeof(buf), HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
244+
if (ret < (int)(1 + sizeof(dim))) {
245+
hid_err(hdev, "unable to request dimensions (%d)\n", ret);
246+
return ret;
247+
}
248+
249+
memcpy(&dim, buf + 1, sizeof(dim));
250+
251+
/* finger position */
252+
input_set_abs_params(input, ABS_MT_POSITION_X,
253+
le16_to_int(dim.min_x), le16_to_int(dim.max_x), 0, 0);
254+
/* Y axis is inverted */
255+
input_set_abs_params(input, ABS_MT_POSITION_Y,
256+
-le16_to_int(dim.max_y), -le16_to_int(dim.min_y), 0, 0);
257+
x_span = le16_to_int(dim.max_x) - le16_to_int(dim.min_x);
258+
y_span = le16_to_int(dim.max_y) - le16_to_int(dim.min_y);
259+
260+
/* X/Y resolution */
261+
input_abs_set_res(input, ABS_MT_POSITION_X, 100 * x_span / le32_to_cpu(dim.width) );
262+
input_abs_set_res(input, ABS_MT_POSITION_Y, 100 * y_span / le32_to_cpu(dim.height) );
263+
264+
/* copy info, as input_mt_init_slots() does */
265+
dev->absinfo[ABS_X] = dev->absinfo[ABS_MT_POSITION_X];
266+
dev->absinfo[ABS_Y] = dev->absinfo[ABS_MT_POSITION_Y];
267+
268+
msc->query_dimensions = false;
269+
}
270+
214271
return 0;
215272
}
216273

@@ -660,11 +717,6 @@ struct tp_mouse_report {
660717
u8 padding[4];
661718
};
662719

663-
static inline int le16_to_int(__le16 x)
664-
{
665-
return (signed short)le16_to_cpu(x);
666-
}
667-
668720
static void report_finger_data(struct input_dev *input, int slot,
669721
const struct input_mt_pos *pos,
670722
const struct tp_finger *f)
@@ -971,6 +1023,7 @@ static int magicmouse_setup_input_mtp(struct input_dev *input,
9711023
{
9721024
int error;
9731025
int mt_flags = 0;
1026+
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
9741027

9751028
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
9761029
__clear_bit(BTN_0, input->keybit);
@@ -1036,6 +1089,18 @@ static int magicmouse_setup_input_mtp(struct input_dev *input,
10361089
if (error)
10371090
return error;
10381091

1092+
/*
1093+
* Override the default input->open function to send the MT
1094+
* enable every time the device is opened. This ensures it works
1095+
* even if we missed a reset event due to the device being closed.
1096+
* input->close is overridden for symmetry.
1097+
*
1098+
* This also takes care of the dimensions query.
1099+
*/
1100+
input->open = magicmouse_open;
1101+
input->close = magicmouse_close;
1102+
msc->query_dimensions = true;
1103+
10391104
return 0;
10401105
}
10411106

@@ -1046,15 +1111,6 @@ static int magicmouse_setup_input_spi(struct input_dev *input,
10461111
if (ret)
10471112
return ret;
10481113

1049-
/*
1050-
* Override the default input->open function to send the MT
1051-
* enable every time the device is opened. This ensures it works
1052-
* even if we missed a reset event due to the device being closed.
1053-
* input->close is overridden for symmetry.
1054-
*/
1055-
input->open = magicmouse_open;
1056-
input->close = magicmouse_close;
1057-
10581114
return 0;
10591115
}
10601116

0 commit comments

Comments
 (0)