xref: /openbsd-src/sys/arch/macppc/dev/adb.c (revision 36dba039b91cf453f3b66c370c50b00c9aa5378e)
1*36dba039Sjsg /*	$OpenBSD: adb.c,v 1.52 2024/04/14 03:26:25 jsg Exp $	*/
2d9a5f17fSdrahn /*	$NetBSD: adb.c,v 1.6 1999/08/16 06:28:09 tsubai Exp $	*/
3305d9e87Smiod /*	$NetBSD: adb_direct.c,v 1.14 2000/06/08 22:10:45 tsubai Exp $	*/
4305d9e87Smiod 
5305d9e87Smiod /*
6305d9e87Smiod  * Copyright (C) 1996, 1997 John P. Wittkoski
7305d9e87Smiod  * All rights reserved.
8305d9e87Smiod  *
9305d9e87Smiod  * Redistribution and use in source and binary forms, with or without
10305d9e87Smiod  * modification, are permitted provided that the following conditions
11305d9e87Smiod  * are met:
12305d9e87Smiod  * 1. Redistributions of source code must retain the above copyright
13305d9e87Smiod  *    notice, this list of conditions and the following disclaimer.
14305d9e87Smiod  * 2. Redistributions in binary form must reproduce the above copyright
15305d9e87Smiod  *    notice, this list of conditions and the following disclaimer in the
16305d9e87Smiod  *    documentation and/or other materials provided with the distribution.
17305d9e87Smiod  * 3. All advertising materials mentioning features or use of this software
18305d9e87Smiod  *    must display the following acknowledgement:
19305d9e87Smiod  *  This product includes software developed by John P. Wittkoski.
20305d9e87Smiod  * 4. The name of the author may not be used to endorse or promote products
21305d9e87Smiod  *    derived from this software without specific prior written permission.
22305d9e87Smiod  *
23305d9e87Smiod  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24305d9e87Smiod  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25305d9e87Smiod  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26305d9e87Smiod  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27305d9e87Smiod  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28305d9e87Smiod  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29305d9e87Smiod  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30305d9e87Smiod  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31305d9e87Smiod  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32305d9e87Smiod  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33305d9e87Smiod  */
34d9a5f17fSdrahn 
35d9a5f17fSdrahn /*-
36d9a5f17fSdrahn  * Copyright (C) 1994	Bradley A. Grantham
37d9a5f17fSdrahn  * All rights reserved.
38d9a5f17fSdrahn  *
39d9a5f17fSdrahn  * Redistribution and use in source and binary forms, with or without
40d9a5f17fSdrahn  * modification, are permitted provided that the following conditions
41d9a5f17fSdrahn  * are met:
42d9a5f17fSdrahn  * 1. Redistributions of source code must retain the above copyright
43d9a5f17fSdrahn  *    notice, this list of conditions and the following disclaimer.
44d9a5f17fSdrahn  * 2. Redistributions in binary form must reproduce the above copyright
45d9a5f17fSdrahn  *    notice, this list of conditions and the following disclaimer in the
46d9a5f17fSdrahn  *    documentation and/or other materials provided with the distribution.
47d9a5f17fSdrahn  *
48d9a5f17fSdrahn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
49d9a5f17fSdrahn  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50d9a5f17fSdrahn  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
51d9a5f17fSdrahn  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
52d9a5f17fSdrahn  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
53d9a5f17fSdrahn  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
54d9a5f17fSdrahn  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
55d9a5f17fSdrahn  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56d9a5f17fSdrahn  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
57d9a5f17fSdrahn  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58d9a5f17fSdrahn  */
59d9a5f17fSdrahn 
60305d9e87Smiod /*
61305d9e87Smiod  * This code is rather messy, but I don't have time right now
62305d9e87Smiod  * to clean it up as much as I would like.
63305d9e87Smiod  * But it works, so I'm happy. :-) jpw
64305d9e87Smiod  */
65305d9e87Smiod 
66305d9e87Smiod /*
67305d9e87Smiod  * TO DO:
68305d9e87Smiod  *  - We could reduce the time spent in the adb_intr_* routines
69305d9e87Smiod  *    by having them save the incoming and outgoing data directly
70305d9e87Smiod  *    in the adbInbound and adbOutbound queues, as it would reduce
71305d9e87Smiod  *    the number of times we need to copy the data around. It
72305d9e87Smiod  *    would also make the code more readable and easier to follow.
73305d9e87Smiod  *  - (Related to above) Use the header part of adbCommand to
74305d9e87Smiod  *    reduce the number of copies we have to do of the data.
75305d9e87Smiod  *  - (Related to above) Actually implement the adbOutbound queue.
76305d9e87Smiod  *    This is fairly easy once you switch all the intr routines
77305d9e87Smiod  *    over to using adbCommand structs directly.
78305d9e87Smiod  *  - There is a bug in the state machine of adb_intr_cuda
79305d9e87Smiod  *    code that causes hangs, especially on 030 machines, probably
80305d9e87Smiod  *    because of some timing issues. Because I have been unable to
81305d9e87Smiod  *    determine the exact cause of this bug, I used the timeout function
82305d9e87Smiod  *    to check for and recover from this condition. If anyone finds
83305d9e87Smiod  *    the actual cause of this bug, the calls to timeout and the
84305d9e87Smiod  *    adb_cuda_tickle routine can be removed.
85305d9e87Smiod  */
86305d9e87Smiod 
87d9a5f17fSdrahn #include <sys/param.h>
88d9a5f17fSdrahn #include <sys/device.h>
89d9a5f17fSdrahn #include <sys/fcntl.h>
90d9a5f17fSdrahn #include <sys/proc.h>
91d9a5f17fSdrahn #include <sys/signalvar.h>
92c1cc27a7Sgkoehler #include <sys/task.h>
93305d9e87Smiod #include <sys/timeout.h>
94d9a5f17fSdrahn #include <sys/systm.h>
95d9a5f17fSdrahn 
96d9a5f17fSdrahn #include <machine/autoconf.h>
97305d9e87Smiod #include <machine/cpu.h>
98d01ed945Skettenis #include <dev/ofw/openfirm.h>
996784ab1fStobhe #include <dev/wscons/wsconsio.h>
100d9a5f17fSdrahn 
101305d9e87Smiod #include <dev/adb/adb.h>
10278a7e9fcSdrahn #include <macppc/dev/adbvar.h>
103305d9e87Smiod #include <macppc/dev/pm_direct.h>
10478a7e9fcSdrahn #include <macppc/dev/viareg.h>
105d9a5f17fSdrahn 
106d9076e62Sdrahn #include "apm.h"
107d9a5f17fSdrahn 
108305d9e87Smiod #define printf_intr printf
109d9a5f17fSdrahn 
110305d9e87Smiod #ifdef DEBUG
111305d9e87Smiod #ifndef ADB_DEBUG
112305d9e87Smiod #define ADB_DEBUG
113305d9e87Smiod #endif
114305d9e87Smiod #endif
115305d9e87Smiod 
116d80b8bf7Smiod int	adb_polling;		/* Are we polling?  (Debugger mode) */
117d9a5f17fSdrahn #ifdef ADB_DEBUG
118d80b8bf7Smiod int	adb_debug;		/* Output debugging messages */
119d9a5f17fSdrahn #endif /* ADB_DEBUG */
120d9a5f17fSdrahn 
121305d9e87Smiod /* some misc. leftovers */
122305d9e87Smiod #define vPB		0x0000
123305d9e87Smiod #define vPB3		0x08
124305d9e87Smiod #define vPB4		0x10
125305d9e87Smiod #define vPB5		0x20
126305d9e87Smiod #define vSR_INT		0x04
127305d9e87Smiod #define vSR_OUT		0x10
128305d9e87Smiod 
129305d9e87Smiod /* the type of ADB action that we are currently performing */
130305d9e87Smiod #define ADB_ACTION_NOTREADY	0x1	/* has not been initialized yet */
131305d9e87Smiod #define ADB_ACTION_IDLE		0x2	/* the bus is currently idle */
132305d9e87Smiod #define ADB_ACTION_OUT		0x3	/* sending out a command */
133305d9e87Smiod #define ADB_ACTION_IN		0x4	/* receiving data */
134305d9e87Smiod 
135305d9e87Smiod /*
136305d9e87Smiod  * Shortcuts for setting or testing the VIA bit states.
137305d9e87Smiod  * Not all shortcuts are used for every type of ADB hardware.
138305d9e87Smiod  */
139305d9e87Smiod #define ADB_SET_STATE_IDLE_CUDA()   via_reg_or(VIA1, vBufB, (vPB4 | vPB5))
140305d9e87Smiod #define ADB_SET_STATE_TIP()	    via_reg_and(VIA1, vBufB, ~vPB5)
141305d9e87Smiod #define ADB_CLR_STATE_TIP() 	    via_reg_or(VIA1, vBufB, vPB5)
142305d9e87Smiod #define ADB_TOGGLE_STATE_ACK_CUDA() via_reg_xor(VIA1, vBufB, vPB4)
143305d9e87Smiod #define ADB_SET_STATE_ACKOFF_CUDA() via_reg_or(VIA1, vBufB, vPB4)
144305d9e87Smiod #define ADB_SET_SR_INPUT()	    via_reg_and(VIA1, vACR, ~vSR_OUT)
145305d9e87Smiod #define ADB_SET_SR_OUTPUT()	    via_reg_or(VIA1, vACR, vSR_OUT)
146305d9e87Smiod #define ADB_SR()		    read_via_reg(VIA1, vSR)
147305d9e87Smiod #define ADB_VIA_INTR_ENABLE()	    write_via_reg(VIA1, vIER, 0x84)
148305d9e87Smiod #define ADB_VIA_INTR_DISABLE()	    write_via_reg(VIA1, vIER, 0x04)
149305d9e87Smiod #define ADB_VIA_CLR_INTR()	    write_via_reg(VIA1, vIFR, 0x04)
150305d9e87Smiod #define ADB_INTR_IS_OFF		   (vPB3 == (read_via_reg(VIA1, vBufB) & vPB3))
151305d9e87Smiod #define ADB_INTR_IS_ON		   (0 == (read_via_reg(VIA1, vBufB) & vPB3))
152305d9e87Smiod #define ADB_SR_INTR_IS_ON	   (vSR_INT == (read_via_reg(VIA1, \
153305d9e87Smiod 						vIFR) & vSR_INT))
154305d9e87Smiod 
155305d9e87Smiod /*
156305d9e87Smiod  * This is the delay that is required (in uS) between certain
157b3af768dSjsg  * ADB transactions. The actual timing delay for each uS is
158305d9e87Smiod  * calculated at boot time to account for differences in machine speed.
159305d9e87Smiod  */
160305d9e87Smiod #define ADB_DELAY	150
161305d9e87Smiod 
162305d9e87Smiod /*
163305d9e87Smiod  * Maximum ADB message length; includes space for data, result, and
164305d9e87Smiod  * device code - plus a little for safety.
165305d9e87Smiod  */
166305d9e87Smiod #define ADB_MAX_MSG_LENGTH	16
167305d9e87Smiod #define ADB_MAX_HDR_LENGTH	8
168305d9e87Smiod 
169305d9e87Smiod #define ADB_QUEUE		32
170305d9e87Smiod #define ADB_TICKLE_TICKS	4
171305d9e87Smiod 
172305d9e87Smiod /*
173305d9e87Smiod  * Eventually used for two separate queues, the queue between
174305d9e87Smiod  * the upper and lower halves, and the outgoing packet queue.
175305d9e87Smiod  */
176305d9e87Smiod struct adbCommand {
177305d9e87Smiod 	u_char	header[ADB_MAX_HDR_LENGTH];	/* not used yet */
178305d9e87Smiod 	u_char	data[ADB_MAX_MSG_LENGTH];	/* packet data only */
179305d9e87Smiod 	u_char	*saveBuf;	/* where to save result */
180305d9e87Smiod 	u_char	*compRout;	/* completion routine pointer */
181305d9e87Smiod 	u_char	*compData;	/* completion routine data pointer */
182305d9e87Smiod 	u_int	cmd;		/* the original command for this data */
183305d9e87Smiod 	u_int	unsol;		/* 1 if packet was unsolicited */
184305d9e87Smiod 	u_int	ack_only;	/* 1 for no special processing */
185305d9e87Smiod };
186305d9e87Smiod 
187305d9e87Smiod /*
188305d9e87Smiod  * A few variables that we need and their initial values.
189305d9e87Smiod  */
190305d9e87Smiod int	adbHardware = ADB_HW_UNKNOWN;
191305d9e87Smiod int	adbActionState = ADB_ACTION_NOTREADY;
19274a0040aSmiod int	adbWaiting;		/* waiting for return data from the device */
19374a0040aSmiod int	adbWriteDelay;		/* working on (or waiting to do) a write */
194305d9e87Smiod 
19574a0040aSmiod int	adbWaitingCmd;		/* ADB command we are waiting for */
19674a0040aSmiod u_char	*adbBuffer;		/* pointer to user data area */
19774a0040aSmiod void	*adbCompRout;		/* pointer to the completion routine */
19874a0040aSmiod void	*adbCompData;		/* pointer to the completion routine data */
199305d9e87Smiod int	adbStarting = 1;	/* doing adb_reinit so do polling differently */
200305d9e87Smiod 
201305d9e87Smiod u_char	adbInputBuffer[ADB_MAX_MSG_LENGTH];	/* data input buffer */
202305d9e87Smiod u_char	adbOutputBuffer[ADB_MAX_MSG_LENGTH];	/* data output buffer */
203305d9e87Smiod 
20474a0040aSmiod int	adbSentChars;		/* how many characters we have sent */
205305d9e87Smiod 
206305d9e87Smiod struct	adbCommand adbInbound[ADB_QUEUE];	/* incoming queue */
207b3af768dSjsg int	adbInCount;			/* how many packets in queue */
20874a0040aSmiod int	adbInHead;			/* head of in queue */
20974a0040aSmiod int	adbInTail;			/* tail of in queue */
210305d9e87Smiod 
21174a0040aSmiod int	tickle_count;			/* how many tickles seen for this packet? */
21274a0040aSmiod int	tickle_serial;			/* the last packet tickled */
21374a0040aSmiod int	adb_cuda_serial;		/* the current packet */
214305d9e87Smiod struct	timeout adb_cuda_timeout;
215305d9e87Smiod struct	timeout adb_softintr_timeout;
21674a0040aSmiod int	adbempty;			/* nonzero if no adb devices */
217305d9e87Smiod 
2185e53181fSmpi extern struct cfdriver adb_cd;
2195e53181fSmpi 
220305d9e87Smiod volatile u_char *Via1Base;
221305d9e87Smiod 
222305d9e87Smiod /*
223305d9e87Smiod  * The following are private routines.
224305d9e87Smiod  */
225305d9e87Smiod #ifdef ADB_DEBUG
226305d9e87Smiod void	print_single(u_char *);
227305d9e87Smiod #endif
228305d9e87Smiod void	adb_intr_cuda(void);
229305d9e87Smiod void	adb_soft_intr(void);
230305d9e87Smiod int	send_adb_cuda(u_char *, u_char *, void *, void *, int);
231a7265231Scheloha void	adb_cuda_tickle(void *);
232305d9e87Smiod void	adb_pass_up(struct adbCommand *);
233305d9e87Smiod void	adb_op_comprout(caddr_t, caddr_t, int);
2345e53181fSmpi void	adb_reinit(struct adb_softc *);
2355e53181fSmpi int	count_adbs(struct adb_softc *);
2365e53181fSmpi int	get_ind_adb_info(struct adb_softc *, ADBDataBlock *, int);
237305d9e87Smiod int	get_adb_info(ADBDataBlock *, int);
238305d9e87Smiod int	adb_op(Ptr, Ptr, Ptr, short);
239305d9e87Smiod void	adb_hw_setup(void);
240305d9e87Smiod int	adb_cmd_result(u_char *);
241305d9e87Smiod void	setsoftadb(void);
242305d9e87Smiod 
243305d9e87Smiod int	adb_intr(void *arg);
244305d9e87Smiod void	adb_cuda_autopoll(void);
2453a3b5185Sgwk void 	adb_cuda_fileserver_mode(void);
2466784ab1fStobhe uint8_t pmu_backlight; /* keyboard backlight value */
2476784ab1fStobhe int	pmu_get_backlight(struct wskbd_backlight *);
2486784ab1fStobhe int	pmu_set_backlight(struct wskbd_backlight *);
2496784ab1fStobhe extern int (*wskbd_get_backlight)(struct wskbd_backlight *);
2506784ab1fStobhe extern int (*wskbd_set_backlight)(struct wskbd_backlight *);
2516784ab1fStobhe 
252305d9e87Smiod 
253c1cc27a7Sgkoehler #ifndef SMALL_KERNEL
254c1cc27a7Sgkoehler void	adb_shutdown(void *);
255c1cc27a7Sgkoehler struct	task adb_shutdown_task = TASK_INITIALIZER(adb_shutdown, NULL);
256bdedaf02Sgkoehler #ifdef SUSPEND
257bdedaf02Sgkoehler void	adb_suspend(void *);
258bdedaf02Sgkoehler struct	task adb_suspend_task = TASK_INITIALIZER(adb_suspend, NULL);
259bdedaf02Sgkoehler struct	taskq *adb_suspendq;
260bdedaf02Sgkoehler #endif
261c1cc27a7Sgkoehler #endif
262c1cc27a7Sgkoehler 
263305d9e87Smiod #ifdef ADB_DEBUG
264305d9e87Smiod /*
265305d9e87Smiod  * print_single
266305d9e87Smiod  * Diagnostic display routine. Displays the hex values of the
267305d9e87Smiod  * specified elements of the u_char. The length of the "string"
268305d9e87Smiod  * is in [0].
269305d9e87Smiod  */
270305d9e87Smiod void
print_single(u_char * str)271af7e7ea9Sderaadt print_single(u_char *str)
272305d9e87Smiod {
273305d9e87Smiod 	int x;
274305d9e87Smiod 
27574a0040aSmiod 	if (str == NULL) {
276305d9e87Smiod 		printf_intr("no data - null pointer\n");
277305d9e87Smiod 		return;
278305d9e87Smiod 	}
27974a0040aSmiod 	if (*str == '\0') {
280305d9e87Smiod 		printf_intr("nothing returned\n");
281305d9e87Smiod 		return;
282305d9e87Smiod 	}
283305d9e87Smiod 	if (*str > 20) {
284305d9e87Smiod 		printf_intr("ADB: ACK > 20 no way!\n");
285305d9e87Smiod 		*str = 20;
286305d9e87Smiod 	}
287305d9e87Smiod 	printf_intr("(length=0x%x):", *str);
288305d9e87Smiod 	for (x = 1; x <= *str; x++)
289305d9e87Smiod 		printf_intr("  0x%02x", str[x]);
290305d9e87Smiod 	printf_intr("\n");
291305d9e87Smiod }
292305d9e87Smiod #endif
293305d9e87Smiod 
294305d9e87Smiod void
adb_cuda_tickle(void * unused)295a7265231Scheloha adb_cuda_tickle(void *unused)
296305d9e87Smiod {
297305d9e87Smiod 	volatile int s;
298305d9e87Smiod 
299305d9e87Smiod 	if (adbActionState == ADB_ACTION_IN) {
300305d9e87Smiod 		if (tickle_serial == adb_cuda_serial) {
301305d9e87Smiod 			if (++tickle_count > 0) {
302305d9e87Smiod 				s = splhigh();
303305d9e87Smiod 				adbActionState = ADB_ACTION_IDLE;
304305d9e87Smiod 				adbInputBuffer[0] = 0;
305305d9e87Smiod 				ADB_SET_STATE_IDLE_CUDA();
306305d9e87Smiod 				splx(s);
307305d9e87Smiod 			}
308305d9e87Smiod 		} else {
309305d9e87Smiod 			tickle_serial = adb_cuda_serial;
310305d9e87Smiod 			tickle_count = 0;
311305d9e87Smiod 		}
312305d9e87Smiod 	} else {
313305d9e87Smiod 		tickle_serial = adb_cuda_serial;
314305d9e87Smiod 		tickle_count = 0;
315305d9e87Smiod 	}
316305d9e87Smiod 
317305d9e87Smiod 	timeout_add(&adb_cuda_timeout, ADB_TICKLE_TICKS);
318305d9e87Smiod }
319305d9e87Smiod 
320305d9e87Smiod /*
321b3af768dSjsg  * called when an adb interrupt happens
322305d9e87Smiod  *
323305d9e87Smiod  * Cuda version of adb_intr
324305d9e87Smiod  * TO DO: do we want to add some calls to intr_dispatch() here to
325305d9e87Smiod  * grab serial interrupts?
326305d9e87Smiod  */
327305d9e87Smiod void
adb_intr_cuda(void)328305d9e87Smiod adb_intr_cuda(void)
329305d9e87Smiod {
330305d9e87Smiod 	volatile int i, ending;
331305d9e87Smiod 	volatile unsigned int s;
332305d9e87Smiod 	struct adbCommand packet;
333305d9e87Smiod 
334305d9e87Smiod 	s = splhigh();		/* can't be too careful - might be called */
335305d9e87Smiod 				/* from a routine, NOT an interrupt */
336305d9e87Smiod 
337305d9e87Smiod 	ADB_VIA_CLR_INTR();	/* clear interrupt */
338305d9e87Smiod 	ADB_VIA_INTR_DISABLE();	/* disable ADB interrupt on IIs. */
339305d9e87Smiod 
340305d9e87Smiod switch_start:
341305d9e87Smiod 	switch (adbActionState) {
342305d9e87Smiod 	case ADB_ACTION_IDLE:
343305d9e87Smiod 		/*
344305d9e87Smiod 		 * This is an unexpected packet, so grab the first (dummy)
345305d9e87Smiod 		 * byte, set up the proper vars, and tell the chip we are
346305d9e87Smiod 		 * starting to receive the packet by setting the TIP bit.
347305d9e87Smiod 		 */
348305d9e87Smiod 		adbInputBuffer[1] = ADB_SR();
349305d9e87Smiod 		adb_cuda_serial++;
350305d9e87Smiod 		if (ADB_INTR_IS_OFF)	/* must have been a fake start */
351305d9e87Smiod 			break;
352305d9e87Smiod 
353305d9e87Smiod 		ADB_SET_SR_INPUT();
354305d9e87Smiod 		ADB_SET_STATE_TIP();
355305d9e87Smiod 
356305d9e87Smiod 		adbInputBuffer[0] = 1;
357305d9e87Smiod 		adbActionState = ADB_ACTION_IN;
358305d9e87Smiod #ifdef ADB_DEBUG
359305d9e87Smiod 		if (adb_debug)
360305d9e87Smiod 			printf_intr("idle 0x%02x ", adbInputBuffer[1]);
361305d9e87Smiod #endif
362305d9e87Smiod 		break;
363305d9e87Smiod 
364305d9e87Smiod 	case ADB_ACTION_IN:
365305d9e87Smiod 		adbInputBuffer[++adbInputBuffer[0]] = ADB_SR();
366305d9e87Smiod 		/* intr off means this is the last byte (end of frame) */
367305d9e87Smiod 		if (ADB_INTR_IS_OFF)
368305d9e87Smiod 			ending = 1;
369305d9e87Smiod 		else
370305d9e87Smiod 			ending = 0;
371305d9e87Smiod 
372305d9e87Smiod 		if (1 == ending) {	/* end of message? */
373305d9e87Smiod #ifdef ADB_DEBUG
374305d9e87Smiod 			if (adb_debug) {
375305d9e87Smiod 				printf_intr("in end 0x%02x ",
376305d9e87Smiod 				    adbInputBuffer[adbInputBuffer[0]]);
377305d9e87Smiod 				print_single(adbInputBuffer);
378305d9e87Smiod 			}
379305d9e87Smiod #endif
380305d9e87Smiod 
381305d9e87Smiod 			/*
382305d9e87Smiod 			 * Are we waiting AND does this packet match what we
383305d9e87Smiod 			 * are waiting for AND is it coming from either the
384305d9e87Smiod 			 * ADB or RTC/PRAM sub-device? This section _should_
385305d9e87Smiod 			 * recognize all ADB and RTC/PRAM type commands, but
386305d9e87Smiod 			 * there may be more... NOTE: commands are always at
387305d9e87Smiod 			 * [4], even for RTC/PRAM commands.
388305d9e87Smiod 			 */
389305d9e87Smiod 			/* set up data for adb_pass_up */
390305d9e87Smiod 			memcpy(packet.data, adbInputBuffer, adbInputBuffer[0] + 1);
391305d9e87Smiod 
392305d9e87Smiod 			if ((adbWaiting == 1) &&
393305d9e87Smiod 			    (adbInputBuffer[4] == adbWaitingCmd) &&
394305d9e87Smiod 			    ((adbInputBuffer[2] == 0x00) ||
395305d9e87Smiod 			    (adbInputBuffer[2] == 0x01))) {
396305d9e87Smiod 				packet.saveBuf = adbBuffer;
397305d9e87Smiod 				packet.compRout = adbCompRout;
398305d9e87Smiod 				packet.compData = adbCompData;
399305d9e87Smiod 				packet.unsol = 0;
400305d9e87Smiod 				packet.ack_only = 0;
401305d9e87Smiod 				adb_pass_up(&packet);
402305d9e87Smiod 
403305d9e87Smiod 				adbWaitingCmd = 0;	/* reset "waiting" vars */
404305d9e87Smiod 				adbWaiting = 0;
40574a0040aSmiod 				adbBuffer = NULL;
40674a0040aSmiod 				adbCompRout = NULL;
40774a0040aSmiod 				adbCompData = NULL;
408305d9e87Smiod 			} else {
409305d9e87Smiod 				packet.unsol = 1;
410305d9e87Smiod 				packet.ack_only = 0;
411305d9e87Smiod 				adb_pass_up(&packet);
412305d9e87Smiod 			}
413305d9e87Smiod 
414305d9e87Smiod 
415305d9e87Smiod 			/* reset vars and signal the end of this frame */
416305d9e87Smiod 			adbActionState = ADB_ACTION_IDLE;
417305d9e87Smiod 			adbInputBuffer[0] = 0;
418305d9e87Smiod 			ADB_SET_STATE_IDLE_CUDA();
419305d9e87Smiod 			/*ADB_SET_SR_INPUT();*/
420305d9e87Smiod 
421305d9e87Smiod 			/*
422305d9e87Smiod 			 * If there is something waiting to be sent out,
423305d9e87Smiod 			 * the set everything up and send the first byte.
424305d9e87Smiod 			 */
425305d9e87Smiod 			if (adbWriteDelay == 1) {
426305d9e87Smiod 				delay(ADB_DELAY);	/* required */
427305d9e87Smiod 				adbSentChars = 0;
428305d9e87Smiod 				adbActionState = ADB_ACTION_OUT;
429305d9e87Smiod 				/*
430305d9e87Smiod 				 * If the interrupt is on, we were too slow
431305d9e87Smiod 				 * and the chip has already started to send
432305d9e87Smiod 				 * something to us, so back out of the write
433305d9e87Smiod 				 * and start a read cycle.
434305d9e87Smiod 				 */
435305d9e87Smiod 				if (ADB_INTR_IS_ON) {
436305d9e87Smiod 					ADB_SET_SR_INPUT();
437305d9e87Smiod 					ADB_SET_STATE_IDLE_CUDA();
438305d9e87Smiod 					adbSentChars = 0;
439305d9e87Smiod 					adbActionState = ADB_ACTION_IDLE;
440305d9e87Smiod 					adbInputBuffer[0] = 0;
441305d9e87Smiod 					break;
442305d9e87Smiod 				}
443305d9e87Smiod 				/*
444305d9e87Smiod 				 * If we got here, it's ok to start sending
445305d9e87Smiod 				 * so load the first byte and tell the chip
446305d9e87Smiod 				 * we want to send.
447305d9e87Smiod 				 */
448305d9e87Smiod 				ADB_SET_STATE_TIP();
449305d9e87Smiod 				ADB_SET_SR_OUTPUT();
450305d9e87Smiod 				write_via_reg(VIA1, vSR, adbOutputBuffer[adbSentChars + 1]);
451305d9e87Smiod 			}
452305d9e87Smiod 		} else {
453305d9e87Smiod 			ADB_TOGGLE_STATE_ACK_CUDA();
454305d9e87Smiod #ifdef ADB_DEBUG
455305d9e87Smiod 			if (adb_debug)
456305d9e87Smiod 				printf_intr("in 0x%02x ",
457305d9e87Smiod 				    adbInputBuffer[adbInputBuffer[0]]);
458305d9e87Smiod #endif
459305d9e87Smiod 		}
460305d9e87Smiod 		break;
461305d9e87Smiod 
462305d9e87Smiod 	case ADB_ACTION_OUT:
463305d9e87Smiod 		i = ADB_SR();	/* reset SR-intr in IFR */
464305d9e87Smiod #ifdef ADB_DEBUG
465305d9e87Smiod 		if (adb_debug)
466305d9e87Smiod 			printf_intr("intr out 0x%02x ", i);
467305d9e87Smiod #endif
468305d9e87Smiod 
469305d9e87Smiod 		adbSentChars++;
470305d9e87Smiod 		if (ADB_INTR_IS_ON) {	/* ADB intr low during write */
471305d9e87Smiod #ifdef ADB_DEBUG
472305d9e87Smiod 			if (adb_debug)
473305d9e87Smiod 				printf_intr("intr was on ");
474305d9e87Smiod #endif
475305d9e87Smiod 			ADB_SET_SR_INPUT();	/* make sure SR is set to IN */
476305d9e87Smiod 			ADB_SET_STATE_IDLE_CUDA();
477305d9e87Smiod 			adbSentChars = 0;	/* must start all over */
478305d9e87Smiod 			adbActionState = ADB_ACTION_IDLE;	/* new state */
479305d9e87Smiod 			adbInputBuffer[0] = 0;
480305d9e87Smiod 			adbWriteDelay = 1;	/* must retry when done with
481305d9e87Smiod 						 * read */
482305d9e87Smiod 			delay(ADB_DELAY);
483305d9e87Smiod 			goto switch_start;	/* process next state right
484305d9e87Smiod 						 * now */
485305d9e87Smiod 			break;
486305d9e87Smiod 		}
487305d9e87Smiod 		if (adbOutputBuffer[0] == adbSentChars) {	/* check for done */
488305d9e87Smiod 			if (0 == adb_cmd_result(adbOutputBuffer)) {	/* do we expect data
489305d9e87Smiod 									 * back? */
490305d9e87Smiod 				adbWaiting = 1;	/* signal waiting for return */
491305d9e87Smiod 				adbWaitingCmd = adbOutputBuffer[2];	/* save waiting command */
492305d9e87Smiod 			} else {	/* no talk, so done */
493305d9e87Smiod 				/* set up stuff for adb_pass_up */
494305d9e87Smiod 				memcpy(packet.data, adbInputBuffer, adbInputBuffer[0] + 1);
495305d9e87Smiod 				packet.saveBuf = adbBuffer;
496305d9e87Smiod 				packet.compRout = adbCompRout;
497305d9e87Smiod 				packet.compData = adbCompData;
498305d9e87Smiod 				packet.cmd = adbWaitingCmd;
499305d9e87Smiod 				packet.unsol = 0;
500305d9e87Smiod 				packet.ack_only = 1;
501305d9e87Smiod 				adb_pass_up(&packet);
502305d9e87Smiod 
503305d9e87Smiod 				/* reset "waiting" vars, just in case */
504305d9e87Smiod 				adbWaitingCmd = 0;
50574a0040aSmiod 				adbBuffer = NULL;
50674a0040aSmiod 				adbCompRout = NULL;
50774a0040aSmiod 				adbCompData = NULL;
508305d9e87Smiod 			}
509305d9e87Smiod 
510305d9e87Smiod 			adbWriteDelay = 0;	/* done writing */
511305d9e87Smiod 			adbActionState = ADB_ACTION_IDLE;	/* signal bus is idle */
512305d9e87Smiod 			ADB_SET_SR_INPUT();
513305d9e87Smiod 			ADB_SET_STATE_IDLE_CUDA();
514305d9e87Smiod #ifdef ADB_DEBUG
515305d9e87Smiod 			if (adb_debug)
516305d9e87Smiod 				printf_intr("write done ");
517305d9e87Smiod #endif
518305d9e87Smiod 		} else {
519305d9e87Smiod 			write_via_reg(VIA1, vSR, adbOutputBuffer[adbSentChars + 1]);	/* send next byte */
520305d9e87Smiod 			ADB_TOGGLE_STATE_ACK_CUDA();	/* signal byte ready to
521305d9e87Smiod 							 * shift */
522305d9e87Smiod #ifdef ADB_DEBUG
523305d9e87Smiod 			if (adb_debug)
524305d9e87Smiod 				printf_intr("toggle ");
525305d9e87Smiod #endif
526305d9e87Smiod 		}
527305d9e87Smiod 		break;
528305d9e87Smiod 
529305d9e87Smiod 	case ADB_ACTION_NOTREADY:
530305d9e87Smiod #ifdef ADB_DEBUG
531305d9e87Smiod 		if (adb_debug)
532305d9e87Smiod 			printf_intr("adb: not yet initialized\n");
533305d9e87Smiod #endif
534305d9e87Smiod 		break;
535305d9e87Smiod 
536305d9e87Smiod 	default:
537305d9e87Smiod 		;
538305d9e87Smiod #ifdef ADB_DEBUG
539305d9e87Smiod 		if (adb_debug)
540305d9e87Smiod 			printf_intr("intr: unknown ADB state\n");
541305d9e87Smiod #endif
542305d9e87Smiod 	}
543305d9e87Smiod 
544305d9e87Smiod 	ADB_VIA_INTR_ENABLE();	/* enable ADB interrupt on IIs. */
545305d9e87Smiod 
546305d9e87Smiod 	splx(s);		/* restore */
547305d9e87Smiod }
548305d9e87Smiod 
549305d9e87Smiod 
550305d9e87Smiod int
send_adb_cuda(u_char * in,u_char * buffer,void * compRout,void * data,int command)551af7e7ea9Sderaadt send_adb_cuda(u_char * in, u_char * buffer, void *compRout, void *data,
552af7e7ea9Sderaadt     int command)
553305d9e87Smiod {
554305d9e87Smiod 	int s, len;
555305d9e87Smiod 
556305d9e87Smiod #ifdef ADB_DEBUG
557305d9e87Smiod 	if (adb_debug)
558305d9e87Smiod 		printf_intr("SEND\n");
559305d9e87Smiod #endif
560305d9e87Smiod 
561305d9e87Smiod 	if (adbActionState == ADB_ACTION_NOTREADY)
562305d9e87Smiod 		return 1;
563305d9e87Smiod 
564305d9e87Smiod 	/* Don't interrupt while we are messing with the ADB */
565305d9e87Smiod 	s = splhigh();
566305d9e87Smiod 
567305d9e87Smiod 	if ((adbActionState == ADB_ACTION_IDLE) &&	/* ADB available? */
568305d9e87Smiod 	    (ADB_INTR_IS_OFF)) {	/* and no incoming interrupt? */
569305d9e87Smiod 	} else
570305d9e87Smiod 		if (adbWriteDelay == 0)	/* it's busy, but is anything waiting? */
571305d9e87Smiod 			adbWriteDelay = 1;	/* if no, then we'll "queue"
572305d9e87Smiod 						 * it up */
573305d9e87Smiod 		else {
574305d9e87Smiod 			splx(s);
575305d9e87Smiod 			return 1;	/* really busy! */
576305d9e87Smiod 		}
577305d9e87Smiod 
578305d9e87Smiod #ifdef ADB_DEBUG
579305d9e87Smiod 	if (adb_debug)
580305d9e87Smiod 		printf_intr("QUEUE\n");
581305d9e87Smiod #endif
582305d9e87Smiod 	if ((long)in == (long)0) {	/* need to convert? */
583305d9e87Smiod 		if ((command & 0x0c) == 0x08)	/* copy addl data ONLY if
584305d9e87Smiod 						 * doing a listen! */
585305d9e87Smiod 			len = buffer[0];	/* length of additional data */
586305d9e87Smiod 		else
587305d9e87Smiod 			len = 0;/* no additional data */
588305d9e87Smiod 
589305d9e87Smiod 		adbOutputBuffer[0] = 2 + len;	/* dev. type + command + addl.
590305d9e87Smiod 						 * data */
591305d9e87Smiod 		adbOutputBuffer[1] = 0x00;	/* mark as an ADB command */
592305d9e87Smiod 		adbOutputBuffer[2] = (u_char)command;	/* load command */
593305d9e87Smiod 
594305d9e87Smiod 		/* copy additional output data, if any */
595305d9e87Smiod 		memcpy(adbOutputBuffer + 3, buffer + 1, len);
596305d9e87Smiod 	} else
597305d9e87Smiod 		/* if data ready, just copy over */
598305d9e87Smiod 		memcpy(adbOutputBuffer, in, in[0] + 2);
599305d9e87Smiod 
600305d9e87Smiod 	adbSentChars = 0;	/* nothing sent yet */
601305d9e87Smiod 	adbBuffer = buffer;	/* save buffer to know where to save result */
602305d9e87Smiod 	adbCompRout = compRout;	/* save completion routine pointer */
603305d9e87Smiod 	adbCompData = data;	/* save completion routine data pointer */
604305d9e87Smiod 	adbWaitingCmd = adbOutputBuffer[2];	/* save wait command */
605305d9e87Smiod 
606305d9e87Smiod 	if (adbWriteDelay != 1) {	/* start command now? */
607305d9e87Smiod #ifdef ADB_DEBUG
608305d9e87Smiod 		if (adb_debug)
609305d9e87Smiod 			printf_intr("out start NOW");
610305d9e87Smiod #endif
611305d9e87Smiod 		delay(ADB_DELAY);
612305d9e87Smiod 		adbActionState = ADB_ACTION_OUT;	/* set next state */
613305d9e87Smiod 		ADB_SET_SR_OUTPUT();	/* set shift register for OUT */
614305d9e87Smiod 		write_via_reg(VIA1, vSR, adbOutputBuffer[adbSentChars + 1]);	/* load byte for output */
615305d9e87Smiod 		ADB_SET_STATE_ACKOFF_CUDA();
616305d9e87Smiod 		ADB_SET_STATE_TIP();	/* tell ADB that we want to send */
617305d9e87Smiod 	}
618305d9e87Smiod 	adbWriteDelay = 1;	/* something in the write "queue" */
619305d9e87Smiod 
620305d9e87Smiod 	splx(s);
621305d9e87Smiod 
62215c42ae5Smiod 	if (adb_polling) /* XXX were VIA1 interrupts blocked ? */
623305d9e87Smiod 		/* poll until byte done */
624305d9e87Smiod 		while ((adbActionState != ADB_ACTION_IDLE) || (ADB_INTR_IS_ON)
625305d9e87Smiod 		    || (adbWaiting == 1))
626305d9e87Smiod 			if (ADB_SR_INTR_IS_ON) {	/* wait for "interrupt" */
627305d9e87Smiod 				adb_intr_cuda();	/* process it */
62853b2c9b4Smiod 				if (cold)
62953b2c9b4Smiod 					delay(ADB_DELAY);
630305d9e87Smiod 				adb_soft_intr();
631305d9e87Smiod 			}
632305d9e87Smiod 
633305d9e87Smiod 	return 0;
634305d9e87Smiod }
635305d9e87Smiod 
636305d9e87Smiod /*
637b3af768dSjsg  * Called when an adb interrupt happens.
638305d9e87Smiod  * This routine simply transfers control over to the appropriate
639305d9e87Smiod  * code for the machine we are running on.
640305d9e87Smiod  */
641305d9e87Smiod int
adb_intr(void * arg)642305d9e87Smiod adb_intr(void *arg)
643305d9e87Smiod {
644305d9e87Smiod 	switch (adbHardware) {
645305d9e87Smiod 	case ADB_HW_PMU:
646305d9e87Smiod 		pm_intr();
647305d9e87Smiod 		break;
648305d9e87Smiod 
649305d9e87Smiod 	case ADB_HW_CUDA:
650305d9e87Smiod 		adb_intr_cuda();
651305d9e87Smiod 		break;
652305d9e87Smiod 	}
653305d9e87Smiod 	return 1;
654305d9e87Smiod }
655305d9e87Smiod 
656305d9e87Smiod 
657305d9e87Smiod /*
658305d9e87Smiod  * adb_pass_up is called by the interrupt-time routines.
659305d9e87Smiod  * It takes the raw packet data that was received from the
660305d9e87Smiod  * device and puts it into the queue that the upper half
661305d9e87Smiod  * processes. It then signals for a soft ADB interrupt which
662305d9e87Smiod  * will eventually call the upper half routine (adb_soft_intr).
663305d9e87Smiod  *
664305d9e87Smiod  * If in->unsol is 0, then this is either the notification
665305d9e87Smiod  * that the packet was sent (on a LISTEN, for example), or the
666305d9e87Smiod  * response from the device (on a TALK). The completion routine
667305d9e87Smiod  * is called only if the user specified one.
668305d9e87Smiod  *
669305d9e87Smiod  * If in->unsol is 1, then this packet was unsolicited and
670305d9e87Smiod  * so we look up the device in the ADB device table to determine
6710f1683a6Smiod  * what its default service routine is.
672305d9e87Smiod  *
673305d9e87Smiod  * If in->ack_only is 1, then we really only need to call
674305d9e87Smiod  * the completion routine, so don't do any other stuff.
675305d9e87Smiod  *
676305d9e87Smiod  * Note that in->data contains the packet header AND data,
677305d9e87Smiod  * while adbInbound[]->data contains ONLY data.
678305d9e87Smiod  *
679305d9e87Smiod  * Note: Called only at interrupt time. Assumes this.
680305d9e87Smiod  */
681305d9e87Smiod void
adb_pass_up(struct adbCommand * in)682305d9e87Smiod adb_pass_up(struct adbCommand *in)
683305d9e87Smiod {
684305d9e87Smiod 	int start = 0, len = 0, cmd = 0;
685305d9e87Smiod 	ADBDataBlock block;
686305d9e87Smiod 
687305d9e87Smiod 	if (adbInCount >= ADB_QUEUE) {
688305d9e87Smiod #ifdef ADB_DEBUG
689305d9e87Smiod 		if (adb_debug)
690305d9e87Smiod 			printf_intr("adb: ring buffer overflow\n");
691305d9e87Smiod #endif
692305d9e87Smiod 		return;
693305d9e87Smiod 	}
694305d9e87Smiod 
695305d9e87Smiod 	if (in->ack_only) {
696305d9e87Smiod 		len = in->data[0];
697305d9e87Smiod 		cmd = in->cmd;
698305d9e87Smiod 		start = 0;
699305d9e87Smiod 	} else {
700305d9e87Smiod 		switch (adbHardware) {
701305d9e87Smiod 		case ADB_HW_CUDA:
702305d9e87Smiod 			/* If it's unsolicited, accept only ADB data for now */
703305d9e87Smiod 			if (in->unsol)
704305d9e87Smiod 				if (0 != in->data[2])
705305d9e87Smiod 					return;
706305d9e87Smiod 			cmd = in->data[4];
707305d9e87Smiod 			if (in->data[0] < 5)
708305d9e87Smiod 				len = 0;
709305d9e87Smiod 			else
710305d9e87Smiod 				len = in->data[0]-4;
711305d9e87Smiod 			start = 4;
712305d9e87Smiod 			break;
713305d9e87Smiod 
714305d9e87Smiod 		case ADB_HW_PMU:
715305d9e87Smiod 			cmd = in->data[1];
716305d9e87Smiod 			if (in->data[0] < 2)
717305d9e87Smiod 				len = 0;
718305d9e87Smiod 			else
719305d9e87Smiod 				len = in->data[0]-1;
720305d9e87Smiod 			start = 1;
721305d9e87Smiod 			break;
722305d9e87Smiod 
723305d9e87Smiod 		case ADB_HW_UNKNOWN:
724305d9e87Smiod 			return;
725305d9e87Smiod 		}
726305d9e87Smiod 
727305d9e87Smiod 		/* Make sure there is a valid device entry for this device */
728305d9e87Smiod 		if (in->unsol) {
729305d9e87Smiod 			/* ignore unsolicited data during adbreinit */
730305d9e87Smiod 			if (adbStarting)
731305d9e87Smiod 				return;
732305d9e87Smiod 			/* get device's comp. routine and data area */
733305d9e87Smiod 			if (-1 == get_adb_info(&block, ADB_CMDADDR(cmd)))
734305d9e87Smiod 				return;
735305d9e87Smiod 		}
736305d9e87Smiod 	}
737305d9e87Smiod 
738305d9e87Smiod 	/*
739305d9e87Smiod  	 * If this is an unsolicited packet, we need to fill in
740305d9e87Smiod  	 * some info so adb_soft_intr can process this packet
741305d9e87Smiod  	 * properly. If it's not unsolicited, then use what
742305d9e87Smiod  	 * the caller sent us.
743305d9e87Smiod  	 */
744305d9e87Smiod 	if (in->unsol) {
745305d9e87Smiod 		adbInbound[adbInTail].compRout = (void *)block.dbServiceRtPtr;
746305d9e87Smiod 		adbInbound[adbInTail].compData = (void *)block.dbDataAreaAddr;
747305d9e87Smiod 		adbInbound[adbInTail].saveBuf = (void *)adbInbound[adbInTail].data;
748305d9e87Smiod 	} else {
749305d9e87Smiod 		adbInbound[adbInTail].compRout = (void *)in->compRout;
750305d9e87Smiod 		adbInbound[adbInTail].compData = (void *)in->compData;
751305d9e87Smiod 		adbInbound[adbInTail].saveBuf = (void *)in->saveBuf;
752305d9e87Smiod 	}
753305d9e87Smiod 
754305d9e87Smiod #ifdef ADB_DEBUG
755305d9e87Smiod 	if (adb_debug && in->data[1] == 2)
756305d9e87Smiod 		printf_intr("adb: caught error\n");
757305d9e87Smiod #endif
758305d9e87Smiod 
759305d9e87Smiod 	/* copy the packet data over */
760305d9e87Smiod 	/*
761305d9e87Smiod 	 * TO DO: If the *_intr routines fed their incoming data
762305d9e87Smiod 	 * directly into an adbCommand struct, which is passed to
763305d9e87Smiod 	 * this routine, then we could eliminate this copy.
764305d9e87Smiod 	 */
765305d9e87Smiod 	memcpy(adbInbound[adbInTail].data + 1, in->data + start + 1, len);
766305d9e87Smiod 	adbInbound[adbInTail].data[0] = len;
767305d9e87Smiod 	adbInbound[adbInTail].cmd = cmd;
768305d9e87Smiod 
769305d9e87Smiod 	adbInCount++;
770305d9e87Smiod 	if (++adbInTail >= ADB_QUEUE)
771305d9e87Smiod 		adbInTail = 0;
772305d9e87Smiod 
773305d9e87Smiod 	/*
774305d9e87Smiod 	 * If the debugger is running, call upper half manually.
775305d9e87Smiod 	 * Otherwise, trigger a soft interrupt to handle the rest later.
776305d9e87Smiod 	 */
777305d9e87Smiod 	if (adb_polling)
778305d9e87Smiod 		adb_soft_intr();
779305d9e87Smiod 	else
780305d9e87Smiod 		setsoftadb();
781305d9e87Smiod }
782305d9e87Smiod 
783305d9e87Smiod 
784305d9e87Smiod /*
785305d9e87Smiod  * Called to process the packets after they have been
786305d9e87Smiod  * placed in the incoming queue.
787305d9e87Smiod  *
788305d9e87Smiod  */
789305d9e87Smiod void
adb_soft_intr(void)790305d9e87Smiod adb_soft_intr(void)
791305d9e87Smiod {
792305d9e87Smiod 	int s;
793305d9e87Smiod 	int cmd = 0;
79474a0040aSmiod 	u_char *buffer;
79574a0040aSmiod 	u_char *comprout;
79674a0040aSmiod 	u_char *compdata;
797305d9e87Smiod 
798305d9e87Smiod /*delay(2*ADB_DELAY);*/
799305d9e87Smiod 
800305d9e87Smiod 	while (adbInCount) {
801305d9e87Smiod #ifdef ADB_DEBUG
802305d9e87Smiod 		if (adb_debug & 0x80)
803305d9e87Smiod 			printf_intr("%x %x %x ",
804305d9e87Smiod 			    adbInCount, adbInHead, adbInTail);
805305d9e87Smiod #endif
806305d9e87Smiod 		/* get the data we need from the queue */
807305d9e87Smiod 		buffer = adbInbound[adbInHead].saveBuf;
808305d9e87Smiod 		comprout = adbInbound[adbInHead].compRout;
809305d9e87Smiod 		compdata = adbInbound[adbInHead].compData;
810305d9e87Smiod 		cmd = adbInbound[adbInHead].cmd;
811305d9e87Smiod 
812305d9e87Smiod 		/* copy over data to data area if it's valid */
813305d9e87Smiod 		/*
814305d9e87Smiod 		 * Note that for unsol packets we don't want to copy the
815305d9e87Smiod 		 * data anywhere, so buffer was already set to 0.
816305d9e87Smiod 		 * For ack_only buffer was set to 0, so don't copy.
817305d9e87Smiod 		 */
818305d9e87Smiod 		if (buffer)
819305d9e87Smiod 			memcpy(buffer, adbInbound[adbInHead].data,
820305d9e87Smiod 			    adbInbound[adbInHead].data[0] + 1);
821305d9e87Smiod 
822305d9e87Smiod #ifdef ADB_DEBUG
823305d9e87Smiod 			if (adb_debug & 0x80) {
824305d9e87Smiod 				printf_intr("%p %p %p %x ",
825305d9e87Smiod 				    buffer, comprout, compdata, (short)cmd);
826305d9e87Smiod 				printf_intr("buf: ");
827305d9e87Smiod 				print_single(adbInbound[adbInHead].data);
828305d9e87Smiod 			}
829305d9e87Smiod #endif
830305d9e87Smiod 		/*
831305d9e87Smiod 		 * Remove the packet from the queue before calling
832305d9e87Smiod                  * the completion routine, so that the completion
833305d9e87Smiod                  * routine can reentrantly process the queue.  For
834305d9e87Smiod                  * example, this happens when polling is turned on
83536fd90dcSjsg                  * by entering the debugger by keystroke.
836305d9e87Smiod                  */
837305d9e87Smiod 		s = splhigh();
838305d9e87Smiod 		adbInCount--;
839305d9e87Smiod 		if (++adbInHead >= ADB_QUEUE)
840305d9e87Smiod 			adbInHead = 0;
841305d9e87Smiod 		splx(s);
842305d9e87Smiod 
843305d9e87Smiod 		/* call default completion routine if it's valid */
844305d9e87Smiod 		if (comprout) {
845305d9e87Smiod 			((int (*)(u_char *, u_char *, int)) comprout)
846305d9e87Smiod 			    (buffer, compdata, cmd);
847305d9e87Smiod 		}
848305d9e87Smiod 
849305d9e87Smiod 	}
850305d9e87Smiod }
851305d9e87Smiod 
852c1cc27a7Sgkoehler #ifndef SMALL_KERNEL
853c1cc27a7Sgkoehler void
adb_shutdown(void * arg)854c1cc27a7Sgkoehler adb_shutdown(void *arg)
855c1cc27a7Sgkoehler {
856c1cc27a7Sgkoehler 	extern int allowpowerdown;
857c1cc27a7Sgkoehler 
858c1cc27a7Sgkoehler 	if (allowpowerdown == 1) {
859c1cc27a7Sgkoehler 		allowpowerdown = 0;
860c1cc27a7Sgkoehler 		prsignal(initprocess, SIGUSR2);
861c1cc27a7Sgkoehler 	}
862c1cc27a7Sgkoehler }
863bdedaf02Sgkoehler 
864bdedaf02Sgkoehler #ifdef SUSPEND
865bdedaf02Sgkoehler void
adb_suspend(void * arg)866bdedaf02Sgkoehler adb_suspend(void *arg)
867bdedaf02Sgkoehler {
868bdedaf02Sgkoehler 	extern struct cfdriver apm_cd;
869bdedaf02Sgkoehler 
870bdedaf02Sgkoehler 	if (apm_cd.cd_ndevs > 0)
871bdedaf02Sgkoehler 		sleep_state(apm_cd.cd_devs[0], SLEEP_SUSPEND);
872bdedaf02Sgkoehler }
873bdedaf02Sgkoehler #endif
874c1cc27a7Sgkoehler #endif /* !SMALL_KERNEL */
875c1cc27a7Sgkoehler 
876c1cc27a7Sgkoehler void
adb_lid_closed_intr(void)877c1cc27a7Sgkoehler adb_lid_closed_intr(void)
878c1cc27a7Sgkoehler {
879c1cc27a7Sgkoehler #ifndef SMALL_KERNEL
880c1cc27a7Sgkoehler 	switch (lid_action) {
881bdedaf02Sgkoehler #ifdef SUSPEND
882c1cc27a7Sgkoehler 	case 1:
883bdedaf02Sgkoehler 		task_add(adb_suspendq, &adb_suspend_task);
884c1cc27a7Sgkoehler 		break;
885bdedaf02Sgkoehler #endif
886c1cc27a7Sgkoehler 	case 2:
887c1cc27a7Sgkoehler 		/* Hibernate. */
888c1cc27a7Sgkoehler 		break;
889c1cc27a7Sgkoehler 	}
890c1cc27a7Sgkoehler #endif
891c1cc27a7Sgkoehler }
892c1cc27a7Sgkoehler 
893c1cc27a7Sgkoehler void
adb_power_button_intr(void)894c1cc27a7Sgkoehler adb_power_button_intr(void)
895c1cc27a7Sgkoehler {
896c1cc27a7Sgkoehler #ifndef SMALL_KERNEL
897c1cc27a7Sgkoehler 	switch (pwr_action) {
898c1cc27a7Sgkoehler 	case 1:
899c1cc27a7Sgkoehler 		task_add(systq, &adb_shutdown_task);
900c1cc27a7Sgkoehler 		break;
901bdedaf02Sgkoehler #ifdef SUSPEND
902c1cc27a7Sgkoehler 	case 2:
903bdedaf02Sgkoehler 		task_add(adb_suspendq, &adb_suspend_task);
904c1cc27a7Sgkoehler 		break;
905bdedaf02Sgkoehler #endif
906c1cc27a7Sgkoehler 	}
907c1cc27a7Sgkoehler #endif
908c1cc27a7Sgkoehler }
909c1cc27a7Sgkoehler 
910305d9e87Smiod 
911305d9e87Smiod /*
912305d9e87Smiod  * This is my version of the ADBOp routine. It mainly just calls the
913305d9e87Smiod  * hardware-specific routine.
914305d9e87Smiod  *
915305d9e87Smiod  *   data 	: pointer to data area to be used by compRout
916305d9e87Smiod  *   compRout	: completion routine
917305d9e87Smiod  *   buffer	: for LISTEN: points to data to send - MAX 8 data bytes,
918305d9e87Smiod  *		  byte 0 = # of bytes
919305d9e87Smiod  *		: for TALK: points to place to save return data
920305d9e87Smiod  *   command	: the adb command to send
921305d9e87Smiod  *   result	: 0 = success
922305d9e87Smiod  *		: -1 = could not complete
923305d9e87Smiod  */
924305d9e87Smiod int
adb_op(Ptr buffer,Ptr compRout,Ptr data,short command)925305d9e87Smiod adb_op(Ptr buffer, Ptr compRout, Ptr data, short command)
926305d9e87Smiod {
927305d9e87Smiod 	int result;
928305d9e87Smiod 
929305d9e87Smiod 	switch (adbHardware) {
930305d9e87Smiod 	case ADB_HW_PMU:
931305d9e87Smiod 		result = pm_adb_op((u_char *)buffer, (void *)compRout,
932305d9e87Smiod 		    (void *)data, (int)command);
933305d9e87Smiod 
934305d9e87Smiod 		if (result == 0)
935305d9e87Smiod 			return 0;
936305d9e87Smiod 		else
937305d9e87Smiod 			return -1;
938305d9e87Smiod 		break;
939305d9e87Smiod 
940305d9e87Smiod 	case ADB_HW_CUDA:
94114bf419fSkrw 		result = send_adb_cuda(NULL, (u_char *)buffer,
942305d9e87Smiod 		    (void *)compRout, (void *)data, (int)command);
943305d9e87Smiod 		if (result == 0)
944305d9e87Smiod 			return 0;
945305d9e87Smiod 		else
946305d9e87Smiod 			return -1;
947305d9e87Smiod 		break;
948305d9e87Smiod 
949305d9e87Smiod 	default:
950305d9e87Smiod 		return -1;
951305d9e87Smiod 	}
952305d9e87Smiod }
953305d9e87Smiod 
954305d9e87Smiod 
955305d9e87Smiod /*
956305d9e87Smiod  * adb_hw_setup
957305d9e87Smiod  * This routine sets up the possible machine specific hardware
958305d9e87Smiod  * config (mainly VIA settings) for the various models.
959305d9e87Smiod  */
960305d9e87Smiod void
adb_hw_setup(void)961305d9e87Smiod adb_hw_setup(void)
962305d9e87Smiod {
963305d9e87Smiod 	volatile int i;
964305d9e87Smiod 
965305d9e87Smiod 	switch (adbHardware) {
966305d9e87Smiod 
967305d9e87Smiod 	case ADB_HW_PMU:
968305d9e87Smiod 		/*
969305d9e87Smiod 		 * XXX - really PM_VIA_CLR_INTR - should we put it in
970305d9e87Smiod 		 * pm_direct.h?
971305d9e87Smiod 		 */
972305d9e87Smiod 		write_via_reg(VIA1, vIFR, 0x90);	/* clear interrupt */
973305d9e87Smiod 		break;
974305d9e87Smiod 
975305d9e87Smiod 	case ADB_HW_CUDA:
976305d9e87Smiod 		via_reg_or(VIA1, vDirB, 0x30);	/* register B bits 4 and 5:
977305d9e87Smiod 						 * outputs */
978305d9e87Smiod 		via_reg_and(VIA1, vDirB, 0xf7);	/* register B bit 3: input */
979305d9e87Smiod 		via_reg_and(VIA1, vACR, ~vSR_OUT);	/* make sure SR is set
980305d9e87Smiod 							 * to IN */
981305d9e87Smiod 		write_via_reg(VIA1, vACR, (read_via_reg(VIA1, vACR) | 0x0c) & ~0x10);
982305d9e87Smiod 		adbActionState = ADB_ACTION_IDLE;	/* used by all types of
983305d9e87Smiod 							 * hardware */
984305d9e87Smiod 		write_via_reg(VIA1, vIER, 0x84);/* make sure VIA interrupts
985305d9e87Smiod 						 * are on */
986305d9e87Smiod 		ADB_SET_STATE_IDLE_CUDA();	/* set ADB bus state to idle */
987305d9e87Smiod 
988305d9e87Smiod 		/* sort of a device reset */
989305d9e87Smiod 		i = ADB_SR();	/* clear interrupt */
990305d9e87Smiod 		ADB_VIA_INTR_DISABLE();	/* no interrupts while clearing */
991305d9e87Smiod 		ADB_SET_STATE_IDLE_CUDA();	/* reset state to idle */
992305d9e87Smiod 		delay(ADB_DELAY);
993305d9e87Smiod 		ADB_SET_STATE_TIP();	/* signal start of frame */
994305d9e87Smiod 		delay(ADB_DELAY);
995305d9e87Smiod 		ADB_TOGGLE_STATE_ACK_CUDA();
996305d9e87Smiod 		delay(ADB_DELAY);
997305d9e87Smiod 		ADB_CLR_STATE_TIP();
998305d9e87Smiod 		delay(ADB_DELAY);
999305d9e87Smiod 		ADB_SET_STATE_IDLE_CUDA();	/* back to idle state */
1000305d9e87Smiod 		i = ADB_SR();	/* clear interrupt */
1001305d9e87Smiod 		ADB_VIA_INTR_ENABLE();	/* ints ok now */
1002305d9e87Smiod 		break;
1003305d9e87Smiod 
1004305d9e87Smiod 	case ADB_HW_UNKNOWN:
1005305d9e87Smiod 	default:
1006305d9e87Smiod 		write_via_reg(VIA1, vIER, 0x04);/* turn interrupts off - TO
1007305d9e87Smiod 						 * DO: turn PB ints off? */
1008305d9e87Smiod 		break;
1009305d9e87Smiod 	}
1010305d9e87Smiod }
1011305d9e87Smiod 
1012305d9e87Smiod /*
1013305d9e87Smiod  * adb_reinit sets up the adb stuff
1014305d9e87Smiod  *
1015305d9e87Smiod  */
1016305d9e87Smiod void
adb_reinit(struct adb_softc * sc)10175e53181fSmpi adb_reinit(struct adb_softc *sc)
1018305d9e87Smiod {
1019305d9e87Smiod 	u_char send_string[ADB_MAX_MSG_LENGTH];
1020305d9e87Smiod 	ADBDataBlock data;	/* temp. holder for getting device info */
1021305d9e87Smiod 	volatile int i, x;
1022305d9e87Smiod 	int s;
1023305d9e87Smiod 	int command;
1024305d9e87Smiod 	int result;
1025305d9e87Smiod 	int saveptr;		/* point to next free relocation address */
1026305d9e87Smiod 	int device;
1027305d9e87Smiod 	int nonewtimes;		/* times thru loop w/o any new devices */
10285e53181fSmpi 	int ADBNumDevices = 0;
1029305d9e87Smiod 
1030305d9e87Smiod 	/* Make sure we are not interrupted while building the table. */
1031305d9e87Smiod 	if (adbHardware != ADB_HW_PMU)	/* ints must be on for PB? */
1032305d9e87Smiod 		s = splhigh();
1033305d9e87Smiod 
1034305d9e87Smiod 	/* Let intr routines know we are running reinit */
1035305d9e87Smiod 	adbStarting = 1;
1036305d9e87Smiod 
1037305d9e87Smiod 	/*
1038305d9e87Smiod 	 * Initialize the ADB table.  For now, we'll always use the same table
1039305d9e87Smiod 	 * that is defined at the beginning of this file - no mallocs.
1040305d9e87Smiod 	 */
1041305d9e87Smiod 	for (i = 0; i < 16; i++)
10425e53181fSmpi 		sc->sc_devtable[i].handler_id = 0;
1043305d9e87Smiod 
1044305d9e87Smiod 	adb_hw_setup();		/* init the VIA bits and hard reset ADB */
1045305d9e87Smiod 
1046305d9e87Smiod 	delay(1000);
1047305d9e87Smiod 
1048305d9e87Smiod 	/* send an ADB reset first */
104974a0040aSmiod 	adb_op_sync((Ptr)0, (short)0x00);
1050305d9e87Smiod 	delay(200000);
1051305d9e87Smiod 
1052305d9e87Smiod 	/*
1053305d9e87Smiod 	 * Probe for ADB devices. Probe devices 1-15 quickly to determine
1054305d9e87Smiod 	 * which device addresses are in use and which are free. For each
1055305d9e87Smiod 	 * address that is in use, move the device at that address to a higher
1056305d9e87Smiod 	 * free address. Continue doing this at that address until no device
1057305d9e87Smiod 	 * responds at that address. Then move the last device that was moved
1058305d9e87Smiod 	 * back to the original address. Do this for the remaining addresses
1059305d9e87Smiod 	 * that we determined were in use.
1060305d9e87Smiod 	 *
1061305d9e87Smiod 	 * When finished, do this entire process over again with the updated
1062305d9e87Smiod 	 * list of in use addresses. Do this until no new devices have been
1063305d9e87Smiod 	 * found in 20 passes though the in use address list. (This probably
1064305d9e87Smiod 	 * seems long and complicated, but it's the best way to detect multiple
1065305d9e87Smiod 	 * devices at the same address - sometimes it takes a couple of tries
1066305d9e87Smiod 	 * before the collision is detected.)
1067305d9e87Smiod 	 */
1068305d9e87Smiod 
1069305d9e87Smiod 	/* initial scan through the devices */
1070305d9e87Smiod 	for (i = 1; i < 16; i++) {
1071305d9e87Smiod 		send_string[0] = 0;
1072305d9e87Smiod 		command = ADBTALK(i, 3);
107374a0040aSmiod 		result = adb_op_sync((Ptr)send_string, (short)command);
1074305d9e87Smiod 
1075305d9e87Smiod 		if (send_string[0] != 0) {
1076305d9e87Smiod 			/* check for valid device handler */
1077305d9e87Smiod 			switch (send_string[2]) {
1078305d9e87Smiod 			case 0:
1079305d9e87Smiod 			case 0xfd:
1080305d9e87Smiod 			case 0xfe:
1081305d9e87Smiod 			case 0xff:
1082305d9e87Smiod 				continue;	/* invalid, skip */
1083305d9e87Smiod 			}
1084305d9e87Smiod 
1085305d9e87Smiod 			/* found a device */
1086305d9e87Smiod 			++ADBNumDevices;
1087305d9e87Smiod 			KASSERT(ADBNumDevices < 16);
10885e53181fSmpi 			sc->sc_devtable[ADBNumDevices].handler_id =
1089305d9e87Smiod 				(int)send_string[2];
10905e53181fSmpi 			sc->sc_devtable[ADBNumDevices].orig_addr = i;
10915e53181fSmpi 			sc->sc_devtable[ADBNumDevices].curr_addr = i;
10925e53181fSmpi 			sc->sc_devtable[ADBNumDevices].data = NULL;
10935e53181fSmpi 			sc->sc_devtable[ADBNumDevices].handler = NULL;
1094305d9e87Smiod 		}
1095305d9e87Smiod 	}
1096305d9e87Smiod 
1097305d9e87Smiod 	/* find highest unused address */
1098305d9e87Smiod 	for (saveptr = 15; saveptr > 0; saveptr--)
1099305d9e87Smiod 		if (-1 == get_adb_info(&data, saveptr))
1100305d9e87Smiod 			break;
1101305d9e87Smiod 
1102305d9e87Smiod #ifdef ADB_DEBUG
1103305d9e87Smiod 	if (adb_debug & 0x80) {
1104305d9e87Smiod 		printf_intr("first free is: 0x%02x\n", saveptr);
1105305d9e87Smiod 		printf_intr("devices: %i\n", ADBNumDevices);
1106305d9e87Smiod 	}
1107305d9e87Smiod #endif
1108305d9e87Smiod 
1109305d9e87Smiod 	nonewtimes = 0;		/* no loops w/o new devices */
1110305d9e87Smiod 	while (saveptr > 0 && nonewtimes++ < 11) {
1111305d9e87Smiod 		for (i = 1; i <= ADBNumDevices; i++) {
11125e53181fSmpi 			device = sc->sc_devtable[i].curr_addr;
1113305d9e87Smiod #ifdef ADB_DEBUG
1114305d9e87Smiod 			if (adb_debug & 0x80)
1115305d9e87Smiod 				printf_intr("moving device 0x%02x to 0x%02x "
1116305d9e87Smiod 				    "(index 0x%02x)  ", device, saveptr, i);
1117305d9e87Smiod #endif
1118305d9e87Smiod 
1119305d9e87Smiod 			/* send TALK R3 to address */
1120305d9e87Smiod 			command = ADBTALK(device, 3);
112174a0040aSmiod 			adb_op_sync((Ptr)send_string, (short)command);
1122305d9e87Smiod 
1123305d9e87Smiod 			/* move device to higher address */
1124305d9e87Smiod 			command = ADBLISTEN(device, 3);
1125305d9e87Smiod 			send_string[0] = 2;
1126305d9e87Smiod 			send_string[1] = (u_char)(saveptr | 0x60);
1127305d9e87Smiod 			send_string[2] = 0xfe;
112874a0040aSmiod 			adb_op_sync((Ptr)send_string, (short)command);
1129305d9e87Smiod 			delay(500);
1130305d9e87Smiod 
1131305d9e87Smiod 			/* send TALK R3 - anything at new address? */
1132305d9e87Smiod 			command = ADBTALK(saveptr, 3);
113374a0040aSmiod 			adb_op_sync((Ptr)send_string, (short)command);
1134305d9e87Smiod 			delay(500);
1135305d9e87Smiod 
1136305d9e87Smiod 			if (send_string[0] == 0) {
1137305d9e87Smiod #ifdef ADB_DEBUG
1138305d9e87Smiod 				if (adb_debug & 0x80)
1139305d9e87Smiod 					printf_intr("failed, continuing\n");
1140305d9e87Smiod #endif
1141305d9e87Smiod 				continue;
1142305d9e87Smiod 			}
1143305d9e87Smiod 
1144305d9e87Smiod 			/* send TALK R3 - anything at old address? */
1145305d9e87Smiod 			command = ADBTALK(device, 3);
114674a0040aSmiod 			result = adb_op_sync((Ptr)send_string, (short)command);
1147305d9e87Smiod 			if (send_string[0] != 0) {
1148305d9e87Smiod 				/* check for valid device handler */
1149305d9e87Smiod 				switch (send_string[2]) {
1150305d9e87Smiod 				case 0:
1151305d9e87Smiod 				case 0xfd:
1152305d9e87Smiod 				case 0xfe:
1153305d9e87Smiod 				case 0xff:
1154305d9e87Smiod 					continue;	/* invalid, skip */
1155305d9e87Smiod 				}
1156305d9e87Smiod 
1157305d9e87Smiod 				/* new device found */
1158305d9e87Smiod 				/* update data for previously moved device */
11595e53181fSmpi 				sc->sc_devtable[i].curr_addr = saveptr;
1160305d9e87Smiod #ifdef ADB_DEBUG
1161305d9e87Smiod 				if (adb_debug & 0x80)
1162305d9e87Smiod 					printf_intr("old device at index %i\n",i);
1163305d9e87Smiod #endif
1164305d9e87Smiod 				/* add new device in table */
1165305d9e87Smiod #ifdef ADB_DEBUG
1166305d9e87Smiod 				if (adb_debug & 0x80)
1167305d9e87Smiod 					printf_intr("new device found\n");
1168305d9e87Smiod #endif
1169305d9e87Smiod 				if (saveptr > ADBNumDevices) {
1170305d9e87Smiod 					++ADBNumDevices;
1171305d9e87Smiod 					KASSERT(ADBNumDevices < 16);
1172305d9e87Smiod 				}
11735e53181fSmpi 				sc->sc_devtable[ADBNumDevices].handler_id =
1174305d9e87Smiod 					(int)send_string[2];
11755e53181fSmpi 				sc->sc_devtable[ADBNumDevices].orig_addr = device;
11765e53181fSmpi 				sc->sc_devtable[ADBNumDevices].curr_addr = device;
1177305d9e87Smiod 				/* These will be set correctly in adbsys.c */
1178305d9e87Smiod 				/* Until then, unsol. data will be ignored. */
11795e53181fSmpi 				sc->sc_devtable[ADBNumDevices].data = NULL;
11805e53181fSmpi 				sc->sc_devtable[ADBNumDevices].handler = NULL;
1181305d9e87Smiod 				/* find next unused address */
1182305d9e87Smiod 				for (x = saveptr; x > 0; x--) {
1183305d9e87Smiod 					if (-1 == get_adb_info(&data, x)) {
1184305d9e87Smiod 						saveptr = x;
1185305d9e87Smiod 						break;
1186305d9e87Smiod 					}
1187305d9e87Smiod 				}
1188305d9e87Smiod 				if (x == 0)
1189305d9e87Smiod 					saveptr = 0;
1190305d9e87Smiod #ifdef ADB_DEBUG
1191305d9e87Smiod 				if (adb_debug & 0x80)
1192305d9e87Smiod 					printf_intr("new free is 0x%02x\n",
1193305d9e87Smiod 					    saveptr);
1194305d9e87Smiod #endif
1195305d9e87Smiod 				nonewtimes = 0;
1196305d9e87Smiod 			} else {
1197305d9e87Smiod #ifdef ADB_DEBUG
1198305d9e87Smiod 				if (adb_debug & 0x80)
1199305d9e87Smiod 					printf_intr("moving back...\n");
1200305d9e87Smiod #endif
1201305d9e87Smiod 				/* move old device back */
1202305d9e87Smiod 				command = ADBLISTEN(saveptr, 3);
1203305d9e87Smiod 				send_string[0] = 2;
1204305d9e87Smiod 				send_string[1] = (u_char)(device | 0x60);
1205305d9e87Smiod 				send_string[2] = 0xfe;
120674a0040aSmiod 				adb_op_sync((Ptr)send_string, (short)command);
1207305d9e87Smiod 				delay(1000);
1208305d9e87Smiod 			}
1209305d9e87Smiod 		}
1210305d9e87Smiod 	}
1211305d9e87Smiod 
1212305d9e87Smiod #ifdef ADB_DEBUG
1213305d9e87Smiod 	if (adb_debug) {
1214305d9e87Smiod 		for (i = 1; i <= ADBNumDevices; i++) {
12155e53181fSmpi 			x = get_ind_adb_info(sc, &data, i);
1216305d9e87Smiod 			if (x != -1)
1217305d9e87Smiod 				printf_intr("index 0x%x, addr 0x%x, type 0x%x\n",
1218305d9e87Smiod 				    i, x, data.devType);
1219305d9e87Smiod 		}
1220305d9e87Smiod 	}
1221305d9e87Smiod #endif
1222305d9e87Smiod 
1223305d9e87Smiod #ifdef ADB_DEBUG
1224305d9e87Smiod 	if (adb_debug) {
1225305d9e87Smiod 		if (0 == ADBNumDevices)	/* tell user if no devices found */
1226305d9e87Smiod 			printf_intr("adb: no devices found\n");
1227305d9e87Smiod 	}
1228305d9e87Smiod #endif
1229305d9e87Smiod 
1230305d9e87Smiod 	adbStarting = 0;	/* not starting anymore */
1231305d9e87Smiod #ifdef ADB_DEBUG
1232305d9e87Smiod 	if (adb_debug)
1233305d9e87Smiod 		printf_intr("adb: adb_reinit complete\n");
1234305d9e87Smiod #endif
1235305d9e87Smiod 
1236305d9e87Smiod 	if (adbHardware == ADB_HW_CUDA) {
1237a7265231Scheloha 		timeout_set(&adb_cuda_timeout, adb_cuda_tickle, NULL);
1238305d9e87Smiod 		timeout_add(&adb_cuda_timeout, ADB_TICKLE_TICKS);
1239305d9e87Smiod 	}
1240305d9e87Smiod 
1241305d9e87Smiod 	if (adbHardware != ADB_HW_PMU)	/* ints must be on for PB? */
1242305d9e87Smiod 		splx(s);
1243305d9e87Smiod }
1244305d9e87Smiod 
1245305d9e87Smiod 
1246305d9e87Smiod /*
1247305d9e87Smiod  * adb_cmd_result
1248305d9e87Smiod  *
1249305d9e87Smiod  * This routine lets the caller know whether the specified adb command string
1250305d9e87Smiod  * should expect a returned result, such as a TALK command.
1251305d9e87Smiod  *
1252305d9e87Smiod  * returns: 0 if a result should be expected
1253305d9e87Smiod  *          1 if a result should NOT be expected
1254305d9e87Smiod  */
1255305d9e87Smiod int
adb_cmd_result(u_char * in)1256305d9e87Smiod adb_cmd_result(u_char *in)
1257305d9e87Smiod {
1258305d9e87Smiod 	switch (adbHardware) {
1259305d9e87Smiod 	case ADB_HW_CUDA:
1260305d9e87Smiod 		/* was it an ADB talk command? */
1261305d9e87Smiod 		if ((in[1] == 0x00) && ((in[2] & 0x0c) == 0x0c))
1262305d9e87Smiod 			return 0;
1263305d9e87Smiod 		/* was it an RTC/PRAM read date/time? */
1264305d9e87Smiod 		if ((in[1] == 0x01) && (in[2] == 0x03))
1265305d9e87Smiod 			return 0;
1266305d9e87Smiod 		return 1;
1267305d9e87Smiod 
1268305d9e87Smiod 	case ADB_HW_PMU:
1269305d9e87Smiod 		return 1;
1270305d9e87Smiod 
1271305d9e87Smiod 	default:
1272305d9e87Smiod 		return 1;
1273305d9e87Smiod 	}
1274305d9e87Smiod }
1275305d9e87Smiod 
1276305d9e87Smiod 
1277305d9e87Smiod /*
1278305d9e87Smiod  * adb_op_sync
1279305d9e87Smiod  *
1280305d9e87Smiod  * This routine does exactly what the adb_op routine does, except that after
1281305d9e87Smiod  * the adb_op is called, it waits until the return value is present before
1282305d9e87Smiod  * returning.
1283305d9e87Smiod  */
1284305d9e87Smiod int
adb_op_sync(Ptr buffer,short command)128574a0040aSmiod adb_op_sync(Ptr buffer, short command)
1286305d9e87Smiod {
1287305d9e87Smiod 	int tmout;
1288305d9e87Smiod 	int result;
1289305d9e87Smiod 	volatile int flag = 0;
1290305d9e87Smiod 
1291305d9e87Smiod 	result = adb_op(buffer, (void *)adb_op_comprout,
1292305d9e87Smiod 	    (void *)&flag, command);	/* send command */
1293305d9e87Smiod 	if (result == 0) {		/* send ok? */
1294305d9e87Smiod 		/*
1295305d9e87Smiod 		 * Total time to wait is calculated as follows:
1296305d9e87Smiod 		 *  - Tlt (stop to start time): 260 usec
1297305d9e87Smiod 		 *  - start bit: 100 usec
1298305d9e87Smiod 		 *  - up to 8 data bytes: 64 * 100 usec = 6400 usec
1299305d9e87Smiod 		 *  - stop bit (with SRQ): 140 usec
1300305d9e87Smiod 		 * Total: 6900 usec
1301305d9e87Smiod 		 *
1302305d9e87Smiod 		 * This is the total time allowed by the specification.  Any
1303305d9e87Smiod 		 * device that doesn't conform to this will fail to operate
1304305d9e87Smiod 		 * properly on some Apple systems.  In spite of this we
1305305d9e87Smiod 		 * double the time to wait; some Cuda-based apparently
1306305d9e87Smiod 		 * queues some commands and allows the main CPU to continue
1307305d9e87Smiod 		 * processing (radical concept, eh?).  To be safe, allow
1308305d9e87Smiod 		 * time for two complete ADB transactions to occur.
1309305d9e87Smiod 		 */
1310305d9e87Smiod 		for (tmout = 13800; !flag && tmout >= 10; tmout -= 10)
1311305d9e87Smiod 			delay(10);
1312305d9e87Smiod 		if (!flag && tmout > 0)
1313305d9e87Smiod 			delay(tmout);
1314305d9e87Smiod 
1315305d9e87Smiod 		if (!flag)
1316305d9e87Smiod 			result = -2;
1317305d9e87Smiod 	}
1318305d9e87Smiod 
1319305d9e87Smiod 	return result;
1320305d9e87Smiod }
1321305d9e87Smiod 
1322305d9e87Smiod 
1323305d9e87Smiod /*
1324305d9e87Smiod  * adb_op_comprout
1325305d9e87Smiod  *
1326305d9e87Smiod  * This function is used by the adb_op_sync routine so it knows when the
1327305d9e87Smiod  * function is done.
1328305d9e87Smiod  */
1329305d9e87Smiod void
adb_op_comprout(caddr_t buffer,caddr_t compdata,int cmd)133074a0040aSmiod adb_op_comprout(caddr_t buffer, caddr_t compdata, int cmd)
1331305d9e87Smiod {
133274a0040aSmiod 	*(int *)compdata = 0x01;		/* update flag value */
1333305d9e87Smiod }
1334305d9e87Smiod 
1335305d9e87Smiod int
count_adbs(struct adb_softc * sc)13365e53181fSmpi count_adbs(struct adb_softc *sc)
1337305d9e87Smiod {
1338305d9e87Smiod 	int i;
1339305d9e87Smiod 	int found;
1340305d9e87Smiod 
1341305d9e87Smiod 	found = 0;
1342305d9e87Smiod 
1343305d9e87Smiod 	for (i = 1; i < 16; i++)
13445e53181fSmpi 		if (0 != sc->sc_devtable[i].handler_id)
1345305d9e87Smiod 			found++;
1346305d9e87Smiod 
1347305d9e87Smiod 	return found;
1348305d9e87Smiod }
1349305d9e87Smiod 
1350305d9e87Smiod int
get_ind_adb_info(struct adb_softc * sc,ADBDataBlock * info,int index)13515e53181fSmpi get_ind_adb_info(struct adb_softc *sc, ADBDataBlock * info, int index)
1352305d9e87Smiod {
1353305d9e87Smiod 	if ((index < 1) || (index > 15))	/* check range 1-15 */
1354305d9e87Smiod 		return (-1);
1355305d9e87Smiod 
1356305d9e87Smiod #ifdef ADB_DEBUG
1357305d9e87Smiod 	if (adb_debug & 0x80)
13585e53181fSmpi 		printf_intr("index 0x%x handler id 0x%x\n", index,
13595e53181fSmpi 		    sc->sc_devtable[index].handler_id);
1360305d9e87Smiod #endif
13615e53181fSmpi 	if (0 == sc->sc_devtable[index].handler_id)	/* make sure it's a valid entry */
1362305d9e87Smiod 		return (-1);
1363305d9e87Smiod 
13645e53181fSmpi 	info->devType = sc->sc_devtable[index].handler_id;
13655e53181fSmpi 	info->origADBAddr = sc->sc_devtable[index].orig_addr;
13665e53181fSmpi 	info->dbServiceRtPtr = (Ptr)sc->sc_devtable[index].handler;
13675e53181fSmpi 	info->dbDataAreaAddr = (Ptr)sc->sc_devtable[index].data;
1368305d9e87Smiod 
13695e53181fSmpi 	return (sc->sc_devtable[index].curr_addr);
1370305d9e87Smiod }
1371305d9e87Smiod 
1372305d9e87Smiod int
get_adb_info(ADBDataBlock * info,int adbAddr)1373305d9e87Smiod get_adb_info(ADBDataBlock * info, int adbAddr)
1374305d9e87Smiod {
13755e53181fSmpi 	struct adb_softc *sc = adb_cd.cd_devs[0];
1376305d9e87Smiod 	int i;
1377305d9e87Smiod 
13785e53181fSmpi 	if (sc == NULL)
13795e53181fSmpi 		return (-1);
13805e53181fSmpi 
1381305d9e87Smiod 	if ((adbAddr < 1) || (adbAddr > 15))	/* check range 1-15 */
1382305d9e87Smiod 		return (-1);
1383305d9e87Smiod 
1384305d9e87Smiod 	for (i = 1; i < 15; i++)
13855e53181fSmpi 		if (sc->sc_devtable[i].curr_addr == adbAddr) {
13865e53181fSmpi 			info->devType = sc->sc_devtable[i].handler_id;
13875e53181fSmpi 			info->origADBAddr = sc->sc_devtable[i].orig_addr;
13885e53181fSmpi 			info->dbServiceRtPtr = (Ptr)sc->sc_devtable[i].handler;
13895e53181fSmpi 			info->dbDataAreaAddr = sc->sc_devtable[i].data;
1390305d9e87Smiod 			return 0;	/* found */
1391305d9e87Smiod 		}
1392305d9e87Smiod 
1393305d9e87Smiod 	return (-1);		/* not found */
1394305d9e87Smiod }
1395305d9e87Smiod 
1396305d9e87Smiod int
set_adb_info(ADBSetInfoBlock * info,int adbAddr)1397305d9e87Smiod set_adb_info(ADBSetInfoBlock * info, int adbAddr)
1398305d9e87Smiod {
13995e53181fSmpi 	struct adb_softc *sc = adb_cd.cd_devs[0];
1400305d9e87Smiod 	int i;
1401305d9e87Smiod 
14025e53181fSmpi 	if (sc == NULL)
14035e53181fSmpi 		return (-1);
14045e53181fSmpi 
1405305d9e87Smiod 	if ((adbAddr < 1) || (adbAddr > 15))	/* check range 1-15 */
1406305d9e87Smiod 		return (-1);
1407305d9e87Smiod 
1408305d9e87Smiod 	for (i = 1; i < 15; i++)
14095e53181fSmpi 		if (sc->sc_devtable[i].curr_addr == adbAddr) {
14105e53181fSmpi 			sc->sc_devtable[i].handler =
1411305d9e87Smiod 			    (void *)(info->siServiceRtPtr);
14125e53181fSmpi 			sc->sc_devtable[i].data = info->siDataAreaAddr;
1413305d9e87Smiod 			return 0;	/* found */
1414305d9e87Smiod 		}
1415305d9e87Smiod 
1416305d9e87Smiod 	return (-1);		/* not found */
1417305d9e87Smiod 
1418305d9e87Smiod }
1419305d9e87Smiod 
1420305d9e87Smiod /* caller should really use machine-independent version: getPramTime */
1421305d9e87Smiod /* this version does pseudo-adb access only */
1422305d9e87Smiod int
adb_read_date_time(time_t * time)1423305d9e87Smiod adb_read_date_time(time_t *time)
1424305d9e87Smiod {
1425305d9e87Smiod 	u_char output[ADB_MAX_MSG_LENGTH];
1426305d9e87Smiod 	int result;
1427305d9e87Smiod 	int retcode;
1428305d9e87Smiod 	volatile int flag = 0;
14293e481181Smpi 	u_int32_t t;
1430305d9e87Smiod 
1431305d9e87Smiod 	switch (adbHardware) {
1432305d9e87Smiod 	case ADB_HW_PMU:
1433305d9e87Smiod 		pm_read_date_time(time);
1434305d9e87Smiod 		retcode = 0;
1435305d9e87Smiod 		break;
1436305d9e87Smiod 
1437305d9e87Smiod 	case ADB_HW_CUDA:
1438305d9e87Smiod 		output[0] = 0x02;	/* 2 byte message */
1439305d9e87Smiod 		output[1] = 0x01;	/* to pram/rtc device */
1440305d9e87Smiod 		output[2] = 0x03;	/* read date/time */
1441305d9e87Smiod 		result = send_adb_cuda((u_char *)output, (u_char *)output,
1442305d9e87Smiod 		    (void *)adb_op_comprout, (void *)&flag, (int)0);
1443305d9e87Smiod 		if (result != 0) {	/* exit if not sent */
1444305d9e87Smiod 			retcode = -1;
1445305d9e87Smiod 			break;
1446305d9e87Smiod 		}
1447305d9e87Smiod 
1448305d9e87Smiod 		while (0 == flag)	/* wait for result */
1449305d9e87Smiod 			;
1450305d9e87Smiod 
1451305d9e87Smiod 		delay(20); /* completion occurs too soon? */
14523e481181Smpi 		memcpy(&t, output + 1, sizeof(t));
14533e481181Smpi 		*time = (time_t)t;
1454305d9e87Smiod 		retcode = 0;
1455305d9e87Smiod 		break;
1456305d9e87Smiod 
1457305d9e87Smiod 	case ADB_HW_UNKNOWN:
1458305d9e87Smiod 	default:
1459305d9e87Smiod 		retcode = -1;
1460305d9e87Smiod 		break;
1461305d9e87Smiod 	}
1462305d9e87Smiod 	if (retcode == 0) {
1463305d9e87Smiod #define DIFF19041970 2082844800
1464305d9e87Smiod 		*time -= DIFF19041970;
1465305d9e87Smiod 
1466305d9e87Smiod 	} else {
1467305d9e87Smiod 		*time = 0;
1468305d9e87Smiod 	}
1469305d9e87Smiod 	return retcode;
1470305d9e87Smiod }
1471305d9e87Smiod 
1472305d9e87Smiod /* caller should really use machine-independent version: setPramTime */
1473305d9e87Smiod /* this version does pseudo-adb access only */
1474305d9e87Smiod int
adb_set_date_time(time_t time)1475305d9e87Smiod adb_set_date_time(time_t time)
1476305d9e87Smiod {
1477305d9e87Smiod 	u_char output[ADB_MAX_MSG_LENGTH];
1478305d9e87Smiod 	int result;
1479305d9e87Smiod 	volatile int flag = 0;
14803e481181Smpi 	u_int32_t t;
1481305d9e87Smiod 
1482305d9e87Smiod 	time += DIFF19041970;
1483305d9e87Smiod 	switch (adbHardware) {
1484305d9e87Smiod 
1485305d9e87Smiod 	case ADB_HW_CUDA:
14863e481181Smpi 		t = time;		/* XXX eventually truncates */
14873e481181Smpi 
1488305d9e87Smiod 		output[0] = 0x06;	/* 6 byte message */
1489305d9e87Smiod 		output[1] = 0x01;	/* to pram/rtc device */
1490305d9e87Smiod 		output[2] = 0x09;	/* set date/time */
14913e481181Smpi 		output[3] = (u_char)(t >> 24);
14923e481181Smpi 		output[4] = (u_char)(t >> 16);
14933e481181Smpi 		output[5] = (u_char)(t >> 8);
14943e481181Smpi 		output[6] = (u_char)(t);
149514bf419fSkrw 		result = send_adb_cuda((u_char *)output, NULL,
1496305d9e87Smiod 		    (void *)adb_op_comprout, (void *)&flag, (int)0);
1497305d9e87Smiod 		if (result != 0)	/* exit if not sent */
1498305d9e87Smiod 			return -1;
1499305d9e87Smiod 
1500305d9e87Smiod 		while (0 == flag)	/* wait for send to finish */
1501305d9e87Smiod 			;
1502305d9e87Smiod 
1503305d9e87Smiod 		return 0;
1504305d9e87Smiod 
1505305d9e87Smiod 	case ADB_HW_PMU:
1506305d9e87Smiod 		pm_set_date_time(time);
1507305d9e87Smiod 		return 0;
1508305d9e87Smiod 
1509305d9e87Smiod 	default:
1510305d9e87Smiod 		return -1;
1511305d9e87Smiod 	}
1512305d9e87Smiod }
1513305d9e87Smiod 
1514305d9e87Smiod 
1515305d9e87Smiod int
adb_poweroff(void)1516305d9e87Smiod adb_poweroff(void)
1517305d9e87Smiod {
1518305d9e87Smiod 	u_char output[ADB_MAX_MSG_LENGTH];
1519305d9e87Smiod 	int result;
1520305d9e87Smiod 
1521305d9e87Smiod 	adb_polling = 1;
1522305d9e87Smiod 
1523305d9e87Smiod 	switch (adbHardware) {
1524305d9e87Smiod 	case ADB_HW_PMU:
152504c80311Sgwk 		/* Clear the wake on AC loss event */
152604c80311Sgwk 		pmu_fileserver_mode(0);
1527305d9e87Smiod 		pm_adb_poweroff();
1528305d9e87Smiod 
1529*36dba039Sjsg 		for (;;)	/* wait for power off */
1530*36dba039Sjsg 			;
1531305d9e87Smiod 
1532305d9e87Smiod 		return 0;
1533305d9e87Smiod 
1534305d9e87Smiod 	case ADB_HW_CUDA:
1535305d9e87Smiod 		output[0] = 0x02;	/* 2 byte message */
1536305d9e87Smiod 		output[1] = 0x01;	/* to pram/rtc/soft-power device */
1537ab4b69ddSgwk 		output[2] = 0x0a;	/* set poweroff */
153814bf419fSkrw 		result = send_adb_cuda((u_char *)output, NULL,
153914bf419fSkrw 		    NULL, NULL, (int)0);
1540305d9e87Smiod 		if (result != 0)	/* exit if not sent */
1541305d9e87Smiod 			return -1;
1542305d9e87Smiod 
1543*36dba039Sjsg 		for (;;)		/* wait for power off */
1544*36dba039Sjsg 			;
1545305d9e87Smiod 
1546305d9e87Smiod 		return 0;
1547305d9e87Smiod 
1548305d9e87Smiod 	default:
1549305d9e87Smiod 		return -1;
1550305d9e87Smiod 	}
1551305d9e87Smiod }
1552305d9e87Smiod 
1553305d9e87Smiod void
setsoftadb(void)1554af7e7ea9Sderaadt setsoftadb(void)
1555305d9e87Smiod {
1556305d9e87Smiod 	if (!timeout_initialized(&adb_softintr_timeout))
1557305d9e87Smiod 		timeout_set(&adb_softintr_timeout, (void *)adb_soft_intr, NULL);
1558305d9e87Smiod 	timeout_add(&adb_softintr_timeout, 1);
1559305d9e87Smiod }
1560305d9e87Smiod 
1561305d9e87Smiod void
adb_cuda_autopoll(void)1562af7e7ea9Sderaadt adb_cuda_autopoll(void)
1563305d9e87Smiod {
1564305d9e87Smiod 	volatile int flag = 0;
1565305d9e87Smiod 	int result;
1566305d9e87Smiod 	u_char output[16];
1567305d9e87Smiod 
1568305d9e87Smiod 	output[0] = 0x03;	/* 3-byte message */
1569ab4b69ddSgwk 	output[1] = 0x01;	/* to pram/rtc/soft-power device */
1570305d9e87Smiod 	output[2] = 0x01;	/* cuda autopoll */
1571305d9e87Smiod 	output[3] = 0x01;
1572305d9e87Smiod 	result = send_adb_cuda(output, output, adb_op_comprout,
1573305d9e87Smiod 	    (void *)&flag, 0);
1574305d9e87Smiod 	if (result != 0)	/* exit if not sent */
1575305d9e87Smiod 		return;
1576305d9e87Smiod 
1577305d9e87Smiod 	while (flag == 0);	/* wait for result */
1578305d9e87Smiod }
1579305d9e87Smiod 
1580305d9e87Smiod void
adb_cuda_fileserver_mode(void)1581af7e7ea9Sderaadt adb_cuda_fileserver_mode(void)
1582ab4b69ddSgwk {
1583ab4b69ddSgwk 	volatile int flag = 0;
1584ab4b69ddSgwk 	int result;
1585ab4b69ddSgwk 	u_char output[16];
1586ab4b69ddSgwk 
1587ab4b69ddSgwk 	output[0] = 0x03;	/* 3-byte message */
1588ab4b69ddSgwk 	output[1] = 0x01; 	/* to pram/rtc device/soft-power device */
1589ab4b69ddSgwk 	output[2] = 0x13;	/* cuda file server mode */
15903a3b5185Sgwk 	output[3] = 0x01;	/* True - Turn on after AC loss */
1591ab4b69ddSgwk 
1592ab4b69ddSgwk 	result = send_adb_cuda(output, output, adb_op_comprout,
1593ab4b69ddSgwk 	    (void *)&flag, 0);
1594ab4b69ddSgwk 	if (result != 0)
1595ab4b69ddSgwk 		return;
1596ab4b69ddSgwk 
1597ab4b69ddSgwk 	while (flag == 0);
1598ab4b69ddSgwk }
1599ab4b69ddSgwk 
1600ab4b69ddSgwk void
adb_restart(void)1601af7e7ea9Sderaadt adb_restart(void)
1602305d9e87Smiod {
1603305d9e87Smiod 	int result;
1604305d9e87Smiod 	u_char output[16];
1605305d9e87Smiod 
1606305d9e87Smiod 	adb_polling = 1;
1607305d9e87Smiod 
1608305d9e87Smiod 	switch (adbHardware) {
1609305d9e87Smiod 	case ADB_HW_CUDA:
1610305d9e87Smiod 		output[0] = 0x02;	/* 2 byte message */
1611305d9e87Smiod 		output[1] = 0x01;	/* to pram/rtc/soft-power device */
1612305d9e87Smiod 		output[2] = 0x11;	/* restart */
161314bf419fSkrw 		result = send_adb_cuda((u_char *)output, NULL,
161414bf419fSkrw 				       NULL, NULL, (int)0);
1615305d9e87Smiod 		if (result != 0)	/* exit if not sent */
1616305d9e87Smiod 			return;
1617305d9e87Smiod 		while (1);		/* not return */
1618305d9e87Smiod 
1619305d9e87Smiod 	case ADB_HW_PMU:
1620305d9e87Smiod 		pm_adb_restart();
1621305d9e87Smiod 		while (1);		/* not return */
1622305d9e87Smiod 	}
1623305d9e87Smiod }
1624305d9e87Smiod 
1625d9a5f17fSdrahn /*
1626d9a5f17fSdrahn  * Driver definition.
1627d9a5f17fSdrahn  */
1628305d9e87Smiod 
1629305d9e87Smiod int	adbmatch(struct device *, void *, void *);
1630305d9e87Smiod void	adbattach(struct device *, struct device *, void *);
1631305d9e87Smiod 
163289ed722cSmpi const struct cfattach adb_ca = {
1633d9a5f17fSdrahn 	sizeof(struct adb_softc), adbmatch, adbattach
1634d9a5f17fSdrahn };
1635d9a5f17fSdrahn 
1636d80b8bf7Smiod int
adbmatch(struct device * parent,void * cf,void * aux)1637093da1aaSdrahn adbmatch(struct device *parent, void *cf, void *aux)
1638d9a5f17fSdrahn {
1639d9a5f17fSdrahn 	struct confargs *ca = aux;
1640d9a5f17fSdrahn 
1641d9a5f17fSdrahn 	if (ca->ca_nreg < 8)
1642d9a5f17fSdrahn 		return 0;
1643d9a5f17fSdrahn 
1644d9a5f17fSdrahn 	if (ca->ca_nintr < 4)
1645d9a5f17fSdrahn 		return 0;
1646d9a5f17fSdrahn 
1647d9a5f17fSdrahn 	if (strcmp(ca->ca_name, "via-cuda") == 0)
1648d9a5f17fSdrahn 		return 1;
1649d9a5f17fSdrahn 
1650d9a5f17fSdrahn 	if (strcmp(ca->ca_name, "via-pmu") == 0)
1651d9a5f17fSdrahn 		return 1;
1652d9a5f17fSdrahn 
1653d9a5f17fSdrahn 	return 0;
1654d9a5f17fSdrahn }
1655d9a5f17fSdrahn 
1656d80b8bf7Smiod void
adbattach(struct device * parent,struct device * self,void * aux)1657093da1aaSdrahn adbattach(struct device *parent, struct device *self, void *aux)
1658d9a5f17fSdrahn {
1659d9a5f17fSdrahn 	struct adb_softc *sc = (struct adb_softc *)self;
1660d9a5f17fSdrahn 	struct confargs *ca = aux;
1661d01ed945Skettenis 	struct confargs nca;
1662d01ed945Skettenis 	char name[32];
1663d01ed945Skettenis 	int node;
1664d9a5f17fSdrahn 	ADBDataBlock adbdata;
1665d9a5f17fSdrahn 	struct adb_attach_args aa_args;
1666d9a5f17fSdrahn 	int totaladbs;
1667d9a5f17fSdrahn 	int adbindex, adbaddr;
1668d9a5f17fSdrahn 
1669bdedaf02Sgkoehler #if !defined(SMALL_KERNEL) && defined(SUSPEND)
1670bdedaf02Sgkoehler 	adb_suspendq = taskq_create(sc->sc_dev.dv_xname, 1, IPL_TTY, 0);
1671bdedaf02Sgkoehler 	if (adb_suspendq == NULL) {
1672bdedaf02Sgkoehler 		printf(": can't create taskq\n");
1673bdedaf02Sgkoehler 		return;
1674bdedaf02Sgkoehler 	}
1675bdedaf02Sgkoehler #endif
1676bdedaf02Sgkoehler 
1677d9a5f17fSdrahn 	ca->ca_reg[0] += ca->ca_baseaddr;
1678d9a5f17fSdrahn 
1679d9a5f17fSdrahn 	sc->sc_regbase = mapiodev(ca->ca_reg[0], ca->ca_reg[1]);
1680d9a5f17fSdrahn 	Via1Base = sc->sc_regbase;
1681d9a5f17fSdrahn 
1682d9a5f17fSdrahn 	if (strcmp(ca->ca_name, "via-cuda") == 0)
1683d9a5f17fSdrahn 		adbHardware = ADB_HW_CUDA;
1684873b33feSmiod 	else if (strcmp(ca->ca_name, "via-pmu") == 0) {
1685e73bc5f9Smartin 		adbHardware = ADB_HW_PMU;
1686c1cc27a7Sgkoehler 		pm_in_adbattach(sc->sc_dev.dv_xname);
1687d9a5f17fSdrahn 
1688873b33feSmiod 		/*
1689873b33feSmiod 		 * Bus reset can take a long time if no adb devices are
1690873b33feSmiod 		 * connected, e.g. on a Mac Mini; so check for an adb
1691873b33feSmiod 		 * child in the OF tree to speed up pm_adb_op().
1692873b33feSmiod 		 */
1693873b33feSmiod 		adbempty = 1;
1694873b33feSmiod 		for (node = OF_child(ca->ca_node); node; node = OF_peer(node)) {
1695873b33feSmiod 			if (OF_getprop(node, "name", name, sizeof name) <= 0)
1696873b33feSmiod 				continue;
1697873b33feSmiod 			if (strcmp(name, "adb") == 0) {
1698873b33feSmiod 				adbempty = 0;
1699873b33feSmiod 				break;
1700873b33feSmiod 			}
1701873b33feSmiod 		}
1702873b33feSmiod 	}
1703873b33feSmiod 
1704d9a5f17fSdrahn 	adb_polling = 1;
1705418200e4Smpi 	if (!adbempty) {
17065e53181fSmpi 		adb_reinit(sc);
17075e53181fSmpi 		totaladbs = count_adbs(sc);
1708418200e4Smpi 		printf(": irq %d, %s, %d target%s", ca->ca_intr[0], ca->ca_name,
1709418200e4Smpi 		    totaladbs, (totaladbs == 1) ? "" : "s");
1710418200e4Smpi 	}
1711418200e4Smpi 	printf("\n");
1712d9a5f17fSdrahn 
1713bb536b7dSmpi 	mac_intr_establish(parent, ca->ca_intr[0], IST_LEVEL, IPL_TTY,
17141ac74572Sderaadt 	    adb_intr, sc, sc->sc_dev.dv_xname);
1715d9a5f17fSdrahn 
1716d9a5f17fSdrahn 	/* init powerpc globals which control RTC functionality */
1717d9a5f17fSdrahn 	time_read = adb_read_date_time;
1718d9a5f17fSdrahn 	time_write = adb_set_date_time;
1719d9a5f17fSdrahn 
1720d9076e62Sdrahn #if NAPM > 0
17216ca343deSmpi 	if (adbHardware == ADB_HW_PMU) {
1722d9076e62Sdrahn 		/* Magic for signalling the apm driver to match. */
17236ca343deSmpi 		nca.ca_name = "apm";
17246ca343deSmpi 		nca.ca_node = node;
17256ca343deSmpi 		config_found(self, &nca, NULL);
17266ca343deSmpi 	}
1727d9076e62Sdrahn #endif
1728d9076e62Sdrahn 
1729d01ed945Skettenis 	/* Attach I2C controller. */
1730d01ed945Skettenis 	for (node = OF_child(ca->ca_node); node; node = OF_peer(node)) {
1731d01ed945Skettenis 		if (OF_getprop(node, "name", name, sizeof name) <= 0)
1732d01ed945Skettenis 			continue;
1733d01ed945Skettenis 		if (strcmp(name, "pmu-i2c") == 0) {
1734715b6a7bSderaadt 			nca.ca_name = "piic";
1735d01ed945Skettenis 			nca.ca_node = node;
1736d01ed945Skettenis 			config_found(self, &nca, NULL);
1737d01ed945Skettenis 		}
1738d01ed945Skettenis 	}
1739ab4b69ddSgwk 
1740ab4b69ddSgwk 	if (adbHardware == ADB_HW_CUDA)
17413a3b5185Sgwk 		adb_cuda_fileserver_mode();
17426784ab1fStobhe 	if (adbHardware == ADB_HW_PMU) {
17436784ab1fStobhe 		wskbd_get_backlight = pmu_get_backlight;
17446784ab1fStobhe 		wskbd_set_backlight = pmu_set_backlight;
174504c80311Sgwk 		pmu_fileserver_mode(1);
17466784ab1fStobhe 	}
174753b2c9b4Smiod 
17480547ba71Smpi 	/*
17490547ba71Smpi 	 * XXX If the machine doesn't have an ADB bus (PowerBook5,6+)
17500547ba71Smpi 	 * yes it sounds stupid to attach adb(4), but don't try to send
17510547ba71Smpi 	 * ADB commands otherwise the PMU may shutdown the machine...
17520547ba71Smpi 	 */
17530547ba71Smpi 	if (adbempty)
17540547ba71Smpi 		return;
17550547ba71Smpi 
17560547ba71Smpi 	/* for each ADB device */
17570547ba71Smpi 	for (adbindex = 1; adbindex <= totaladbs; adbindex++) {
17580547ba71Smpi 		/* Get the ADB information */
17595e53181fSmpi 		adbaddr = get_ind_adb_info(sc, &adbdata, adbindex);
17600547ba71Smpi 
17610547ba71Smpi 		aa_args.name = adb_device_name;
17620547ba71Smpi 		aa_args.origaddr = adbdata.origADBAddr;
17630547ba71Smpi 		aa_args.adbaddr = adbaddr;
17640547ba71Smpi 		aa_args.handler_id = adbdata.devType;
17650547ba71Smpi 
17660547ba71Smpi 		(void)config_found(self, &aa_args, adbprint);
17670547ba71Smpi 	}
17680547ba71Smpi 
176953b2c9b4Smiod 	if (adbHardware == ADB_HW_CUDA)
177053b2c9b4Smiod 		adb_cuda_autopoll();
177153b2c9b4Smiod 	adb_polling = 0;
1772d9a5f17fSdrahn }
17736784ab1fStobhe 
17746784ab1fStobhe int
pmu_get_backlight(struct wskbd_backlight * kbl)17756784ab1fStobhe pmu_get_backlight(struct wskbd_backlight *kbl)
17766784ab1fStobhe {
17776784ab1fStobhe 	kbl->min = 0;
17786784ab1fStobhe 	kbl->max = 0xff;
17796784ab1fStobhe 	kbl->curval = pmu_backlight;
17806784ab1fStobhe 	return 0;
17816784ab1fStobhe }
17826784ab1fStobhe 
17836784ab1fStobhe int
pmu_set_backlight(struct wskbd_backlight * kbl)17846784ab1fStobhe pmu_set_backlight(struct wskbd_backlight *kbl)
17856784ab1fStobhe {
17866784ab1fStobhe 	pmu_backlight = kbl->curval;
17876784ab1fStobhe 	return pmu_set_kbl(pmu_backlight);
17886784ab1fStobhe }
1789