svn commit: r184299 - in head/sys: conf dev/adb powerpc/conf powerpc/powermac

Nathan Whitehorn nwhitehorn at FreeBSD.org
Sun Oct 26 12:37:39 PDT 2008


Author: nwhitehorn
Date: Sun Oct 26 19:37:38 2008
New Revision: 184299
URL: http://svn.freebsd.org/changeset/base/184299

Log:
  Add ADB support. This provides support for the external ADB bus on the PowerMac
  G3 as well as the internal ADB keyboard and mice in PowerBooks and iBooks. This
  also brings in Mac GPIO support, for which we should eventually have a better
  interface.
  
  Obtained from:  NetBSD (CUDA and PMU drivers)

Added:
  head/sys/dev/adb/
  head/sys/dev/adb/adb.h   (contents, props changed)
  head/sys/dev/adb/adb_bus.c   (contents, props changed)
  head/sys/dev/adb/adb_hb_if.m   (contents, props changed)
  head/sys/dev/adb/adb_if.m   (contents, props changed)
  head/sys/dev/adb/adb_kbd.c   (contents, props changed)
  head/sys/dev/adb/adb_mouse.c   (contents, props changed)
  head/sys/dev/adb/adbvar.h   (contents, props changed)
  head/sys/powerpc/powermac/cuda.c   (contents, props changed)
  head/sys/powerpc/powermac/cudavar.h   (contents, props changed)
  head/sys/powerpc/powermac/macgpio.c   (contents, props changed)
  head/sys/powerpc/powermac/macgpiovar.h   (contents, props changed)
  head/sys/powerpc/powermac/pmu.c   (contents, props changed)
  head/sys/powerpc/powermac/pmuvar.h   (contents, props changed)
  head/sys/powerpc/powermac/viareg.h   (contents, props changed)
Modified:
  head/sys/conf/files.powerpc
  head/sys/powerpc/conf/GENERIC
  head/sys/powerpc/powermac/macio.c

Modified: head/sys/conf/files.powerpc
==============================================================================
--- head/sys/conf/files.powerpc	Sun Oct 26 19:33:22 2008	(r184298)
+++ head/sys/conf/files.powerpc	Sun Oct 26 19:37:38 2008	(r184299)
@@ -28,6 +28,11 @@ opt_ah.h			optional	ath_hal			\
 crypto/blowfish/bf_enc.c	optional	crypto | ipsec
 crypto/des/des_enc.c		optional	crypto | ipsec | netsmb
 dev/bm/if_bm.c			optional	bm powermac
+dev/adb/adb_bus.c		optional	adb
+dev/adb/adb_kbd.c		optional	adb
+dev/adb/adb_mouse.c		optional	adb
+dev/adb/adb_hb_if.m		optional	adb
+dev/adb/adb_if.m		optional	adb
 dev/cfi/cfi_bus_lbc.c		optional	cfi
 dev/fb/fb.c			optional	sc
 dev/hwpmc/hwpmc_powerpc.c	optional	hwpmc
@@ -119,6 +124,9 @@ powerpc/powermac/macio.c	optional	powerm
 powerpc/powermac/openpic_macio.c optional	powermac pci
 powerpc/powermac/pswitch.c	optional	powermac pswitch
 powerpc/powermac/uninorth.c	optional	powermac pci
+powerpc/powermac/cuda.c		optional	powermac cuda
+powerpc/powermac/pmu.c		optional	powermac pmu 
+powerpc/powermac/macgpio.c	optional	powermac pci 
 powerpc/powerpc/atomic.S	standard
 powerpc/powerpc/autoconf.c	standard
 powerpc/powerpc/bcopy.c		standard

