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