From f697a802bbad27dd0dcdd7c8a9b8b0490357c9fd Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Sat, 28 Nov 2009 17:48:25 +0000 Subject: [PATCH] Add support for interpreting taps on ADB touchpads as a button click. Submitted by: Andreas Tobler MFC after: 2 weeks --- sys/dev/adb/adb.h | 1 + sys/dev/adb/adb_bus.c | 18 ++++++ sys/dev/adb/adb_mouse.c | 131 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 149 insertions(+), 1 deletion(-) diff --git a/sys/dev/adb/adb.h b/sys/dev/adb/adb.h index 10c3db235900..acb5ae27d4c6 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 faab048b52c9..fd46f27e9630 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 f602f1cd08df..7eecb7ad7611 100644 --- a/sys/dev/adb/adb_mouse.c +++ b/sys/dev/adb/adb_mouse.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -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); +}