Added: head/sys/dev/adb/adb.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/adb/adb.h	Sun Oct 26 19:37:38 2008	(r184299)
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (C) 2008 Nathan Whitehorn
+ * 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 AUTHOR ``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 TOOLS GMBH 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef	_POWERPC_ADB_H_
+#define	_POWERPC_ADB_H_
+
+#include "adb_hb_if.h"
+#include "adb_if.h"
+
+enum {
+	ADB_COMMAND_FLUSH	= 0,
+	ADB_COMMAND_LISTEN	= 2,
+	ADB_COMMAND_TALK	= 3,
+};
+
+enum {
+	ADB_DEVICE_DONGLE	= 0x01,
+	ADB_DEVICE_KEYBOARD	= 0x02,
+	ADB_DEVICE_MOUSE	= 0x03,
+	ADB_DEVICE_TABLET	= 0x04,
+	ADB_DEVICE_MODEM	= 0x05,
+	
+	ADB_DEVICE_MISC		= 0x07
+};
+
+struct adb_devinfo {
+	uint8_t address;
+	uint8_t default_address;
+	uint8_t handler_id;
+
+	uint16_t register3;
+};
+
+/* Pass packets down through the bus manager */
+u_int adb_send_packet(device_t dev, u_char command, u_char reg, int len, 
+    u_char *data);
+u_int adb_set_autopoll(device_t dev, u_char enable);
+
+/* Pass packets up from the interface */
+u_int adb_receive_raw_packet(device_t dev, u_char status, u_char command, 
+    int len, u_char *data);
+
+uint8_t adb_get_device_type(device_t dev);
+uint8_t adb_get_device_handler(device_t dev);
+uint8_t adb_set_device_handler(device_t dev, uint8_t newhandler);
+
+uint8_t adb_read_register(device_t dev, u_char reg, size_t *len, void *data);
+
+/* Bits for implementing ADB host bus adapters */
+extern devclass_t adb_devclass;
+extern driver_t adb_driver;
+
+#endif
+

