1 1.21 thorpej /* $NetBSD: btmagic.c,v 1.21 2021/08/07 16:19:09 thorpej Exp $ */ 2 1.1 plunky 3 1.1 plunky /*- 4 1.1 plunky * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 1.1 plunky * All rights reserved. 6 1.1 plunky * 7 1.1 plunky * This code is derived from software contributed to The NetBSD Foundation 8 1.1 plunky * by Iain Hibbert. 9 1.1 plunky * 10 1.1 plunky * This code is derived from software contributed to The NetBSD Foundation 11 1.1 plunky * by Lennart Augustsson (lennart (at) augustsson.net) at 12 1.1 plunky * Carlstedt Research & Technology. 13 1.1 plunky * 14 1.1 plunky * Redistribution and use in source and binary forms, with or without 15 1.1 plunky * modification, are permitted provided that the following conditions 16 1.1 plunky * are met: 17 1.1 plunky * 1. Redistributions of source code must retain the above copyright 18 1.1 plunky * notice, this list of conditions and the following disclaimer. 19 1.1 plunky * 2. Redistributions in binary form must reproduce the above copyright 20 1.1 plunky * notice, this list of conditions and the following disclaimer in the 21 1.1 plunky * documentation and/or other materials provided with the distribution. 22 1.1 plunky * 23 1.1 plunky * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 24 1.1 plunky * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 1.1 plunky * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 1.1 plunky * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 27 1.1 plunky * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 1.1 plunky * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 1.1 plunky * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 1.1 plunky * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 1.1 plunky * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 1.1 plunky * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 1.1 plunky * POSSIBILITY OF SUCH DAMAGE. 34 1.1 plunky */ 35 1.1 plunky /*- 36 1.1 plunky * Copyright (c) 2006 Itronix Inc. 37 1.1 plunky * All rights reserved. 38 1.1 plunky * 39 1.1 plunky * Written by Iain Hibbert for Itronix Inc. 40 1.1 plunky * 41 1.1 plunky * Redistribution and use in source and binary forms, with or without 42 1.1 plunky * modification, are permitted provided that the following conditions 43 1.1 plunky * are met: 44 1.1 plunky * 1. Redistributions of source code must retain the above copyright 45 1.1 plunky * notice, this list of conditions and the following disclaimer. 46 1.1 plunky * 2. Redistributions in binary form must reproduce the above copyright 47 1.1 plunky * notice, this list of conditions and the following disclaimer in the 48 1.1 plunky * documentation and/or other materials provided with the distribution. 49 1.1 plunky * 3. The name of Itronix Inc. may not be used to endorse 50 1.1 plunky * or promote products derived from this software without specific 51 1.1 plunky * prior written permission. 52 1.1 plunky * 53 1.1 plunky * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 54 1.1 plunky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 55 1.1 plunky * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 56 1.1 plunky * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 57 1.1 plunky * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 58 1.1 plunky * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 59 1.1 plunky * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 60 1.1 plunky * ON ANY THEORY OF LIABILITY, WHETHER IN 61 1.1 plunky * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 62 1.1 plunky * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 63 1.1 plunky * POSSIBILITY OF SUCH DAMAGE. 64 1.1 plunky */ 65 1.1 plunky 66 1.1 plunky 67 1.1 plunky /***************************************************************************** 68 1.1 plunky * 69 1.1 plunky * Apple Bluetooth Magic Mouse driver 70 1.1 plunky * 71 1.1 plunky * The Apple Magic Mouse is a HID device but it doesn't provide a proper HID 72 1.1 plunky * descriptor, and requires extra initializations to enable the proprietary 73 1.1 plunky * touch reports. We match against the vendor-id and product-id and provide 74 1.1 plunky * our own Bluetooth connection handling as the bthidev driver does not cater 75 1.1 plunky * for such complications. 76 1.1 plunky * 77 1.1 plunky * This driver interprets the touch reports only as far as emulating a 78 1.1 plunky * middle mouse button and providing horizontal and vertical scroll action. 79 1.1 plunky * Full gesture support would be more complicated and is left as an exercise 80 1.1 plunky * for the reader. 81 1.1 plunky * 82 1.1 plunky * Credit for decoding the proprietary touch reports goes to Michael Poole 83 1.1 plunky * who wrote the Linux hid-magicmouse input driver. 84 1.1 plunky * 85 1.1 plunky *****************************************************************************/ 86 1.1 plunky 87 1.1 plunky #include <sys/cdefs.h> 88 1.21 thorpej __KERNEL_RCSID(0, "$NetBSD: btmagic.c,v 1.21 2021/08/07 16:19:09 thorpej Exp $"); 89 1.1 plunky 90 1.1 plunky #include <sys/param.h> 91 1.1 plunky #include <sys/conf.h> 92 1.1 plunky #include <sys/device.h> 93 1.1 plunky #include <sys/fcntl.h> 94 1.1 plunky #include <sys/kernel.h> 95 1.1 plunky #include <sys/malloc.h> 96 1.1 plunky #include <sys/mbuf.h> 97 1.1 plunky #include <sys/proc.h> 98 1.1 plunky #include <sys/socketvar.h> 99 1.1 plunky #include <sys/systm.h> 100 1.1 plunky #include <sys/sysctl.h> 101 1.1 plunky 102 1.1 plunky #include <prop/proplib.h> 103 1.1 plunky 104 1.1 plunky #include <netbt/bluetooth.h> 105 1.1 plunky #include <netbt/l2cap.h> 106 1.1 plunky 107 1.1 plunky #include <dev/bluetooth/btdev.h> 108 1.1 plunky #include <dev/bluetooth/bthid.h> 109 1.1 plunky #include <dev/bluetooth/bthidev.h> 110 1.1 plunky 111 1.17 bouyer #include <dev/hid/hid.h> 112 1.1 plunky #include <dev/usb/usb.h> 113 1.1 plunky #include <dev/usb/usbdevs.h> 114 1.1 plunky 115 1.1 plunky #include <dev/wscons/wsconsio.h> 116 1.1 plunky #include <dev/wscons/wsmousevar.h> 117 1.1 plunky 118 1.1 plunky #undef DPRINTF 119 1.1 plunky #ifdef BTMAGIC_DEBUG 120 1.1 plunky #define DPRINTF(sc, ...) do { \ 121 1.1 plunky printf("%s: ", device_xname((sc)->sc_dev)); \ 122 1.1 plunky printf(__VA_ARGS__); \ 123 1.1 plunky printf("\n"); \ 124 1.1 plunky } while (/*CONSTCOND*/0) 125 1.1 plunky #else 126 1.1 plunky #define DPRINTF(...) (void)0 127 1.1 plunky #endif 128 1.1 plunky 129 1.1 plunky struct btmagic_softc { 130 1.1 plunky bdaddr_t sc_laddr; /* local address */ 131 1.1 plunky bdaddr_t sc_raddr; /* remote address */ 132 1.1 plunky struct sockopt sc_mode; /* link mode */ 133 1.1 plunky 134 1.1 plunky device_t sc_dev; 135 1.1 plunky uint16_t sc_state; 136 1.1 plunky uint16_t sc_flags; 137 1.1 plunky 138 1.1 plunky callout_t sc_timeout; 139 1.1 plunky 140 1.1 plunky /* control */ 141 1.1 plunky struct l2cap_channel *sc_ctl; 142 1.1 plunky struct l2cap_channel *sc_ctl_l; 143 1.1 plunky 144 1.1 plunky /* interrupt */ 145 1.1 plunky struct l2cap_channel *sc_int; 146 1.1 plunky struct l2cap_channel *sc_int_l; 147 1.1 plunky 148 1.1 plunky /* wsmouse child */ 149 1.1 plunky device_t sc_wsmouse; 150 1.1 plunky int sc_enabled; 151 1.1 plunky 152 1.1 plunky /* config */ 153 1.1 plunky int sc_resolution; /* for soft scaling */ 154 1.1 plunky int sc_firm; /* firm touch threshold */ 155 1.1 plunky int sc_dist; /* scroll distance threshold */ 156 1.1 plunky int sc_scale; /* scroll descaling */ 157 1.1 plunky struct sysctllog *sc_log; /* sysctl teardown log */ 158 1.1 plunky 159 1.1 plunky /* remainders */ 160 1.1 plunky int sc_rx; 161 1.1 plunky int sc_ry; 162 1.1 plunky int sc_rz; 163 1.1 plunky int sc_rw; 164 1.1 plunky 165 1.1 plunky /* previous touches */ 166 1.15 plunky uint32_t sc_smask; /* active IDs */ 167 1.12 bouyer int sc_nfingers; /* number of active IDs */ 168 1.12 bouyer int sc_ax[16]; 169 1.12 bouyer int sc_ay[16]; 170 1.1 plunky 171 1.1 plunky /* previous mouse buttons */ 172 1.12 bouyer int sc_mb_id; /* which ID selects the button */ 173 1.1 plunky uint32_t sc_mb; 174 1.14 bouyer /* button emulation with tap */ 175 1.14 bouyer int sc_tapmb_id; /* which ID selects the button */ 176 1.14 bouyer struct timeval sc_taptime; 177 1.14 bouyer int sc_taptimeout; 178 1.14 bouyer callout_t sc_tapcallout; 179 1.1 plunky }; 180 1.1 plunky 181 1.1 plunky /* sc_flags */ 182 1.1 plunky #define BTMAGIC_CONNECTING __BIT(0) /* we are connecting */ 183 1.1 plunky #define BTMAGIC_ENABLED __BIT(1) /* touch reports enabled */ 184 1.1 plunky 185 1.1 plunky /* sc_state */ 186 1.1 plunky #define BTMAGIC_CLOSED 0 187 1.1 plunky #define BTMAGIC_WAIT_CTL 1 188 1.1 plunky #define BTMAGIC_WAIT_INT 2 189 1.1 plunky #define BTMAGIC_OPEN 3 190 1.1 plunky 191 1.1 plunky /* autoconf(9) glue */ 192 1.1 plunky static int btmagic_match(device_t, cfdata_t, void *); 193 1.1 plunky static void btmagic_attach(device_t, device_t, void *); 194 1.1 plunky static int btmagic_detach(device_t, int); 195 1.1 plunky static int btmagic_listen(struct btmagic_softc *); 196 1.1 plunky static int btmagic_connect(struct btmagic_softc *); 197 1.1 plunky static int btmagic_sysctl_resolution(SYSCTLFN_PROTO); 198 1.1 plunky static int btmagic_sysctl_scale(SYSCTLFN_PROTO); 199 1.16 msaitoh static int btmagic_tap(struct btmagic_softc *, int); 200 1.14 bouyer static int btmagic_sysctl_taptimeout(SYSCTLFN_PROTO); 201 1.1 plunky 202 1.1 plunky CFATTACH_DECL_NEW(btmagic, sizeof(struct btmagic_softc), 203 1.1 plunky btmagic_match, btmagic_attach, btmagic_detach, NULL); 204 1.1 plunky 205 1.1 plunky /* wsmouse(4) accessops */ 206 1.16 msaitoh static int btmagic_wsmouse_enable(void *); 207 1.16 msaitoh static int btmagic_wsmouse_ioctl(void *, unsigned long, void *, int, struct lwp *); 208 1.1 plunky static void btmagic_wsmouse_disable(void *); 209 1.1 plunky 210 1.1 plunky static const struct wsmouse_accessops btmagic_wsmouse_accessops = { 211 1.1 plunky btmagic_wsmouse_enable, 212 1.1 plunky btmagic_wsmouse_ioctl, 213 1.1 plunky btmagic_wsmouse_disable, 214 1.1 plunky }; 215 1.1 plunky 216 1.1 plunky /* bluetooth(9) protocol methods for L2CAP */ 217 1.1 plunky static void btmagic_connecting(void *); 218 1.1 plunky static void btmagic_ctl_connected(void *); 219 1.1 plunky static void btmagic_int_connected(void *); 220 1.1 plunky static void btmagic_ctl_disconnected(void *, int); 221 1.1 plunky static void btmagic_int_disconnected(void *, int); 222 1.1 plunky static void *btmagic_ctl_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 223 1.1 plunky static void *btmagic_int_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 224 1.1 plunky static void btmagic_complete(void *, int); 225 1.1 plunky static void btmagic_linkmode(void *, int); 226 1.1 plunky static void btmagic_input(void *, struct mbuf *); 227 1.1 plunky static void btmagic_input_basic(struct btmagic_softc *, uint8_t *, size_t); 228 1.12 bouyer static void btmagic_input_magicm(struct btmagic_softc *, uint8_t *, size_t); 229 1.12 bouyer static void btmagic_input_magict(struct btmagic_softc *, uint8_t *, size_t); 230 1.14 bouyer static void btmagic_tapcallout(void *); 231 1.12 bouyer 232 1.12 bouyer /* report types (data[1]) */ 233 1.12 bouyer #define BASIC_REPORT_ID 0x10 234 1.12 bouyer #define TRACKPAD_REPORT_ID 0x28 235 1.12 bouyer #define MOUSE_REPORT_ID 0x29 236 1.12 bouyer #define BATT_STAT_REPORT_ID 0x30 237 1.15 plunky #define BATT_STRENGTH_REPORT_ID 0x47 238 1.12 bouyer #define SURFACE_REPORT_ID 0x61 239 1.1 plunky 240 1.1 plunky static const struct btproto btmagic_ctl_proto = { 241 1.1 plunky btmagic_connecting, 242 1.1 plunky btmagic_ctl_connected, 243 1.1 plunky btmagic_ctl_disconnected, 244 1.1 plunky btmagic_ctl_newconn, 245 1.1 plunky btmagic_complete, 246 1.1 plunky btmagic_linkmode, 247 1.1 plunky btmagic_input, 248 1.1 plunky }; 249 1.1 plunky 250 1.1 plunky static const struct btproto btmagic_int_proto = { 251 1.1 plunky btmagic_connecting, 252 1.1 plunky btmagic_int_connected, 253 1.1 plunky btmagic_int_disconnected, 254 1.1 plunky btmagic_int_newconn, 255 1.1 plunky btmagic_complete, 256 1.1 plunky btmagic_linkmode, 257 1.1 plunky btmagic_input, 258 1.1 plunky }; 259 1.1 plunky 260 1.1 plunky /* btmagic internals */ 261 1.1 plunky static void btmagic_timeout(void *); 262 1.1 plunky static int btmagic_ctl_send(struct btmagic_softc *, const uint8_t *, size_t); 263 1.1 plunky static void btmagic_enable(struct btmagic_softc *); 264 1.1 plunky static void btmagic_check_battery(struct btmagic_softc *); 265 1.1 plunky static int btmagic_scale(int, int *, int); 266 1.1 plunky 267 1.1 plunky 268 1.1 plunky /***************************************************************************** 269 1.1 plunky * 270 1.1 plunky * Magic Mouse autoconf(9) routines 271 1.1 plunky */ 272 1.1 plunky 273 1.1 plunky static int 274 1.1 plunky btmagic_match(device_t self, cfdata_t cfdata, void *aux) 275 1.1 plunky { 276 1.1 plunky uint16_t v, p; 277 1.1 plunky 278 1.1 plunky if (prop_dictionary_get_uint16(aux, BTDEVvendor, &v) 279 1.1 plunky && prop_dictionary_get_uint16(aux, BTDEVproduct, &p) 280 1.1 plunky && v == USB_VENDOR_APPLE 281 1.12 bouyer && (p == USB_PRODUCT_APPLE_MAGICMOUSE || 282 1.12 bouyer p == USB_PRODUCT_APPLE_MAGICTRACKPAD)) 283 1.1 plunky return 2; /* trump bthidev(4) */ 284 1.1 plunky 285 1.1 plunky return 0; 286 1.1 plunky } 287 1.1 plunky 288 1.1 plunky static void 289 1.1 plunky btmagic_attach(device_t parent, device_t self, void *aux) 290 1.1 plunky { 291 1.1 plunky struct btmagic_softc *sc = device_private(self); 292 1.1 plunky struct wsmousedev_attach_args wsma; 293 1.1 plunky const struct sysctlnode *node; 294 1.1 plunky prop_object_t obj; 295 1.5 plunky int err; 296 1.1 plunky 297 1.1 plunky /* 298 1.1 plunky * Init softc 299 1.1 plunky */ 300 1.1 plunky sc->sc_dev = self; 301 1.1 plunky sc->sc_state = BTMAGIC_CLOSED; 302 1.14 bouyer sc->sc_mb_id = -1; 303 1.14 bouyer sc->sc_tapmb_id = -1; 304 1.1 plunky callout_init(&sc->sc_timeout, 0); 305 1.1 plunky callout_setfunc(&sc->sc_timeout, btmagic_timeout, sc); 306 1.14 bouyer callout_init(&sc->sc_tapcallout, 0); 307 1.14 bouyer callout_setfunc(&sc->sc_tapcallout, btmagic_tapcallout, sc); 308 1.1 plunky sockopt_init(&sc->sc_mode, BTPROTO_L2CAP, SO_L2CAP_LM, 0); 309 1.1 plunky 310 1.1 plunky /* 311 1.1 plunky * extract config from proplist 312 1.1 plunky */ 313 1.1 plunky obj = prop_dictionary_get(aux, BTDEVladdr); 314 1.19 thorpej bdaddr_copy(&sc->sc_laddr, prop_data_value(obj)); 315 1.1 plunky 316 1.1 plunky obj = prop_dictionary_get(aux, BTDEVraddr); 317 1.19 thorpej bdaddr_copy(&sc->sc_raddr, prop_data_value(obj)); 318 1.1 plunky 319 1.1 plunky obj = prop_dictionary_get(aux, BTDEVmode); 320 1.1 plunky if (prop_object_type(obj) == PROP_TYPE_STRING) { 321 1.19 thorpej if (prop_string_equals_string(obj, BTDEVauth)) 322 1.1 plunky sockopt_setint(&sc->sc_mode, L2CAP_LM_AUTH); 323 1.19 thorpej else if (prop_string_equals_string(obj, BTDEVencrypt)) 324 1.1 plunky sockopt_setint(&sc->sc_mode, L2CAP_LM_ENCRYPT); 325 1.19 thorpej else if (prop_string_equals_string(obj, BTDEVsecure)) 326 1.1 plunky sockopt_setint(&sc->sc_mode, L2CAP_LM_SECURE); 327 1.1 plunky else { 328 1.1 plunky aprint_error(" unknown %s\n", BTDEVmode); 329 1.1 plunky return; 330 1.1 plunky } 331 1.1 plunky 332 1.1 plunky aprint_verbose(" %s %s", BTDEVmode, 333 1.19 thorpej prop_string_value(obj)); 334 1.4 plunky } else 335 1.4 plunky sockopt_setint(&sc->sc_mode, 0); 336 1.1 plunky 337 1.1 plunky aprint_normal(": 3 buttons, W and Z dirs\n"); 338 1.1 plunky aprint_naive("\n"); 339 1.1 plunky 340 1.1 plunky /* 341 1.1 plunky * set defaults 342 1.1 plunky */ 343 1.1 plunky sc->sc_resolution = 650; 344 1.1 plunky sc->sc_firm = 6; 345 1.1 plunky sc->sc_dist = 130; 346 1.1 plunky sc->sc_scale = 20; 347 1.14 bouyer sc->sc_taptimeout = 100; 348 1.1 plunky 349 1.1 plunky sysctl_createv(&sc->sc_log, 0, NULL, &node, 350 1.1 plunky 0, 351 1.1 plunky CTLTYPE_NODE, device_xname(self), 352 1.1 plunky NULL, 353 1.1 plunky NULL, 0, 354 1.1 plunky NULL, 0, 355 1.1 plunky CTL_HW, 356 1.1 plunky CTL_CREATE, CTL_EOL); 357 1.1 plunky 358 1.1 plunky if (node != NULL) { 359 1.1 plunky sysctl_createv(&sc->sc_log, 0, NULL, NULL, 360 1.1 plunky CTLFLAG_READWRITE, 361 1.1 plunky CTLTYPE_INT, "soft_resolution", 362 1.1 plunky NULL, 363 1.1 plunky btmagic_sysctl_resolution, 0, 364 1.3 dsl (void *)sc, 0, 365 1.1 plunky CTL_HW, node->sysctl_num, 366 1.1 plunky CTL_CREATE, CTL_EOL); 367 1.1 plunky 368 1.1 plunky sysctl_createv(&sc->sc_log, 0, NULL, NULL, 369 1.1 plunky CTLFLAG_READWRITE, 370 1.1 plunky CTLTYPE_INT, "firm_touch_threshold", 371 1.1 plunky NULL, 372 1.1 plunky NULL, 0, 373 1.1 plunky &sc->sc_firm, sizeof(sc->sc_firm), 374 1.1 plunky CTL_HW, node->sysctl_num, 375 1.1 plunky CTL_CREATE, CTL_EOL); 376 1.1 plunky 377 1.1 plunky sysctl_createv(&sc->sc_log, 0, NULL, NULL, 378 1.1 plunky CTLFLAG_READWRITE, 379 1.1 plunky CTLTYPE_INT, "scroll_distance_threshold", 380 1.1 plunky NULL, 381 1.1 plunky NULL, 0, 382 1.1 plunky &sc->sc_dist, sizeof(sc->sc_dist), 383 1.1 plunky CTL_HW, node->sysctl_num, 384 1.1 plunky CTL_CREATE, CTL_EOL); 385 1.1 plunky 386 1.1 plunky sysctl_createv(&sc->sc_log, 0, NULL, NULL, 387 1.1 plunky CTLFLAG_READWRITE, 388 1.1 plunky CTLTYPE_INT, "scroll_downscale_factor", 389 1.1 plunky NULL, 390 1.1 plunky btmagic_sysctl_scale, 0, 391 1.3 dsl (void *)sc, 0, 392 1.1 plunky CTL_HW, node->sysctl_num, 393 1.1 plunky CTL_CREATE, CTL_EOL); 394 1.14 bouyer sysctl_createv(&sc->sc_log, 0, NULL, NULL, 395 1.14 bouyer CTLFLAG_READWRITE, 396 1.14 bouyer CTLTYPE_INT, "taptimeout", 397 1.14 bouyer "timeout for tap detection in milliseconds", 398 1.14 bouyer btmagic_sysctl_taptimeout, 0, 399 1.14 bouyer (void *)sc, 0, 400 1.14 bouyer CTL_HW, node->sysctl_num, 401 1.14 bouyer CTL_CREATE, CTL_EOL); 402 1.1 plunky } 403 1.1 plunky 404 1.1 plunky /* 405 1.1 plunky * attach the wsmouse 406 1.1 plunky */ 407 1.1 plunky wsma.accessops = &btmagic_wsmouse_accessops; 408 1.1 plunky wsma.accesscookie = self; 409 1.21 thorpej sc->sc_wsmouse = config_found(self, &wsma, wsmousedevprint, CFARGS_NONE); 410 1.1 plunky if (sc->sc_wsmouse == NULL) { 411 1.1 plunky aprint_error_dev(self, "failed to attach wsmouse\n"); 412 1.1 plunky return; 413 1.1 plunky } 414 1.1 plunky 415 1.2 plunky pmf_device_register(self, NULL, NULL); 416 1.2 plunky 417 1.1 plunky /* 418 1.1 plunky * start bluetooth connections 419 1.1 plunky */ 420 1.1 plunky mutex_enter(bt_lock); 421 1.5 plunky if ((err = btmagic_listen(sc)) != 0) 422 1.5 plunky aprint_error_dev(self, "failed to listen (%d)\n", err); 423 1.1 plunky btmagic_connect(sc); 424 1.1 plunky mutex_exit(bt_lock); 425 1.1 plunky } 426 1.1 plunky 427 1.1 plunky static int 428 1.1 plunky btmagic_detach(device_t self, int flags) 429 1.1 plunky { 430 1.1 plunky struct btmagic_softc *sc = device_private(self); 431 1.1 plunky int err = 0; 432 1.1 plunky 433 1.1 plunky mutex_enter(bt_lock); 434 1.1 plunky 435 1.1 plunky /* release interrupt listen */ 436 1.1 plunky if (sc->sc_int_l != NULL) { 437 1.7 rmind l2cap_detach_pcb(&sc->sc_int_l); 438 1.1 plunky sc->sc_int_l = NULL; 439 1.1 plunky } 440 1.1 plunky 441 1.1 plunky /* release control listen */ 442 1.1 plunky if (sc->sc_ctl_l != NULL) { 443 1.7 rmind l2cap_detach_pcb(&sc->sc_ctl_l); 444 1.1 plunky sc->sc_ctl_l = NULL; 445 1.1 plunky } 446 1.1 plunky 447 1.1 plunky /* close interrupt channel */ 448 1.1 plunky if (sc->sc_int != NULL) { 449 1.10 rtr l2cap_disconnect_pcb(sc->sc_int, 0); 450 1.7 rmind l2cap_detach_pcb(&sc->sc_int); 451 1.1 plunky sc->sc_int = NULL; 452 1.1 plunky } 453 1.1 plunky 454 1.1 plunky /* close control channel */ 455 1.1 plunky if (sc->sc_ctl != NULL) { 456 1.10 rtr l2cap_disconnect_pcb(sc->sc_ctl, 0); 457 1.7 rmind l2cap_detach_pcb(&sc->sc_ctl); 458 1.1 plunky sc->sc_ctl = NULL; 459 1.1 plunky } 460 1.1 plunky 461 1.14 bouyer callout_halt(&sc->sc_tapcallout, bt_lock); 462 1.14 bouyer callout_destroy(&sc->sc_tapcallout); 463 1.1 plunky callout_halt(&sc->sc_timeout, bt_lock); 464 1.1 plunky callout_destroy(&sc->sc_timeout); 465 1.1 plunky 466 1.1 plunky mutex_exit(bt_lock); 467 1.1 plunky 468 1.2 plunky pmf_device_deregister(self); 469 1.2 plunky 470 1.1 plunky sockopt_destroy(&sc->sc_mode); 471 1.1 plunky 472 1.1 plunky sysctl_teardown(&sc->sc_log); 473 1.1 plunky 474 1.1 plunky if (sc->sc_wsmouse != NULL) { 475 1.1 plunky err = config_detach(sc->sc_wsmouse, flags); 476 1.1 plunky sc->sc_wsmouse = NULL; 477 1.1 plunky } 478 1.1 plunky 479 1.1 plunky return err; 480 1.1 plunky } 481 1.1 plunky 482 1.1 plunky /* 483 1.1 plunky * listen for our device 484 1.1 plunky * 485 1.1 plunky * bt_lock is held 486 1.1 plunky */ 487 1.1 plunky static int 488 1.1 plunky btmagic_listen(struct btmagic_softc *sc) 489 1.1 plunky { 490 1.1 plunky struct sockaddr_bt sa; 491 1.1 plunky int err; 492 1.1 plunky 493 1.1 plunky memset(&sa, 0, sizeof(sa)); 494 1.1 plunky sa.bt_len = sizeof(sa); 495 1.1 plunky sa.bt_family = AF_BLUETOOTH; 496 1.1 plunky bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); 497 1.1 plunky 498 1.1 plunky /* 499 1.1 plunky * Listen on control PSM 500 1.1 plunky */ 501 1.7 rmind err = l2cap_attach_pcb(&sc->sc_ctl_l, &btmagic_ctl_proto, sc); 502 1.1 plunky if (err) 503 1.1 plunky return err; 504 1.1 plunky 505 1.1 plunky err = l2cap_setopt(sc->sc_ctl_l, &sc->sc_mode); 506 1.1 plunky if (err) 507 1.1 plunky return err; 508 1.1 plunky 509 1.1 plunky sa.bt_psm = L2CAP_PSM_HID_CNTL; 510 1.8 rtr err = l2cap_bind_pcb(sc->sc_ctl_l, &sa); 511 1.1 plunky if (err) 512 1.1 plunky return err; 513 1.1 plunky 514 1.8 rtr err = l2cap_listen_pcb(sc->sc_ctl_l); 515 1.1 plunky if (err) 516 1.1 plunky return err; 517 1.1 plunky 518 1.1 plunky /* 519 1.1 plunky * Listen on interrupt PSM 520 1.1 plunky */ 521 1.7 rmind err = l2cap_attach_pcb(&sc->sc_int_l, &btmagic_int_proto, sc); 522 1.1 plunky if (err) 523 1.1 plunky return err; 524 1.1 plunky 525 1.1 plunky err = l2cap_setopt(sc->sc_int_l, &sc->sc_mode); 526 1.1 plunky if (err) 527 1.1 plunky return err; 528 1.1 plunky 529 1.1 plunky sa.bt_psm = L2CAP_PSM_HID_INTR; 530 1.8 rtr err = l2cap_bind_pcb(sc->sc_int_l, &sa); 531 1.1 plunky if (err) 532 1.1 plunky return err; 533 1.1 plunky 534 1.8 rtr err = l2cap_listen_pcb(sc->sc_int_l); 535 1.1 plunky if (err) 536 1.1 plunky return err; 537 1.1 plunky 538 1.1 plunky sc->sc_state = BTMAGIC_WAIT_CTL; 539 1.1 plunky return 0; 540 1.1 plunky } 541 1.1 plunky 542 1.1 plunky /* 543 1.1 plunky * start connecting to our device 544 1.1 plunky * 545 1.1 plunky * bt_lock is held 546 1.1 plunky */ 547 1.1 plunky static int 548 1.1 plunky btmagic_connect(struct btmagic_softc *sc) 549 1.1 plunky { 550 1.1 plunky struct sockaddr_bt sa; 551 1.1 plunky int err; 552 1.1 plunky 553 1.1 plunky memset(&sa, 0, sizeof(sa)); 554 1.1 plunky sa.bt_len = sizeof(sa); 555 1.1 plunky sa.bt_family = AF_BLUETOOTH; 556 1.1 plunky 557 1.7 rmind err = l2cap_attach_pcb(&sc->sc_ctl, &btmagic_ctl_proto, sc); 558 1.1 plunky if (err) { 559 1.1 plunky printf("%s: l2cap_attach failed (%d)\n", 560 1.1 plunky device_xname(sc->sc_dev), err); 561 1.1 plunky return err; 562 1.1 plunky } 563 1.1 plunky 564 1.1 plunky err = l2cap_setopt(sc->sc_ctl, &sc->sc_mode); 565 1.5 plunky if (err) { 566 1.5 plunky printf("%s: l2cap_setopt failed (%d)\n", 567 1.5 plunky device_xname(sc->sc_dev), err); 568 1.1 plunky return err; 569 1.5 plunky } 570 1.1 plunky 571 1.1 plunky bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); 572 1.8 rtr err = l2cap_bind_pcb(sc->sc_ctl, &sa); 573 1.1 plunky if (err) { 574 1.8 rtr printf("%s: l2cap_bind_pcb failed (%d)\n", 575 1.1 plunky device_xname(sc->sc_dev), err); 576 1.1 plunky return err; 577 1.1 plunky } 578 1.1 plunky 579 1.1 plunky sa.bt_psm = L2CAP_PSM_HID_CNTL; 580 1.1 plunky bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); 581 1.9 rtr err = l2cap_connect_pcb(sc->sc_ctl, &sa); 582 1.1 plunky if (err) { 583 1.9 rtr printf("%s: l2cap_connect_pcb failed (%d)\n", 584 1.1 plunky device_xname(sc->sc_dev), err); 585 1.1 plunky return err; 586 1.1 plunky } 587 1.1 plunky 588 1.1 plunky SET(sc->sc_flags, BTMAGIC_CONNECTING); 589 1.1 plunky sc->sc_state = BTMAGIC_WAIT_CTL; 590 1.1 plunky return 0; 591 1.1 plunky } 592 1.1 plunky 593 1.1 plunky /* validate soft_resolution */ 594 1.1 plunky static int 595 1.1 plunky btmagic_sysctl_resolution(SYSCTLFN_ARGS) 596 1.1 plunky { 597 1.1 plunky struct sysctlnode node; 598 1.1 plunky struct btmagic_softc *sc; 599 1.1 plunky int t, error; 600 1.1 plunky 601 1.1 plunky node = *rnode; 602 1.1 plunky sc = node.sysctl_data; 603 1.1 plunky 604 1.1 plunky t = sc->sc_resolution; 605 1.1 plunky node.sysctl_data = &t; 606 1.1 plunky error = sysctl_lookup(SYSCTLFN_CALL(&node)); 607 1.1 plunky if (error || newp == NULL) 608 1.1 plunky return error; 609 1.1 plunky 610 1.1 plunky if (t < 100 || t > 4000 || (t / sc->sc_scale) == 0) 611 1.1 plunky return EINVAL; 612 1.1 plunky 613 1.1 plunky sc->sc_resolution = t; 614 1.1 plunky DPRINTF(sc, "sc_resolution = %u", t); 615 1.1 plunky return 0; 616 1.1 plunky } 617 1.1 plunky 618 1.1 plunky /* validate scroll_downscale_factor */ 619 1.1 plunky static int 620 1.1 plunky btmagic_sysctl_scale(SYSCTLFN_ARGS) 621 1.1 plunky { 622 1.1 plunky struct sysctlnode node; 623 1.1 plunky struct btmagic_softc *sc; 624 1.1 plunky int t, error; 625 1.1 plunky 626 1.1 plunky node = *rnode; 627 1.1 plunky sc = node.sysctl_data; 628 1.1 plunky 629 1.1 plunky t = sc->sc_scale; 630 1.1 plunky node.sysctl_data = &t; 631 1.1 plunky error = sysctl_lookup(SYSCTLFN_CALL(&node)); 632 1.1 plunky if (error || newp == NULL) 633 1.1 plunky return error; 634 1.1 plunky 635 1.1 plunky if (t < 1 || t > 40 || (sc->sc_resolution / t) == 0) 636 1.1 plunky return EINVAL; 637 1.1 plunky 638 1.1 plunky sc->sc_scale = t; 639 1.1 plunky DPRINTF(sc, "sc_scale = %u", t); 640 1.1 plunky return 0; 641 1.1 plunky } 642 1.1 plunky 643 1.14 bouyer /* validate tap timeout */ 644 1.14 bouyer static int 645 1.14 bouyer btmagic_sysctl_taptimeout(SYSCTLFN_ARGS) 646 1.14 bouyer { 647 1.14 bouyer struct sysctlnode node; 648 1.14 bouyer struct btmagic_softc *sc; 649 1.14 bouyer int t, error; 650 1.14 bouyer 651 1.14 bouyer node = *rnode; 652 1.14 bouyer sc = node.sysctl_data; 653 1.14 bouyer 654 1.14 bouyer t = sc->sc_taptimeout; 655 1.14 bouyer node.sysctl_data = &t; 656 1.14 bouyer error = sysctl_lookup(SYSCTLFN_CALL(&node)); 657 1.14 bouyer if (error || newp == NULL) 658 1.14 bouyer return error; 659 1.14 bouyer 660 1.18 riastrad if (t < uimax(1000 / hz, 1) || t > 999) 661 1.14 bouyer return EINVAL; 662 1.14 bouyer 663 1.14 bouyer sc->sc_taptimeout = t; 664 1.14 bouyer DPRINTF(sc, "taptimeout = %u", t); 665 1.14 bouyer return 0; 666 1.14 bouyer } 667 1.14 bouyer 668 1.1 plunky /***************************************************************************** 669 1.1 plunky * 670 1.1 plunky * wsmouse(4) accessops 671 1.1 plunky */ 672 1.1 plunky 673 1.1 plunky static int 674 1.1 plunky btmagic_wsmouse_enable(void *self) 675 1.1 plunky { 676 1.1 plunky struct btmagic_softc *sc = device_private(self); 677 1.1 plunky 678 1.1 plunky if (sc->sc_enabled) 679 1.1 plunky return EBUSY; 680 1.1 plunky 681 1.1 plunky sc->sc_enabled = 1; 682 1.1 plunky DPRINTF(sc, "enable"); 683 1.1 plunky return 0; 684 1.1 plunky } 685 1.1 plunky 686 1.1 plunky static int 687 1.1 plunky btmagic_wsmouse_ioctl(void *self, unsigned long cmd, void *data, 688 1.1 plunky int flag, struct lwp *l) 689 1.1 plunky { 690 1.1 plunky /* struct btmagic_softc *sc = device_private(self); */ 691 1.1 plunky int err; 692 1.1 plunky 693 1.1 plunky switch (cmd) { 694 1.1 plunky case WSMOUSEIO_GTYPE: 695 1.1 plunky *(uint *)data = WSMOUSE_TYPE_BLUETOOTH; 696 1.1 plunky err = 0; 697 1.1 plunky break; 698 1.1 plunky 699 1.1 plunky default: 700 1.1 plunky err = EPASSTHROUGH; 701 1.1 plunky break; 702 1.1 plunky } 703 1.1 plunky 704 1.1 plunky return err; 705 1.1 plunky } 706 1.1 plunky 707 1.1 plunky static void 708 1.1 plunky btmagic_wsmouse_disable(void *self) 709 1.1 plunky { 710 1.1 plunky struct btmagic_softc *sc = device_private(self); 711 1.1 plunky 712 1.1 plunky DPRINTF(sc, "disable"); 713 1.1 plunky sc->sc_enabled = 0; 714 1.1 plunky } 715 1.1 plunky 716 1.1 plunky 717 1.1 plunky /***************************************************************************** 718 1.1 plunky * 719 1.1 plunky * setup routines 720 1.1 plunky */ 721 1.1 plunky 722 1.1 plunky static void 723 1.1 plunky btmagic_timeout(void *arg) 724 1.1 plunky { 725 1.1 plunky struct btmagic_softc *sc = arg; 726 1.1 plunky 727 1.1 plunky mutex_enter(bt_lock); 728 1.1 plunky callout_ack(&sc->sc_timeout); 729 1.1 plunky 730 1.1 plunky switch (sc->sc_state) { 731 1.1 plunky case BTMAGIC_CLOSED: 732 1.1 plunky if (sc->sc_int != NULL) { 733 1.10 rtr l2cap_disconnect_pcb(sc->sc_int, 0); 734 1.1 plunky break; 735 1.1 plunky } 736 1.1 plunky 737 1.1 plunky if (sc->sc_ctl != NULL) { 738 1.10 rtr l2cap_disconnect_pcb(sc->sc_ctl, 0); 739 1.1 plunky break; 740 1.1 plunky } 741 1.1 plunky break; 742 1.1 plunky 743 1.1 plunky case BTMAGIC_OPEN: 744 1.1 plunky if (!ISSET(sc->sc_flags, BTMAGIC_ENABLED)) { 745 1.1 plunky btmagic_enable(sc); 746 1.1 plunky break; 747 1.1 plunky } 748 1.1 plunky 749 1.1 plunky btmagic_check_battery(sc); 750 1.1 plunky break; 751 1.1 plunky 752 1.1 plunky case BTMAGIC_WAIT_CTL: 753 1.1 plunky case BTMAGIC_WAIT_INT: 754 1.1 plunky default: 755 1.1 plunky break; 756 1.1 plunky } 757 1.1 plunky mutex_exit(bt_lock); 758 1.1 plunky } 759 1.1 plunky 760 1.1 plunky /* 761 1.1 plunky * Send report on control channel 762 1.1 plunky * 763 1.1 plunky * bt_lock is held 764 1.1 plunky */ 765 1.1 plunky static int 766 1.1 plunky btmagic_ctl_send(struct btmagic_softc *sc, const uint8_t *data, size_t len) 767 1.1 plunky { 768 1.1 plunky struct mbuf *m; 769 1.1 plunky 770 1.1 plunky if (len > MLEN) 771 1.1 plunky return EINVAL; 772 1.1 plunky 773 1.1 plunky m = m_gethdr(M_DONTWAIT, MT_DATA); 774 1.1 plunky if (m == NULL) 775 1.1 plunky return ENOMEM; 776 1.1 plunky 777 1.1 plunky #ifdef BTMAGIC_DEBUG 778 1.1 plunky printf("%s: send", device_xname(sc->sc_dev)); 779 1.1 plunky for (size_t i = 0; i < len; i++) 780 1.1 plunky printf(" 0x%02x", data[i]); 781 1.1 plunky printf("\n"); 782 1.1 plunky #endif 783 1.1 plunky 784 1.1 plunky memcpy(mtod(m, uint8_t *), data, len); 785 1.1 plunky m->m_pkthdr.len = m->m_len = len; 786 1.11 rtr return l2cap_send_pcb(sc->sc_ctl, m); 787 1.1 plunky } 788 1.1 plunky 789 1.1 plunky /* 790 1.1 plunky * Enable touch reports by sending the following report 791 1.1 plunky * 792 1.1 plunky * SET_REPORT(FEATURE, 0xd7) = 0x01 793 1.1 plunky * 794 1.1 plunky * bt_lock is held 795 1.1 plunky */ 796 1.1 plunky static void 797 1.1 plunky btmagic_enable(struct btmagic_softc *sc) 798 1.1 plunky { 799 1.1 plunky static const uint8_t rep[] = { 0x53, 0xd7, 0x01 }; 800 1.1 plunky 801 1.1 plunky if (btmagic_ctl_send(sc, rep, sizeof(rep)) != 0) { 802 1.1 plunky printf("%s: cannot enable touch reports\n", 803 1.1 plunky device_xname(sc->sc_dev)); 804 1.1 plunky 805 1.1 plunky return; 806 1.1 plunky } 807 1.1 plunky 808 1.1 plunky SET(sc->sc_flags, BTMAGIC_ENABLED); 809 1.1 plunky } 810 1.1 plunky 811 1.1 plunky /* 812 1.1 plunky * Request the battery level by sending the following report 813 1.1 plunky * 814 1.1 plunky * GET_REPORT(FEATURE, 0x47) 815 1.1 plunky * 816 1.1 plunky * bt_lock is held 817 1.1 plunky */ 818 1.1 plunky static void 819 1.1 plunky btmagic_check_battery(struct btmagic_softc *sc) 820 1.1 plunky { 821 1.1 plunky static const uint8_t rep[] = { 0x43, 0x47 }; 822 1.1 plunky 823 1.1 plunky if (btmagic_ctl_send(sc, rep, sizeof(rep)) != 0) 824 1.1 plunky printf("%s: cannot request battery level\n", 825 1.1 plunky device_xname(sc->sc_dev)); 826 1.1 plunky } 827 1.1 plunky 828 1.1 plunky /* 829 1.1 plunky * the Magic Mouse has a base resolution of 1300dpi which is rather flighty. We 830 1.1 plunky * scale the output to the requested resolution, taking care to account for the 831 1.1 plunky * remainders to prevent loss of small deltas. 832 1.1 plunky */ 833 1.1 plunky static int 834 1.1 plunky btmagic_scale(int delta, int *remainder, int resolution) 835 1.1 plunky { 836 1.1 plunky int new; 837 1.1 plunky 838 1.1 plunky delta += *remainder; 839 1.1 plunky new = delta * resolution / 1300; 840 1.1 plunky *remainder = delta - new * 1300 / resolution; 841 1.1 plunky return new; 842 1.1 plunky } 843 1.1 plunky 844 1.1 plunky 845 1.1 plunky /***************************************************************************** 846 1.1 plunky * 847 1.1 plunky * bluetooth(9) callback methods for L2CAP 848 1.1 plunky * 849 1.1 plunky * All these are called from Bluetooth Protocol code, holding bt_lock. 850 1.1 plunky */ 851 1.1 plunky 852 1.1 plunky static void 853 1.1 plunky btmagic_connecting(void *arg) 854 1.1 plunky { 855 1.1 plunky 856 1.1 plunky /* dont care */ 857 1.1 plunky } 858 1.1 plunky 859 1.1 plunky static void 860 1.1 plunky btmagic_ctl_connected(void *arg) 861 1.1 plunky { 862 1.1 plunky struct sockaddr_bt sa; 863 1.1 plunky struct btmagic_softc *sc = arg; 864 1.1 plunky int err; 865 1.1 plunky 866 1.1 plunky if (sc->sc_state != BTMAGIC_WAIT_CTL) 867 1.1 plunky return; 868 1.1 plunky 869 1.1 plunky KASSERT(sc->sc_ctl != NULL); 870 1.1 plunky KASSERT(sc->sc_int == NULL); 871 1.1 plunky 872 1.1 plunky if (ISSET(sc->sc_flags, BTMAGIC_CONNECTING)) { 873 1.1 plunky /* initiate connect on interrupt PSM */ 874 1.7 rmind err = l2cap_attach_pcb(&sc->sc_int, &btmagic_int_proto, sc); 875 1.1 plunky if (err) 876 1.1 plunky goto fail; 877 1.1 plunky 878 1.1 plunky err = l2cap_setopt(sc->sc_int, &sc->sc_mode); 879 1.1 plunky if (err) 880 1.1 plunky goto fail; 881 1.1 plunky 882 1.1 plunky memset(&sa, 0, sizeof(sa)); 883 1.1 plunky sa.bt_len = sizeof(sa); 884 1.1 plunky sa.bt_family = AF_BLUETOOTH; 885 1.1 plunky bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); 886 1.1 plunky 887 1.8 rtr err = l2cap_bind_pcb(sc->sc_int, &sa); 888 1.1 plunky if (err) 889 1.1 plunky goto fail; 890 1.1 plunky 891 1.1 plunky sa.bt_psm = L2CAP_PSM_HID_INTR; 892 1.1 plunky bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); 893 1.9 rtr err = l2cap_connect_pcb(sc->sc_int, &sa); 894 1.1 plunky if (err) 895 1.1 plunky goto fail; 896 1.1 plunky } 897 1.1 plunky 898 1.1 plunky sc->sc_state = BTMAGIC_WAIT_INT; 899 1.1 plunky return; 900 1.1 plunky 901 1.1 plunky fail: 902 1.7 rmind l2cap_detach_pcb(&sc->sc_ctl); 903 1.1 plunky sc->sc_ctl = NULL; 904 1.1 plunky 905 1.1 plunky printf("%s: connect failed (%d)\n", device_xname(sc->sc_dev), err); 906 1.1 plunky } 907 1.1 plunky 908 1.1 plunky static void 909 1.1 plunky btmagic_int_connected(void *arg) 910 1.1 plunky { 911 1.1 plunky struct btmagic_softc *sc = arg; 912 1.1 plunky 913 1.1 plunky if (sc->sc_state != BTMAGIC_WAIT_INT) 914 1.1 plunky return; 915 1.1 plunky 916 1.1 plunky KASSERT(sc->sc_ctl != NULL); 917 1.1 plunky KASSERT(sc->sc_int != NULL); 918 1.1 plunky 919 1.1 plunky printf("%s: connected\n", device_xname(sc->sc_dev)); 920 1.1 plunky CLR(sc->sc_flags, BTMAGIC_CONNECTING); 921 1.1 plunky sc->sc_state = BTMAGIC_OPEN; 922 1.1 plunky 923 1.1 plunky /* trigger the setup */ 924 1.1 plunky CLR(sc->sc_flags, BTMAGIC_ENABLED); 925 1.1 plunky callout_schedule(&sc->sc_timeout, hz); 926 1.1 plunky } 927 1.1 plunky 928 1.1 plunky /* 929 1.1 plunky * Disconnected 930 1.1 plunky * 931 1.1 plunky * Depending on our state, this could mean several things, but essentially 932 1.1 plunky * we are lost. If both channels are closed, schedule another connection. 933 1.1 plunky */ 934 1.1 plunky static void 935 1.1 plunky btmagic_ctl_disconnected(void *arg, int err) 936 1.1 plunky { 937 1.1 plunky struct btmagic_softc *sc = arg; 938 1.1 plunky 939 1.1 plunky if (sc->sc_ctl != NULL) { 940 1.7 rmind l2cap_detach_pcb(&sc->sc_ctl); 941 1.1 plunky sc->sc_ctl = NULL; 942 1.1 plunky } 943 1.1 plunky 944 1.1 plunky if (sc->sc_int == NULL) { 945 1.5 plunky printf("%s: disconnected (%d)\n", device_xname(sc->sc_dev), err); 946 1.1 plunky CLR(sc->sc_flags, BTMAGIC_CONNECTING); 947 1.1 plunky sc->sc_state = BTMAGIC_WAIT_CTL; 948 1.1 plunky } else { 949 1.1 plunky /* 950 1.1 plunky * The interrupt channel should have been closed first, 951 1.1 plunky * but its potentially unsafe to detach that from here. 952 1.1 plunky * Give them a second to do the right thing or let the 953 1.1 plunky * callout handle it. 954 1.1 plunky */ 955 1.1 plunky sc->sc_state = BTMAGIC_CLOSED; 956 1.1 plunky callout_schedule(&sc->sc_timeout, hz); 957 1.1 plunky } 958 1.1 plunky } 959 1.1 plunky 960 1.1 plunky static void 961 1.1 plunky btmagic_int_disconnected(void *arg, int err) 962 1.1 plunky { 963 1.1 plunky struct btmagic_softc *sc = arg; 964 1.1 plunky 965 1.1 plunky if (sc->sc_int != NULL) { 966 1.7 rmind l2cap_detach_pcb(&sc->sc_int); 967 1.1 plunky sc->sc_int = NULL; 968 1.1 plunky } 969 1.1 plunky 970 1.1 plunky if (sc->sc_ctl == NULL) { 971 1.5 plunky printf("%s: disconnected (%d)\n", device_xname(sc->sc_dev), err); 972 1.1 plunky CLR(sc->sc_flags, BTMAGIC_CONNECTING); 973 1.1 plunky sc->sc_state = BTMAGIC_WAIT_CTL; 974 1.1 plunky } else { 975 1.1 plunky /* 976 1.1 plunky * The control channel should be closing also, allow 977 1.1 plunky * them a chance to do that before we force it. 978 1.1 plunky */ 979 1.1 plunky sc->sc_state = BTMAGIC_CLOSED; 980 1.1 plunky callout_schedule(&sc->sc_timeout, hz); 981 1.1 plunky } 982 1.1 plunky } 983 1.1 plunky 984 1.1 plunky /* 985 1.1 plunky * New Connections 986 1.1 plunky * 987 1.1 plunky * We give a new L2CAP handle back if this matches the BDADDR we are 988 1.1 plunky * listening for and we are in the right state. btmagic_connected will 989 1.1 plunky * be called when the connection is open, so nothing else to do here 990 1.1 plunky */ 991 1.1 plunky static void * 992 1.1 plunky btmagic_ctl_newconn(void *arg, struct sockaddr_bt *laddr, 993 1.1 plunky struct sockaddr_bt *raddr) 994 1.1 plunky { 995 1.1 plunky struct btmagic_softc *sc = arg; 996 1.1 plunky 997 1.1 plunky if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0) 998 1.1 plunky return NULL; 999 1.1 plunky 1000 1.1 plunky if (sc->sc_state != BTMAGIC_WAIT_CTL 1001 1.1 plunky || ISSET(sc->sc_flags, BTMAGIC_CONNECTING) 1002 1.1 plunky || sc->sc_ctl != NULL 1003 1.1 plunky || sc->sc_int != NULL) { 1004 1.1 plunky DPRINTF(sc, "reject ctl newconn %s%s%s%s", 1005 1.1 plunky (sc->sc_state == BTMAGIC_WAIT_CTL) ? " (WAITING)": "", 1006 1.1 plunky ISSET(sc->sc_flags, BTMAGIC_CONNECTING) ? " (CONNECTING)" : "", 1007 1.1 plunky (sc->sc_ctl != NULL) ? " (GOT CONTROL)" : "", 1008 1.1 plunky (sc->sc_int != NULL) ? " (GOT INTERRUPT)" : ""); 1009 1.1 plunky 1010 1.1 plunky return NULL; 1011 1.1 plunky } 1012 1.1 plunky 1013 1.7 rmind l2cap_attach_pcb(&sc->sc_ctl, &btmagic_ctl_proto, sc); 1014 1.1 plunky return sc->sc_ctl; 1015 1.1 plunky } 1016 1.1 plunky 1017 1.1 plunky static void * 1018 1.1 plunky btmagic_int_newconn(void *arg, struct sockaddr_bt *laddr, 1019 1.1 plunky struct sockaddr_bt *raddr) 1020 1.1 plunky { 1021 1.1 plunky struct btmagic_softc *sc = arg; 1022 1.1 plunky 1023 1.1 plunky if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0) 1024 1.1 plunky return NULL; 1025 1.1 plunky 1026 1.1 plunky if (sc->sc_state != BTMAGIC_WAIT_INT 1027 1.1 plunky || ISSET(sc->sc_flags, BTMAGIC_CONNECTING) 1028 1.1 plunky || sc->sc_ctl == NULL 1029 1.1 plunky || sc->sc_int != NULL) { 1030 1.1 plunky DPRINTF(sc, "reject int newconn %s%s%s%s", 1031 1.1 plunky (sc->sc_state == BTMAGIC_WAIT_INT) ? " (WAITING)": "", 1032 1.1 plunky ISSET(sc->sc_flags, BTMAGIC_CONNECTING) ? " (CONNECTING)" : "", 1033 1.1 plunky (sc->sc_ctl == NULL) ? " (NO CONTROL)" : "", 1034 1.1 plunky (sc->sc_int != NULL) ? " (GOT INTERRUPT)" : ""); 1035 1.1 plunky 1036 1.1 plunky return NULL; 1037 1.1 plunky } 1038 1.1 plunky 1039 1.7 rmind l2cap_attach_pcb(&sc->sc_int, &btmagic_int_proto, sc); 1040 1.1 plunky return sc->sc_int; 1041 1.1 plunky } 1042 1.1 plunky 1043 1.1 plunky static void 1044 1.1 plunky btmagic_complete(void *arg, int count) 1045 1.1 plunky { 1046 1.1 plunky 1047 1.1 plunky /* dont care */ 1048 1.1 plunky } 1049 1.1 plunky 1050 1.1 plunky static void 1051 1.1 plunky btmagic_linkmode(void *arg, int new) 1052 1.1 plunky { 1053 1.1 plunky struct btmagic_softc *sc = arg; 1054 1.1 plunky int mode; 1055 1.1 plunky 1056 1.1 plunky (void)sockopt_getint(&sc->sc_mode, &mode); 1057 1.1 plunky 1058 1.1 plunky if (ISSET(mode, L2CAP_LM_AUTH) && !ISSET(new, L2CAP_LM_AUTH)) 1059 1.1 plunky printf("%s: auth failed\n", device_xname(sc->sc_dev)); 1060 1.1 plunky else if (ISSET(mode, L2CAP_LM_ENCRYPT) && !ISSET(new, L2CAP_LM_ENCRYPT)) 1061 1.1 plunky printf("%s: encrypt off\n", device_xname(sc->sc_dev)); 1062 1.1 plunky else if (ISSET(mode, L2CAP_LM_SECURE) && !ISSET(new, L2CAP_LM_SECURE)) 1063 1.1 plunky printf("%s: insecure\n", device_xname(sc->sc_dev)); 1064 1.1 plunky else 1065 1.1 plunky return; 1066 1.1 plunky 1067 1.1 plunky if (sc->sc_int != NULL) 1068 1.10 rtr l2cap_disconnect_pcb(sc->sc_int, 0); 1069 1.1 plunky 1070 1.1 plunky if (sc->sc_ctl != NULL) 1071 1.10 rtr l2cap_disconnect_pcb(sc->sc_ctl, 0); 1072 1.1 plunky } 1073 1.1 plunky 1074 1.1 plunky /* 1075 1.1 plunky * Receive transaction from the mouse. We don't differentiate between 1076 1.1 plunky * interrupt and control channel here, there is no need. 1077 1.1 plunky */ 1078 1.1 plunky static void 1079 1.1 plunky btmagic_input(void *arg, struct mbuf *m) 1080 1.1 plunky { 1081 1.1 plunky struct btmagic_softc *sc = arg; 1082 1.1 plunky uint8_t *data; 1083 1.1 plunky size_t len; 1084 1.1 plunky 1085 1.1 plunky if (sc->sc_state != BTMAGIC_OPEN 1086 1.1 plunky || sc->sc_wsmouse == NULL 1087 1.1 plunky || sc->sc_enabled == 0) 1088 1.1 plunky goto release; 1089 1.1 plunky 1090 1.1 plunky if (m->m_pkthdr.len > m->m_len) 1091 1.1 plunky printf("%s: truncating input\n", device_xname(sc->sc_dev)); 1092 1.1 plunky 1093 1.1 plunky data = mtod(m, uint8_t *); 1094 1.1 plunky len = m->m_len; 1095 1.1 plunky 1096 1.1 plunky if (len < 1) 1097 1.1 plunky goto release; 1098 1.1 plunky 1099 1.1 plunky switch (BTHID_TYPE(data[0])) { 1100 1.1 plunky case BTHID_HANDSHAKE: 1101 1.1 plunky DPRINTF(sc, "Handshake: 0x%x", BTHID_HANDSHAKE_PARAM(data[0])); 1102 1.1 plunky callout_schedule(&sc->sc_timeout, hz); 1103 1.1 plunky break; 1104 1.1 plunky 1105 1.1 plunky case BTHID_DATA: 1106 1.1 plunky if (len < 2) 1107 1.1 plunky break; 1108 1.1 plunky 1109 1.1 plunky switch (data[1]) { 1110 1.12 bouyer case BASIC_REPORT_ID: /* Basic mouse (input) */ 1111 1.1 plunky btmagic_input_basic(sc, data + 2, len - 2); 1112 1.1 plunky break; 1113 1.1 plunky 1114 1.12 bouyer case TRACKPAD_REPORT_ID: /* Magic trackpad (input) */ 1115 1.12 bouyer btmagic_input_magict(sc, data + 2, len - 2); 1116 1.12 bouyer break; 1117 1.15 plunky 1118 1.12 bouyer case MOUSE_REPORT_ID: /* Magic touch (input) */ 1119 1.12 bouyer btmagic_input_magicm(sc, data + 2, len - 2); 1120 1.1 plunky break; 1121 1.1 plunky 1122 1.12 bouyer case BATT_STAT_REPORT_ID: /* Battery status (input) */ 1123 1.1 plunky if (len != 3) 1124 1.1 plunky break; 1125 1.1 plunky 1126 1.1 plunky printf("%s: Battery ", device_xname(sc->sc_dev)); 1127 1.1 plunky switch (data[2]) { 1128 1.1 plunky case 0: printf("Ok\n"); break; 1129 1.1 plunky case 1: printf("Warning\n"); break; 1130 1.1 plunky case 2: printf("Critical\n"); break; 1131 1.1 plunky default: printf("0x%02x\n", data[2]); break; 1132 1.1 plunky } 1133 1.1 plunky break; 1134 1.1 plunky 1135 1.15 plunky case BATT_STRENGTH_REPORT_ID: /* Battery strength (feature) */ 1136 1.1 plunky if (len != 3) 1137 1.1 plunky break; 1138 1.1 plunky 1139 1.1 plunky printf("%s: Battery %d%%\n", device_xname(sc->sc_dev), 1140 1.1 plunky data[2]); 1141 1.1 plunky break; 1142 1.1 plunky 1143 1.12 bouyer case SURFACE_REPORT_ID: /* Surface detection (input) */ 1144 1.1 plunky if (len != 3) 1145 1.1 plunky break; 1146 1.1 plunky 1147 1.1 plunky DPRINTF(sc, "Mouse %s", 1148 1.1 plunky (data[2] == 0 ? "lowered" : "raised")); 1149 1.1 plunky break; 1150 1.1 plunky 1151 1.1 plunky case 0x60: /* unknown (input) */ 1152 1.1 plunky case 0xf0: /* unknown (feature) */ 1153 1.1 plunky case 0xf1: /* unknown (feature) */ 1154 1.1 plunky default: 1155 1.1 plunky #if BTMAGIC_DEBUG 1156 1.1 plunky printf("%s: recv", device_xname(sc->sc_dev)); 1157 1.1 plunky for (size_t i = 0; i < len; i++) 1158 1.1 plunky printf(" 0x%02x", data[i]); 1159 1.1 plunky printf("\n"); 1160 1.1 plunky #endif 1161 1.1 plunky break; 1162 1.1 plunky } 1163 1.1 plunky break; 1164 1.1 plunky 1165 1.1 plunky default: 1166 1.1 plunky DPRINTF(sc, "transaction (type 0x%x)", BTHID_TYPE(data[0])); 1167 1.1 plunky break; 1168 1.1 plunky } 1169 1.1 plunky 1170 1.1 plunky release: 1171 1.1 plunky m_freem(m); 1172 1.1 plunky } 1173 1.1 plunky 1174 1.1 plunky /* 1175 1.1 plunky * parse the Basic report (0x10), which according to the provided 1176 1.1 plunky * HID descriptor is in the following format 1177 1.1 plunky * 1178 1.1 plunky * button 1 1-bit 1179 1.1 plunky * button 2 1-bit 1180 1.1 plunky * padding 6-bits 1181 1.1 plunky * dX 16-bits (signed) 1182 1.1 plunky * dY 16-bits (signed) 1183 1.1 plunky * 1184 1.1 plunky * Even when the magic touch reports are enabled, the basic report is 1185 1.1 plunky * sent for mouse move events where no touches are detected. 1186 1.1 plunky */ 1187 1.1 plunky static const struct { 1188 1.1 plunky struct hid_location button1; 1189 1.1 plunky struct hid_location button2; 1190 1.1 plunky struct hid_location dX; 1191 1.1 plunky struct hid_location dY; 1192 1.1 plunky } basic = { 1193 1.1 plunky .button1 = { .pos = 0, .size = 1 }, 1194 1.1 plunky .button2 = { .pos = 1, .size = 1 }, 1195 1.1 plunky .dX = { .pos = 8, .size = 16 }, 1196 1.1 plunky .dY = { .pos = 24, .size = 16 }, 1197 1.1 plunky }; 1198 1.1 plunky 1199 1.1 plunky static void 1200 1.1 plunky btmagic_input_basic(struct btmagic_softc *sc, uint8_t *data, size_t len) 1201 1.1 plunky { 1202 1.1 plunky int dx, dy; 1203 1.1 plunky uint32_t mb; 1204 1.1 plunky int s; 1205 1.1 plunky 1206 1.1 plunky if (len != 5) 1207 1.1 plunky return; 1208 1.1 plunky 1209 1.1 plunky dx = hid_get_data(data, &basic.dX); 1210 1.1 plunky dx = btmagic_scale(dx, &sc->sc_rx, sc->sc_resolution); 1211 1.1 plunky 1212 1.1 plunky dy = hid_get_data(data, &basic.dY); 1213 1.1 plunky dy = btmagic_scale(dy, &sc->sc_ry, sc->sc_resolution); 1214 1.1 plunky 1215 1.1 plunky mb = 0; 1216 1.1 plunky if (hid_get_udata(data, &basic.button1)) 1217 1.1 plunky mb |= __BIT(0); 1218 1.1 plunky if (hid_get_udata(data, &basic.button2)) 1219 1.1 plunky mb |= __BIT(2); 1220 1.1 plunky 1221 1.1 plunky if (dx != 0 || dy != 0 || mb != sc->sc_mb) { 1222 1.1 plunky sc->sc_mb = mb; 1223 1.1 plunky 1224 1.1 plunky s = spltty(); 1225 1.1 plunky wsmouse_input(sc->sc_wsmouse, mb, 1226 1.1 plunky dx, -dy, 0, 0, WSMOUSE_INPUT_DELTA); 1227 1.1 plunky splx(s); 1228 1.1 plunky } 1229 1.1 plunky } 1230 1.1 plunky 1231 1.1 plunky /* 1232 1.1 plunky * the Magic touch report (0x29), according to the Linux driver 1233 1.1 plunky * written by Michael Poole, is variable length starting with the 1234 1.1 plunky * fixed 40-bit header 1235 1.1 plunky * 1236 1.1 plunky * dX lsb 8-bits (signed) 1237 1.1 plunky * dY lsb 8-bits (signed) 1238 1.1 plunky * button 1 1-bit 1239 1.1 plunky * button 2 1-bit 1240 1.1 plunky * dX msb 2-bits (signed) 1241 1.1 plunky * dY msb 2-bits (signed) 1242 1.1 plunky * timestamp 18-bits 1243 1.1 plunky * 1244 1.1 plunky * followed by (up to 5?) touch reports of 64-bits each 1245 1.1 plunky * 1246 1.1 plunky * abs W 12-bits (signed) 1247 1.1 plunky * abs Z 12-bits (signed) 1248 1.1 plunky * axis major 8-bits 1249 1.1 plunky * axis minor 8-bits 1250 1.1 plunky * pressure 6-bits 1251 1.1 plunky * id 4-bits 1252 1.1 plunky * angle 6-bits (from E(0)->N(32)->W(64)) 1253 1.1 plunky * unknown 4-bits 1254 1.1 plunky * phase 4-bits 1255 1.1 plunky */ 1256 1.1 plunky 1257 1.1 plunky static const struct { 1258 1.1 plunky struct hid_location dXl; 1259 1.1 plunky struct hid_location dYl; 1260 1.1 plunky struct hid_location button1; 1261 1.1 plunky struct hid_location button2; 1262 1.1 plunky struct hid_location dXm; 1263 1.1 plunky struct hid_location dYm; 1264 1.1 plunky struct hid_location timestamp; 1265 1.1 plunky } magic = { 1266 1.1 plunky .dXl = { .pos = 0, .size = 8 }, 1267 1.1 plunky .dYl = { .pos = 8, .size = 8 }, 1268 1.1 plunky .button1 = { .pos = 16, .size = 1 }, 1269 1.1 plunky .button2 = { .pos = 17, .size = 1 }, 1270 1.1 plunky .dXm = { .pos = 18, .size = 2 }, 1271 1.1 plunky .dYm = { .pos = 20, .size = 2 }, 1272 1.1 plunky .timestamp = { .pos = 22, .size = 18 }, 1273 1.1 plunky }; 1274 1.1 plunky 1275 1.1 plunky static const struct { 1276 1.1 plunky struct hid_location aW; 1277 1.1 plunky struct hid_location aZ; 1278 1.1 plunky struct hid_location major; 1279 1.1 plunky struct hid_location minor; 1280 1.1 plunky struct hid_location pressure; 1281 1.1 plunky struct hid_location id; 1282 1.1 plunky struct hid_location angle; 1283 1.1 plunky struct hid_location unknown; 1284 1.1 plunky struct hid_location phase; 1285 1.1 plunky } touch = { 1286 1.1 plunky .aW = { .pos = 0, .size = 12 }, 1287 1.1 plunky .aZ = { .pos = 12, .size = 12 }, 1288 1.1 plunky .major = { .pos = 24, .size = 8 }, 1289 1.1 plunky .minor = { .pos = 32, .size = 8 }, 1290 1.1 plunky .pressure = { .pos = 40, .size = 6 }, 1291 1.1 plunky .id = { .pos = 46, .size = 4 }, 1292 1.1 plunky .angle = { .pos = 50, .size = 6 }, 1293 1.1 plunky .unknown = { .pos = 56, .size = 4 }, 1294 1.1 plunky .phase = { .pos = 60, .size = 4 }, 1295 1.1 plunky }; 1296 1.1 plunky 1297 1.1 plunky /* 1298 1.1 plunky * the phase of the touch starts at 0x01 as the finger is first detected 1299 1.1 plunky * approaching the mouse, increasing to 0x04 while the finger is touching, 1300 1.1 plunky * then increases towards 0x07 as the finger is lifted, and we get 0x00 1301 1.1 plunky * when the touch is cancelled. The values below seem to be produced for 1302 1.1 plunky * every touch, the others less consistently depending on how fast the 1303 1.1 plunky * approach or departure is. 1304 1.1 plunky * 1305 1.1 plunky * In fact we ignore touches unless they are in the steady 0x04 phase. 1306 1.1 plunky */ 1307 1.1 plunky #define BTMAGIC_PHASE_START 0x3 1308 1.1 plunky #define BTMAGIC_PHASE_CONT 0x4 1309 1.1 plunky #define BTMAGIC_PHASE_END 0x7 1310 1.1 plunky #define BTMAGIC_PHASE_CANCEL 0x0 1311 1.1 plunky 1312 1.1 plunky static void 1313 1.12 bouyer btmagic_input_magicm(struct btmagic_softc *sc, uint8_t *data, size_t len) 1314 1.1 plunky { 1315 1.1 plunky uint32_t mb; 1316 1.1 plunky int dx, dy, dz, dw; 1317 1.1 plunky int id, nf, az, aw, tz, tw; 1318 1.1 plunky int s; 1319 1.1 plunky 1320 1.1 plunky if (((len - 5) % 8) != 0) 1321 1.1 plunky return; 1322 1.1 plunky 1323 1.1 plunky dx = (hid_get_data(data, &magic.dXm) << 8) 1324 1.1 plunky | (hid_get_data(data, &magic.dXl) & 0xff); 1325 1.1 plunky dx = btmagic_scale(dx, &sc->sc_rx, sc->sc_resolution); 1326 1.1 plunky 1327 1.1 plunky dy = (hid_get_data(data, &magic.dYm) << 8) 1328 1.1 plunky | (hid_get_data(data, &magic.dYl) & 0xff); 1329 1.1 plunky dy = btmagic_scale(dy, &sc->sc_ry, sc->sc_resolution); 1330 1.1 plunky 1331 1.1 plunky mb = 0; 1332 1.1 plunky if (hid_get_udata(data, &magic.button1)) 1333 1.1 plunky mb |= __BIT(0); 1334 1.1 plunky if (hid_get_udata(data, &magic.button2)) 1335 1.1 plunky mb |= __BIT(2); 1336 1.1 plunky 1337 1.1 plunky nf = 0; 1338 1.1 plunky dz = 0; 1339 1.1 plunky dw = 0; 1340 1.1 plunky len = (len - 5) / 8; 1341 1.1 plunky for (data += 5; len-- > 0; data += 8) { 1342 1.1 plunky id = hid_get_udata(data, &touch.id); 1343 1.1 plunky az = hid_get_data(data, &touch.aZ); 1344 1.1 plunky aw = hid_get_data(data, &touch.aW); 1345 1.1 plunky 1346 1.1 plunky /* 1347 1.1 plunky * scrolling is triggered by an established touch moving 1348 1.1 plunky * beyond a minimum distance from its start point and is 1349 1.1 plunky * cancelled as the touch starts to fade. 1350 1.1 plunky * 1351 1.1 plunky * Multiple touches may be scrolling simultaneously, the 1352 1.1 plunky * effect is cumulative. 1353 1.1 plunky */ 1354 1.1 plunky 1355 1.1 plunky switch (hid_get_udata(data, &touch.phase)) { 1356 1.1 plunky case BTMAGIC_PHASE_CONT: 1357 1.12 bouyer #define sc_az sc_ay 1358 1.12 bouyer #define sc_aw sc_ax 1359 1.1 plunky tz = az - sc->sc_az[id]; 1360 1.1 plunky tw = aw - sc->sc_aw[id]; 1361 1.1 plunky 1362 1.12 bouyer if (ISSET(sc->sc_smask, __BIT(id))) { 1363 1.1 plunky /* scrolling finger */ 1364 1.1 plunky dz += btmagic_scale(tz, &sc->sc_rz, 1365 1.1 plunky sc->sc_resolution / sc->sc_scale); 1366 1.1 plunky dw += btmagic_scale(tw, &sc->sc_rw, 1367 1.1 plunky sc->sc_resolution / sc->sc_scale); 1368 1.1 plunky } else if (abs(tz) > sc->sc_dist 1369 1.1 plunky || abs(tw) > sc->sc_dist) { 1370 1.1 plunky /* new scrolling finger */ 1371 1.1 plunky if (sc->sc_smask == 0) { 1372 1.1 plunky sc->sc_rz = 0; 1373 1.1 plunky sc->sc_rw = 0; 1374 1.1 plunky } 1375 1.1 plunky 1376 1.12 bouyer SET(sc->sc_smask, __BIT(id)); 1377 1.1 plunky } else { 1378 1.1 plunky /* not scrolling finger */ 1379 1.1 plunky az = sc->sc_az[id]; 1380 1.1 plunky aw = sc->sc_aw[id]; 1381 1.1 plunky } 1382 1.1 plunky 1383 1.1 plunky /* count firm touches for middle-click */ 1384 1.1 plunky if (hid_get_udata(data, &touch.pressure) > sc->sc_firm) 1385 1.1 plunky nf++; 1386 1.1 plunky 1387 1.1 plunky break; 1388 1.1 plunky 1389 1.1 plunky default: 1390 1.12 bouyer CLR(sc->sc_smask, __BIT(id)); 1391 1.1 plunky break; 1392 1.1 plunky } 1393 1.1 plunky 1394 1.1 plunky sc->sc_az[id] = az; 1395 1.1 plunky sc->sc_aw[id] = aw; 1396 1.12 bouyer #undef sc_az 1397 1.12 bouyer #undef sc_aw 1398 1.1 plunky } 1399 1.1 plunky 1400 1.1 plunky /* 1401 1.1 plunky * The mouse only has one click detector, and says left or right but 1402 1.1 plunky * never both. We convert multiple firm touches while clicking into 1403 1.1 plunky * a middle button press, and cancel any scroll effects while click 1404 1.1 plunky * is active. 1405 1.1 plunky */ 1406 1.1 plunky if (mb != 0) { 1407 1.1 plunky if (sc->sc_mb != 0) 1408 1.1 plunky mb = sc->sc_mb; 1409 1.1 plunky else if (nf > 1) 1410 1.1 plunky mb = __BIT(1); 1411 1.1 plunky 1412 1.1 plunky sc->sc_smask = 0; 1413 1.1 plunky dz = 0; 1414 1.1 plunky dw = 0; 1415 1.1 plunky } 1416 1.1 plunky 1417 1.1 plunky if (dx != 0 || dy != 0 || dz != 0 || dw != 0 || mb != sc->sc_mb) { 1418 1.1 plunky sc->sc_mb = mb; 1419 1.1 plunky 1420 1.1 plunky s = spltty(); 1421 1.1 plunky wsmouse_input(sc->sc_wsmouse, mb, 1422 1.1 plunky dx, -dy, -dz, dw, WSMOUSE_INPUT_DELTA); 1423 1.1 plunky splx(s); 1424 1.1 plunky } 1425 1.1 plunky } 1426 1.12 bouyer 1427 1.12 bouyer /* 1428 1.12 bouyer * the Magic touch trackpad report (0x28), according to the Linux driver 1429 1.12 bouyer * written by Michael Poole and Chase Douglas, is variable length starting 1430 1.12 bouyer * with the fixed 24-bit header 1431 1.12 bouyer * 1432 1.12 bouyer * button 1 1-bit 1433 1.12 bouyer * unknown 5-bits 1434 1.12 bouyer * timestamp 18-bits 1435 1.12 bouyer * 1436 1.12 bouyer * followed by (up to 5?) touch reports of 72-bits each 1437 1.12 bouyer * 1438 1.12 bouyer * abs X 13-bits (signed) 1439 1.12 bouyer * abs Y 13-bits (signed) 1440 1.12 bouyer * unknown 6-bits 1441 1.12 bouyer * axis major 8-bits 1442 1.12 bouyer * axis minor 8-bits 1443 1.12 bouyer * pressure 6-bits 1444 1.12 bouyer * id 4-bits 1445 1.12 bouyer * angle 6-bits (from E(0)->N(32)->W(64)) 1446 1.12 bouyer * unknown 4-bits 1447 1.12 bouyer * phase 4-bits 1448 1.12 bouyer */ 1449 1.12 bouyer 1450 1.12 bouyer static const struct { 1451 1.12 bouyer struct hid_location button; 1452 1.12 bouyer struct hid_location timestamp; 1453 1.12 bouyer } magict = { 1454 1.12 bouyer .button = { .pos = 0, .size = 1 }, 1455 1.12 bouyer .timestamp = { .pos = 6, .size = 18 }, 1456 1.12 bouyer }; 1457 1.12 bouyer 1458 1.12 bouyer static const struct { 1459 1.12 bouyer struct hid_location aX; 1460 1.12 bouyer struct hid_location aY; 1461 1.12 bouyer struct hid_location major; 1462 1.12 bouyer struct hid_location minor; 1463 1.12 bouyer struct hid_location pressure; 1464 1.12 bouyer struct hid_location id; 1465 1.12 bouyer struct hid_location angle; 1466 1.12 bouyer struct hid_location unknown; 1467 1.12 bouyer struct hid_location phase; 1468 1.12 bouyer } toucht = { 1469 1.12 bouyer .aX = { .pos = 0, .size = 13 }, 1470 1.12 bouyer .aY = { .pos = 13, .size = 13 }, 1471 1.12 bouyer .major = { .pos = 32, .size = 8 }, 1472 1.12 bouyer .minor = { .pos = 40, .size = 8 }, 1473 1.12 bouyer .pressure = { .pos = 48, .size = 6 }, 1474 1.12 bouyer .id = { .pos = 54, .size = 4 }, 1475 1.12 bouyer .angle = { .pos = 58, .size = 6 }, 1476 1.12 bouyer .unknown = { .pos = 64, .size = 4 }, 1477 1.12 bouyer .phase = { .pos = 68, .size = 4 }, 1478 1.12 bouyer }; 1479 1.12 bouyer 1480 1.12 bouyer /* 1481 1.12 bouyer * as for btmagic_input_magicm, 1482 1.12 bouyer * the phase of the touch starts at 0x01 as the finger is first detected 1483 1.12 bouyer * approaching the mouse, increasing to 0x04 while the finger is touching, 1484 1.12 bouyer * then increases towards 0x07 as the finger is lifted, and we get 0x00 1485 1.12 bouyer * when the touch is cancelled. The values below seem to be produced for 1486 1.12 bouyer * every touch, the others less consistently depending on how fast the 1487 1.12 bouyer * approach or departure is. 1488 1.12 bouyer * 1489 1.12 bouyer * In fact we ignore touches unless they are in the steady 0x04 phase. 1490 1.12 bouyer */ 1491 1.12 bouyer 1492 1.12 bouyer /* min and max values reported */ 1493 1.12 bouyer #define MAGICT_X_MIN (-2910) 1494 1.12 bouyer #define MAGICT_X_MAX (3170) 1495 1.12 bouyer #define MAGICT_Y_MIN (-2565) 1496 1.12 bouyer #define MAGICT_Y_MAX (2455) 1497 1.12 bouyer 1498 1.12 bouyer /* 1499 1.12 bouyer * area for detecting the buttons: divide in 3 areas on X, 1500 1.12 bouyer * below -1900 on y 1501 1.12 bouyer */ 1502 1.12 bouyer #define MAGICT_B_YMAX (-1900) 1503 1.12 bouyer #define MAGICT_B_XSIZE ((MAGICT_X_MAX - MAGICT_X_MIN) / 3) 1504 1.12 bouyer #define MAGICT_B_X1MAX (MAGICT_X_MIN + MAGICT_B_XSIZE) 1505 1.12 bouyer #define MAGICT_B_X2MAX (MAGICT_X_MIN + MAGICT_B_XSIZE * 2) 1506 1.12 bouyer 1507 1.12 bouyer static void 1508 1.12 bouyer btmagic_input_magict(struct btmagic_softc *sc, uint8_t *data, size_t len) 1509 1.12 bouyer { 1510 1.12 bouyer bool bpress; 1511 1.12 bouyer uint32_t mb; 1512 1.12 bouyer int id, ax, ay, tx, ty; 1513 1.12 bouyer int dx, dy, dz, dw; 1514 1.12 bouyer int s; 1515 1.12 bouyer 1516 1.12 bouyer if (((len - 3) % 9) != 0) 1517 1.12 bouyer return; 1518 1.12 bouyer 1519 1.12 bouyer bpress = 0; 1520 1.12 bouyer if (hid_get_udata(data, &magict.button)) 1521 1.12 bouyer bpress = 1; 1522 1.12 bouyer 1523 1.12 bouyer dx = dy = dz = dw = 0; 1524 1.12 bouyer mb = 0; 1525 1.12 bouyer 1526 1.12 bouyer len = (len - 3) / 9; 1527 1.12 bouyer for (data += 3; len-- > 0; data += 9) { 1528 1.12 bouyer id = hid_get_udata(data, &toucht.id); 1529 1.12 bouyer ax = hid_get_data(data, &toucht.aX); 1530 1.12 bouyer ay = hid_get_data(data, &toucht.aY); 1531 1.12 bouyer 1532 1.12 bouyer DPRINTF(sc, 1533 1.15 plunky "btmagic_input_magict: id %d ax %d ay %d phase %ld %s\n", 1534 1.12 bouyer id, ax, ay, hid_get_udata(data, &toucht.phase), 1535 1.12 bouyer bpress ? "button pressed" : ""); 1536 1.12 bouyer 1537 1.12 bouyer /* 1538 1.12 bouyer * a single touch is interpreted as a mouse move. 1539 1.12 bouyer * If a button is pressed, the touch in the button area 1540 1.12 bouyer * defined above defines the button; a second touch is 1541 1.12 bouyer * interpreted as a mouse move. 1542 1.12 bouyer */ 1543 1.12 bouyer 1544 1.12 bouyer switch (hid_get_udata(data, &toucht.phase)) { 1545 1.12 bouyer case BTMAGIC_PHASE_CONT: 1546 1.12 bouyer if (bpress) { 1547 1.12 bouyer if (sc->sc_mb == 0 && ay < MAGICT_B_YMAX) { 1548 1.12 bouyer /* 1549 1.12 bouyer * we have a new button press, 1550 1.12 bouyer * and this id tells which one 1551 1.12 bouyer */ 1552 1.12 bouyer if (ax < MAGICT_B_X1MAX) 1553 1.12 bouyer mb = __BIT(0); 1554 1.12 bouyer else if (ax > MAGICT_B_X2MAX) 1555 1.12 bouyer mb = __BIT(2); 1556 1.12 bouyer else 1557 1.12 bouyer mb = __BIT(1); 1558 1.12 bouyer sc->sc_mb_id = id; 1559 1.12 bouyer } else { 1560 1.12 bouyer /* keep previous state */ 1561 1.12 bouyer mb = sc->sc_mb; 1562 1.12 bouyer } 1563 1.12 bouyer } else { 1564 1.12 bouyer /* no button pressed */ 1565 1.12 bouyer mb = 0; 1566 1.12 bouyer sc->sc_mb_id = -1; 1567 1.12 bouyer } 1568 1.12 bouyer if (id == sc->sc_mb_id) { 1569 1.12 bouyer /* 1570 1.12 bouyer * this id selects the button 1571 1.12 bouyer * ignore for move/scroll 1572 1.12 bouyer */ 1573 1.12 bouyer continue; 1574 1.12 bouyer } 1575 1.13 christos if (id >= __arraycount(sc->sc_ax)) 1576 1.13 christos continue; 1577 1.12 bouyer 1578 1.12 bouyer tx = ax - sc->sc_ax[id]; 1579 1.12 bouyer ty = ay - sc->sc_ay[id]; 1580 1.12 bouyer 1581 1.12 bouyer if (ISSET(sc->sc_smask, __BIT(id))) { 1582 1.14 bouyer struct timeval now_tv; 1583 1.14 bouyer getmicrotime(&now_tv); 1584 1.14 bouyer if (sc->sc_nfingers == 1 && mb == 0 && 1585 1.14 bouyer timercmp(&sc->sc_taptime, &now_tv, >)) { 1586 1.14 bouyer /* still detecting a tap */ 1587 1.14 bouyer continue; 1588 1.14 bouyer } 1589 1.14 bouyer 1590 1.12 bouyer if (sc->sc_nfingers == 1 || mb != 0) { 1591 1.12 bouyer /* single finger moving */ 1592 1.12 bouyer dx += btmagic_scale(tx, &sc->sc_rx, 1593 1.12 bouyer sc->sc_resolution); 1594 1.12 bouyer dy += btmagic_scale(ty, &sc->sc_ry, 1595 1.12 bouyer sc->sc_resolution); 1596 1.12 bouyer } else { 1597 1.12 bouyer /* scrolling fingers */ 1598 1.12 bouyer dz += btmagic_scale(ty, &sc->sc_rz, 1599 1.12 bouyer sc->sc_resolution / sc->sc_scale); 1600 1.12 bouyer dw += btmagic_scale(tx, &sc->sc_rw, 1601 1.12 bouyer sc->sc_resolution / sc->sc_scale); 1602 1.12 bouyer } 1603 1.12 bouyer } else if (ay > MAGICT_B_YMAX) { /* new finger */ 1604 1.12 bouyer sc->sc_rx = 0; 1605 1.12 bouyer sc->sc_ry = 0; 1606 1.12 bouyer sc->sc_rz = 0; 1607 1.12 bouyer sc->sc_rw = 0; 1608 1.12 bouyer KASSERT(!ISSET(sc->sc_smask, __BIT(id))); 1609 1.12 bouyer SET(sc->sc_smask, __BIT(id)); 1610 1.12 bouyer sc->sc_nfingers++; 1611 1.14 bouyer if (sc->sc_tapmb_id == -1 && 1612 1.14 bouyer mb == 0 && sc->sc_mb == 0) { 1613 1.14 bouyer sc->sc_tapmb_id = id; 1614 1.14 bouyer getmicrotime(&sc->sc_taptime); 1615 1.14 bouyer sc->sc_taptime.tv_usec += 1616 1.14 bouyer sc->sc_taptimeout * 1000; 1617 1.14 bouyer if (sc->sc_taptime.tv_usec > 1000000) { 1618 1.14 bouyer sc->sc_taptime.tv_usec -= 1619 1.14 bouyer 1000000; 1620 1.14 bouyer sc->sc_taptime.tv_sec++; 1621 1.14 bouyer } 1622 1.14 bouyer } 1623 1.14 bouyer 1624 1.12 bouyer } 1625 1.12 bouyer 1626 1.12 bouyer break; 1627 1.12 bouyer default: 1628 1.12 bouyer if (ISSET(sc->sc_smask, __BIT(id))) { 1629 1.12 bouyer CLR(sc->sc_smask, __BIT(id)); 1630 1.12 bouyer sc->sc_nfingers--; 1631 1.12 bouyer KASSERT(sc->sc_nfingers >= 0); 1632 1.14 bouyer if (id == sc->sc_tapmb_id) { 1633 1.14 bouyer mb = btmagic_tap(sc, id); 1634 1.14 bouyer } 1635 1.12 bouyer } 1636 1.12 bouyer break; 1637 1.12 bouyer } 1638 1.12 bouyer 1639 1.13 christos if (id >= __arraycount(sc->sc_ax)) 1640 1.13 christos continue; 1641 1.13 christos 1642 1.12 bouyer sc->sc_ax[id] = ax; 1643 1.12 bouyer sc->sc_ay[id] = ay; 1644 1.12 bouyer } 1645 1.12 bouyer 1646 1.12 bouyer if (dx != 0 || dy != 0 || dz != 0 || dw != 0 || mb != sc->sc_mb) { 1647 1.12 bouyer sc->sc_mb = mb; 1648 1.12 bouyer 1649 1.12 bouyer s = spltty(); 1650 1.12 bouyer wsmouse_input(sc->sc_wsmouse, mb, 1651 1.12 bouyer dx, dy, -dz, dw, WSMOUSE_INPUT_DELTA); 1652 1.12 bouyer splx(s); 1653 1.12 bouyer } 1654 1.12 bouyer } 1655 1.14 bouyer 1656 1.14 bouyer static int 1657 1.14 bouyer btmagic_tap(struct btmagic_softc *sc, int id) 1658 1.14 bouyer { 1659 1.14 bouyer struct timeval now_tv; 1660 1.14 bouyer 1661 1.14 bouyer sc->sc_tapmb_id = -1; 1662 1.14 bouyer getmicrotime(&now_tv); 1663 1.14 bouyer if (timercmp(&sc->sc_taptime, &now_tv, >)) { 1664 1.14 bouyer /* got a tap */ 1665 1.14 bouyer callout_schedule( 1666 1.14 bouyer &sc->sc_tapcallout, 1667 1.14 bouyer mstohz(sc->sc_taptimeout)); 1668 1.14 bouyer return __BIT(0); 1669 1.14 bouyer } 1670 1.14 bouyer return 0; 1671 1.14 bouyer } 1672 1.14 bouyer 1673 1.14 bouyer static void 1674 1.14 bouyer btmagic_tapcallout(void *arg) 1675 1.14 bouyer { 1676 1.14 bouyer struct btmagic_softc *sc = arg; 1677 1.14 bouyer int s; 1678 1.14 bouyer 1679 1.14 bouyer mutex_enter(bt_lock); 1680 1.14 bouyer callout_ack(&sc->sc_tapcallout); 1681 1.14 bouyer if ((sc->sc_mb & __BIT(0)) != 0) { 1682 1.14 bouyer sc->sc_mb &= ~__BIT(0); 1683 1.14 bouyer s = spltty(); 1684 1.14 bouyer wsmouse_input(sc->sc_wsmouse, sc->sc_mb, 1685 1.14 bouyer 0, 0, 0, 0, WSMOUSE_INPUT_DELTA); 1686 1.14 bouyer splx(s); 1687 1.14 bouyer } 1688 1.14 bouyer mutex_exit(bt_lock); 1689 1.14 bouyer } 1690