pm_direct.c revision 1.2
1/*	$NetBSD: pm_direct.c,v 1.2 1998/11/15 19:41:33 tsubai 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#ifdef DEBUG
35#ifndef ADB_DEBUG
36#define ADB_DEBUG
37#endif
38#endif
39
40/* #define	PM_GRAB_SI	1 */
41
42#include <sys/param.h>
43#include <sys/cdefs.h>
44#include <sys/device.h>
45#include <sys/systm.h>
46
47#include <machine/adbsys.h>
48#include <machine/cpu.h>
49
50#include <macppc/dev/adbvar.h>
51#include <macppc/dev/pm_direct.h>
52#include <macppc/dev/viareg.h>
53
54extern int adb_polling;		/* Are we polling?  (Debugger mode) */
55
56/* hardware dependent values */
57#define ADBDelay 100		/* XXX */
58#define HwCfgFlags3 0x20000	/* XXX */
59
60/* define the types of the Power Manager */
61#define PM_HW_UNKNOWN		0x00	/* don't know */
62#define PM_HW_PB1XX		0x01	/* PowerBook 1XX series */
63#define	PM_HW_PB5XX		0x02	/* PowerBook Duo and 5XX series */
64
65/* useful macros */
66#define PM_SR()			read_via_reg(VIA1, vSR)
67#define PM_VIA_INTR_ENABLE()	write_via_reg(VIA1, vIER, 0x90)
68#define PM_VIA_INTR_DISABLE()	write_via_reg(VIA1, vIER, 0x10)
69#define PM_VIA_CLR_INTR()	write_via_reg(VIA1, vIFR, 0x90)
70#if 0
71#define PM_SET_STATE_ACKON()	via_reg_or(VIA2, vBufB, 0x04)
72#define PM_SET_STATE_ACKOFF()	via_reg_and(VIA2, vBufB, ~0x04)
73#define PM_IS_ON		(0x02 == (read_via_reg(VIA2, vBufB) & 0x02))
74#define PM_IS_OFF		(0x00 == (read_via_reg(VIA2, vBufB) & 0x02))
75#else
76#define PM_SET_STATE_ACKON()	via_reg_or(VIA2, vBufB, 0x10)
77#define PM_SET_STATE_ACKOFF()	via_reg_and(VIA2, vBufB, ~0x10)
78#define PM_IS_ON		(0x08 == (read_via_reg(VIA2, vBufB) & 0x08))
79#define PM_IS_OFF		(0x00 == (read_via_reg(VIA2, vBufB) & 0x08))
80#endif
81
82/*
83 * Variables for internal use
84 */
85int	pmHardware = PM_HW_UNKNOWN;
86u_short	pm_existent_ADB_devices = 0x0;	/* each bit expresses the existent ADB device */
87u_int	pm_LCD_brightness = 0x0;
88u_int	pm_LCD_contrast = 0x0;
89u_int	pm_counter = 0;			/* clock count */
90
91/* these values shows that number of data returned after 'send' cmd is sent */
92signed char pm_send_cmd_type[] = {
93	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
94	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
95	0x01, 0x01,   -1,   -1,   -1,   -1,   -1,   -1,
96	0x00, 0x00,   -1,   -1,   -1,   -1,   -1, 0x00,
97	  -1, 0x00, 0x02, 0x01, 0x01,   -1,   -1,   -1,
98	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
99	0x04, 0x14,   -1,   -1,   -1,   -1,   -1,   -1,
100	0x00, 0x00, 0x02,   -1,   -1,   -1,   -1,   -1,
101	0x01, 0x01,   -1,   -1,   -1,   -1,   -1,   -1,
102	0x00, 0x00,   -1,   -1,   -1,   -1,   -1,   -1,
103	0x01, 0x00, 0x02, 0x02,   -1, 0x01, 0x03, 0x01,
104	0x00, 0x01, 0x00, 0x00, 0x00,   -1,   -1,   -1,
105	0x02,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
106	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   -1,   -1,
107	0x01, 0x01, 0x01,   -1,   -1,   -1,   -1,   -1,
108	0x00, 0x00,   -1,   -1,   -1,   -1, 0x04, 0x04,
109	0x04,   -1, 0x00,   -1,   -1,   -1,   -1,   -1,
110	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
111	0x01, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
112	0x00, 0x00,   -1,   -1,   -1,   -1,   -1,   -1,
113	0x02, 0x02, 0x02, 0x04,   -1, 0x00,   -1,   -1,
114	0x01, 0x01, 0x03, 0x02,   -1,   -1,   -1,   -1,
115	  -1,   -1,   -1,   -1,   -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	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
120	0x01, 0x01,   -1,   -1, 0x00, 0x00,   -1,   -1,
121	  -1, 0x04, 0x00,   -1,   -1,   -1,   -1,   -1,
122	0x03,   -1, 0x00,   -1, 0x00,   -1,   -1, 0x00,
123	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
124	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1
125};
126
127/* these values shows that number of data returned after 'receive' cmd is sent */
128signed char pm_receive_cmd_type[] = {
129	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
131	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132	0x02, 0x02,   -1,   -1,   -1,   -1,   -1, 0x00,
133	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
135	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136	0x05, 0x15,   -1,   -1,   -1,   -1,   -1,   -1,
137	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138	0x02, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
139	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140	0x02, 0x00, 0x03, 0x03,   -1,   -1,   -1,   -1,
141	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142	0x04, 0x04, 0x03, 0x09,   -1,   -1,   -1,   -1,
143	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144	  -1,   -1,   -1,   -1,   -1,   -1, 0x01, 0x01,
145	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146	0x06,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
147	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148	0x02, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
149	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150	0x02, 0x00, 0x00, 0x00,   -1,   -1,   -1,   -1,
151	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
153	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
155	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156	0x02, 0x02,   -1,   -1, 0x02,   -1,   -1,   -1,
157	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
158	  -1,   -1, 0x02,   -1,   -1,   -1,   -1, 0x00,
159	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
161};
162
163
164/*
165 * Define the private functions
166 */
167
168/* for debugging */
169#ifdef ADB_DEBUG
170void	pm_printerr __P((char *, int, int, char *));
171#endif
172
173int	pm_wait_busy __P((int));
174int	pm_wait_free __P((int));
175
176/* these functions are for the PB1XX series */
177int	pm_receive_pm1 __P((u_char *));
178int	pm_send_pm1 __P((u_char,int));
179int	pm_pmgrop_pm1 __P((PMData *));
180void	pm_intr_pm1 __P((void));
181
182/* these functions are for the PB Duo series and the PB 5XX series */
183int	pm_receive_pm2 __P((u_char *));
184int	pm_send_pm2 __P((u_char));
185int	pm_pmgrop_pm2 __P((PMData *));
186void	pm_intr_pm2 __P((void));
187
188/* this function is MRG-Based (for testing) */
189int	pm_pmgrop_mrg __P((PMData *));
190
191/* these functions are called from adb_direct.c */
192void	pm_setup_adb __P((void));
193void	pm_check_adb_devices __P((int));
194void	pm_intr __P((void));
195int	pm_adb_op __P((u_char *, void *, void *, int));
196
197/* these functions also use the variables of adb_direct.c */
198void	pm_adb_get_TALK_result __P((PMData *));
199void	pm_adb_get_ADB_data __P((PMData *));
200void	pm_adb_poll_next_device_pm1 __P((PMData *));
201
202
203/*
204 * These variables are in adb_direct.c.
205 */
206extern u_char	*adbBuffer;	/* pointer to user data area */
207extern void	*adbCompRout;	/* pointer to the completion routine */
208extern void	*adbCompData;	/* pointer to the completion routine data */
209extern int	adbWaiting;	/* waiting for return data from the device */
210extern int	adbWaitingCmd;	/* ADB command we are waiting for */
211extern int	adbStarting;	/* doing ADB reinit, so do "polling" differently */
212
213#define	ADB_MAX_MSG_LENGTH	16
214#define	ADB_MAX_HDR_LENGTH	8
215struct adbCommand {
216	u_char	header[ADB_MAX_HDR_LENGTH];	/* not used yet */
217	u_char	data[ADB_MAX_MSG_LENGTH];	/* packet data only */
218	u_char	*saveBuf;	/* where to save result */
219	u_char	*compRout;	/* completion routine pointer */
220	u_char	*compData;	/* completion routine data pointer */
221	u_int	cmd;		/* the original command for this data */
222	u_int	unsol;		/* 1 if packet was unsolicited */
223	u_int	ack_only;	/* 1 for no special processing */
224};
225extern	void	adb_pass_up __P((struct adbCommand *));
226
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					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#else
543	panic("pm_pmgrop_pm1");
544#endif
545}
546
547
548/*
549 * My PM interrupt routine for PB1XX series
550 */
551void
552pm_intr_pm1()
553{
554#if 0
555	int s;
556	int rval;
557	PMData pmdata;
558
559	s = splhigh();
560
561	PM_VIA_CLR_INTR();				/* clear VIA1 interrupt */
562
563	/* ask PM what happend */
564	pmdata.command = 0x78;
565	pmdata.num_data = 0;
566	pmdata.data[0] = pmdata.data[1] = 0;
567	pmdata.s_buf = &pmdata.data[2];
568	pmdata.r_buf = &pmdata.data[2];
569	rval = pm_pmgrop_pm1(&pmdata);
570	if (rval != 0) {
571#ifdef ADB_DEBUG
572		if (adb_debug)
573			printf("pm: PM is not ready. error code=%08x\n", rval);
574#endif
575		splx(s);
576	}
577
578	if ((pmdata.data[2] & 0x10) == 0x10) {
579		if ((pmdata.data[2] & 0x0f) == 0) {
580			/* ADB data that were requested by TALK command */
581			pm_adb_get_TALK_result(&pmdata);
582		} else if ((pmdata.data[2] & 0x08) == 0x8) {
583			/* PM is requesting to poll  */
584			pm_adb_poll_next_device_pm1(&pmdata);
585		} else if ((pmdata.data[2] & 0x04) == 0x4) {
586			/* ADB device event */
587			pm_adb_get_ADB_data(&pmdata);
588		}
589	} else {
590#ifdef ADB_DEBUG
591		if (adb_debug)
592			pm_printerr("driver does not supported this event.",
593			    rval, pmdata.num_data, pmdata.data);
594#endif
595	}
596
597	splx(s);
598#else
599	panic("pm_intr_pm1");
600#endif
601}
602
603
604
605/*
606 * Functions for the PB Duo series and the PB 5XX series
607 */
608
609/*
610 * Receive data from PM for the PB Duo series and the PB 5XX series
611 */
612int
613pm_receive_pm2(data)
614	u_char *data;
615{
616	int i;
617	int rval;
618
619	rval = 0xffffcd34;
620
621	switch (1) {
622		default:
623			/* set VIA SR to input mode */
624			via_reg_or(VIA1, vACR, 0x0c);
625			via_reg_and(VIA1, vACR, ~0x10);
626			i = PM_SR();
627
628			PM_SET_STATE_ACKOFF();
629			if (pm_wait_busy((int)ADBDelay*32) != 0)
630				break;		/* timeout */
631
632			PM_SET_STATE_ACKON();
633			rval = 0xffffcd33;
634			if (pm_wait_free((int)ADBDelay*32) == 0)
635				break;		/* timeout */
636
637			*data = PM_SR();
638			rval = 0;
639
640			break;
641	}
642
643	PM_SET_STATE_ACKON();
644	via_reg_or(VIA1, vACR, 0x1c);
645
646	return rval;
647}
648
649
650
651/*
652 * Send data to PM for the PB Duo series and the PB 5XX series
653 */
654int
655pm_send_pm2(data)
656	u_char data;
657{
658	int rval;
659
660	via_reg_or(VIA1, vACR, 0x1c);
661	write_via_reg(VIA1, vSR, data);	/* PM_SR() = data; */
662
663	PM_SET_STATE_ACKOFF();
664	rval = 0xffffcd36;
665	if (pm_wait_busy((int)ADBDelay*32) != 0) {
666		PM_SET_STATE_ACKON();
667
668		via_reg_or(VIA1, vACR, 0x1c);
669
670		return rval;
671	}
672
673	PM_SET_STATE_ACKON();
674	rval = 0xffffcd35;
675	if (pm_wait_free((int)ADBDelay*32) != 0)
676		rval = 0;
677
678	PM_SET_STATE_ACKON();
679	via_reg_or(VIA1, vACR, 0x1c);
680
681	return rval;
682}
683
684
685
686/*
687 * My PMgrOp routine for the PB Duo series and the PB 5XX series
688 */
689int
690pm_pmgrop_pm2(pmdata)
691	PMData *pmdata;
692{
693	int i;
694	int s;
695	u_char via1_vIER;
696	int rval = 0;
697	int num_pm_data = 0;
698	u_char pm_cmd;
699	short pm_num_rx_data;
700	u_char pm_data;
701	u_char *pm_buf;
702
703	s = splhigh();
704
705	/* disable all inetrrupts but PM */
706	via1_vIER = 0x10;
707	via1_vIER &= read_via_reg(VIA1, vIER);
708	write_via_reg(VIA1, vIER, via1_vIER);
709	if (via1_vIER != 0x0)
710		via1_vIER |= 0x80;
711
712	switch (pmdata->command) {
713		default:
714			/* wait until PM is free */
715			pm_cmd = (u_char)(pmdata->command & 0xff);
716			rval = 0xcd38;
717			if (pm_wait_free(ADBDelay * 4) == 0)
718				break;			/* timeout */
719
720			if (HwCfgFlags3 & 0x00200000) {
721				/* PB 160, PB 165(c), PB 180(c)? */
722				int delay = ADBDelay * 16;
723
724				write_via_reg(VIA2, vDirA, 0x00);
725				while ((read_via_reg(VIA2, 0x200) == 0x07) &&
726				    (delay >= 0))
727					delay--;
728
729				if (delay < 0) {
730					rval = 0xffffcd38;
731					break;		/* timeout */
732				}
733			}
734
735			/* send PM command */
736			if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
737				break;				/* timeout */
738
739			/* send number of PM data */
740			num_pm_data = pmdata->num_data;
741			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
742				if (pm_send_cmd_type[pm_cmd] < 0) {
743					if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
744						break;		/* timeout */
745					pmdata->command = 0;
746				}
747			} else {				/* PB 1XX series ? */
748				if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
749					break;			/* timeout */
750			}
751			/* send PM data */
752			pm_buf = (u_char *)pmdata->s_buf;
753			for (i = 0 ; i < num_pm_data; i++)
754				if ((rval = pm_send_pm2(pm_buf[i])) != 0)
755					break;			/* timeout */
756			if (i != num_pm_data)
757				break;				/* timeout */
758
759
760			/* check if PM will send me data  */
761			pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
762			pmdata->num_data = pm_num_rx_data;
763			if (pm_num_rx_data == 0) {
764				rval = 0;
765				break;				/* no return data */
766			}
767
768			/* receive PM command */
769			pm_data = pmdata->command;
770			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
771				pm_num_rx_data--;
772				if (pm_num_rx_data == 0)
773					if ((rval = pm_receive_pm2(&pm_data)) != 0) {
774						rval = 0xffffcd37;
775						break;
776					}
777				pmdata->command = pm_data;
778			} else {				/* PB 1XX series ? */
779				if ((rval = pm_receive_pm2(&pm_data)) != 0) {
780					rval = 0xffffcd37;
781					break;
782				}
783				pmdata->command = pm_data;
784			}
785
786			/* receive number of PM data */
787			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
788				if (pm_num_rx_data < 0) {
789					if ((rval = pm_receive_pm2(&pm_data)) != 0)
790						break;		/* timeout */
791					num_pm_data = pm_data;
792				} else
793					num_pm_data = pm_num_rx_data;
794				pmdata->num_data = num_pm_data;
795			} else {				/* PB 1XX serias ? */
796				if ((rval = pm_receive_pm2(&pm_data)) != 0)
797					break;			/* timeout */
798				num_pm_data = pm_data;
799				pmdata->num_data = num_pm_data;
800			}
801
802			/* receive PM data */
803			pm_buf = (u_char *)pmdata->r_buf;
804			for (i = 0; i < num_pm_data; i++) {
805				if ((rval = pm_receive_pm2(&pm_data)) != 0)
806					break;			/* timeout */
807				pm_buf[i] = pm_data;
808			}
809
810			rval = 0;
811	}
812
813	/* restore former value */
814	write_via_reg(VIA1, vIER, via1_vIER);
815	splx(s);
816
817	return rval;
818}
819
820
821/*
822 * My PM interrupt routine for the PB Duo series and the PB 5XX series
823 */
824void
825pm_intr_pm2()
826{
827	int s;
828	int rval;
829	PMData pmdata;
830
831	s = splhigh();
832
833	PM_VIA_CLR_INTR();			/* clear VIA1 interrupt */
834						/* ask PM what happend */
835	pmdata.command = 0x78;
836	pmdata.num_data = 0;
837	pmdata.s_buf = &pmdata.data[2];
838	pmdata.r_buf = &pmdata.data[2];
839	rval = pm_pmgrop_pm2(&pmdata);
840	if (rval != 0) {
841#ifdef ADB_DEBUG
842		if (adb_debug)
843			printf("pm: PM is not ready. error code: %08x\n", rval);
844#endif
845		splx(s);
846	}
847
848	switch ((u_int)(pmdata.data[2] & 0xff)) {
849		case 0x00:			/* 1 sec interrupt? */
850			break;
851		case 0x80:			/* 1 sec interrupt? */
852			pm_counter++;
853			break;
854		case 0x08:			/* Brightness/Contrast button on LCD panel */
855			/* get brightness and contrast of the LCD */
856			pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
857			pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
858/*
859			pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
860			pmdata.command = 0x33;
861			pmdata.num_data = 1;
862			pmdata.s_buf = pmdata.data;
863			pmdata.r_buf = pmdata.data;
864			pmdata.data[0] = pm_LCD_contrast;
865			rval = pm_pmgrop_pm2(&pmdata);
866			pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
867*/
868			/* this is an experimental code */
869			pmdata.command = 0x41;
870			pmdata.num_data = 1;
871			pmdata.s_buf = pmdata.data;
872			pmdata.r_buf = pmdata.data;
873			pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
874			if (pm_LCD_brightness < 0x08)
875				pm_LCD_brightness = 0x08;
876			if (pm_LCD_brightness > 0x78)
877				pm_LCD_brightness = 0x78;
878			pmdata.data[0] = pm_LCD_brightness;
879			rval = pm_pmgrop_pm2(&pmdata);
880			break;
881		case 0x10:			/* ADB data that were requested by TALK command */
882		case 0x14:
883			pm_adb_get_TALK_result(&pmdata);
884			break;
885		case 0x16:			/* ADB device event */
886		case 0x18:
887		case 0x1e:
888			pm_adb_get_ADB_data(&pmdata);
889			break;
890		default:
891#ifdef ADB_DEBUG
892			if (adb_debug)
893				pm_printerr("driver does not supported this event.",
894				    pmdata.data[2], pmdata.num_data,
895				    pmdata.data);
896#endif
897			break;
898	}
899
900	splx(s);
901}
902
903
904#if 0
905/*
906 * MRG-based PMgrOp routine
907 */
908int
909pm_pmgrop_mrg(pmdata)
910	PMData *pmdata;
911{
912	u_int32_t rval=0;
913
914	asm("
915		movl	%1, a0
916		.word	0xa085
917		movl	d0, %0"
918		: "=g" (rval)
919		: "g" (pmdata)
920		: "a0", "d0" );
921
922	return rval;
923}
924#endif
925
926
927/*
928 * My PMgrOp routine
929 */
930int
931pmgrop(pmdata)
932	PMData *pmdata;
933{
934	switch (pmHardware) {
935		case PM_HW_PB1XX:
936			return (pm_pmgrop_pm1(pmdata));
937			break;
938		case PM_HW_PB5XX:
939			return (pm_pmgrop_pm2(pmdata));
940			break;
941		default:
942			/* return (pmgrop_mrg(pmdata)); */
943			return 1;
944	}
945}
946
947
948/*
949 * My PM interrupt routine
950 */
951void
952pm_intr()
953{
954	switch (pmHardware) {
955		case PM_HW_PB1XX:
956			pm_intr_pm1();
957			break;
958		case PM_HW_PB5XX:
959			pm_intr_pm2();
960			break;
961		default:
962			break;
963	}
964}
965
966
967
968/*
969 * Synchronous ADBOp routine for the Power Manager
970 */
971int
972pm_adb_op(buffer, compRout, data, command)
973	u_char *buffer;
974	void *compRout;
975	void *data;
976	int command;
977{
978	int i;
979	int s;
980	int rval;
981	int delay;
982	PMData pmdata;
983	struct adbCommand packet;
984
985	if (adbWaiting == 1)
986		return 1;
987
988	s = splhigh();
989	write_via_reg(VIA1, vIER, 0x10);
990
991 	adbBuffer = buffer;
992	adbCompRout = compRout;
993	adbCompData = data;
994
995	pmdata.command = 0x20;
996	pmdata.s_buf = pmdata.data;
997	pmdata.r_buf = pmdata.data;
998
999	/* if the command is LISTEN, add number of ADB data to number of PM data */
1000	if ((command & 0xc) == 0x8) {
1001		if (buffer != (u_char *)0)
1002			pmdata.num_data = buffer[0] + 3;
1003	} else {
1004		pmdata.num_data = 3;
1005	}
1006
1007	pmdata.data[0] = (u_char)(command & 0xff);
1008	pmdata.data[1] = 0;
1009	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, copy ADB data to PM buffer */
1010		if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
1011			pmdata.data[2] = buffer[0];		/* number of data */
1012			for (i = 0; i < buffer[0]; i++)
1013				pmdata.data[3 + i] = buffer[1 + i];
1014		} else
1015			pmdata.data[2] = 0;
1016	} else
1017		pmdata.data[2] = 0;
1018
1019	if ((command & 0xc) != 0xc) {		/* if the command is not TALK */
1020		/* set up stuff for adb_pass_up */
1021		packet.data[0] = 1 + pmdata.data[2];
1022		packet.data[1] = command;
1023		for (i = 0; i < pmdata.data[2]; i++)
1024			packet.data[i+2] = pmdata.data[i+3];
1025		packet.saveBuf = adbBuffer;
1026		packet.compRout = adbCompRout;
1027		packet.compData = adbCompData;
1028		packet.cmd = command;
1029		packet.unsol = 0;
1030		packet.ack_only = 1;
1031		adb_polling = 1;
1032		adb_pass_up(&packet);
1033		adb_polling = 0;
1034	}
1035
1036	rval = pmgrop(&pmdata);
1037	if (rval != 0)
1038		return 1;
1039
1040	adbWaiting = 1;
1041	adbWaitingCmd = command;
1042
1043	PM_VIA_INTR_ENABLE();
1044
1045	/* wait until the PM interrupt is occured */
1046	delay = 0x80000;
1047	while (adbWaiting == 1) {
1048		if (read_via_reg(VIA1, vIFR) & 0x14)
1049			pm_intr();
1050#ifdef PM_GRAB_SI
1051#if 0
1052			zshard(0);		/* grab any serial interrupts */
1053#else
1054			(void)intr_dispatch(0x70);
1055#endif
1056#endif
1057		if ((--delay) < 0)
1058			return 1;
1059	}
1060
1061	/* this command enables the interrupt by operating ADB devices */
1062	if (HwCfgFlags3 & 0x00020000) {		/* PB Duo series, PB 5XX series */
1063		pmdata.command = 0x20;
1064		pmdata.num_data = 4;
1065		pmdata.s_buf = pmdata.data;
1066		pmdata.r_buf = pmdata.data;
1067		pmdata.data[0] = 0x00;
1068		pmdata.data[1] = 0x86;	/* magic spell for awaking the PM */
1069		pmdata.data[2] = 0x00;
1070		pmdata.data[3] = 0x0c;	/* each bit may express the existent ADB device */
1071	} else {				/* PB 1XX series */
1072		pmdata.command = 0x20;
1073		pmdata.num_data = 3;
1074		pmdata.s_buf = pmdata.data;
1075		pmdata.r_buf = pmdata.data;
1076		pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1077		pmdata.data[1] = 0x04;
1078		pmdata.data[2] = 0x00;
1079	}
1080	rval = pmgrop(&pmdata);
1081
1082	splx(s);
1083	return rval;
1084}
1085
1086
1087void
1088pm_adb_get_TALK_result(pmdata)
1089	PMData *pmdata;
1090{
1091	int i;
1092	struct adbCommand packet;
1093
1094	/* set up data for adb_pass_up */
1095	packet.data[0] = pmdata->num_data-1;
1096	packet.data[1] = pmdata->data[3];
1097	for (i = 0; i <packet.data[0]-1; i++)
1098		packet.data[i+2] = pmdata->data[i+4];
1099
1100	packet.saveBuf = adbBuffer;
1101	packet.compRout = adbCompRout;
1102	packet.compData = adbCompData;
1103	packet.unsol = 0;
1104	packet.ack_only = 0;
1105	adb_polling = 1;
1106	adb_pass_up(&packet);
1107	adb_polling = 0;
1108
1109	adbWaiting = 0;
1110	adbBuffer = (long)0;
1111	adbCompRout = (long)0;
1112	adbCompData = (long)0;
1113}
1114
1115
1116void
1117pm_adb_get_ADB_data(pmdata)
1118	PMData *pmdata;
1119{
1120	int i;
1121	struct adbCommand packet;
1122
1123	/* set up data for adb_pass_up */
1124	packet.data[0] = pmdata->num_data-1;	/* number of raw data */
1125	packet.data[1] = pmdata->data[3];	/* ADB command */
1126	for (i = 0; i <packet.data[0]-1; i++)
1127		packet.data[i+2] = pmdata->data[i+4];
1128	packet.unsol = 1;
1129	packet.ack_only = 0;
1130	adb_pass_up(&packet);
1131}
1132
1133
1134void
1135pm_adb_poll_next_device_pm1(pmdata)
1136	PMData *pmdata;
1137{
1138	int i;
1139	int ndid;
1140	u_short bendid = 0x1;
1141	int rval;
1142	PMData tmp_pmdata;
1143
1144	/* find another existent ADB device to poll */
1145	for (i = 1; i < 16; i++) {
1146		ndid = (((pmdata->data[3] & 0xf0) >> 4) + i) & 0xf;
1147		bendid <<= ndid;
1148		if ((pm_existent_ADB_devices & bendid) != 0)
1149			break;
1150	}
1151
1152	/* poll the other device */
1153	tmp_pmdata.command = 0x20;
1154	tmp_pmdata.num_data = 3;
1155	tmp_pmdata.s_buf = tmp_pmdata.data;
1156	tmp_pmdata.r_buf = tmp_pmdata.data;
1157	tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1158	tmp_pmdata.data[1] = 0x04;	/* magic spell for awaking the PM */
1159	tmp_pmdata.data[2] = 0x00;
1160	rval = pmgrop(&tmp_pmdata);
1161}
1162
1163void
1164pm_adb_restart()
1165{
1166	PMData p;
1167
1168	p.command = 0xd0;	/* reset CPU */
1169	p.num_data = 0;
1170	p.s_buf = p.data;
1171	p.r_buf = p.data;
1172	pmgrop(&p);
1173}
1174
1175void
1176pm_read_date_time(time)
1177	u_long *time;
1178{
1179	PMData p;
1180
1181	p.command = 0x38;	/* read time */
1182	p.num_data = 0;
1183	p.s_buf = p.data;
1184	p.r_buf = p.data;
1185	pmgrop(&p);
1186
1187	bcopy(p.data, &time, 4);
1188}
1189