Added: head/sys/dev/adb/adb_bus.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/adb/adb_bus.c	Sun Oct 26 19:37:38 2008	(r184299)
@@ -0,0 +1,384 @@
+/*-
+ * Copyright (C) 2008 Nathan Whitehorn
+ * 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 AUTHOR ``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 TOOLS GMBH 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+
+#include <machine/bus.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include "adb.h"
+#include "adbvar.h"
+
+static int adb_bus_probe(device_t dev);
+static int adb_bus_attach(device_t dev);
+static int adb_bus_detach(device_t dev);
+static void adb_probe_nomatch(device_t dev, device_t child);
+static int adb_print_child(device_t dev, device_t child);
+
+static int adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, uint8_t reg, int len, u_char *data);
+
+static char *adb_device_string[] = {
+	"HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc"
+};
+
+static device_method_t adb_bus_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		adb_bus_probe),
+	DEVMETHOD(device_attach,	adb_bus_attach),
+	DEVMETHOD(device_detach,        adb_bus_detach),
+        DEVMETHOD(device_shutdown,      bus_generic_shutdown),
+        DEVMETHOD(device_suspend,       bus_generic_suspend),
+        DEVMETHOD(device_resume,        bus_generic_resume),
+
+	/* Bus Interface */
+        DEVMETHOD(bus_probe_nomatch,    adb_probe_nomatch),
+        DEVMETHOD(bus_print_child,	adb_print_child),
+
+	{ 0, 0 },
+};
+
+driver_t adb_driver = {
+	"adb",
+	adb_bus_methods,
+	sizeof(struct adb_softc),
+};
+
+devclass_t adb_devclass;
+
+static int
+adb_bus_probe(device_t dev)
+{
+	device_set_desc(dev, "Apple Desktop Bus");
+	return (0);
+}
+
+static int
+adb_bus_attach(device_t dev)
+{
+	struct adb_softc *sc = device_get_softc(dev);
+	uint8_t i, next_free;
+	uint16_t r3;
+
+	sc->sc_dev = dev;
+	sc->parent = device_get_parent(dev);
+
+	sc->packet_reply = 0;
+	sc->autopoll_mask = 0;
+
+	mtx_init(&sc->sc_sync_mtx,"adbsyn",NULL,MTX_DEF | MTX_RECURSE);
+
+	/* Initialize devinfo */
+	for (i = 0; i < 16; i++) {
+		sc->devinfo[i].address = i;
+		sc->devinfo[i].default_address = 0;
+	}
+	
+	/* Reset ADB bus */
+	adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL);
+	DELAY(1500);
+
+	/* Enumerate bus */
+	next_free = 8;
+
+	for (i = 1; i < 7; i++) {
+	    int8_t first_relocated = -1;
+	    int reply = 0;
+
+	    do {
+		reply = adb_send_raw_packet_sync(dev,i,
+			    ADB_COMMAND_TALK,3,0,NULL);
+	
+		if (reply) {
+			/* If we got a response, relocate to next_free */
+			r3 = sc->devinfo[i].register3;
+			r3 &= 0xf000;
+			r3 |= ((uint16_t)(next_free) & 0x000f) << 8;
+			r3 |= 0x00fe;
+
+			adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3,
+			    sizeof(uint16_t),(u_char *)(&r3));
+
+			adb_send_raw_packet_sync(dev,next_free,
+			    ADB_COMMAND_TALK,3,0,NULL);
+
+			sc->devinfo[next_free].default_address = i;
+			if (first_relocated < 0)
+				first_relocated = next_free;
+
+			next_free++;
+		} else if (first_relocated > 0) {
+			/* Collisions removed, relocate first device back */
+
+			r3 = sc->devinfo[i].register3;
+			r3 &= 0xf000;
+			r3 |= ((uint16_t)(i) & 0x000f) << 8;
+			
+			adb_send_raw_packet_sync(dev,first_relocated,
+			    ADB_COMMAND_LISTEN,3,
+			    sizeof(uint16_t),(u_char *)(&r3));
+			adb_send_raw_packet_sync(dev,i,
+			    ADB_COMMAND_TALK,3,0,NULL);
+
+			sc->devinfo[i].default_address = i;
+			sc->devinfo[(int)(first_relocated)].default_address = 0;
+			break;
+		}
+	    } while (reply);
+	}
+
+	for (i = 0; i < 16; i++) {
+		if (sc->devinfo[i].default_address) {
+			sc->children[i] = device_add_child(dev, NULL, -1);
+			device_set_ivars(sc->children[i], &sc->devinfo[i]);
+		}
+	}
+
+	return (bus_generic_attach(dev));
+}
+
+static int adb_bus_detach(device_t dev)
+{
+	struct adb_softc *sc = device_get_softc(dev);
+
+	mtx_destroy(&sc->sc_sync_mtx);
+
+	return (bus_generic_detach(dev));
+}
+	
+
+static void
+adb_probe_nomatch(device_t dev, device_t child)
+{
+	struct adb_devinfo *dinfo;
+
+	if (bootverbose) {
+		dinfo = device_get_ivars(child);
+
+		device_printf(dev,"ADB %s at device %d (no driver attached)\n",
+		    adb_device_string[dinfo->default_address],dinfo->address);
+	}
+}
+
+u_int
+adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len, 
+    u_char *data) 
+{
+	struct adb_softc *sc = device_get_softc(dev);
+	u_char addr = command >> 4;
+
+	if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) {
+		memcpy(&sc->devinfo[addr].register3,data,2);
+		sc->devinfo[addr].handler_id = data[1];
+	}
+
+	if (sc->sync_packet == command)  {
+		memcpy(sc->syncreg,data,(len > 8) ? 8 : len);
+		atomic_store_rel_int(&sc->packet_reply,len + 1);
+	}
+
+	if (sc->children[addr] != NULL) {
+		ADB_RECEIVE_PACKET(sc->children[addr],status,
+			(command & 0x0f) >> 2,command & 0x03,len,data);
+	}
+	
+	return (0);
+}
+
+static int
+adb_print_child(device_t dev, device_t child)
+{
+	struct adb_devinfo *dinfo;
+	int retval = 0;
+	
+	dinfo = device_get_ivars(child);
+	
+	retval += bus_print_child_header(dev,child);
+	printf(" at device %d",dinfo->address);
+	retval += bus_print_child_footer(dev, child);
+
+	return (retval);
+}
+
+u_int 
+adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data)
+{
+	u_char command_byte = 0;
+	struct adb_devinfo *dinfo;
+	struct adb_softc *sc;
+
+	sc = device_get_softc(device_get_parent(dev));
+	dinfo = device_get_ivars(dev);
+	
+	command_byte |= dinfo->address << 4;
+	command_byte |= command << 2;
+	command_byte |= reg;
+
+	ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
+
+	return (0);
+}
+
+u_int
+adb_set_autopoll(device_t dev, u_char enable) 
+{
+	struct adb_devinfo *dinfo;
+	struct adb_softc *sc;
+	uint16_t mod = 0;
+
+	sc = device_get_softc(device_get_parent(dev));
+	dinfo = device_get_ivars(dev);
+	
+	mod = enable << dinfo->address;
+	if (enable) {
+		sc->autopoll_mask |= mod;
+	} else {
+		mod = ~mod;
+		sc->autopoll_mask &= mod;
+	}
+
+	ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask);
+
+	return (0);
+}
+
+uint8_t 
+adb_get_device_type(device_t dev) 
+{
+	struct adb_devinfo *dinfo;
+
+	dinfo = device_get_ivars(dev);
+	return (dinfo->default_address);
+}
+
+uint8_t 
+adb_get_device_handler(device_t dev) 
+{
+	struct adb_devinfo *dinfo;
+
+	dinfo = device_get_ivars(dev);
+	return (dinfo->handler_id);
+}
+
+static int 
+adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, 
+    uint8_t reg, int len, u_char *data) 
+{
+	u_char command_byte = 0;
+	struct adb_softc *sc;
+	int result = -1;
+	int i = 0;
+
+	sc = device_get_softc(dev);
+	
+	command_byte |= to << 4;
+	command_byte |= command << 2;
+	command_byte |= reg;
+
+	/* Wait if someone else has a synchronous request pending */
+	mtx_lock(&sc->sc_sync_mtx);
+
+	sc->packet_reply = 0;
+	sc->sync_packet = command_byte;
+
+	ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
+
+	while (!atomic_fetchadd_int(&sc->packet_reply,0)) {
+		/* Sometimes CUDA controllers hang up during cold boots.
+		   Try poking them. */
+		if (i > 10)
+			ADB_HB_CONTROLLER_POLL(sc->parent);
+
+		DELAY(100);
+		i++;
+	}
+
+	result = sc->packet_reply - 1;
+
+	/* Clear packet sync */
+	sc->packet_reply = 0;
+	sc->sync_packet = 0xffff; /* We can't match a 16 bit value */
+
+	mtx_unlock(&sc->sc_sync_mtx);
+
+	return (result);
+}
+
+uint8_t 
+adb_set_device_handler(device_t dev, uint8_t newhandler) 
+{
+	struct adb_softc *sc;
+	struct adb_devinfo *dinfo;
+	uint16_t newr3;
+
+	dinfo = device_get_ivars(dev);
+	sc = device_get_softc(device_get_parent(dev));
+
+	newr3 = dinfo->register3 & 0xff00;
+	newr3 |= (uint16_t)(newhandler);
+
+	adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 
+	    ADB_COMMAND_LISTEN, 3, sizeof(uint16_t), (u_char *)(&newr3));
+	adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 
+	    ADB_COMMAND_TALK, 3, 0, NULL);
+
+	return (dinfo->handler_id);
+}
+
+uint8_t 
+adb_read_register(device_t dev, u_char reg, 
+    size_t *len, void *data) 
+{
+	struct adb_softc *sc;
+	struct adb_devinfo *dinfo;
+	size_t orig_len;
+
+	dinfo = device_get_ivars(dev);
+	sc = device_get_softc(device_get_parent(dev));
+
+	orig_len = *len;
+
+	mtx_lock(&sc->sc_sync_mtx);
+	
+	*len = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
+	           ADB_COMMAND_TALK, reg, 0, NULL);
+
+	if (*len > 0)
+		memcpy(data,sc->syncreg,*len);
+
+	mtx_unlock(&sc->sc_sync_mtx);
+
+	return ((*len > 0) ? 0 : -1);
+}
+

