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