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