Added: head/sys/dev/adb/adb_hb_if.m
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/adb/adb_hb_if.m	Sun Oct 26 19:37:38 2008	(r184299)
@@ -0,0 +1,58 @@
+#-
+# Copyright (c) 2008 Nathan Whitehorn
+# 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 AUTHOR 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 AUTHOR 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.
+#
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+
+#include <dev/adb/adb.h>
+
+INTERFACE adb_hb;
+
+#
+# Bus level operations. These are used by the ADB bus manager, and are
+# required to inplement an ADB interface.
+#
+
+METHOD u_int send_raw_packet {
+	device_t dev;
+	u_char command_byte;
+
+	int len;
+	u_char *data;
+	u_char poll;
+};
+
+METHOD u_int controller_poll {
+	device_t dev;
+};
+
+METHOD u_int set_autopoll_mask {
+	device_t dev;
+
+	uint16_t mask;
+};
+

Added: head/sys/dev/adb/adb_if.m
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/adb/adb_if.m	Sun Oct 26 19:37:38 2008	(r184299)
@@ -0,0 +1,49 @@
+#-
+# Copyright (c) 2008 Nathan Whitehorn
+# 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 AUTHOR 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 AUTHOR 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.
+#
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+
+#include <dev/adb/adb.h>
+
+INTERFACE adb;
+
+#
+# Driver level operations
+#
+
+METHOD u_int receive_packet {
+	device_t dev;
+
+	u_char status;
+	u_char command;
+	u_char reg;
+
+	int len;
+	u_char *data;
+};
+

