summaryrefslogtreecommitdiffstats
path: root/sys/dev/adb
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2009-11-28 17:48:25 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2009-11-28 17:48:25 +0000
commit4e780937910bd3d67bb667de4e55969a62ecb079 (patch)
tree07dae7eda5debe92aebe8de49a9a342474958dec /sys/dev/adb
parent7670914da0cc10a422fba58b44dd3390dd048fa0 (diff)
downloadFreeBSD-src-4e780937910bd3d67bb667de4e55969a62ecb079.zip
FreeBSD-src-4e780937910bd3d67bb667de4e55969a62ecb079.tar.gz
Add support for interpreting taps on ADB touchpads as a button click.
Submitted by: Andreas Tobler <andreast-list at fgznet dot ch> MFC after: 2 weeks
Diffstat (limited to 'sys/dev/adb')
-rw-r--r--sys/dev/adb/adb.h1
-rw-r--r--sys/dev/adb/adb_bus.c18
-rw-r--r--sys/dev/adb/adb_mouse.c131
3 files changed, 149 insertions, 1 deletions
diff --git a/sys/dev/adb/adb.h b/sys/dev/adb/adb.h
index 10c3db2..acb5ae2 100644
--- a/sys/dev/adb/adb.h
+++ b/sys/dev/adb/adb.h
@@ -69,6 +69,7 @@ uint8_t adb_get_device_handler(device_t dev);
uint8_t adb_set_device_handler(device_t dev, uint8_t newhandler);
size_t adb_read_register(device_t dev, u_char reg, void *data);
+size_t adb_write_register(device_t dev, u_char reg, size_t len, void *data);
/* Bits for implementing ADB host bus adapters */
extern devclass_t adb_devclass;
diff --git a/sys/dev/adb/adb_bus.c b/sys/dev/adb/adb_bus.c
index faab048..fd46f27 100644
--- a/sys/dev/adb/adb_bus.c
+++ b/sys/dev/adb/adb_bus.c
@@ -402,3 +402,21 @@ adb_read_register(device_t dev, u_char reg, void *data)
return (result);
}
+size_t
+adb_write_register(device_t dev, u_char reg, size_t len, void *data)
+{
+ struct adb_softc *sc;
+ struct adb_devinfo *dinfo;
+ size_t result;
+
+ dinfo = device_get_ivars(dev);
+ sc = device_get_softc(device_get_parent(dev));
+
+ result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
+ ADB_COMMAND_LISTEN, reg, len, (u_char *)data, NULL);
+
+ result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
+ ADB_COMMAND_TALK, reg, 0, NULL, NULL);
+
+ return (result);
+}
diff --git a/sys/dev/adb/adb_mouse.c b/sys/dev/adb/adb_mouse.c
index f602f1c..7eecb7a 100644
--- a/sys/dev/adb/adb_mouse.c
+++ b/sys/dev/adb/adb_mouse.c
@@ -35,6 +35,7 @@
#include <sys/poll.h>
#include <sys/condvar.h>
#include <sys/selinfo.h>
+#include <sys/sysctl.h>
#include <sys/uio.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
@@ -51,6 +52,8 @@
static int adb_mouse_probe(device_t dev);
static int adb_mouse_attach(device_t dev);
static int adb_mouse_detach(device_t dev);
+static void adb_init_trackpad(device_t dev);
+static int adb_tapping_sysctl(SYSCTL_HANDLER_ARGS);
static d_open_t ams_open;
static d_close_t ams_close;
@@ -77,6 +80,8 @@ struct adb_mouse_softc {
u_char id[4];
int buttons;
+ u_int sc_tapping;
+ int button_buf;
int last_buttons;
int xdelta, ydelta;
@@ -167,6 +172,8 @@ adb_mouse_attach(device_t dev)
sc->mode.packetsize = 5;
sc->buttons = 0;
+ sc->sc_tapping = 0;
+ sc->button_buf = 0;
sc->last_buttons = 0;
sc->packet_read_len = 0;
@@ -205,6 +212,7 @@ adb_mouse_attach(device_t dev)
case 3:
sc->flags |= AMS_TOUCHPAD;
sc->hw.type = MOUSE_PAD;
+ adb_init_trackpad(dev);
description = "Touchpad";
break;
}
@@ -259,6 +267,70 @@ adb_mouse_detach(device_t dev)
return (0);
}
+static void
+adb_init_trackpad(device_t dev)
+{
+ struct adb_mouse_softc *sc;
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid *tree;
+
+ size_t r1_len;
+ u_char r1[8];
+ u_char r2[8];
+
+ sc = device_get_softc(dev);
+
+ r1_len = adb_read_register(dev, 1, r1);
+
+ /* An Extended Mouse register1 must return 8 bytes. */
+ if (r1_len != 8)
+ return;
+
+ if((r1[6] != 0x0d))
+ {
+ r1[6] = 0x0d;
+
+ adb_write_register(dev, 1, 8, r1);
+
+ r1_len = adb_read_register(dev, 1, r1);
+
+ if (r1[6] != 0x0d)
+ {
+ device_printf(dev, "ADB Mouse = 0x%x "
+ "(non-Extended Mode)\n", r1[6]);
+ return;
+ } else {
+ device_printf(dev, "ADB Mouse = 0x%x "
+ "(Extended Mode)\n", r1[6]);
+
+ /* Set ADB Extended Features to default values,
+ enabled. */
+ r2[0] = 0x19; /* Clicking: 0x19 disabled 0x99 enabled */
+ r2[1] = 0x94; /* Dragging: 0x14 disabled 0x94 enabled */
+ r2[2] = 0x19;
+ r2[3] = 0xff; /* DragLock: 0xff disabled 0xb2 enabled */
+ r2[4] = 0xb2;
+ r2[5] = 0x8a;
+ r2[6] = 0x1b;
+
+ r2[7] = 0x57; /* 0x57 bits 3:0 for W mode */
+
+ adb_write_register(dev, 2, 8, r2);
+
+ }
+ }
+
+ /*
+ * Set up sysctl
+ */
+ ctx = device_get_sysctl_ctx(dev);
+ tree = device_get_sysctl_tree(dev);
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tapping",
+ CTLTYPE_INT | CTLFLAG_RW, sc, 0, adb_tapping_sysctl,
+ "I", "Tapping the pad causes button events");
+ return;
+}
+
static u_int
adb_mouse_receive_packet(device_t dev, u_char status, u_char command,
u_char reg, int len, u_char *data)
@@ -266,7 +338,7 @@ adb_mouse_receive_packet(device_t dev, u_char status, u_char command,
struct adb_mouse_softc *sc;
int i = 0;
int xdelta, ydelta;
- int buttons;
+ int buttons, tmp_buttons;
sc = device_get_softc(dev);
@@ -298,6 +370,30 @@ adb_mouse_receive_packet(device_t dev, u_char status, u_char command,
if (ydelta & (0x40 << 3*(len-2)))
ydelta |= 0xffffffc0 << 3*(len - 2);
+ if ((sc->flags & AMS_TOUCHPAD) && (sc->sc_tapping == 1)) {
+ tmp_buttons = buttons;
+ if (buttons == 0x12) {
+ /* Map a double tap on button 3.
+ Keep the button state for the next sequence.
+ A double tap sequence is followed by a single tap
+ sequence.
+ */
+ tmp_buttons = 0x3;
+ sc->button_buf = tmp_buttons;
+ } else if (buttons == 0x2) {
+ /* Map a single tap on button 2. But only if it is
+ not a successor from a double tap.
+ */
+ if (sc->button_buf != 0x3)
+ tmp_buttons = 0x2;
+ else
+ tmp_buttons = 0;
+
+ sc->button_buf = 0;
+ }
+ buttons = tmp_buttons;
+ }
+
/*
* Some mice report high-numbered buttons on the wrong button number,
* so set the highest-numbered real button as pressed if there are
@@ -554,3 +650,36 @@ ams_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
return (0);
}
+static int
+adb_tapping_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct adb_mouse_softc *sc = arg1;
+ device_t dev;
+ int error;
+ u_char r2[8];
+ u_int tapping;
+
+ dev = sc->sc_dev;
+ tapping = sc->sc_tapping;
+
+ error = sysctl_handle_int(oidp, &tapping, 0, req);
+
+ if (error || !req->newptr)
+ return (error);
+
+ if (tapping == 1) {
+ adb_read_register(dev, 2, r2);
+ r2[0] = 0x99; /* enable tapping. */
+ adb_write_register(dev, 2, 8, r2);
+ sc->sc_tapping = 1;
+ } else if (tapping == 0) {
+ adb_read_register(dev, 2, r2);
+ r2[0] = 0x19; /* disable tapping. */
+ adb_write_register(dev, 2, 8, r2);
+ sc->sc_tapping = 0;
+ }
+ else
+ return (EINVAL);
+
+ return (0);
+}
OpenPOWER on IntegriCloud