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