Added: head/sys/dev/adb/adb_kbd.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/adb/adb_kbd.c	Sun Oct 26 19:37:38 2008	(r184299)
@@ -0,0 +1,692 @@
+/*-
+ * Copyright (C) 2008 Nathan Whitehorn
+ * 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 AUTHOR ``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 TOOLS GMBH 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kbio.h>
+#include <sys/condvar.h>
+#include <sys/callout.h>
+#include <sys/kernel.h>
+
+#include <machine/bus.h>
+
+#include "opt_kbd.h"
+#include <dev/kbd/kbdreg.h>
+#include <dev/kbd/kbdtables.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include "adb.h"
+
+#define KBD_DRIVER_NAME "akbd"
+
+#define AKBD_EMULATE_ATKBD 1
+
+static int adb_kbd_probe(device_t dev);
+static int adb_kbd_attach(device_t dev);
+static int adb_kbd_detach(device_t dev);
+static void akbd_repeat(void *xsc);
+
+static u_int adb_kbd_receive_packet(device_t dev, u_char status, 
+	u_char command, u_char reg, int len, u_char *data);
+
+struct adb_kbd_softc {
+	keyboard_t sc_kbd;
+
+	device_t sc_dev;
+	struct mtx sc_mutex;
+	struct cv  sc_cv;
+
+	int sc_mode;
+	int sc_state;
+
+	int have_led_control;
+
+	uint8_t buffer[8];
+	volatile int buffers;
+
+	struct callout sc_repeater;
+	int sc_repeatstart;
+	int sc_repeatcontinue;
+	uint8_t last_press;
+};
+
+static device_method_t adb_kbd_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,         adb_kbd_probe),
+        DEVMETHOD(device_attach,        adb_kbd_attach),
+        DEVMETHOD(device_detach,        adb_kbd_detach),
+        DEVMETHOD(device_shutdown,      bus_generic_shutdown),
+        DEVMETHOD(device_suspend,       bus_generic_suspend),
+        DEVMETHOD(device_resume,        bus_generic_resume),
+
+	/* ADB interface */
+	DEVMETHOD(adb_receive_packet,	adb_kbd_receive_packet),
+
+	{ 0, 0 }
+};
+
+static driver_t adb_kbd_driver = {
+	"akbd",
+	adb_kbd_methods,
+	sizeof(struct adb_kbd_softc),
+};
+
+static devclass_t adb_kbd_devclass;
+
+DRIVER_MODULE(akbd, adb, adb_kbd_driver, adb_kbd_devclass, 0, 0);
+
+static const uint8_t adb_to_at_scancode_map[128] = { 30, 31, 32, 33, 35, 34, 
+	44, 45, 46, 47, 0, 48, 16, 17, 18, 19, 21, 20, 2, 3, 4, 5, 7, 6, 13, 
+	10, 8, 12, 9, 11, 27, 24, 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43, 
+	51, 53, 49, 50, 52, 15, 57, 41, 14, 0, 1, 29, 0, 42, 58, 56, 97, 98, 
+	100, 95, 0, 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 91, 89, 0, 74, 13, 0, 
+	0, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73, 0, 0, 0, 63, 64, 65, 61, 
+	66, 67, 0, 87, 0, 105, 0, 70, 0, 68, 0, 88, 0, 107, 102, 94, 96, 103, 
+	62, 99, 60, 101, 59, 54, 93, 90, 0, 0 };
+
+/* keyboard driver declaration */
+static int              akbd_configure(int flags);
+static kbd_probe_t      akbd_probe;
+static kbd_init_t       akbd_init;
+static kbd_term_t       akbd_term;
+static kbd_intr_t       akbd_interrupt;
+static kbd_test_if_t    akbd_test_if;
+static kbd_enable_t     akbd_enable;
+static kbd_disable_t    akbd_disable;
+static kbd_read_t       akbd_read;
+static kbd_check_t      akbd_check;
+static kbd_read_char_t  akbd_read_char;
+static kbd_check_char_t akbd_check_char;
+static kbd_ioctl_t      akbd_ioctl;
+static kbd_lock_t       akbd_lock;
+static kbd_clear_state_t akbd_clear_state;
+static kbd_get_state_t  akbd_get_state;
+static kbd_set_state_t  akbd_set_state;
+static kbd_poll_mode_t  akbd_poll;
+
+keyboard_switch_t akbdsw = {
+        akbd_probe,
+        akbd_init,
+        akbd_term,
+        akbd_interrupt,
+        akbd_test_if,
+        akbd_enable,
+        akbd_disable,
+        akbd_read,
+        akbd_check,
+        akbd_read_char,
+        akbd_check_char,
+        akbd_ioctl,
+        akbd_lock,
+        akbd_clear_state,
+        akbd_get_state,
+        akbd_set_state,
+        genkbd_get_fkeystr,
+        akbd_poll,
+        genkbd_diag,
+};
+
+KEYBOARD_DRIVER(akbd, akbdsw, akbd_configure);
+
+static int 
+adb_kbd_probe(device_t dev) 
+{
+	uint8_t type;
+
+	type = adb_get_device_type(dev);
+
+	if (type != ADB_DEVICE_KEYBOARD)
+		return (ENXIO);
+
+	switch(adb_get_device_handler(dev)) {
+	case 1:
+		device_set_desc(dev,"Apple Standard Keyboard");
+		break;
+	case 2:
+		device_set_desc(dev,"Apple Extended Keyboard");
+		break;
+	case 4:
+		device_set_desc(dev,"Apple ISO Keyboard");
+		break;
+	case 5:
+		device_set_desc(dev,"Apple Extended ISO Keyboard");
+		break;
+	case 8:
+		device_set_desc(dev,"Apple Keyboard II");
+		break;
+	case 9:
+		device_set_desc(dev,"Apple ISO Keyboard II");
+		break;
+	case 12:
+		device_set_desc(dev,"PowerBook Keyboard");
+		break;
+	case 13:
+		device_set_desc(dev,"PowerBook ISO Keyboard");
+		break;
+	case 24:
+		device_set_desc(dev,"PowerBook Extended Keyboard");
+		break;
+	case 27:
+		device_set_desc(dev,"Apple Design Keyboard");
+		break;
+	case 195:
+		device_set_desc(dev,"PowerBook G3 Keyboard");
+		break;
+	case 196:
+		device_set_desc(dev,"iBook Keyboard");
+		break;
+	default:
+		device_set_desc(dev,"ADB Keyboard");
+		break;
+	}
+
+	return (0);
+}
+
+static int
+ms_to_ticks(int ms)
+{
+	if (hz > 1000)
+		return ms*(hz/1000);
+
+	return ms/(1000/hz);
+}
+	
+static int 
+adb_kbd_attach(device_t dev) 
+{
+	struct adb_kbd_softc *sc;
+	keyboard_switch_t *sw;
+
+	sw = kbd_get_switch(KBD_DRIVER_NAME);
+	if (sw == NULL) {
+		return ENXIO;
+	}
+
+	sc = device_get_softc(dev);
+	sc->sc_dev = dev;
+	sc->sc_mode = K_RAW;
+	sc->sc_state = 0;
+	sc->have_led_control = 0;
+	sc->buffers = 0;
+
+	/* Try stepping forward to the extended keyboard protocol */
+	adb_set_device_handler(dev,3);
+
+	mtx_init(&sc->sc_mutex,KBD_DRIVER_NAME,MTX_DEF,0);
+	cv_init(&sc->sc_cv,KBD_DRIVER_NAME);
+	callout_init(&sc->sc_repeater, 0);
+
+#ifdef AKBD_EMULATE_ATKBD
+	kbd_init_struct(&sc->sc_kbd, KBD_DRIVER_NAME, KB_101, 0, 0, 0, 0);
+	kbd_set_maps(&sc->sc_kbd, &key_map, &accent_map, fkey_tab,
+            sizeof(fkey_tab) / sizeof(fkey_tab[0]));
+#else
+	#error ADB raw mode not implemented
+#endif
+
+	KBD_FOUND_DEVICE(&sc->sc_kbd);
+	KBD_PROBE_DONE(&sc->sc_kbd);
+	KBD_INIT_DONE(&sc->sc_kbd);
+	KBD_CONFIG_DONE(&sc->sc_kbd);
+
+	(*sw->enable)(&sc->sc_kbd);
+
+	kbd_register(&sc->sc_kbd);
+
+#ifdef KBD_INSTALL_CDEV
+	if (kbd_attach(&sc->sc_kbd)) {
+		adb_kbd_detach(dev);
+		return ENXIO;
+	}
+#endif
+
+	adb_set_autopoll(dev,1);
+
+	/* Check (asynchronously) if we can read out the LED state from 
+	   this keyboard by reading the key state register */
+	adb_send_packet(dev,ADB_COMMAND_TALK,2,0,NULL);
+
+	return (0);
+}
+
+static int 
+adb_kbd_detach(device_t dev) 
+{
+	struct adb_kbd_softc *sc;
+	keyboard_t *kbd;
+
+	sc = device_get_softc(dev);
+
+	adb_set_autopoll(dev,0);
+	callout_stop(&sc->sc_repeater);
+
+	mtx_lock(&sc->sc_mutex);
+
+	kbd = kbd_get_keyboard(kbd_find_keyboard(KBD_DRIVER_NAME,
+	          device_get_unit(dev)));
+
+	kbdd_disable(kbd);
+
+#ifdef KBD_INSTALL_CDEV
+	kbd_detach(kbd);
+#endif
+
+	kbdd_term(kbd);
+
+	mtx_unlock(&sc->sc_mutex);
+
+	mtx_destroy(&sc->sc_mutex);
+	cv_destroy(&sc->sc_cv);
+
+	return (0);
+}
+
+static u_int 
+adb_kbd_receive_packet(device_t dev, u_char status, 
+    u_char command, u_char reg, int len, u_char *data)
+{
+	struct adb_kbd_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (command != ADB_COMMAND_TALK)
+		return 0;
+
+	if (reg == 2 && len == 2) {
+		sc->have_led_control = 1;
+		return 0;
+	}
+
+	if (reg != 0 || len != 2)
+		return (0);
+
+	mtx_lock(&sc->sc_mutex);
+		if ((data[0] & 0x7f) == 57 && sc->buffers < 7) {
+			/* Fake the down/up cycle for caps lock */
+			sc->buffer[sc->buffers++] = data[0] & 0x7f;
+			sc->buffer[sc->buffers++] = (data[0] & 0x7f) | (1 << 7);
+		} else {
+			sc->buffer[sc->buffers++] = data[0];
+		}
+
+		if (sc->buffer[sc->buffers-1] < 0xff)
+			sc->last_press = sc->buffer[sc->buffers-1];
+
+		if ((data[1] & 0x7f) == 57 && sc->buffers < 7) {
+			/* Fake the down/up cycle for caps lock */
+			sc->buffer[sc->buffers++] = data[1] & 0x7f;
+			sc->buffer[sc->buffers++] = (data[1] & 0x7f) | (1 << 7);
+		} else {
+			sc->buffer[sc->buffers++] = data[1];
+		}
+
+		if (sc->buffer[sc->buffers-1] < 0xff)
+			sc->last_press = sc->buffer[sc->buffers-1];
+
+		/* Stop any existing key repeating */
+		callout_stop(&sc->sc_repeater);
+
+		/* Schedule a repeat callback on keydown */
+		if (!(sc->last_press & (1 << 7))) {
+			callout_reset(&sc->sc_repeater, 
+			    ms_to_ticks(sc->sc_kbd.kb_delay1), akbd_repeat, sc);
+		}
+	mtx_unlock(&sc->sc_mutex);
+
+	cv_broadcast(&sc->sc_cv);
+
+	if (KBD_IS_ACTIVE(&sc->sc_kbd) && KBD_IS_BUSY(&sc->sc_kbd)) {
+		sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd,
+			 KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg);
+	}
+
+	return (0);
+}
+
+static void
+akbd_repeat(void *xsc) {
+	struct adb_kbd_softc *sc = xsc;
+	int notify_kbd = 0;
+
+	/* Fake an up/down key repeat so long as we have the
+	   free buffers */
+	mtx_lock(&sc->sc_mutex);
+		if (sc->buffers < 7) {
+			sc->buffer[sc->buffers++] = sc->last_press | (1 << 7);
+			sc->buffer[sc->buffers++] = sc->last_press;
+
+			notify_kbd = 1;
+		}
+	mtx_unlock(&sc->sc_mutex);
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list