xref: /freebsd/sys/dev/hid/bcm5974.c (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2012 Huang Wen Hui
5  * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 #include <sys/param.h>
32 #include <sys/bus.h>
33 #include <sys/endian.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/module.h>
37 #include <sys/sysctl.h>
38 #include <sys/systm.h>
39 
40 #include <dev/evdev/input.h>
41 #include <dev/evdev/evdev.h>
42 
43 #define HID_DEBUG_VAR   bcm5974_debug
44 #include <dev/hid/hid.h>
45 #include <dev/hid/hidbus.h>
46 #include <dev/hid/hidquirk.h>
47 
48 #include <dev/usb/usb.h>
49 #include <dev/usb/usbdi.h>
50 #include <dev/usb/usbhid.h>
51 #include <dev/usb/usb_ioctl.h>
52 
53 #include "usbdevs.h"
54 
55 #define	BCM5974_BUFFER_MAX	(248 * 4)	/* 4 Type4 SPI frames */
56 #define	BCM5974_TLC_PAGE	HUP_GENERIC_DESKTOP
57 #define	BCM5974_TLC_USAGE	HUG_MOUSE
58 
59 /* magic to switch device from HID (default) mode into raw */
60 /* Type1 & Type2 trackpads */
61 #define	BCM5974_USB_IFACE_INDEX	0
62 #define	BCM5974_USB_REPORT_LEN	8
63 #define	BCM5974_USB_REPORT_ID	0
64 #define	BCM5974_USB_MODE_RAW	0x01
65 #define	BCM5974_USB_MODE_HID	0x08
66 /* Type4 trackpads */
67 #define	BCM5974_HID_REPORT_LEN	2
68 #define	BCM5974_HID_REPORT_ID	2
69 #define	BCM5974_HID_MODE_RAW	0x01
70 #define	BCM5974_HID_MODE_HID	0x00
71 
72 /* Tunables */
73 static	SYSCTL_NODE(_hw_hid, OID_AUTO, bcm5974, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
74     "HID wellspring touchpad");
75 
76 #ifdef HID_DEBUG
77 enum wsp_log_level {
78 	BCM5974_LLEVEL_DISABLED = 0,
79 	BCM5974_LLEVEL_ERROR,
80 	BCM5974_LLEVEL_DEBUG,		/* for troubleshooting */
81 	BCM5974_LLEVEL_INFO,		/* for diagnostics */
82 };
83 /* the default is to only log errors */
84 static int bcm5974_debug = BCM5974_LLEVEL_ERROR;
85 
86 SYSCTL_INT(_hw_hid_bcm5974, OID_AUTO, debug, CTLFLAG_RWTUN,
87     &bcm5974_debug, BCM5974_LLEVEL_ERROR, "BCM5974 debug level");
88 #endif					/* HID_DEBUG */
89 
90 /*
91  * Some tables, structures, definitions and constant values for the
92  * touchpad protocol has been copied from Linux's
93  * "drivers/input/mouse/bcm5974.c" which has the following copyright
94  * holders under GPLv2. All device specific code in this driver has
95  * been written from scratch. The decoding algorithm is based on
96  * output from FreeBSD's usbdump.
97  *
98  * Copyright (C) 2008      Henrik Rydberg (rydberg@euromail.se)
99  * Copyright (C) 2008      Scott Shawcroft (scott.shawcroft@gmail.com)
100  * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
101  * Copyright (C) 2005      Johannes Berg (johannes@sipsolutions.net)
102  * Copyright (C) 2005      Stelian Pop (stelian@popies.net)
103  * Copyright (C) 2005      Frank Arnold (frank@scirocco-5v-turbo.de)
104  * Copyright (C) 2005      Peter Osterlund (petero2@telia.com)
105  * Copyright (C) 2005      Michael Hanselmann (linux-kernel@hansmi.ch)
106  * Copyright (C) 2006      Nicolas Boichat (nicolas@boichat.ch)
107  */
108 
109 /* trackpad header types */
110 enum tp_type {
111 	TYPE1,			/* plain trackpad */
112 	TYPE2,			/* button integrated in trackpad */
113 	TYPE3,			/* additional header fields since June 2013 */
114 	TYPE4,                  /* additional header field for pressure data */
115 	TYPE_MT2U,			/* Magic Trackpad 2 USB */
116 	TYPE_CNT
117 };
118 
119 /* list of device capability bits */
120 #define	HAS_INTEGRATED_BUTTON	1
121 #define	USES_COMPACT_REPORT	2
122 
123 struct tp_type_params {
124 	uint8_t	caps;		/* device capability bitmask */
125 	uint8_t	button;		/* offset to button data */
126 	uint8_t	offset;		/* offset to trackpad finger data */
127 	uint8_t delta;		/* offset from header to finger struct */
128 } const static tp[TYPE_CNT] = {
129 	[TYPE1] = {
130 		.caps = 0,
131 		.button = 0,
132 		.offset = 13 * 2,
133 		.delta = 0,
134 	},
135 	[TYPE2] = {
136 		.caps = HAS_INTEGRATED_BUTTON,
137 		.button = 15,
138 		.offset = 15 * 2,
139 		.delta = 0,
140 	},
141 	[TYPE3] = {
142 		.caps = HAS_INTEGRATED_BUTTON,
143 		.button = 23,
144 		.offset = 19 * 2,
145 		.delta = 0,
146 	},
147 	[TYPE4] = {
148 		.caps = HAS_INTEGRATED_BUTTON,
149 		.button = 31,
150 		.offset = 23 * 2,
151 		.delta = 2,
152 	},
153 	[TYPE_MT2U] = {
154 		.caps = HAS_INTEGRATED_BUTTON | USES_COMPACT_REPORT,
155 		.button = 1,
156 		.offset = 12,
157 		.delta = 0,
158 	},
159 };
160 
161 /* trackpad finger structure - compact version for external "Magic" devices */
162 struct tp_finger_compact {
163 	uint32_t coords; /* not struct directly due to endian conversion */
164 	uint8_t touch_major;
165 	uint8_t touch_minor;
166 	uint8_t size;
167 	uint8_t pressure;
168 	uint8_t id_ori;
169 } __packed;
170 
171 _Static_assert((sizeof(struct tp_finger_compact) == 9), "tp_finger struct size must be 9");
172 
173 /* trackpad finger structure - little endian */
174 struct tp_finger {
175 	uint16_t	origin;		/* zero when switching track finger */
176 	uint16_t	abs_x;		/* absolute x coodinate */
177 	uint16_t	abs_y;		/* absolute y coodinate */
178 	uint16_t	rel_x;		/* relative x coodinate */
179 	uint16_t	rel_y;		/* relative y coodinate */
180 	uint16_t	tool_major;	/* tool area, major axis */
181 	uint16_t	tool_minor;	/* tool area, minor axis */
182 	uint16_t	orientation;	/* 16384 when point, else 15 bit angle */
183 	uint16_t	touch_major;	/* touch area, major axis */
184 	uint16_t	touch_minor;	/* touch area, minor axis */
185 	uint16_t	unused[2];	/* zeros */
186 	uint16_t	pressure;	/* pressure on forcetouch touchpad */
187 	uint16_t	multi;		/* one finger: varies, more fingers:
188 					 * constant */
189 } __packed;
190 
191 #define BCM5974_LE2H(x) ((int32_t)(int16_t)le16toh(x))
192 
193 /* trackpad finger data size, empirically at least ten fingers */
194 #define	MAX_FINGERS		MAX_MT_SLOTS
195 
196 #define	MAX_FINGER_ORIENTATION	16384
197 
198 enum {
199 	BCM5974_FLAG_WELLSPRING1,
200 	BCM5974_FLAG_WELLSPRING2,
201 	BCM5974_FLAG_WELLSPRING3,
202 	BCM5974_FLAG_WELLSPRING4,
203 	BCM5974_FLAG_WELLSPRING4A,
204 	BCM5974_FLAG_WELLSPRING5,
205 	BCM5974_FLAG_WELLSPRING6A,
206 	BCM5974_FLAG_WELLSPRING6,
207 	BCM5974_FLAG_WELLSPRING5A,
208 	BCM5974_FLAG_WELLSPRING7,
209 	BCM5974_FLAG_WELLSPRING7A,
210 	BCM5974_FLAG_WELLSPRING8,
211 	BCM5974_FLAG_WELLSPRING9,
212 	BCM5974_FLAG_MAGIC_TRACKPAD2_USB,
213 	BCM5974_FLAG_MAX,
214 };
215 
216 /* device-specific parameters */
217 struct bcm5974_axis {
218 	int snratio;			/* signal-to-noise ratio */
219 	int min;			/* device minimum reading */
220 	int max;			/* device maximum reading */
221 	int size;			/* physical size, mm */
222 };
223 
224 /* device-specific configuration */
225 struct bcm5974_dev_params {
226 	const struct tp_type_params* tp;
227 	struct bcm5974_axis p;		/* finger pressure limits */
228 	struct bcm5974_axis w;		/* finger width limits */
229 	struct bcm5974_axis x;		/* horizontal limits */
230 	struct bcm5974_axis y;		/* vertical limits */
231 	struct bcm5974_axis o;		/* orientation limits */
232 };
233 
234 /* logical signal quality */
235 #define	SN_PRESSURE	45		/* pressure signal-to-noise ratio */
236 #define	SN_WIDTH	25		/* width signal-to-noise ratio */
237 #define	SN_COORD	250		/* coordinate signal-to-noise ratio */
238 #define	SN_ORIENT	10		/* orientation signal-to-noise ratio */
239 
240 static const struct bcm5974_dev_params bcm5974_dev_params[BCM5974_FLAG_MAX] = {
241 	[BCM5974_FLAG_WELLSPRING1] = {
242 		.tp = tp + TYPE1,
243 		.p = { SN_PRESSURE, 0, 256, 0 },
244 		.w = { SN_WIDTH, 0, 2048, 0 },
245 		.x = { SN_COORD, -4824, 5342, 105 },
246 		.y = { SN_COORD, -172, 5820, 75 },
247 		.o = { SN_ORIENT,
248 		    -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
249 	},
250 	[BCM5974_FLAG_WELLSPRING2] = {
251 		.tp = tp + TYPE1,
252 		.p = { SN_PRESSURE, 0, 256, 0 },
253 		.w = { SN_WIDTH, 0, 2048, 0 },
254 		.x = { SN_COORD, -4824, 4824, 105 },
255 		.y = { SN_COORD, -172, 4290, 75 },
256 		.o = { SN_ORIENT,
257 		    -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
258 	},
259 	[BCM5974_FLAG_WELLSPRING3] = {
260 		.tp = tp + TYPE2,
261 		.p = { SN_PRESSURE, 0, 300, 0 },
262 		.w = { SN_WIDTH, 0, 2048, 0 },
263 		.x = { SN_COORD, -4460, 5166, 105 },
264 		.y = { SN_COORD, -75, 6700, 75 },
265 		.o = { SN_ORIENT,
266 		    -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
267 	},
268 	[BCM5974_FLAG_WELLSPRING4] = {
269 		.tp = tp + TYPE2,
270 		.p = { SN_PRESSURE, 0, 300, 0 },
271 		.w = { SN_WIDTH, 0, 2048, 0 },
272 		.x = { SN_COORD, -4620, 5140, 105 },
273 		.y = { SN_COORD, -150, 6600, 75 },
274 		.o = { SN_ORIENT,
275 		    -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
276 	},
277 	[BCM5974_FLAG_WELLSPRING4A] = {
278 		.tp = tp + TYPE2,
279 		.p = { SN_PRESSURE, 0, 300, 0 },
280 		.w = { SN_WIDTH, 0, 2048, 0 },
281 		.x = { SN_COORD, -4616, 5112, 105 },
282 		.y = { SN_COORD, -142, 5234, 75 },
283 		.o = { SN_ORIENT,
284 		    -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
285 	},
286 	[BCM5974_FLAG_WELLSPRING5] = {
287 		.tp = tp + TYPE2,
288 		.p = { SN_PRESSURE, 0, 300, 0 },
289 		.w = { SN_WIDTH, 0, 2048, 0 },
290 		.x = { SN_COORD, -4415, 5050, 105 },
291 		.y = { SN_COORD, -55, 6680, 75 },
292 		.o = { SN_ORIENT,
293 		    -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
294 	},
295 	[BCM5974_FLAG_WELLSPRING6] = {
296 		.tp = tp + TYPE2,
297 		.p = { SN_PRESSURE, 0, 300, 0 },
298 		.w = { SN_WIDTH, 0, 2048, 0 },
299 		.x = { SN_COORD, -4620, 5140, 105 },
300 		.y = { SN_COORD, -150, 6600, 75 },
301 		.o = { SN_ORIENT,
302 		    -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
303 	},
304 	[BCM5974_FLAG_WELLSPRING5A] = {
305 		.tp = tp + TYPE2,
306 		.p = { SN_PRESSURE, 0, 300, 0 },
307 		.w = { SN_WIDTH, 0, 2048, 0 },
308 		.x = { SN_COORD, -4750, 5280, 105 },
309 		.y = { SN_COORD, -150, 6730, 75 },
310 		.o = { SN_ORIENT,
311 		    -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
312 	},
313 	[BCM5974_FLAG_WELLSPRING6A] = {
314 		.tp = tp + TYPE2,
315 		.p = { SN_PRESSURE, 0, 300, 0 },
316 		.w = { SN_WIDTH, 0, 2048, 0 },
317 		.x = { SN_COORD, -4620, 5140, 105 },
318 		.y = { SN_COORD, -150, 6600, 75 },
319 		.o = { SN_ORIENT,
320 		    -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
321 	},
322 	[BCM5974_FLAG_WELLSPRING7] = {
323 		.tp = tp + TYPE2,
324 		.p = { SN_PRESSURE, 0, 300, 0 },
325 		.w = { SN_WIDTH, 0, 2048, 0 },
326 		.x = { SN_COORD, -4750, 5280, 105 },
327 		.y = { SN_COORD, -150, 6730, 75 },
328 		.o = { SN_ORIENT,
329 		    -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
330 	},
331 	[BCM5974_FLAG_WELLSPRING7A] = {
332 		.tp = tp + TYPE2,
333 		.p = { SN_PRESSURE, 0, 300, 0 },
334 		.w = { SN_WIDTH, 0, 2048, 0 },
335 		.x = { SN_COORD, -4750, 5280, 105 },
336 		.y = { SN_COORD, -150, 6730, 75 },
337 		.o = { SN_ORIENT,
338 		    -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
339 	},
340 	[BCM5974_FLAG_WELLSPRING8] = {
341 		.tp = tp + TYPE3,
342 		.p = { SN_PRESSURE, 0, 300, 0 },
343 		.w = { SN_WIDTH, 0, 2048, 0 },
344 		.x = { SN_COORD, -4620, 5140, 105 },
345 		.y = { SN_COORD, -150, 6600, 75 },
346 		.o = { SN_ORIENT,
347 		    -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
348 	},
349 	/*
350 	 * NOTE: Actually force-sensitive. Pressure has a "size" equal to the max
351 	 * so that the "resolution" is 1 (i.e. values will be interpreted as grams).
352 	 * No scientific measurements have been done :) but a really hard press
353 	 * results in a value around 3500 on model 4.
354 	 */
355 	[BCM5974_FLAG_WELLSPRING9] = {
356 		.tp = tp + TYPE4,
357 		.p = { SN_PRESSURE, 0, 4096, 4096 },
358 		.w = { SN_WIDTH, 0, 2048, 0 },
359 		.x = { SN_COORD, -4828, 5345, 105 },
360 		.y = { SN_COORD, -203, 6803, 75 },
361 		.o = { SN_ORIENT,
362 		    -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
363 	},
364 	[BCM5974_FLAG_MAGIC_TRACKPAD2_USB] = {
365 		.tp = tp + TYPE_MT2U,
366 		.p = { SN_PRESSURE, 0, 256, 256 },
367 		.w = { SN_WIDTH, 0, 2048, 0 },
368 		.x = { SN_COORD, -3678, 3934, 48 },
369 		.y = { SN_COORD, -2478, 2587, 44 },
370 		.o = { SN_ORIENT, -3, 4, 0 },
371 	},
372 };
373 
374 #define	BCM5974_DEV(v,p,i)	{					\
375 	HID_BVPI(BUS_USB, USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i),	\
376 	HID_TLC(BCM5974_TLC_PAGE, BCM5974_TLC_USAGE),			\
377 }
378 
379 static const struct hid_device_id bcm5974_devs[] = {
380 	/* MacbookAir1.1 */
381 	BCM5974_DEV(APPLE, WELLSPRING_ANSI, BCM5974_FLAG_WELLSPRING1),
382 	BCM5974_DEV(APPLE, WELLSPRING_ISO, BCM5974_FLAG_WELLSPRING1),
383 	BCM5974_DEV(APPLE, WELLSPRING_JIS, BCM5974_FLAG_WELLSPRING1),
384 
385 	/* MacbookProPenryn, aka wellspring2 */
386 	BCM5974_DEV(APPLE, WELLSPRING2_ANSI, BCM5974_FLAG_WELLSPRING2),
387 	BCM5974_DEV(APPLE, WELLSPRING2_ISO, BCM5974_FLAG_WELLSPRING2),
388 	BCM5974_DEV(APPLE, WELLSPRING2_JIS, BCM5974_FLAG_WELLSPRING2),
389 
390 	/* Macbook5,1 (unibody), aka wellspring3 */
391 	BCM5974_DEV(APPLE, WELLSPRING3_ANSI, BCM5974_FLAG_WELLSPRING3),
392         BCM5974_DEV(APPLE, WELLSPRING3_ISO, BCM5974_FLAG_WELLSPRING3),
393 	BCM5974_DEV(APPLE, WELLSPRING3_JIS, BCM5974_FLAG_WELLSPRING3),
394 
395 	/* MacbookAir3,2 (unibody), aka wellspring4 */
396 	BCM5974_DEV(APPLE, WELLSPRING4_ANSI, BCM5974_FLAG_WELLSPRING4),
397 	BCM5974_DEV(APPLE, WELLSPRING4_ISO, BCM5974_FLAG_WELLSPRING4),
398 	BCM5974_DEV(APPLE, WELLSPRING4_JIS, BCM5974_FLAG_WELLSPRING4),
399 
400 	/* MacbookAir3,1 (unibody), aka wellspring4 */
401 	BCM5974_DEV(APPLE, WELLSPRING4A_ANSI, BCM5974_FLAG_WELLSPRING4A),
402 	BCM5974_DEV(APPLE, WELLSPRING4A_ISO, BCM5974_FLAG_WELLSPRING4A),
403 	BCM5974_DEV(APPLE, WELLSPRING4A_JIS, BCM5974_FLAG_WELLSPRING4A),
404 
405 	/* Macbook8 (unibody, March 2011) */
406 	BCM5974_DEV(APPLE, WELLSPRING5_ANSI, BCM5974_FLAG_WELLSPRING5),
407 	BCM5974_DEV(APPLE, WELLSPRING5_ISO, BCM5974_FLAG_WELLSPRING5),
408 	BCM5974_DEV(APPLE, WELLSPRING5_JIS, BCM5974_FLAG_WELLSPRING5),
409 
410 	/* MacbookAir4,1 (unibody, July 2011) */
411 	BCM5974_DEV(APPLE, WELLSPRING6A_ANSI, BCM5974_FLAG_WELLSPRING6A),
412 	BCM5974_DEV(APPLE, WELLSPRING6A_ISO, BCM5974_FLAG_WELLSPRING6A),
413 	BCM5974_DEV(APPLE, WELLSPRING6A_JIS, BCM5974_FLAG_WELLSPRING6A),
414 
415 	/* MacbookAir4,2 (unibody, July 2011) */
416 	BCM5974_DEV(APPLE, WELLSPRING6_ANSI, BCM5974_FLAG_WELLSPRING6),
417 	BCM5974_DEV(APPLE, WELLSPRING6_ISO, BCM5974_FLAG_WELLSPRING6),
418 	BCM5974_DEV(APPLE, WELLSPRING6_JIS, BCM5974_FLAG_WELLSPRING6),
419 
420 	/* Macbook8,2 (unibody) */
421 	BCM5974_DEV(APPLE, WELLSPRING5A_ANSI, BCM5974_FLAG_WELLSPRING5A),
422 	BCM5974_DEV(APPLE, WELLSPRING5A_ISO, BCM5974_FLAG_WELLSPRING5A),
423 	BCM5974_DEV(APPLE, WELLSPRING5A_JIS, BCM5974_FLAG_WELLSPRING5A),
424 
425 	/* MacbookPro10,1 (unibody, June 2012) */
426 	/* MacbookPro11,1-3 (unibody, June 2013) */
427 	BCM5974_DEV(APPLE, WELLSPRING7_ANSI, BCM5974_FLAG_WELLSPRING7),
428 	BCM5974_DEV(APPLE, WELLSPRING7_ISO, BCM5974_FLAG_WELLSPRING7),
429         BCM5974_DEV(APPLE, WELLSPRING7_JIS, BCM5974_FLAG_WELLSPRING7),
430 
431         /* MacbookPro10,2 (unibody, October 2012) */
432         BCM5974_DEV(APPLE, WELLSPRING7A_ANSI, BCM5974_FLAG_WELLSPRING7A),
433         BCM5974_DEV(APPLE, WELLSPRING7A_ISO, BCM5974_FLAG_WELLSPRING7A),
434         BCM5974_DEV(APPLE, WELLSPRING7A_JIS, BCM5974_FLAG_WELLSPRING7A),
435 
436 	/* MacbookAir6,2 (unibody, June 2013) */
437 	BCM5974_DEV(APPLE, WELLSPRING8_ANSI, BCM5974_FLAG_WELLSPRING8),
438 	BCM5974_DEV(APPLE, WELLSPRING8_ISO, BCM5974_FLAG_WELLSPRING8),
439 	BCM5974_DEV(APPLE, WELLSPRING8_JIS, BCM5974_FLAG_WELLSPRING8),
440 
441 	/* MacbookPro12,1 MacbookPro11,4 */
442 	BCM5974_DEV(APPLE, WELLSPRING9_ANSI, BCM5974_FLAG_WELLSPRING9),
443 	BCM5974_DEV(APPLE, WELLSPRING9_ISO, BCM5974_FLAG_WELLSPRING9),
444 	BCM5974_DEV(APPLE, WELLSPRING9_JIS, BCM5974_FLAG_WELLSPRING9),
445 
446 	/* External "Magic" devices */
447 	BCM5974_DEV(APPLE, MAGIC_TRACKPAD2, BCM5974_FLAG_MAGIC_TRACKPAD2_USB),
448 };
449 
450 struct bcm5974_softc {
451 	device_t sc_dev;
452 	struct evdev_dev *sc_evdev;
453 	/* device configuration */
454 	const struct bcm5974_dev_params *sc_params;
455 	bool sc_saved_mode;
456 };
457 
458 static const uint8_t bcm5974_rdesc[] = {
459 	0x05, BCM5974_TLC_PAGE,	/* Usage Page (BCM5974_TLC_PAGE)	*/
460 	0x09, BCM5974_TLC_USAGE,/* Usage (BCM5974_TLC_USAGE)		*/
461 	0xA1, 0x01,		/* Collection (Application)		*/
462 	0x06, 0x00, 0xFF,	/*   Usage Page (Vendor Defined 0xFF00)	*/
463 	0x09, 0x01,		/*   Usage (0x01)			*/
464 	0x15, 0x00,		/*   Logical Minimum (0)		*/
465 	0x26, 0xFF, 0x00,	/*   Logical Maximum (255)		*/
466 	0x75, 0x08,		/*   Report Size (8)			*/
467 	0x96,			/*   Report Count (BCM5974_BUFFER_MAX)	*/
468 	BCM5974_BUFFER_MAX & 0xFF,
469 	BCM5974_BUFFER_MAX >> 8 & 0xFF,
470 	0x81, 0x02,		/*   Input (Data,Var,Abs)		*/
471 	0xC0,			/* End Collection			*/
472 };
473 
474 /*
475  * function prototypes
476  */
477 static evdev_open_t	bcm5974_ev_open;
478 static evdev_close_t	bcm5974_ev_close;
479 static const struct evdev_methods bcm5974_evdev_methods = {
480 	.ev_open =	&bcm5974_ev_open,
481 	.ev_close =	&bcm5974_ev_close,
482 };
483 static hid_intr_t	bcm5974_intr;
484 
485 /* Device methods. */
486 static device_identify_t bcm5974_identify;
487 static device_probe_t	bcm5974_probe;
488 static device_attach_t	bcm5974_attach;
489 static device_detach_t	bcm5974_detach;
490 
491 /*
492  * Type1 and Type2 touchpads use keyboard USB interface to switch from HID to
493  * RAW mode. Although it is possible to extend hkbd driver to support such a
494  * mode change requests, it's not wanted due to cross device tree dependencies.
495  * So, find lowest common denominator (struct usb_device of grandparent usbhid
496  * driver) of touchpad and keyboard drivers and issue direct USB requests.
497  */
498 static int
499 bcm5974_set_device_mode_usb(struct bcm5974_softc *sc, bool on)
500 {
501 	uint8_t mode_bytes[BCM5974_USB_REPORT_LEN];
502 	struct usb_ctl_request ucr;
503 	int err;
504 
505 	ucr.ucr_request.bmRequestType = UT_READ_CLASS_INTERFACE;
506 	ucr.ucr_request.bRequest = UR_GET_REPORT;
507 	USETW2(ucr.ucr_request.wValue,
508 	    UHID_FEATURE_REPORT, BCM5974_USB_REPORT_ID);
509 	ucr.ucr_request.wIndex[0] = BCM5974_USB_IFACE_INDEX;
510 	ucr.ucr_request.wIndex[1] = 0;
511 	USETW(ucr.ucr_request.wLength, BCM5974_USB_REPORT_LEN);
512 	ucr.ucr_data = mode_bytes;
513 
514 	err = hid_ioctl(sc->sc_dev, USB_REQUEST, (uintptr_t)&ucr);
515 	if (err != 0) {
516 		DPRINTF("Failed to read device mode (%d)\n", err);
517 		return (EIO);
518 	}
519 #if 0
520 	/*
521 	 * XXX Need to wait at least 250ms for hardware to get
522 	 * ready. The device mode handling appears to be handled
523 	 * asynchronously and we should not issue these commands too
524 	 * quickly.
525 	 */
526 	pause("WHW", hz / 4);
527 #endif
528 	mode_bytes[0] = on ? BCM5974_USB_MODE_RAW : BCM5974_USB_MODE_HID;
529 	ucr.ucr_request.bmRequestType = UT_WRITE_CLASS_INTERFACE;
530 	ucr.ucr_request.bRequest = UR_SET_REPORT;
531 
532 	err = hid_ioctl(sc->sc_dev, USB_REQUEST, (uintptr_t)&ucr);
533 	if (err != 0) {
534 		DPRINTF("Failed to write device mode (%d)\n", err);
535 		return (EIO);
536 	}
537 
538 	return (0);
539 }
540 
541 static int
542 bcm5974_set_device_mode_hid(struct bcm5974_softc *sc, bool on)
543 {
544 	uint8_t	mode_bytes[BCM5974_HID_REPORT_LEN] = {
545 		BCM5974_HID_REPORT_ID,
546 		on ? BCM5974_HID_MODE_RAW : BCM5974_HID_MODE_HID,
547 	};
548 #if 0
549 	int err;
550 
551 	err = hid_get_report(sc->sc_dev, mode_bytes, BCM5974_HID_REPORT_LEN,
552 	    NULL, HID_FEATURE_REPORT, BCM5974_HID_REPORT_ID);
553 	if (err != 0) {
554 		DPRINTF("Failed to read device mode (%d)\n", err);
555 		return (err);
556 	}
557 	/*
558 	 * XXX Need to wait at least 250ms for hardware to get
559 	 * ready. The device mode handling appears to be handled
560 	 * asynchronously and we should not issue these commands too
561 	 * quickly.
562 	 */
563 	pause("WHW", hz / 4);
564 	mode_bytes[1] = on ? BCM5974_HID_MODE_RAW : BCM5974_HID_MODE_HID;
565 #endif
566 	return (hid_set_report(sc->sc_dev, mode_bytes, BCM5974_HID_REPORT_LEN,
567 	    HID_FEATURE_REPORT, BCM5974_HID_REPORT_ID));
568 }
569 
570 static int
571 bcm5974_set_device_mode(struct bcm5974_softc *sc, bool on)
572 {
573 	int err = 0;
574 
575 	switch (sc->sc_params->tp - tp) {
576 	case TYPE1:
577 	case TYPE2:
578 		err = bcm5974_set_device_mode_usb(sc, on);
579 		break;
580 	case TYPE3:	/* Type 3 does not require a mode switch */
581 		break;
582 	case TYPE4:
583 	case TYPE_MT2U:
584 		err = bcm5974_set_device_mode_hid(sc, on);
585 		break;
586 	default:
587 		KASSERT(0 == 1, ("Unknown trackpad type"));
588 	}
589 
590 	if (!err)
591 		sc->sc_saved_mode = on;
592 
593 	return (err);
594 }
595 
596 static void
597 bcm5974_identify(driver_t *driver, device_t parent)
598 {
599 	void *d_ptr;
600 	hid_size_t d_len;
601 
602 	/*
603 	 * The bcm5974 touchpad has no stable RAW mode TLC in its report
604 	 * descriptor.  So replace existing HID mode mouse TLC with dummy one
605 	 * to set proper transport layer buffer sizes, make driver probe
606 	 * simpler and prevent unwanted hms driver attachment.
607 	 */
608 	if (HIDBUS_LOOKUP_ID(parent, bcm5974_devs) != NULL &&
609 	    hid_get_report_descr(parent, &d_ptr, &d_len) == 0 &&
610 	    hid_is_mouse(d_ptr, d_len))
611 		hid_set_report_descr(parent, bcm5974_rdesc,
612 		    sizeof(bcm5974_rdesc));
613 }
614 
615 static int
616 bcm5974_probe(device_t dev)
617 {
618 	int err;
619 
620 	err = HIDBUS_LOOKUP_DRIVER_INFO(dev, bcm5974_devs);
621 	if (err != 0)
622 		return (err);
623 
624 	hidbus_set_desc(dev, "Touchpad");
625 
626 	return (BUS_PROBE_DEFAULT);
627 }
628 
629 static int
630 bcm5974_attach(device_t dev)
631 {
632 	struct bcm5974_softc *sc = device_get_softc(dev);
633 	const struct hid_device_info *hw = hid_get_device_info(dev);
634 	int err;
635 
636 	DPRINTFN(BCM5974_LLEVEL_INFO, "sc=%p\n", sc);
637 
638 	sc->sc_dev = dev;
639 
640 	/* get device specific configuration */
641 	sc->sc_params = bcm5974_dev_params + hidbus_get_driver_info(dev);
642 
643 	sc->sc_evdev = evdev_alloc();
644 	evdev_set_name(sc->sc_evdev, device_get_desc(dev));
645 	evdev_set_phys(sc->sc_evdev, device_get_nameunit(dev));
646 	evdev_set_id(sc->sc_evdev, hw->idBus, hw->idVendor, hw->idProduct,
647 	    hw->idVersion);
648 	evdev_set_serial(sc->sc_evdev, hw->serial);
649 	evdev_set_methods(sc->sc_evdev, sc, &bcm5974_evdev_methods);
650 	evdev_support_prop(sc->sc_evdev, INPUT_PROP_POINTER);
651 	evdev_support_event(sc->sc_evdev, EV_SYN);
652 	evdev_support_event(sc->sc_evdev, EV_ABS);
653 	evdev_support_event(sc->sc_evdev, EV_KEY);
654 	evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */
655 
656 #define BCM5974_ABS(evdev, code, param)					\
657 	evdev_support_abs((evdev), (code), (param).min, (param).max,	\
658 	((param).max - (param).min) / (param).snratio, 0,		\
659 	(param).size != 0 ? ((param).max - (param).min) / (param).size : 0);
660 
661 	/* finger position */
662 	BCM5974_ABS(sc->sc_evdev, ABS_MT_POSITION_X, sc->sc_params->x);
663 	BCM5974_ABS(sc->sc_evdev, ABS_MT_POSITION_Y, sc->sc_params->y);
664 	/* finger pressure */
665 	BCM5974_ABS(sc->sc_evdev, ABS_MT_PRESSURE, sc->sc_params->p);
666 	/* finger touch area */
667 	BCM5974_ABS(sc->sc_evdev, ABS_MT_TOUCH_MAJOR, sc->sc_params->w);
668 	BCM5974_ABS(sc->sc_evdev, ABS_MT_TOUCH_MINOR, sc->sc_params->w);
669 	/* finger approach area */
670 	if ((sc->sc_params->tp->caps & USES_COMPACT_REPORT) == 0) {
671 		BCM5974_ABS(sc->sc_evdev, ABS_MT_WIDTH_MAJOR, sc->sc_params->w);
672 		BCM5974_ABS(sc->sc_evdev, ABS_MT_WIDTH_MINOR, sc->sc_params->w);
673 	}
674 	/* finger orientation */
675 	BCM5974_ABS(sc->sc_evdev, ABS_MT_ORIENTATION, sc->sc_params->o);
676 	/* button properties */
677 	evdev_support_key(sc->sc_evdev, BTN_LEFT);
678 	if ((sc->sc_params->tp->caps & HAS_INTEGRATED_BUTTON) != 0)
679 		evdev_support_prop(sc->sc_evdev, INPUT_PROP_BUTTONPAD);
680 	/* Enable automatic touch assignment for type B MT protocol */
681 	evdev_support_abs(sc->sc_evdev, ABS_MT_SLOT,
682 	    0, MAX_FINGERS - 1, 0, 0, 0);
683 	evdev_support_abs(sc->sc_evdev, ABS_MT_TRACKING_ID,
684 	    -1, MAX_FINGERS - 1, 0, 0, 0);
685 	if ((sc->sc_params->tp->caps & USES_COMPACT_REPORT) == 0)
686 		evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_TRACK);
687 	evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_AUTOREL);
688 	/* Synaptics compatibility events */
689 	evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_STCOMPAT);
690 
691 	err = evdev_register(sc->sc_evdev);
692 	if (err)
693 		goto detach;
694 
695 	hidbus_set_intr(dev, bcm5974_intr, sc);
696 
697 	return (0);
698 
699 detach:
700 	bcm5974_detach(dev);
701 	return (ENOMEM);
702 }
703 
704 static int
705 bcm5974_detach(device_t dev)
706 {
707 	struct bcm5974_softc *sc = device_get_softc(dev);
708 
709 	evdev_free(sc->sc_evdev);
710 
711 	return (0);
712 }
713 
714 static int
715 bcm5974_resume(device_t dev)
716 {
717 	struct bcm5974_softc *sc = device_get_softc(dev);
718 
719 	bcm5974_set_device_mode(sc, sc->sc_saved_mode);
720 
721 	return (0);
722 }
723 
724 static void
725 bcm5974_intr(void *context, void *data, hid_size_t len)
726 {
727 	struct bcm5974_softc *sc = context;
728 	const struct bcm5974_dev_params *params = sc->sc_params;
729 	union evdev_mt_slot slot_data;
730 	struct tp_finger *f;
731 	struct tp_finger_compact *fc;
732 	int coords;
733 	int ntouch;			/* the finger number in touch */
734 	int ibt;			/* button status */
735 	int i;
736 	int slot;
737 	uint8_t fsize = sizeof(struct tp_finger) + params->tp->delta;
738 
739 	if ((params->tp->caps & USES_COMPACT_REPORT) != 0)
740 		fsize = sizeof(struct tp_finger_compact) + params->tp->delta;
741 
742 	if ((len < params->tp->offset + fsize) ||
743 	    ((len - params->tp->offset) % fsize) != 0) {
744 		DPRINTFN(BCM5974_LLEVEL_INFO, "Invalid length: %d, %x, %x\n",
745 		    len, sc->tp_data[0], sc->tp_data[1]);
746 		return;
747 	}
748 
749 	ibt = ((uint8_t *)data)[params->tp->button];
750 	ntouch = (len - params->tp->offset) / fsize;
751 
752 	for (i = 0, slot = 0; i != ntouch; i++) {
753 		if ((params->tp->caps & USES_COMPACT_REPORT) != 0) {
754 			fc = (struct tp_finger_compact *)(((uint8_t *)data) +
755 			     params->tp->offset + params->tp->delta + i * fsize);
756 			coords = (int)le32toh(fc->coords);
757 			DPRINTFN(BCM5974_LLEVEL_INFO,
758 			    "[%d]ibt=%d, taps=%d, x=%5d, y=%5d, state=%4d, "
759 			    "tchmaj=%4d, tchmin=%4d, size=%4d, pressure=%4d, "
760 			    "ot=%4x, id=%4x\n",
761 			    i, ibt, ntouch, coords << 19 >> 19,
762 			    coords << 6 >> 19, (u_int)coords >> 30,
763 			    fc->touch_major, fc->touch_minor, fc->size,
764 			    fc->pressure, fc->id_ori >> 5, fc->id_ori & 0x0f);
765 			if (fc->touch_major == 0)
766 				continue;
767 			slot_data = (union evdev_mt_slot) {
768 				.id = fc->id_ori & 0x0f,
769 				.x = coords << 19 >> 19,
770 				.y = params->y.min + params->y.max -
771 				    ((coords << 6) >> 19),
772 				.p = fc->pressure,
773 				.maj = fc->touch_major << 2,
774 				.min = fc->touch_minor << 2,
775 				.ori = (int)(fc->id_ori >> 5) - 4,
776 			};
777 			evdev_mt_push_slot(sc->sc_evdev, slot, &slot_data);
778 			slot++;
779 			continue;
780 		}
781 		f = (struct tp_finger *)(((uint8_t *)data) +
782 		    params->tp->offset + params->tp->delta + i * fsize);
783 		DPRINTFN(BCM5974_LLEVEL_INFO,
784 		    "[%d]ibt=%d, taps=%d, o=%4d, ax=%5d, ay=%5d, "
785 		    "rx=%5d, ry=%5d, tlmaj=%4d, tlmin=%4d, ot=%4x, "
786 		    "tchmaj=%4d, tchmin=%4d, pressure=%4d, m=%4x\n",
787 		    i, ibt, ntouch, BCM5974_LE2H(f->origin),
788 		    BCM5974_LE2H(f->abs_x), BCM5974_LE2H(f->abs_y),
789 		    BCM5974_LE2H(f->rel_x), BCM5974_LE2H(f->rel_y),
790 		    BCM5974_LE2H(f->tool_major), BCM5974_LE2H(f->tool_minor),
791 		    BCM5974_LE2H(f->orientation), BCM5974_LE2H(f->touch_major),
792 		    BCM5974_LE2H(f->touch_minor), BCM5974_LE2H(f->pressure),
793 		    BCM5974_LE2H(f->multi));
794 
795 		if (BCM5974_LE2H(f->touch_major) == 0)
796 			continue;
797 		slot_data = (union evdev_mt_slot) {
798 			.id = slot,
799 			.x = BCM5974_LE2H(f->abs_x),
800 			.y = params->y.min + params->y.max -
801 			     BCM5974_LE2H(f->abs_y),
802 			.p = BCM5974_LE2H(f->pressure),
803 			.maj = BCM5974_LE2H(f->touch_major) << 1,
804 			.min = BCM5974_LE2H(f->touch_minor) << 1,
805 			.w_maj = BCM5974_LE2H(f->tool_major) << 1,
806 			.w_min = BCM5974_LE2H(f->tool_minor) << 1,
807 			.ori = params->o.max - BCM5974_LE2H(f->orientation),
808 		};
809 		evdev_mt_push_slot(sc->sc_evdev, slot, &slot_data);
810 		slot++;
811 	}
812 
813 	evdev_push_key(sc->sc_evdev, BTN_LEFT, ibt);
814 	evdev_sync(sc->sc_evdev);
815 }
816 
817 static int
818 bcm5974_ev_open(struct evdev_dev *evdev)
819 {
820 	struct bcm5974_softc *sc = evdev_get_softc(evdev);
821 	int err;
822 
823 	/*
824 	 * By default the touchpad behaves like a HID device, sending
825 	 * packets with reportID = 8. Such reports contain only
826 	 * limited information. They encode movement deltas and button
827 	 * events, but do not include data from the pressure
828 	 * sensors. The device input mode can be switched from HID
829 	 * reports to raw sensor data using vendor-specific USB
830 	 * control commands:
831 	 */
832 	err = bcm5974_set_device_mode(sc, true);
833 	if (err != 0) {
834 		DPRINTF("failed to set mode to RAW MODE (%d)\n", err);
835 		return (err);
836 	}
837 
838 	return (hid_intr_start(sc->sc_dev));
839 }
840 
841 static int
842 bcm5974_ev_close(struct evdev_dev *evdev)
843 {
844 	struct bcm5974_softc *sc = evdev_get_softc(evdev);
845 	int err;
846 
847 	err = hid_intr_stop(sc->sc_dev);
848 	if (err != 0)
849 		return (err);
850 
851 	/*
852 	 * During re-enumeration of the device we need to force the
853 	 * device back into HID mode before switching it to RAW
854 	 * mode. Else the device does not work like expected.
855 	 */
856 	err = bcm5974_set_device_mode(sc, false);
857 	if (err != 0)
858 		DPRINTF("Failed to set mode to HID MODE (%d)\n", err);
859 
860 	return (err);
861 }
862 
863 static device_method_t bcm5974_methods[] = {
864 	/* Device interface */
865 	DEVMETHOD(device_identify,	bcm5974_identify),
866 	DEVMETHOD(device_probe,		bcm5974_probe),
867 	DEVMETHOD(device_attach,	bcm5974_attach),
868 	DEVMETHOD(device_detach,	bcm5974_detach),
869 	DEVMETHOD(device_resume,	bcm5974_resume),
870 	DEVMETHOD_END
871 };
872 
873 static driver_t bcm5974_driver = {
874 	.name = "bcm5974",
875 	.methods = bcm5974_methods,
876 	.size = sizeof(struct bcm5974_softc)
877 };
878 
879 DRIVER_MODULE(bcm5974, hidbus, bcm5974_driver, NULL, NULL);
880 MODULE_DEPEND(bcm5974, hidbus, 1, 1, 1);
881 MODULE_DEPEND(bcm5974, hid, 1, 1, 1);
882 MODULE_DEPEND(bcm5974, evdev, 1, 1, 1);
883 MODULE_VERSION(bcm5974, 1);
884 HID_PNP_INFO(bcm5974_devs);
885