146283Sdfr/*	$NetBSD: adb.c,v 1.53 2009/11/01 01:51:35 snj Exp $	*/
246283Sdfr
398944Sobrien/*
498944Sobrien * Copyright (C) 1994	Bradley A. Grantham
546283Sdfr * All rights reserved.
698944Sobrien *
746283Sdfr * Redistribution and use in source and binary forms, with or without
898944Sobrien * modification, are permitted provided that the following conditions
998944Sobrien * are met:
1098944Sobrien * 1. Redistributions of source code must retain the above copyright
1198944Sobrien *    notice, this list of conditions and the following disclaimer.
1246283Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1398944Sobrien *    notice, this list of conditions and the following disclaimer in the
1498944Sobrien *    documentation and/or other materials provided with the distribution.
1598944Sobrien *
1698944Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1746283Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1898944Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1998944Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2098944Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2198944Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2298944Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2346283Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2446283Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2546283Sdfr * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2646283Sdfr */
2746283Sdfr
2846283Sdfr#include <sys/cdefs.h>
2946283Sdfr__KERNEL_RCSID(0, "$NetBSD: adb.c,v 1.53 2009/11/01 01:51:35 snj Exp $");
3046283Sdfr
3146283Sdfr#include "opt_adb.h"
3246283Sdfr
3346283Sdfr#include <sys/param.h>
3446283Sdfr#include <sys/device.h>
3546283Sdfr#include <sys/fcntl.h>
3698944Sobrien#include <sys/poll.h>
3798944Sobrien#include <sys/select.h>
3898944Sobrien#include <sys/proc.h>
3998944Sobrien#include <sys/signalvar.h>
4046283Sdfr#include <sys/systm.h>
4146283Sdfr#include <sys/cpu.h>
4246283Sdfr#include <sys/intr.h>
4346283Sdfr
4446283Sdfr#include <machine/autoconf.h>
4546283Sdfr
4646283Sdfr#include <mac68k/mac68k/macrom.h>
4746283Sdfr#include <mac68k/dev/adbvar.h>
4846283Sdfr#include <mac68k/dev/akbdvar.h>
4946283Sdfr
5046283Sdfr#include "aed.h"		/* ADB Event Device for compatibility */
5198944Sobrien
5246283Sdfr/*
5346283Sdfr * Function declarations.
5446283Sdfr */
5598944Sobrienstatic int	adbmatch(device_t, cfdata_t, void *);
5646283Sdfrstatic void	adbattach(device_t, device_t, void *);
5798944Sobrienstatic int	adbprint(void *, const char *);
5898944Sobrienvoid		adb_config_interrupts(device_t);
5998944Sobrien
6098944Sobrienextern void	adb_jadbproc(void);
6146283Sdfr
6298944Sobrien/*
6346283Sdfr * Global variables.
6498944Sobrien */
6546283Sdfrint	adb_polling = 0;	/* Are we polling?  (Debugger mode) */
6698944Sobrien#ifdef ADB_DEBUG
6798944Sobrienint	adb_debug = 0;		/* Output debugging messages */
6846283Sdfr#endif /* ADB_DEBUG */
6998944Sobrien
7046283Sdfrextern struct	mac68k_machine_S mac68k_machine;
7198944Sobrienextern int	adbHardware;
7246283Sdfrextern char	*adbHardwareDescr[];
7398944Sobrien
7446283Sdfr/*
7598944Sobrien * Driver definition.
7646283Sdfr */
7798944SobrienCFATTACH_DECL_NEW(adb, 0,
7846283Sdfr    adbmatch, adbattach, NULL, NULL);
7998944Sobrien
8046283Sdfrstatic int
8198944Sobrienadbmatch(device_t parent, cfdata_t cf, void *aux)
8246283Sdfr{
8398944Sobrien	static bool adb_matched;
8446283Sdfr
8598944Sobrien	/* Allow only one instance. */
8646283Sdfr	if (adb_matched)
8798944Sobrien		return (0);
8846283Sdfr
8998944Sobrien	adb_matched = true;
9046283Sdfr	return (1);
9146283Sdfr}
9246283Sdfr
9346283Sdfrstatic void
9446283Sdfradbattach(device_t parent, device_t self, void *aux)
9546283Sdfr{
9646283Sdfr
9746283Sdfr	adb_softintr_cookie = softint_establish(SOFTINT_SERIAL,
9846283Sdfr	    (void (*)(void *))adb_soft_intr, NULL);
9946283Sdfr	printf("\n");
10046283Sdfr
10146283Sdfr	/*
10246283Sdfr	 * Defer configuration until interrupts are enabled.
10398944Sobrien	 */
10498944Sobrien	config_interrupts(self, adb_config_interrupts);
10598944Sobrien}
10698944Sobrien
10798944Sobrienvoid
10898944Sobrienadb_config_interrupts(device_t self)
10998944Sobrien{
11098944Sobrien	ADBDataBlock adbdata;
11198944Sobrien	struct adb_attach_args aa_args;
11298944Sobrien	int totaladbs;
11398944Sobrien	int adbindex, adbaddr;
11498944Sobrien
11546283Sdfr	printf("%s", self->dv_xname);
11646283Sdfr	adb_polling = 1;
11798944Sobrien
11898944Sobrien#ifdef MRG_ADB
11998944Sobrien	if (!mrg_romready()) {
12098944Sobrien		printf(": no ROM ADB driver in this kernel for this machine\n");
12198944Sobrien		return;
12298944Sobrien	}
12398944Sobrien
12498944Sobrien#ifdef ADB_DEBUG
12546283Sdfr	if (adb_debug)
12646283Sdfr		printf("adb: call mrg_initadbintr\n");
12746283Sdfr#endif
128130803Smarcel
12998944Sobrien	mrg_initadbintr();	/* Mac ROM Glue okay to do ROM intr */
13046283Sdfr#ifdef ADB_DEBUG
13146283Sdfr	if (adb_debug)
13246283Sdfr		printf("adb: returned from mrg_initadbintr\n");
13346283Sdfr#endif
13446283Sdfr
135130803Smarcel	/* ADBReInit pre/post-processing */
13646283Sdfr	JADBProc = adb_jadbproc;
13746283Sdfr
13846283Sdfr	/* Initialize ADB */
13946283Sdfr#ifdef ADB_DEBUG
14046283Sdfr	if (adb_debug)
141130803Smarcel		printf("adb: calling ADBAlternateInit.\n");
14246283Sdfr#endif
14346283Sdfr
14446283Sdfr	printf(" (mrg)");
14546283Sdfr	ADBAlternateInit();
14646283Sdfr#else
14746283Sdfr	ADBReInit();
148130803Smarcel	printf(" (direct, %s)", adbHardwareDescr[adbHardware]);
14946283Sdfr#endif /* MRG_ADB */
15046283Sdfr
15146283Sdfr#ifdef ADB_DEBUG
15246283Sdfr	if (adb_debug)
15346283Sdfr		printf("adb: done with ADBReInit\n");
15446283Sdfr#endif
15598944Sobrien
15646283Sdfr	totaladbs = CountADBs();
15798944Sobrien
15898944Sobrien	printf(": %d target%s\n", totaladbs, (totaladbs == 1) ? "" : "s");
15998944Sobrien
16098944Sobrien#if NAED > 0
16198944Sobrien	/* ADB event device for compatibility */
16246283Sdfr	aa_args.origaddr = 0;
16346283Sdfr	aa_args.adbaddr = 0;
16446283Sdfr	aa_args.handler_id = 0;
16546283Sdfr	(void)config_found(self, &aa_args, adbprint);
16646283Sdfr#endif
167130803Smarcel
16846283Sdfr	/* for each ADB device */
16946283Sdfr	for (adbindex = 1; adbindex <= totaladbs; adbindex++) {
17046283Sdfr		/* Get the ADB information */
17146283Sdfr		adbaddr = GetIndADB(&adbdata, adbindex);
17246283Sdfr
17346283Sdfr		aa_args.origaddr = (int)(adbdata.origADBAddr);
17446283Sdfr		aa_args.adbaddr = adbaddr;
175130803Smarcel		aa_args.handler_id = (int)(adbdata.devType);
17698944Sobrien
17746283Sdfr		(void)config_found(self, &aa_args, adbprint);
17846283Sdfr	}
17946283Sdfr	adb_polling = 0;
18046283Sdfr}
181130803Smarcel
18246283Sdfr
18398944Sobrienint
18446283Sdfradbprint(void *args, const char *name)
18546283Sdfr{
18646283Sdfr	struct adb_attach_args *aa_args = (struct adb_attach_args *)args;
18746283Sdfr	int rv = UNCONF;
18846283Sdfr
18946283Sdfr	if (name) {	/* no configured device matched */
19046283Sdfr		rv = UNSUPP; /* most ADB device types are unsupported */
19146283Sdfr
19246283Sdfr		/* print out what kind of ADB device we have found */
19398944Sobrien		aprint_normal("%s addr %d: ", name, aa_args->adbaddr);
19446283Sdfr		switch(aa_args->origaddr) {
19546283Sdfr#ifdef DIAGNOSTIC
19646283Sdfr		case 0:
19798944Sobrien			aprint_normal("ADB event device");
19898944Sobrien			rv = UNCONF;
19998944Sobrien			break;
20046283Sdfr		case ADBADDR_SECURE:
20146283Sdfr			aprint_normal("security dongle (%d)",
20246283Sdfr			    aa_args->handler_id);
20346283Sdfr			break;
20446283Sdfr#endif
20598944Sobrien		case ADBADDR_MAP:
20698944Sobrien			aprint_normal("mapped device (%d)",
20798944Sobrien			    aa_args->handler_id);
20898944Sobrien			rv = UNCONF;
20998944Sobrien			break;
21098944Sobrien		case ADBADDR_REL:
21198944Sobrien			aprint_normal("relative positioning device (%d)",
21298944Sobrien			    aa_args->handler_id);
21398944Sobrien			rv = UNCONF;
21498944Sobrien			break;
21598944Sobrien#ifdef DIAGNOSTIC
21698944Sobrien		case ADBADDR_ABS:
21798944Sobrien			switch (aa_args->handler_id) {
21898944Sobrien			case ADB_ARTPAD:
21998944Sobrien				aprint_normal("WACOM ArtPad II");
22046283Sdfr				break;
22146283Sdfr			default:
22298944Sobrien				aprint_normal("absolute positioning device (%d)",
22398944Sobrien				    aa_args->handler_id);
22446283Sdfr				break;
22546283Sdfr			}
22646283Sdfr			break;
22746283Sdfr		case ADBADDR_DATATX:
22898944Sobrien			aprint_normal("data transfer device (modem?) (%d)",
22946283Sdfr			    aa_args->handler_id);
23046283Sdfr			break;
23146283Sdfr		case ADBADDR_MISC:
23246283Sdfr			switch (aa_args->handler_id) {
23346283Sdfr			case ADB_POWERKEY:
23446283Sdfr				aprint_normal("Sophisticated Circuits PowerKey");
23546283Sdfr				break;
23646283Sdfr			default:
23746283Sdfr				aprint_normal("misc. device (remote control?) (%d)",
23846283Sdfr				    aa_args->handler_id);
23946283Sdfr				break;
24046283Sdfr			}
24146283Sdfr			break;
24246283Sdfr		default:
24346283Sdfr			aprint_normal("unknown type device, (handler %d)",
24446283Sdfr			    aa_args->handler_id);
24546283Sdfr			break;
24698944Sobrien#endif /* DIAGNOSTIC */
247130803Smarcel		}
24846283Sdfr	} else		/* a device matched and was configured */
24946283Sdfr		aprint_normal(" addr %d: ", aa_args->adbaddr);
25098944Sobrien
25198944Sobrien	return (rv);
25246283Sdfr}
25346283Sdfr
25446283Sdfr
255130803Smarcel/*
25646283Sdfr * adb_op_sync
25746283Sdfr *
25846283Sdfr * This routine does exactly what the adb_op routine does, except that after
25946283Sdfr * the adb_op is called, it waits until the return value is present before
260130803Smarcel * returning.
26146283Sdfr *
26246283Sdfr * NOTE: The user specified compRout is ignored, since this routine specifies
26346283Sdfr * it's own to adb_op, which is why you really called this in the first place
26446283Sdfr * anyway.
265130803Smarcel */
26646283Sdfrint
26746283Sdfradb_op_sync(Ptr buffer, Ptr compRout, Ptr data, short command)
26846283Sdfr{
26946283Sdfr	int result;
270130803Smarcel	volatile int flag = 0;
27146283Sdfr
27246283Sdfr	result = ADBOp(buffer, (void *)adb_op_comprout, __UNVOLATILE(&flag),
27346283Sdfr	    command);	/* send command */
27446283Sdfr	if (result == 0) {		/* send ok? */
275130803Smarcel		adb_spin(&flag);
27646283Sdfr		if (!flag)
27746283Sdfr			result = -2;
27846283Sdfr	}
27946283Sdfr
28046283Sdfr	return result;
281130803Smarcel}
28246283Sdfr
28346283Sdfr/*
28446283Sdfr * adb_spin
28546283Sdfr *
28646283Sdfr * Implements a spin-wait with timeout to be used for synchronous
28746283Sdfr * operations on the ADB bus.
28846283Sdfr *
28946283Sdfr * Total time to wait is calculated as follows:
29046283Sdfr *  - Tlt (stop to start time): 260 usec
29146283Sdfr *  - start bit: 100 usec
292130803Smarcel *  - up to 8 data bytes: 64 * 100 usec = 6400 usec
29346283Sdfr *  - stop bit (with SRQ): 140 usec
29446283Sdfr * Total: 6900 usec
29546283Sdfr *
29646283Sdfr * This is the total time allowed by the specification.  Any device that
29798944Sobrien * doesn't conform to this will fail to operate properly on some Apple
29898944Sobrien * systems.  In spite of this we double the time to wait; Cuda-based
29946283Sdfr * systems apparently queue commands and allow the main CPU to continue
300130803Smarcel * processing (how radical!).  To be safe, allow time for two complete
30146283Sdfr * ADB transactions to occur.
30246283Sdfr */
30346283Sdfrvoid
30446283Sdfradb_spin(volatile int *fp)
30546283Sdfr{
30646283Sdfr	int tmout;
307130803Smarcel
30846283Sdfr	for (tmout = 13800; *fp == 0 && tmout >= 10; tmout -= 10)
30946283Sdfr		delay(10);
31046283Sdfr	if (*fp == 0 && tmout > 0)
31146283Sdfr		delay(tmout);
31246283Sdfr}
31346283Sdfr
31446283Sdfr
31546283Sdfr/*
31646283Sdfr * adb_op_comprout
31746283Sdfr *
31846283Sdfr * This function is used by the adb_op_sync routine so it knows when the
31998944Sobrien * function is done.
32046283Sdfr */
32146283Sdfrvoid
32246283Sdfradb_op_comprout(void)
32346283Sdfr{
32446283Sdfr	__asm("movw	#1,%a2@			| update flag value");
32598944Sobrien}
32646283Sdfr