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
This commit is contained in:
parent
6a3c9cdcd1
commit
8692d33ed3
|
@ -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 @@ struct btmagic_softc {
|
|||
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_complete(void *, int);
|
|||
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 @@ btmagic_match(device_t self, cfdata_t cfdata, void *aux)
|
|||
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 @@ btmagic_input(void *arg, struct mbuf *m)
|
|||
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 @@ btmagic_input(void *arg, struct mbuf *m)
|
|||
}
|
||||
break;
|
||||
|
||||
case 0x47: /* Battery strength (feature) */
|
||||
case BATT_STRENGHT_REPORT_ID: /* Battery strength (feature) */
|
||||
if (len != 3)
|
||||
break;
|
||||
|
||||
|
@ -1076,7 +1091,7 @@ btmagic_input(void *arg, struct mbuf *m)
|
|||
data[2]);
|
||||
break;
|
||||
|
||||
case 0x61: /* Surface detection (input) */
|
||||
case SURFACE_REPORT_ID: /* Surface detection (input) */
|
||||
if (len != 3)
|
||||
break;
|
||||
|
||||
|
@ -1246,7 +1261,7 @@ static const struct {
|
|||
#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 @@ btmagic_input_magic(struct btmagic_softc *sc, uint8_t *data, size_t len)
|
|||
|
||||
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 @@ btmagic_input_magic(struct btmagic_softc *sc, uint8_t *data, size_t len)
|
|||
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 @@ btmagic_input_magic(struct btmagic_softc *sc, uint8_t *data, size_t len)
|
|||
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 @@ btmagic_input_magic(struct btmagic_softc *sc, uint8_t *data, size_t len)
|
|||
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) {
|
||||
/*
|
||||
* this id selects the button
|
||||
* ignore for move/scroll
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
tx = ax - sc->sc_ax[id];
|
||||
ty = ay - sc->sc_ay[id];
|
||||
|
||||
if (ISSET(sc->sc_smask, __BIT(id))) {
|
||||
if (sc->sc_nfingers == 1 || mb != 0) {
|
||||
/* single finger moving */
|
||||
dx += btmagic_scale(tx, &sc->sc_rx,
|
||||
sc->sc_resolution);
|
||||
dy += btmagic_scale(ty, &sc->sc_ry,
|
||||
sc->sc_resolution);
|
||||
} else {
|
||||
/* scrolling fingers */
|
||||
dz += btmagic_scale(ty, &sc->sc_rz,
|
||||
sc->sc_resolution / sc->sc_scale);
|
||||
dw += btmagic_scale(tx, &sc->sc_rw,
|
||||
sc->sc_resolution / sc->sc_scale);
|
||||
}
|
||||
} else if (ay > MAGICT_B_YMAX) { /* new finger */
|
||||
sc->sc_rx = 0;
|
||||
sc->sc_ry = 0;
|
||||
sc->sc_rz = 0;
|
||||
sc->sc_rw = 0;
|
||||
|
||||
KASSERT(!ISSET(sc->sc_smask, __BIT(id)));
|
||||
SET(sc->sc_smask, __BIT(id));
|
||||
sc->sc_nfingers++;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
if (ISSET(sc->sc_smask, __BIT(id))) {
|
||||
CLR(sc->sc_smask, __BIT(id));
|
||||
sc->sc_nfingers--;
|
||||
KASSERT(sc->sc_nfingers >= 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
sc->sc_ax[id] = ax;
|
||||
sc->sc_ay[id] = ay;
|
||||
}
|
||||
|
||||
if (dx != 0 || dy != 0 || dz != 0 || dw != 0 || mb != sc->sc_mb) {
|
||||
sc->sc_mb = mb;
|
||||
|
||||
s = spltty();
|
||||
wsmouse_input(sc->sc_wsmouse, mb,
|
||||
dx, dy, -dz, dw, WSMOUSE_INPUT_DELTA);
|
||||
splx(s);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue