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