Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/bluetooth Add support for Apple Magic Trackpad.
details: https://anonhg.NetBSD.org/src/rev/2e6c67e8ca54
branches: trunk
changeset: 337211:2e6c67e8ca54
user: bouyer <bouyer%NetBSD.org@localhost>
date: Mon Apr 06 17:45:31 2015 +0000
description:
Add support for Apple Magic Trackpad.
3 button emulation by detecting in which area of the bottom of
the device the trackpad's button is pressed.
Pointer move support with 1 finger touch, X/Y scroll with 2-finger touch.
TODO:
- detect tap to emulate button press and drag/n/drop.
- Detect and support zoom, if wsmouse allows to report this
diffstat:
sys/dev/bluetooth/btmagic.c | 254 +++++++++++++++++++++++++++++++++++++++++--
1 files changed, 237 insertions(+), 17 deletions(-)
diffs (truncated from 357 to 300 lines):
diff -r 8f2222e82e8c -r 2e6c67e8ca54 sys/dev/bluetooth/btmagic.c
--- a/sys/dev/bluetooth/btmagic.c Mon Apr 06 17:16:25 2015 +0000
+++ b/sys/dev/bluetooth/btmagic.c Mon Apr 06 17:45:31 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: btmagic.c,v 1.11 2014/08/05 07:55:31 rtr Exp $ */
+/* $NetBSD: btmagic.c,v 1.12 2015/04/06 17:45:31 bouyer Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -85,7 +85,7 @@
*****************************************************************************/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: btmagic.c,v 1.11 2014/08/05 07:55:31 rtr Exp $");
+__KERNEL_RCSID(0, "$NetBSD: btmagic.c,v 1.12 2015/04/06 17:45:31 bouyer Exp $");
#include <sys/param.h>
#include <sys/conf.h>
@@ -163,11 +163,13 @@
int sc_rw;
/* previous touches */
- uint32_t sc_smask; /* scrolling */
- int sc_az[16];
- int sc_aw[16];
+ uint32_t sc_smask; /* active(s) IDs */
+ int sc_nfingers; /* number of active IDs */
+ int sc_ax[16];
+ int sc_ay[16];
/* previous mouse buttons */
+ int sc_mb_id; /* which ID selects the button */
uint32_t sc_mb;
};
@@ -216,7 +218,16 @@
static void btmagic_linkmode(void *, int);
static void btmagic_input(void *, struct mbuf *);
static void btmagic_input_basic(struct btmagic_softc *, uint8_t *, size_t);
-static void btmagic_input_magic(struct btmagic_softc *, uint8_t *, size_t);
+static void btmagic_input_magicm(struct btmagic_softc *, uint8_t *, size_t);
+static void btmagic_input_magict(struct btmagic_softc *, uint8_t *, size_t);
+
+/* report types (data[1]) */
+#define BASIC_REPORT_ID 0x10
+#define TRACKPAD_REPORT_ID 0x28
+#define MOUSE_REPORT_ID 0x29
+#define BATT_STAT_REPORT_ID 0x30
+#define BATT_STRENGHT_REPORT_ID 0x47
+#define SURFACE_REPORT_ID 0x61
static const struct btproto btmagic_ctl_proto = {
btmagic_connecting,
@@ -259,7 +270,8 @@
if (prop_dictionary_get_uint16(aux, BTDEVvendor, &v)
&& prop_dictionary_get_uint16(aux, BTDEVproduct, &p)
&& v == USB_VENDOR_APPLE
- && p == USB_PRODUCT_APPLE_MAGICMOUSE)
+ && (p == USB_PRODUCT_APPLE_MAGICMOUSE ||
+ p == USB_PRODUCT_APPLE_MAGICTRACKPAD))
return 2; /* trump bthidev(4) */
return 0;
@@ -1047,15 +1059,18 @@
break;
switch (data[1]) {
- case 0x10: /* Basic mouse (input) */
+ case BASIC_REPORT_ID: /* Basic mouse (input) */
btmagic_input_basic(sc, data + 2, len - 2);
break;
- case 0x29: /* Magic touch (input) */
- btmagic_input_magic(sc, data + 2, len - 2);
+ case TRACKPAD_REPORT_ID: /* Magic trackpad (input) */
+ btmagic_input_magict(sc, data + 2, len - 2);
+ break;
+ case MOUSE_REPORT_ID: /* Magic touch (input) */
+ btmagic_input_magicm(sc, data + 2, len - 2);
break;
- case 0x30: /* Battery status (input) */
+ case BATT_STAT_REPORT_ID: /* Battery status (input) */
if (len != 3)
break;
@@ -1068,7 +1083,7 @@
}
break;
- case 0x47: /* Battery strength (feature) */
+ case BATT_STRENGHT_REPORT_ID: /* Battery strength (feature) */
if (len != 3)
break;
@@ -1076,7 +1091,7 @@
data[2]);
break;
- case 0x61: /* Surface detection (input) */
+ case SURFACE_REPORT_ID: /* Surface detection (input) */
if (len != 3)
break;
@@ -1246,7 +1261,7 @@
#define BTMAGIC_PHASE_CANCEL 0x0
static void
-btmagic_input_magic(struct btmagic_softc *sc, uint8_t *data, size_t len)
+btmagic_input_magicm(struct btmagic_softc *sc, uint8_t *data, size_t len)
{
uint32_t mb;
int dx, dy, dz, dw;
@@ -1290,10 +1305,12 @@
switch (hid_get_udata(data, &touch.phase)) {
case BTMAGIC_PHASE_CONT:
+#define sc_az sc_ay
+#define sc_aw sc_ax
tz = az - sc->sc_az[id];
tw = aw - sc->sc_aw[id];
- if (ISSET(sc->sc_smask, id)) {
+ if (ISSET(sc->sc_smask, __BIT(id))) {
/* scrolling finger */
dz += btmagic_scale(tz, &sc->sc_rz,
sc->sc_resolution / sc->sc_scale);
@@ -1307,7 +1324,7 @@
sc->sc_rw = 0;
}
- SET(sc->sc_smask, id);
+ SET(sc->sc_smask, __BIT(id));
} else {
/* not scrolling finger */
az = sc->sc_az[id];
@@ -1321,12 +1338,14 @@
break;
default:
- CLR(sc->sc_smask, id);
+ CLR(sc->sc_smask, __BIT(id));
break;
}
sc->sc_az[id] = az;
sc->sc_aw[id] = aw;
+#undef sc_az
+#undef sc_aw
}
/*
@@ -1355,3 +1374,204 @@
splx(s);
}
}
+
+/*
+ * the Magic touch trackpad report (0x28), according to the Linux driver
+ * written by Michael Poole and Chase Douglas, is variable length starting
+ * with the fixed 24-bit header
+ *
+ * button 1 1-bit
+ * unknown 5-bits
+ * timestamp 18-bits
+ *
+ * followed by (up to 5?) touch reports of 72-bits each
+ *
+ * abs X 13-bits (signed)
+ * abs Y 13-bits (signed)
+ * unknown 6-bits
+ * axis major 8-bits
+ * axis minor 8-bits
+ * pressure 6-bits
+ * id 4-bits
+ * angle 6-bits (from E(0)->N(32)->W(64))
+ * unknown 4-bits
+ * phase 4-bits
+ */
+
+static const struct {
+ struct hid_location button;
+ struct hid_location timestamp;
+} magict = {
+ .button = { .pos = 0, .size = 1 },
+ .timestamp = { .pos = 6, .size = 18 },
+};
+
+static const struct {
+ struct hid_location aX;
+ struct hid_location aY;
+ struct hid_location major;
+ struct hid_location minor;
+ struct hid_location pressure;
+ struct hid_location id;
+ struct hid_location angle;
+ struct hid_location unknown;
+ struct hid_location phase;
+} toucht = {
+ .aX = { .pos = 0, .size = 13 },
+ .aY = { .pos = 13, .size = 13 },
+ .major = { .pos = 32, .size = 8 },
+ .minor = { .pos = 40, .size = 8 },
+ .pressure = { .pos = 48, .size = 6 },
+ .id = { .pos = 54, .size = 4 },
+ .angle = { .pos = 58, .size = 6 },
+ .unknown = { .pos = 64, .size = 4 },
+ .phase = { .pos = 68, .size = 4 },
+};
+
+/*
+ * as for btmagic_input_magicm,
+ * the phase of the touch starts at 0x01 as the finger is first detected
+ * approaching the mouse, increasing to 0x04 while the finger is touching,
+ * then increases towards 0x07 as the finger is lifted, and we get 0x00
+ * when the touch is cancelled. The values below seem to be produced for
+ * every touch, the others less consistently depending on how fast the
+ * approach or departure is.
+ *
+ * In fact we ignore touches unless they are in the steady 0x04 phase.
+ */
+
+/* min and max values reported */
+#define MAGICT_X_MIN (-2910)
+#define MAGICT_X_MAX (3170)
+#define MAGICT_Y_MIN (-2565)
+#define MAGICT_Y_MAX (2455)
+
+/*
+ * area for detecting the buttons: divide in 3 areas on X,
+ * below -1900 on y
+ */
+#define MAGICT_B_YMAX (-1900)
+#define MAGICT_B_XSIZE ((MAGICT_X_MAX - MAGICT_X_MIN) / 3)
+#define MAGICT_B_X1MAX (MAGICT_X_MIN + MAGICT_B_XSIZE)
+#define MAGICT_B_X2MAX (MAGICT_X_MIN + MAGICT_B_XSIZE * 2)
+
+static void
+btmagic_input_magict(struct btmagic_softc *sc, uint8_t *data, size_t len)
+{
+ bool bpress;
+ uint32_t mb;
+ int id, ax, ay, tx, ty;
+ int dx, dy, dz, dw;
+ int s;
+
+ if (((len - 3) % 9) != 0)
+ return;
+
+ bpress = 0;
+ if (hid_get_udata(data, &magict.button))
+ bpress = 1;
+
+ dx = dy = dz = dw = 0;
+ mb = 0;
+
+ len = (len - 3) / 9;
+ for (data += 3; len-- > 0; data += 9) {
+ id = hid_get_udata(data, &toucht.id);
+ ax = hid_get_data(data, &toucht.aX);
+ ay = hid_get_data(data, &toucht.aY);
+
+ DPRINTF(sc,
+ "btmagic_input_magicm: id %d ax %d ay %d phase %ld %s\n",
+ id, ax, ay, hid_get_udata(data, &toucht.phase),
+ bpress ? "button pressed" : "");
+
+ /*
+ * a single touch is interpreted as a mouse move.
+ * If a button is pressed, the touch in the button area
+ * defined above defines the button; a second touch is
+ * interpreted as a mouse move.
+ */
+
+ switch (hid_get_udata(data, &toucht.phase)) {
+ case BTMAGIC_PHASE_CONT:
+ if (bpress) {
+ if (sc->sc_mb == 0 && ay < MAGICT_B_YMAX) {
+ /*
+ * we have a new button press,
+ * and this id tells which one
+ */
+ if (ax < MAGICT_B_X1MAX)
+ mb = __BIT(0);
+ else if (ax > MAGICT_B_X2MAX)
+ mb = __BIT(2);
+ else
+ mb = __BIT(1);
+ sc->sc_mb_id = id;
+ } else {
+ /* keep previous state */
+ mb = sc->sc_mb;
+ }
+ } else {
+ /* no button pressed */
+ mb = 0;
+ sc->sc_mb_id = -1;
+ }
+ if (id == sc->sc_mb_id) {
+ /*
Home |
Main Index |
Thread Index |
Old Index