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