pm_direct.c revision 1.18
1/*	$NetBSD: pm_direct.c,v 1.18 2001/11/20 03:19:42 chs Exp $	*/
2
3/*
4 * Copyright (C) 1997 Takashi Hamada
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *  This product includes software developed by Takashi Hamada
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32/* From: pm_direct.c 1.3 03/18/98 Takashi Hamada */
33
34#include "opt_adb.h"
35
36#ifdef DEBUG
37#ifndef ADB_DEBUG
38#define ADB_DEBUG
39#endif
40#endif
41
42/* #define	PM_GRAB_SI	1 */
43
44#include <sys/types.h>
45#include <sys/cdefs.h>
46#include <sys/systm.h>
47
48#include <machine/viareg.h>
49#include <machine/param.h>
50#include <machine/cpu.h>
51#include <machine/adbsys.h>
52
53#include <mac68k/mac68k/macrom.h>
54#include <mac68k/dev/adbvar.h>
55#include <mac68k/dev/pm_direct.h>
56
57/* hardware dependent values */
58extern u_short ADBDelay;
59extern u_int32_t HwCfgFlags3;
60extern struct mac68k_machine_S mac68k_machine;
61
62
63/* define the types of the Power Manager */
64#define PM_HW_UNKNOWN		0x00	/* don't know */
65#define PM_HW_PB1XX		0x01	/* PowerBook 1XX series */
66#define	PM_HW_PB5XX		0x02	/* PowerBook Duo and 5XX series */
67
68/* useful macros */
69#define PM_SR()			via_reg(VIA1, vSR)
70#define PM_VIA_INTR_ENABLE()	via_reg(VIA1, vIER) = 0x90
71#define PM_VIA_INTR_DISABLE()	via_reg(VIA1, vIER) = 0x10
72#define PM_VIA_CLR_INTR()	via_reg(VIA1, vIFR) = 0x90
73#define PM_SET_STATE_ACKON()	via_reg(VIA2, vBufB) |= 0x04
74#define PM_SET_STATE_ACKOFF()	via_reg(VIA2, vBufB) &= ~0x04
75#define PM_IS_ON		(0x02 == (via_reg(VIA2, vBufB) & 0x02))
76#define PM_IS_OFF		(0x00 == (via_reg(VIA2, vBufB) & 0x02))
77
78/*
79 * Variables for internal use
80 */
81int	pmHardware = PM_HW_UNKNOWN;
82u_short	pm_existent_ADB_devices = 0x0;	/* each bit expresses the existent ADB device */
83u_int	pm_LCD_brightness = 0x0;
84u_int	pm_LCD_contrast = 0x0;
85u_int	pm_counter = 0;			/* clock count */
86
87/* these values shows that number of data returned after 'send' cmd is sent */
88char pm_send_cmd_type[] = {
89	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
90	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
91	0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
92	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
93	0xff, 0x00, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff,
94	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
95	0x04, 0x14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
96	0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff,
97	0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
98	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
99	0x01, 0x00, 0x02, 0x02, 0xff, 0x01, 0x03, 0x01,
100	0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
101	0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
102	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
103	0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
104	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x04, 0x04,
105	0x04, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
106	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
107	0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
108	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
109	0x02, 0x02, 0x02, 0x04, 0xff, 0x00, 0xff, 0xff,
110	0x01, 0x01, 0x03, 0x02, 0xff, 0xff, 0xff, 0xff,
111	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
112	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
113	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
114	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
115	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
116	0x01, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
117	0xff, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
118	0x03, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00,
119	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
120	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
121};
122
123/* these values shows that number of data returned after 'receive' cmd is sent */
124char pm_receive_cmd_type[] = {
125	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
127	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128	0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
129	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
131	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132	0x05, 0x15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
133	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134	0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
135	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136	0x02, 0x00, 0x03, 0x03, 0xff, 0xff, 0xff, 0xff,
137	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138	0x04, 0x04, 0x03, 0x09, 0xff, 0xff, 0xff, 0xff,
139	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01,
141	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142	0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
143	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144	0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
145	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146	0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
147	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
149	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
151	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152	0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff,
153	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
154	0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0xff, 0x00,
155	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
157};
158
159
160/*
161 * Define the private functions
162 */
163
164/* for debugging */
165#ifdef ADB_DEBUG
166void	pm_printerr __P((char *, int, int, char *));
167#endif
168
169int	pm_wait_busy __P((int));
170int	pm_wait_free __P((int));
171
172/* these functions are for the PB1XX series */
173int	pm_receive_pm1 __P((u_char *));
174int	pm_send_pm1 __P((u_char,int));
175int	pm_pmgrop_pm1 __P((PMData *));
176void	pm_intr_pm1 __P((void *));
177
178/* these functions are for the PB Duo series and the PB 5XX series */
179int	pm_receive_pm2 __P((u_char *));
180int	pm_send_pm2 __P((u_char));
181int	pm_pmgrop_pm2 __P((PMData *));
182void	pm_intr_pm2 __P((void *));
183
184/* this function is MRG-Based (for testing) */
185int	pm_pmgrop_mrg __P((PMData *));
186
187/* these functions are called from adb_direct.c */
188void	pm_setup_adb __P((void));
189void	pm_check_adb_devices __P((int));
190void	pm_intr __P((void *));
191int	pm_adb_op __P((u_char *, void *, void *, int));
192void	pm_hw_setup __P((void));
193
194/* these functions also use the variables of adb_direct.c */
195void	pm_adb_get_TALK_result __P((PMData *));
196void	pm_adb_get_ADB_data __P((PMData *));
197void	pm_adb_poll_next_device_pm1 __P((PMData *));
198
199
200/*
201 * These variables are in adb_direct.c.
202 */
203extern u_char	*adbBuffer;	/* pointer to user data area */
204extern void	*adbCompRout;	/* pointer to the completion routine */
205extern void	*adbCompData;	/* pointer to the completion routine data */
206extern int	adbWaiting;	/* waiting for return data from the device */
207extern int	adbWaitingCmd;	/* ADB command we are waiting for */
208extern int	adbStarting;	/* doing ADB reinit, so do "polling" differently */
209
210#define	ADB_MAX_MSG_LENGTH	16
211#define	ADB_MAX_HDR_LENGTH	8
212struct adbCommand {
213	u_char	header[ADB_MAX_HDR_LENGTH];	/* not used yet */
214	u_char	data[ADB_MAX_MSG_LENGTH];	/* packet data only */
215	u_char	*saveBuf;	/* where to save result */
216	u_char	*compRout;	/* completion routine pointer */
217	u_char	*compData;	/* completion routine data pointer */
218	u_int	cmd;		/* the original command for this data */
219	u_int	unsol;		/* 1 if packet was unsolicited */
220	u_int	ack_only;	/* 1 for no special processing */
221};
222extern	void	adb_pass_up __P((struct adbCommand *));
223
224#ifdef ADB_DEBUG
225/*
226 * This function dumps contents of the PMData
227 */
228void
229pm_printerr(ttl, rval, num, data)
230	char *ttl;
231	int rval;
232	int num;
233	char *data;
234{
235	int i;
236
237	printf("pm: %s:%04x %02x ", ttl, rval, num);
238	for (i = 0; i < num; i++)
239		printf("%02x ", data[i]);
240	printf("\n");
241}
242#endif
243
244
245
246/*
247 * Check the hardware type of the Power Manager
248 */
249void
250pm_setup_adb()
251{
252	switch (mac68k_machine.machineid) {
253		case MACH_MACPB140:
254		case MACH_MACPB145:
255		case MACH_MACPB150:
256		case MACH_MACPB160:
257		case MACH_MACPB165:
258		case MACH_MACPB165C:
259		case MACH_MACPB170:
260		case MACH_MACPB180:
261		case MACH_MACPB180C:
262			pmHardware = PM_HW_PB1XX;
263			break;
264		case MACH_MACPB210:
265		case MACH_MACPB230:
266		case MACH_MACPB250:
267		case MACH_MACPB270:
268		case MACH_MACPB280:
269		case MACH_MACPB280C:
270		case MACH_MACPB500:
271			pmHardware = PM_HW_PB5XX;
272			break;
273		default:
274			break;
275	}
276}
277
278
279/*
280 * Check the existent ADB devices
281 */
282void
283pm_check_adb_devices(id)
284	int id;
285{
286	u_short ed = 0x1;
287
288	ed <<= id;
289	pm_existent_ADB_devices |= ed;
290}
291
292
293/*
294 * Wait until PM IC is busy
295 */
296int
297pm_wait_busy(delay)
298	int delay;
299{
300	while (PM_IS_ON) {
301#ifdef PM_GRAB_SI
302		(void)intr_dispatch(0x70);	/* grab any serial interrupts */
303#endif
304		if ((--delay) < 0)
305			return 1;	/* timeout */
306	}
307	return 0;
308}
309
310
311/*
312 * Wait until PM IC is free
313 */
314int
315pm_wait_free(delay)
316	int delay;
317{
318	while (PM_IS_OFF) {
319#ifdef PM_GRAB_SI
320		(void)intr_dispatch(0x70);	/* grab any serial interrupts */
321#endif
322		if ((--delay) < 0)
323			return 0;	/* timeout */
324	}
325	return 1;
326}
327
328
329
330/*
331 * Functions for the PB1XX series
332 */
333
334/*
335 * Receive data from PM for the PB1XX series
336 */
337int
338pm_receive_pm1(data)
339	u_char *data;
340{
341	int rval = 0xffffcd34;
342
343	via_reg(VIA2, vDirA) = 0x00;
344
345	switch (1) {
346		default:
347			if (pm_wait_busy(0x40) != 0)
348				break;			/* timeout */
349
350			PM_SET_STATE_ACKOFF();
351			*data = via_reg(VIA2, 0x200);
352
353			rval = 0xffffcd33;
354			if (pm_wait_free(0x40) == 0)
355				break;			/* timeout */
356
357			rval = 0x00;
358			break;
359	}
360
361	PM_SET_STATE_ACKON();
362	via_reg(VIA2, vDirA) = 0x00;
363
364	return rval;
365}
366
367
368
369/*
370 * Send data to PM for the PB1XX series
371 */
372int
373pm_send_pm1(data, timo)
374	u_char data;
375	int timo;
376{
377	int rval;
378
379	via_reg(VIA2, vDirA) = 0xff;
380	via_reg(VIA2, 0x200) = data;
381
382	PM_SET_STATE_ACKOFF();
383#if 0
384	if (pm_wait_busy(0x400) == 0) {
385#else
386	if (pm_wait_busy(timo) == 0) {
387#endif
388		PM_SET_STATE_ACKON();
389		if (pm_wait_free(0x40) != 0)
390			rval = 0x0;
391		else
392			rval = 0xffffcd35;
393	} else {
394		rval = 0xffffcd36;
395	}
396
397	PM_SET_STATE_ACKON();
398	via_reg(VIA2, vDirA) = 0x00;
399
400	return rval;
401}
402
403
404/*
405 * My PMgrOp routine for the PB1XX series
406 */
407int
408pm_pmgrop_pm1(pmdata)
409	PMData *pmdata;
410{
411	int i;
412	int s = 0x81815963;
413	u_char via1_vIER, via1_vDirA;
414	int rval = 0;
415	int num_pm_data = 0;
416	u_char pm_cmd;
417	u_char pm_data;
418	u_char *pm_buf;
419
420	/* disable all inetrrupts but PM */
421	via1_vIER = via_reg(VIA1, vIER);
422	PM_VIA_INTR_DISABLE();
423
424	via1_vDirA = via_reg(VIA1, vDirA);
425
426	switch (pmdata->command) {
427		default:
428			for (i = 0; i < 7; i++) {
429				via_reg(VIA2, vDirA) = 0x00;
430
431				/* wait until PM is free */
432				if (pm_wait_free(ADBDelay) == 0) {	/* timeout */
433					via_reg(VIA2, vDirA) = 0x00;
434					/* restore formar value */
435					via_reg(VIA1, vDirA) = via1_vDirA;
436					via_reg(VIA1, vIER) = via1_vIER;
437					return 0xffffcd38;
438				}
439
440				switch (mac68k_machine.machineid) {
441					case MACH_MACPB160:
442					case MACH_MACPB165:
443					case MACH_MACPB165C:
444					case MACH_MACPB170:
445					case MACH_MACPB180:
446					case MACH_MACPB180C:
447						{
448							int delay = ADBDelay * 16;
449
450							via_reg(VIA2, vDirA) = 0x00;
451							while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
452								delay--;
453
454							if (delay < 0) {	/* timeout */
455								via_reg(VIA2, vDirA) = 0x00;
456								/* restore formar value */
457								via_reg(VIA1, vIER) = via1_vIER;
458								return 0xffffcd38;
459							}
460						}
461				} /* end switch */
462
463				s = splhigh();
464
465				via1_vDirA = via_reg(VIA1, vDirA);
466				via_reg(VIA1, vDirA) &= 0x7f;
467
468				pm_cmd = (u_char)(pmdata->command & 0xff);
469				if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0)
470					break;	/* send command succeeded */
471
472				via_reg(VIA1, vDirA) = via1_vDirA;
473				splx(s);
474			} /* end for */
475
476			/* failed to send a command */
477			if (i == 7) {
478				via_reg(VIA2, vDirA) = 0x00;
479				/* restore formar value */
480				via_reg(VIA1, vDirA) = via1_vDirA;
481				via_reg(VIA1, vIER) = via1_vIER;
482				if (s != 0x81815963)
483					splx(s);
484				return 0xffffcd38;
485			}
486
487			/* send # of PM data */
488			num_pm_data = pmdata->num_data;
489			if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
490				break;			/* timeout */
491
492			/* send PM data */
493			pm_buf = (u_char *)pmdata->s_buf;
494			for (i = 0; i < num_pm_data; i++)
495				if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
496					break;		/* timeout */
497			if ((i != num_pm_data) && (num_pm_data != 0))
498				break;			/* timeout */
499
500			/* Will PM IC return data? */
501			if ((pm_cmd & 0x08) == 0) {
502				rval = 0;
503				break;			/* no returned data */
504			}
505
506			rval = 0xffffcd37;
507			if (pm_wait_busy(ADBDelay) != 0)
508				break;			/* timeout */
509
510			/* receive PM command */
511			if ((rval = pm_receive_pm1(&pm_data)) != 0)
512				break;
513
514			pmdata->command = pm_data;
515
516			/* receive number of PM data */
517			if ((rval = pm_receive_pm1(&pm_data)) != 0)
518				break;			/* timeout */
519			num_pm_data = pm_data;
520			pmdata->num_data = num_pm_data;
521
522			/* receive PM data */
523			pm_buf = (u_char *)pmdata->r_buf;
524			for (i = 0; i < num_pm_data; i++) {
525				if ((rval = pm_receive_pm1(&pm_data)) != 0)
526					break;		/* timeout */
527				pm_buf[i] = pm_data;
528			}
529
530			rval = 0;
531	}
532
533	via_reg(VIA2, vDirA) = 0x00;
534
535	/* restore formar value */
536	via_reg(VIA1, vDirA) = via1_vDirA;
537	via_reg(VIA1, vIER) = via1_vIER;
538	if (s != 0x81815963)
539		splx(s);
540
541	return rval;
542}
543
544
545/*
546 * My PM interrupt routine for PB1XX series
547 */
548void
549pm_intr_pm1(arg)
550	void *arg;
551{
552	int s;
553	int rval;
554	PMData pmdata;
555
556	s = splhigh();
557
558	PM_VIA_CLR_INTR();				/* clear VIA1 interrupt */
559
560	/* ask PM what happend */
561	pmdata.command = 0x78;
562	pmdata.num_data = 0;
563	pmdata.data[0] = pmdata.data[1] = 0;
564	pmdata.s_buf = &pmdata.data[2];
565	pmdata.r_buf = &pmdata.data[2];
566	rval = pm_pmgrop_pm1(&pmdata);
567	if (rval != 0) {
568#ifdef ADB_DEBUG
569		if (adb_debug)
570			printf("pm: PM is not ready. error code=%08x\n", rval);
571#endif
572		splx(s);
573	}
574
575	if ((pmdata.data[2] & 0x10) == 0x10) {
576		if ((pmdata.data[2] & 0x0f) == 0) {
577			/* ADB data that were requested by TALK command */
578			pm_adb_get_TALK_result(&pmdata);
579		} else if ((pmdata.data[2] & 0x08) == 0x8) {
580			/* PM is requesting to poll  */
581			pm_adb_poll_next_device_pm1(&pmdata);
582		} else if ((pmdata.data[2] & 0x04) == 0x4) {
583			/* ADB device event */
584			pm_adb_get_ADB_data(&pmdata);
585		}
586	} else {
587#ifdef ADB_DEBUG
588		if (adb_debug)
589			pm_printerr("driver does not supported this event.",
590			    rval, pmdata.num_data, pmdata.data);
591#endif
592	}
593
594	splx(s);
595}
596
597
598
599/*
600 * Functions for the PB Duo series and the PB 5XX series
601 */
602
603/*
604 * Receive data from PM for the PB Duo series and the PB 5XX series
605 */
606int
607pm_receive_pm2(data)
608	u_char *data;
609{
610	int i;
611	int rval;
612
613	rval = 0xffffcd34;
614
615	switch (1) {
616		default:
617			/* set VIA SR to input mode */
618			via_reg(VIA1, vACR) |= 0x0c;
619			via_reg(VIA1, vACR) &= ~0x10;
620			i = PM_SR();
621
622			PM_SET_STATE_ACKOFF();
623			if (pm_wait_busy((int)ADBDelay*32) != 0)
624				break;		/* timeout */
625
626			PM_SET_STATE_ACKON();
627			rval = 0xffffcd33;
628			if (pm_wait_free((int)ADBDelay*32) == 0)
629				break;		/* timeout */
630
631			*data = PM_SR();
632			rval = 0;
633
634			break;
635	}
636
637	PM_SET_STATE_ACKON();
638	via_reg(VIA1, vACR) |= 0x1c;
639
640	return rval;
641}
642
643
644
645/*
646 * Send data to PM for the PB Duo series and the PB 5XX series
647 */
648int
649pm_send_pm2(data)
650	u_char data;
651{
652	int rval;
653
654	via_reg(VIA1, vACR) |= 0x1c;
655	PM_SR() = data;
656
657	PM_SET_STATE_ACKOFF();
658	if (pm_wait_busy((int)ADBDelay*32) == 0) {
659		PM_SET_STATE_ACKON();
660		if (pm_wait_free((int)ADBDelay*32) != 0)
661			rval = 0;
662		else
663			rval = 0xffffcd35;
664	} else {
665		rval = 0xffffcd36;
666	}
667
668	PM_SET_STATE_ACKON();
669	via_reg(VIA1, vACR) |= 0x1c;
670
671	return rval;
672}
673
674
675
676/*
677 * My PMgrOp routine for the PB Duo series and the PB 5XX series
678 */
679int
680pm_pmgrop_pm2(pmdata)
681	PMData *pmdata;
682{
683	int i;
684	int s;
685	u_char via1_vIER;
686	int rval = 0;
687	int num_pm_data = 0;
688	u_char pm_cmd;
689	short pm_num_rx_data;
690	u_char pm_data;
691	u_char *pm_buf;
692
693	s = splhigh();
694
695	/* disable all inetrrupts but PM */
696	via1_vIER = 0x10;
697	via1_vIER &= via_reg(VIA1, vIER);
698	via_reg(VIA1, vIER) = via1_vIER;
699	if (via1_vIER != 0x0)
700		via1_vIER |= 0x80;
701
702	switch (pmdata->command) {
703		default:
704			/* wait until PM is free */
705			pm_cmd = (u_char)(pmdata->command & 0xff);
706			rval = 0xcd38;
707			if (pm_wait_free(ADBDelay * 4) == 0)
708				break;			/* timeout */
709
710			if (HwCfgFlags3 & 0x00200000) {
711				/* PB 160, PB 165(c), PB 180(c)? */
712				int delay = ADBDelay * 16;
713
714				via_reg(VIA2, vDirA) = 0x00;
715				while ((via_reg(VIA2, 0x200) == 0x07) &&
716				    (delay >= 0))
717					delay--;
718
719				if (delay < 0) {
720					rval = 0xffffcd38;
721					break;		/* timeout */
722				}
723			}
724
725			/* send PM command */
726			if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
727				break;				/* timeout */
728
729			/* send number of PM data */
730			num_pm_data = pmdata->num_data;
731			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
732				if (pm_send_cmd_type[pm_cmd] < 0) {
733					if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
734						break;		/* timeout */
735					pmdata->command = 0;
736				}
737			} else {				/* PB 1XX series ? */
738				if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
739					break;			/* timeout */
740			}
741			/* send PM data */
742			pm_buf = (u_char *)pmdata->s_buf;
743			for (i = 0 ; i < num_pm_data; i++)
744				if ((rval = pm_send_pm2(pm_buf[i])) != 0)
745					break;			/* timeout */
746			if (i != num_pm_data)
747				break;				/* timeout */
748
749
750			/* check if PM will send me data  */
751			pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
752			pmdata->num_data = pm_num_rx_data;
753			if (pm_num_rx_data == 0) {
754				rval = 0;
755				break;				/* no return data */
756			}
757
758			/* receive PM command */
759			pm_data = pmdata->command;
760			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
761				pm_num_rx_data--;
762				if (pm_num_rx_data == 0)
763					if ((rval = pm_receive_pm2(&pm_data)) != 0) {
764						rval = 0xffffcd37;
765						break;
766					}
767				pmdata->command = pm_data;
768			} else {				/* PB 1XX series ? */
769				if ((rval = pm_receive_pm2(&pm_data)) != 0) {
770					rval = 0xffffcd37;
771					break;
772				}
773				pmdata->command = pm_data;
774			}
775
776			/* receive number of PM data */
777			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
778				if (pm_num_rx_data < 0) {
779					if ((rval = pm_receive_pm2(&pm_data)) != 0)
780						break;		/* timeout */
781					num_pm_data = pm_data;
782				} else
783					num_pm_data = pm_num_rx_data;
784				pmdata->num_data = num_pm_data;
785			} else {				/* PB 1XX serias ? */
786				if ((rval = pm_receive_pm2(&pm_data)) != 0)
787					break;			/* timeout */
788				num_pm_data = pm_data;
789				pmdata->num_data = num_pm_data;
790			}
791
792			/* receive PM data */
793			pm_buf = (u_char *)pmdata->r_buf;
794			for (i = 0; i < num_pm_data; i++) {
795				if ((rval = pm_receive_pm2(&pm_data)) != 0)
796					break;			/* timeout */
797				pm_buf[i] = pm_data;
798			}
799
800			rval = 0;
801	}
802
803	/* restore former value */
804	via_reg(VIA1, vIER) = via1_vIER;
805	splx(s);
806
807	return rval;
808}
809
810
811/*
812 * My PM interrupt routine for the PB Duo series and the PB 5XX series
813 */
814void
815pm_intr_pm2(arg)
816	void *arg;
817{
818	int s;
819	int rval;
820	PMData pmdata;
821
822	s = splhigh();
823
824	PM_VIA_CLR_INTR();			/* clear VIA1 interrupt */
825						/* ask PM what happend */
826	pmdata.command = 0x78;
827	pmdata.num_data = 0;
828	pmdata.s_buf = &pmdata.data[2];
829	pmdata.r_buf = &pmdata.data[2];
830	rval = pm_pmgrop_pm2(&pmdata);
831	if (rval != 0) {
832#ifdef ADB_DEBUG
833		if (adb_debug)
834			printf("pm: PM is not ready. error code: %08x\n", rval);
835#endif
836		splx(s);
837	}
838
839	switch ((u_int)(pmdata.data[2] & 0xff)) {
840		case 0x00:			/* 1 sec interrupt? */
841			break;
842		case 0x80:			/* 1 sec interrupt? */
843			pm_counter++;
844			break;
845		case 0x08:			/* Brightness/Contrast button on LCD panel */
846			/* get brightness and contrast of the LCD */
847			pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
848			pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
849/*
850			pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
851			pmdata.command = 0x33;
852			pmdata.num_data = 1;
853			pmdata.s_buf = pmdata.data;
854			pmdata.r_buf = pmdata.data;
855			pmdata.data[0] = pm_LCD_contrast;
856			rval = pm_pmgrop_pm2(&pmdata);
857			pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
858*/
859			/* this is an experimental code */
860			pmdata.command = 0x41;
861			pmdata.num_data = 1;
862			pmdata.s_buf = pmdata.data;
863			pmdata.r_buf = pmdata.data;
864			pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
865			if (pm_LCD_brightness < 0x25)
866				pm_LCD_brightness = 0x25;
867			if (pm_LCD_brightness > 0x5a)
868				pm_LCD_brightness = 0x7f;
869			pmdata.data[0] = pm_LCD_brightness;
870			rval = pm_pmgrop_pm2(&pmdata);
871			break;
872		case 0x10:			/* ADB data that were requested by TALK command */
873		case 0x14:
874			pm_adb_get_TALK_result(&pmdata);
875			break;
876		case 0x16:			/* ADB device event */
877		case 0x18:
878		case 0x1e:
879			pm_adb_get_ADB_data(&pmdata);
880			break;
881		default:
882#ifdef ADB_DEBUG
883			if (adb_debug)
884				pm_printerr("driver does not supported this event.",
885				    pmdata.data[2], pmdata.num_data,
886				    pmdata.data);
887#endif
888			break;
889	}
890
891	splx(s);
892}
893
894
895/*
896 * MRG-based PMgrOp routine
897 */
898int
899pm_pmgrop_mrg(pmdata)
900	PMData *pmdata;
901{
902	u_int32_t rval=0;
903
904	asm("
905		movl	%1,%%a0
906		.word	0xa085
907		movl	%%d0,%0"
908		: "=g" (rval)
909		: "g" (pmdata)
910		: "a0","d0");
911
912	return rval;
913}
914
915
916/*
917 * My PMgrOp routine
918 */
919int
920pmgrop(pmdata)
921	PMData *pmdata;
922{
923	switch (pmHardware) {
924		case PM_HW_PB1XX:
925			return (pm_pmgrop_pm1(pmdata));
926			break;
927		case PM_HW_PB5XX:
928			return (pm_pmgrop_pm2(pmdata));
929			break;
930		default:
931			/* return (pmgrop_mrg(pmdata)); */
932			return 1;
933	}
934}
935
936
937/*
938 * My PM interrupt routine
939 */
940void
941pm_intr(arg)
942	void *arg;
943{
944	switch (pmHardware) {
945		case PM_HW_PB1XX:
946			pm_intr_pm1(arg);
947			break;
948		case PM_HW_PB5XX:
949			pm_intr_pm2(arg);
950			break;
951		default:
952			break;
953	}
954}
955
956
957void
958pm_hw_setup()
959{
960	switch (pmHardware) {
961		case PM_HW_PB1XX:
962			via1_register_irq(4, pm_intr_pm1, (void *)0);
963			PM_VIA_CLR_INTR();
964			break;
965		case PM_HW_PB5XX:
966			via1_register_irq(4, pm_intr_pm2, (void *)0);
967			PM_VIA_CLR_INTR();
968			break;
969		default:
970			break;
971	}
972}
973
974
975/*
976 * Synchronous ADBOp routine for the Power Manager
977 */
978int
979pm_adb_op(buffer, compRout, data, command)
980	u_char *buffer;
981	void *compRout;
982	void *data;
983	int command;
984{
985	int i;
986	int s;
987	int rval;
988	int delay;
989	PMData pmdata;
990	struct adbCommand packet;
991
992	if (adbWaiting == 1)
993		return 1;
994
995	s = splhigh();
996	via_reg(VIA1, vIER) = 0x10;
997
998 	adbBuffer = buffer;
999	adbCompRout = compRout;
1000	adbCompData = data;
1001
1002	pmdata.command = 0x20;
1003	pmdata.s_buf = pmdata.data;
1004	pmdata.r_buf = pmdata.data;
1005
1006	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, add number of ADB data to number of PM data */
1007		if (buffer != (u_char *)0)
1008			pmdata.num_data = buffer[0] + 3;
1009	} else {
1010		pmdata.num_data = 3;
1011	}
1012
1013	pmdata.data[0] = (u_char)(command & 0xff);
1014	pmdata.data[1] = 0;
1015	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, copy ADB data to PM buffer */
1016		if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
1017			pmdata.data[2] = buffer[0];		/* number of data */
1018			for (i = 0; i < buffer[0]; i++)
1019				pmdata.data[3 + i] = buffer[1 + i];
1020		} else
1021			pmdata.data[2] = 0;
1022	} else
1023		pmdata.data[2] = 0;
1024
1025	if ((command & 0xc) != 0xc) {		/* if the command is not TALK */
1026		/* set up stuff fNULLor adb_pass_up */
1027		packet.data[0] = 1 + pmdata.data[2];
1028		packet.data[1] = command;
1029		for (i = 0; i < pmdata.data[2]; i++)
1030			packet.data[i+2] = pmdata.data[i+3];
1031		packet.saveBuf = adbBuffer;
1032		packet.compRout = adbCompRout;
1033		packet.compData = adbCompData;
1034		packet.cmd = command;
1035		packet.unsol = 0;
1036		packet.ack_only = 1;
1037		adb_polling = 1;
1038		adb_pass_up(&packet);
1039		adb_polling = 0;
1040	}
1041
1042	rval = pmgrop(&pmdata);
1043	if (rval != 0) {
1044		splx(s);
1045		return 1;
1046	}
1047
1048	adbWaiting = 1;
1049	adbWaitingCmd = command;
1050
1051	PM_VIA_INTR_ENABLE();
1052
1053	/* wait until the PM interrupt has occurred */
1054	delay = 0x80000;
1055	while (adbWaiting == 1) {
1056		switch (mac68k_machine.machineid) {
1057		case MACH_MACPB210:
1058		case MACH_MACPB230:	/* daishi tested with Duo230 */
1059		case MACH_MACPB250:
1060		case MACH_MACPB270:
1061		case MACH_MACPB280:
1062		case MACH_MACPB280C:
1063			pm_intr((void *)0);
1064			break;
1065		default:
1066			if ((via_reg(VIA1, vIFR) & 0x10) == 0x10)
1067				pm_intr((void *)0);
1068			break;
1069		}
1070#ifdef PM_GRAB_SI
1071		(void)intr_dispatch(0x70);	/* grab any serial interrupts */
1072#endif
1073		if ((--delay) < 0) {
1074			splx(s);
1075			return 1;
1076		}
1077	}
1078
1079	/* this command enables the interrupt by operating ADB devices */
1080	if (HwCfgFlags3 & 0x00020000) {		/* PB Duo series, PB 5XX series */
1081		pmdata.command = 0x20;
1082		pmdata.num_data = 4;
1083		pmdata.s_buf = pmdata.data;
1084		pmdata.r_buf = pmdata.data;
1085		pmdata.data[0] = 0x00;
1086		pmdata.data[1] = 0x86;	/* magic spell for awaking the PM */
1087		pmdata.data[2] = 0x00;
1088		pmdata.data[3] = 0x0c;	/* each bit may express the existent ADB device */
1089	} else {				/* PB 1XX series */
1090		pmdata.command = 0x20;
1091		pmdata.num_data = 3;
1092		pmdata.s_buf = pmdata.data;
1093		pmdata.r_buf = pmdata.data;
1094		pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1095		pmdata.data[1] = 0x04;
1096		pmdata.data[2] = 0x00;
1097	}
1098	rval = pmgrop(&pmdata);
1099
1100	splx(s);
1101	return rval;
1102}
1103
1104
1105void
1106pm_adb_get_TALK_result(pmdata)
1107	PMData *pmdata;
1108{
1109	int i;
1110	struct adbCommand packet;
1111
1112	/* set up data for adb_pass_up */
1113	packet.data[0] = pmdata->num_data-1;
1114	packet.data[1] = pmdata->data[3];
1115	for (i = 0; i <packet.data[0]-1; i++)
1116		packet.data[i+2] = pmdata->data[i+4];
1117
1118	packet.saveBuf = adbBuffer;
1119	packet.compRout = adbCompRout;
1120	packet.compData = adbCompData;
1121	packet.unsol = 0;
1122	packet.ack_only = 0;
1123	adb_polling = 1;
1124	adb_pass_up(&packet);
1125	adb_polling = 0;
1126
1127	adbWaiting = 0;
1128	adbBuffer = (long)0;
1129	adbCompRout = (long)0;
1130	adbCompData = (long)0;
1131}
1132
1133
1134void
1135pm_adb_get_ADB_data(pmdata)
1136	PMData *pmdata;
1137{
1138	int i;
1139	struct adbCommand packet;
1140
1141	/* set up data for adb_pass_up */
1142	packet.data[0] = pmdata->num_data-1;	/* number of raw data */
1143	packet.data[1] = pmdata->data[3];	/* ADB command */
1144	for (i = 0; i <packet.data[0]-1; i++)
1145		packet.data[i+2] = pmdata->data[i+4];
1146	packet.unsol = 1;
1147	packet.ack_only = 0;
1148	adb_pass_up(&packet);
1149}
1150
1151
1152void
1153pm_adb_poll_next_device_pm1(pmdata)
1154	PMData *pmdata;
1155{
1156	int i;
1157	int ndid;
1158	u_short bendid = 0x1;
1159	int rval;
1160	PMData tmp_pmdata;
1161
1162	/* find another existent ADB device to poll */
1163	for (i = 1; i < 16; i++) {
1164		ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf;
1165		bendid <<= ndid;
1166		if ((pm_existent_ADB_devices & bendid) != 0)
1167			break;
1168	}
1169
1170	/* poll the other device */
1171	tmp_pmdata.command = 0x20;
1172	tmp_pmdata.num_data = 3;
1173	tmp_pmdata.s_buf = tmp_pmdata.data;
1174	tmp_pmdata.r_buf = tmp_pmdata.data;
1175	tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1176	tmp_pmdata.data[1] = 0x04;	/* magic spell for awaking the PM */
1177	tmp_pmdata.data[2] = 0x00;
1178	rval = pmgrop(&tmp_pmdata);
1179}
1180
1181
1182
1183