Module Name: src
Committed By: macallan
Date: Sun Sep 8 05:55:15 UTC 2019
Modified Files:
src/sys/dev/adb: files.adb
Added Files:
src/sys/dev/adb: adb_ktm.c
Log Message:
add driver for Kensington Turbo Mouse ( actually a trackball )
the adbms driver contains basic support, this driver lets you program the
buttons, I'll add other features once I figure out how they work
To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/sys/dev/adb/adb_ktm.c
cvs rdiff -u -r1.8 -r1.9 src/sys/dev/adb/files.adb
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/adb/files.adb
diff -u src/sys/dev/adb/files.adb:1.8 src/sys/dev/adb/files.adb:1.9
--- src/sys/dev/adb/files.adb:1.8 Thu Jun 6 20:59:58 2019
+++ src/sys/dev/adb/files.adb Sun Sep 8 05:55:15 2019
@@ -1,5 +1,5 @@
#
-# $NetBSD: files.adb,v 1.8 2019/06/06 20:59:58 macallan Exp $
+# $NetBSD: files.adb,v 1.9 2019/09/08 05:55:15 macallan Exp $
#
# Apple Desktop Bus protocol and drivers
@@ -8,6 +8,7 @@ defflag adbdebug.h ADBKBD_DEBUG
defflag adbdebug.h ADBMS_DEBUG
defflag adbdebug.h ADBBT_DEBUG
defflag adbdebug.h ADBKBD_POWER_DDB
+defflag adbdebug.h KTM_DEBUG
define adb_bus {}
@@ -28,3 +29,7 @@ file dev/adb/adb_bt.c adbbt
device adbms : wsmousedev
attach adbms at nadb
file dev/adb/adb_ms.c adbms needs-flag
+
+device ktm : wsmousedev
+attach ktm at nadb
+file dev/adb/adb_ktm.c ktm needs-flag
Added files:
Index: src/sys/dev/adb/adb_ktm.c
diff -u /dev/null src/sys/dev/adb/adb_ktm.c:1.1
--- /dev/null Sun Sep 8 05:55:15 2019
+++ src/sys/dev/adb/adb_ktm.c Sun Sep 8 05:55:15 2019
@@ -0,0 +1,486 @@
+/* $NetBSD: adb_ktm.c,v 1.1 2019/09/08 05:55:15 macallan Exp $ */
+
+/*-
+ * Copyright (c) 2019 Michael Lorenz
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: adb_ktm.c,v 1.1 2019/09/08 05:55:15 macallan Exp $");
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/fcntl.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+
+#include <machine/autoconf.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsmousevar.h>
+
+#include <machine/adbsys.h>
+#include <dev/adb/adbvar.h>
+
+#include "adbdebug.h"
+
+#ifdef KTM_DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF while (0) printf
+#endif
+
+/*
+ * State info, per mouse instance.
+ */
+struct ktm_softc {
+ device_t sc_dev;
+ struct adb_device *sc_adbdev;
+ struct adb_bus_accessops *sc_ops;
+
+ uint8_t sc_us; /* cmd to watch for */
+ device_t sc_wsmousedev;
+ /* buffers */
+ uint8_t sc_config[8];
+ int sc_left;
+ int sc_right;
+ int sc_poll;
+ int sc_msg_len;
+ int sc_event;
+ uint8_t sc_buffer[16];
+};
+
+/*
+ * Function declarations.
+ */
+static int ktm_match(device_t, cfdata_t, void *);
+static void ktm_attach(device_t, device_t, void *);
+static void ktm_init(struct ktm_softc *);
+static void ktm_write_config(struct ktm_softc *);
+static void ktm_buttons(struct ktm_softc *);
+static void ktm_process_event(struct ktm_softc *, int, uint8_t *);
+static int ktm_send_sync(struct ktm_softc *, uint8_t, int, uint8_t *);
+
+/* Driver definition. */
+CFATTACH_DECL_NEW(ktm, sizeof(struct ktm_softc),
+ ktm_match, ktm_attach, NULL, NULL);
+
+static int ktm_enable(void *);
+static int ktm_ioctl(void *, u_long, void *, int, struct lwp *);
+static void ktm_disable(void *);
+
+static void ktm_handler(void *, int, uint8_t *);
+static int ktm_wait(struct ktm_softc *, int);
+static int sysctl_ktm_left(SYSCTLFN_ARGS);
+static int sysctl_ktm_right(SYSCTLFN_ARGS);
+
+const struct wsmouse_accessops ktm_accessops = {
+ ktm_enable,
+ ktm_ioctl,
+ ktm_disable,
+};
+
+static int
+ktm_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct adb_attach_args *aaa = aux;
+ if ((aaa->dev->original_addr == ADBADDR_MS) &&
+ (aaa->dev->handler_id == ADBMS_TURBO))
+ return 50; /* beat out adbms */
+ else
+ return 0;
+}
+
+static void
+ktm_attach(device_t parent, device_t self, void *aux)
+{
+ struct ktm_softc *sc = device_private(self);
+ struct adb_attach_args *aaa = aux;
+ struct wsmousedev_attach_args a;
+
+ sc->sc_dev = self;
+ sc->sc_ops = aaa->ops;
+ sc->sc_adbdev = aaa->dev;
+ sc->sc_adbdev->cookie = sc;
+ sc->sc_adbdev->handler = ktm_handler;
+ sc->sc_us = ADBTALK(sc->sc_adbdev->current_addr, 0);
+ printf(" addr %d: Kensington Turbo Mouse\n",
+ sc->sc_adbdev->current_addr);
+
+ sc->sc_poll = 0;
+ sc->sc_msg_len = 0;
+
+ ktm_init(sc);
+
+ a.accessops = &ktm_accessops;
+ a.accesscookie = sc;
+ sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
+}
+
+static int
+ktm_turbo_csum(uint8_t *d)
+{
+ int i = 0, sum = 0;
+
+ for (i = 0; i < 7; i++)
+ sum ^= d[i];
+ return (sum ^ 0xff);
+}
+
+static void
+ktm_write_config(struct ktm_softc *sc)
+{
+ uint8_t addr = sc->sc_adbdev->current_addr;
+
+ ktm_send_sync(sc, ADBFLUSH(addr), 0, NULL);
+ sc->sc_config[7] = ktm_turbo_csum(sc->sc_config);
+ ktm_send_sync(sc, ADBLISTEN(addr, 2), 8, sc->sc_config);
+}
+
+static uint8_t button_to_reg[] = {0, 1, 4, 6};
+
+static void ktm_buttons(struct ktm_softc *sc)
+{
+ uint8_t reg;
+
+ reg = button_to_reg[sc->sc_right] |
+ (button_to_reg[sc->sc_left] << 3);
+ sc->sc_config[1] = reg;
+}
+
+static void
+ktm_init(struct ktm_softc *sc)
+{
+ const struct sysctlnode *me = NULL, *node = NULL;
+ int ret;
+ uint8_t addr;
+
+ /* Found Kensington Turbo Mouse */
+
+/*
+ * byte 0
+ - 0x80 enables EMP output
+ - 0x08 seems to map both buttons together
+ - 0x04 enables the 2nd button
+ - initialized to 0x20 on power up, no idea what that does
+
+ * byte 1 assigns what which button does
+ - 0x08 - button 1 - 1, button 2 - nothing
+ - 0x09 - both buttons - 1
+ - 0x0a - butoon 1 - 1, button 2 - toggle 1
+ - 0x0b - button 1 - 1, button 2 - nothing
+ - 0x0c - button 1 - 1, button 2 - 2
+ - 0x0e - button 1 - 1, button 2 - 3
+ - 0x0f - button 1 - 1, button 2 - toggle 3
+ - 0x10 - button 1 toggle 1, button 2 nothing
+ - 0x11 - button 1 - toggle 1, button 2 - 1
+ - 0x12 - both toggle 1
+ - 0x14 - button 1 toggle 1, button 2 - 2
+ - 0x21 - button 1 - 2, button 2 - 1
+ - 0x31 - button 1 - 3, button 2 - 1
+
+ * byte 2 - 0x40 on powerup, seems to do nothing
+ * byte 3 - 0x01 on powerup, seems to do nothing
+ * byte 4 programs a delay for button presses, apparently in 1/100 seconds
+ * byte 5 and 6 init to 0xff
+ * byte 7 is a simple XOR checksum, writes will only stick if it's valid
+ as in, b[7] = (b[0] ^ b[1] ^ ... ^ b[6]) ^ 0xff
+ */
+
+ /* this seems to be the most reasonable default */
+ uint8_t data[8] = { 0xa5, 0x0e, 0, 0, 1, 0xff, 0xff, 0 };
+
+ addr = sc->sc_adbdev->current_addr;
+ memcpy(sc->sc_config, data, sizeof(data));
+
+ sc->sc_left = 1;
+ sc->sc_right = 3;
+
+ ktm_buttons(sc);
+
+#ifdef KTM_DEBUG
+ {
+ int i;
+ ktm_send_sync(sc, ADBTALK(addr, 2), 0, NULL);
+ printf("reg *");
+ for (i = 0; i < sc->sc_msg_len; i++)
+ printf(" %02x", sc->sc_buffer[i]);
+ printf("\n");
+ }
+#endif
+
+ ktm_write_config(sc);
+
+#ifdef KTM_DEBUG
+ int i, reg;
+ for (reg = 1; reg < 4; reg++) {
+ ktm_send_sync(sc, ADBTALK(addr, reg), 0, NULL);
+ printf("reg %d", reg);
+ for (i = 0; i < sc->sc_msg_len; i++)
+ printf(" %02x", sc->sc_buffer[i]);
+ printf("\n");
+ }
+#endif
+ ret = sysctl_createv(NULL, 0, NULL, &me,
+ CTLFLAG_READWRITE,
+ CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
+ NULL, 0, NULL, 0,
+ CTL_MACHDEP, CTL_CREATE, CTL_EOL);
+
+ ret = sysctl_createv(NULL, 0, NULL, &node,
+ CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
+ CTLTYPE_INT, "left", "left button assigmnent",
+ sysctl_ktm_left, 1, (void *)sc, 0,
+ CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
+
+ ret = sysctl_createv(NULL, 0, NULL, &node,
+ CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
+ CTLTYPE_INT, "right", "right button assigmnent",
+ sysctl_ktm_right, 1, (void *)sc, 0,
+ CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
+ __USE(ret);
+}
+
+static void
+ktm_handler(void *cookie, int len, uint8_t *data)
+{
+ struct ktm_softc *sc = cookie;
+
+#ifdef KTM_DEBUG
+ int i;
+ printf("%s: %02x - ", device_xname(sc->sc_dev), sc->sc_us);
+ for (i = 0; i < len; i++) {
+ printf(" %02x", data[i]);
+ }
+ printf("\n");
+#endif
+ if (len >= 2) {
+ memcpy(sc->sc_buffer, &data[2], len - 2);
+ sc->sc_msg_len = len - 2;
+ if (data[1] == sc->sc_us) {
+ /* make sense of the mouse message */
+ ktm_process_event(sc, sc->sc_msg_len, sc->sc_buffer);
+ return;
+ }
+ wakeup(&sc->sc_event);
+ } else {
+ DPRINTF("bogus message\n");
+ }
+}
+
+static void
+ktm_process_event(struct ktm_softc *sc, int len, uint8_t *buffer)
+{
+ int buttons = 0, mask, dx, dy, i;
+ int button_bit = 1;
+
+ /* Classic Mouse Protocol (up to 2 buttons) */
+ for (i = 0; i < 2; i++, button_bit <<= 1)
+ /* 0 when button down */
+ if (!(buffer[i] & 0x80))
+ buttons |= button_bit;
+ else
+ buttons &= ~button_bit;
+ /* Extended Protocol (up to 6 more buttons) */
+ for (mask = 0x80; i < len;
+ i += (mask == 0x80), button_bit <<= 1) {
+ /* 0 when button down */
+ if (!(buffer[i] & mask))
+ buttons |= button_bit;
+ else
+ buttons &= ~button_bit;
+ mask = ((mask >> 4) & 0xf) | ((mask & 0xf) << 4);
+ }
+
+ /* EMP crap, additional motion bits */
+ int shift = 7, ddx, ddy, sign, smask;
+
+#ifdef KTM_DEBUG
+ printf("EMP packet:");
+ for (i = 0; i < len; i++)
+ printf(" %02x", buffer[i]);
+ printf("\n");
+#endif
+ dx = (int)buffer[1] & 0x7f;
+ dy = (int)buffer[0] & 0x7f;
+ for (i = 2; i < len; i++) {
+ ddx = (buffer[i] & 0x07);
+ ddy = (buffer[i] & 0x70) >> 4;
+ dx |= (ddx << shift);
+ dy |= (ddy << shift);
+ shift += 3;
+ }
+ sign = 1 << (shift - 1);
+ smask = 0xffffffff << shift;
+ if (dx & sign)
+ dx |= smask;
+ if (dy & sign)
+ dy |= smask;
+#ifdef KTM_DEBUG
+ printf("%d %d %08x %d\n", dx, dy, smask, shift);
+#endif
+
+ if (sc->sc_wsmousedev)
+ wsmouse_input(sc->sc_wsmousedev, buttons,
+ dx, -dy, 0, 0,
+ WSMOUSE_INPUT_DELTA);
+}
+
+static int
+ktm_enable(void *v)
+{
+ return 0;
+}
+
+static int
+ktm_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
+{
+
+ switch (cmd) {
+ case WSMOUSEIO_GTYPE:
+ *(u_int *)data = WSMOUSE_TYPE_ADB;
+ break;
+
+ default:
+ return (EPASSTHROUGH);
+ }
+ return (0);
+}
+
+static void
+ktm_disable(void *v)
+{
+}
+
+static int
+ktm_wait(struct ktm_softc *sc, int timeout)
+{
+ int cnt = 0;
+
+ if (sc->sc_poll) {
+ while (sc->sc_msg_len == -1) {
+ sc->sc_ops->poll(sc->sc_ops->cookie);
+ }
+ } else {
+ while ((sc->sc_msg_len == -1) && (cnt < timeout)) {
+ tsleep(&sc->sc_event, 0, "ktmio", hz);
+ cnt++;
+ }
+ }
+ return (sc->sc_msg_len > 0);
+}
+
+static int
+ktm_send_sync(struct ktm_softc *sc, uint8_t cmd, int len, uint8_t *msg)
+{
+ int i;
+
+ sc->sc_msg_len = -1;
+ DPRINTF("send: %02x", cmd);
+ for (i = 0; i < len; i++)
+ DPRINTF(" %02x", msg[i]);
+ DPRINTF("\n");
+ sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, len, msg);
+ ktm_wait(sc, 3);
+ return (sc->sc_msg_len != -1);
+}
+
+static int
+sysctl_ktm_left(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node = *rnode;
+ struct ktm_softc *sc = node.sysctl_data;
+ int reg = sc->sc_left;
+
+ if (newp) {
+
+ /* we're asked to write */
+ node.sysctl_data = ®
+ if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
+
+ reg = *(int *)node.sysctl_data;
+ if ((reg != sc->sc_left) &&
+ (reg >= 0) &&
+ (reg < 4)) {
+ sc->sc_left = reg;
+ ktm_buttons(sc);
+ ktm_write_config(sc);
+ }
+ return 0;
+ }
+ return EINVAL;
+ } else {
+
+ node.sysctl_data = ®
+ node.sysctl_size = 4;
+ return (sysctl_lookup(SYSCTLFN_CALL(&node)));
+ }
+
+ return 0;
+}
+
+static int
+sysctl_ktm_right(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node = *rnode;
+ struct ktm_softc *sc = node.sysctl_data;
+ int reg = sc->sc_right;
+
+ if (newp) {
+
+ /* we're asked to write */
+ node.sysctl_data = ®
+ if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
+
+ reg = *(int *)node.sysctl_data;
+ if ((reg != sc->sc_right) &&
+ (reg >= 0) &&
+ (reg < 4)) {
+ sc->sc_right = reg;
+ ktm_buttons(sc);
+ ktm_write_config(sc);
+ }
+ return 0;
+ }
+ return EINVAL;
+ } else {
+
+ node.sysctl_data = ®
+ node.sysctl_size = 4;
+ return (sysctl_lookup(SYSCTLFN_CALL(&node)));
+ }
+
+ return 0;
+}
+
+SYSCTL_SETUP(sysctl_ktm_setup, "sysctl ktm subtree setup")
+{
+
+ sysctl_createv(NULL, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "machdep", NULL,
+ NULL, 0, NULL, 0,
+ CTL_MACHDEP, CTL_EOL);
+}