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