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 = &reg;
+		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 = &reg;
+		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 = &reg;
+		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 = &reg;
+		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);
+}

Reply via email to