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