pm_direct.c revision 1.15
1/*	$NetBSD: pm_direct.c,v 1.15 2001/09/16 16:34:32 wiz 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, 0x03,   -1,   -1,   -1,   -1,
100	0x00, 0x00, 0x02, 0x02,   -1,   -1,   -1,   -1,
101	0x01, 0x01,   -1,   -1,   -1,   -1,   -1,   -1,
102	0x00, 0x00,   -1,   -1, 0x01,   -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, 0x02,   -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/* these functions are called from adb_direct.c */
189void	pm_setup_adb __P((void));
190void	pm_check_adb_devices __P((int));
191void	pm_intr __P((void));
192int	pm_adb_op __P((u_char *, void *, void *, int));
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#if 0
225/*
226 * Define the external functions
227 */
228extern int	zshard __P((int));		/* from zs.c */
229#endif
230
231#ifdef ADB_DEBUG
232/*
233 * This function dumps contents of the PMData
234 */
235void
236pm_printerr(ttl, rval, num, data)
237	char *ttl;
238	int rval;
239	int num;
240	char *data;
241{
242	int i;
243
244	printf("pm: %s:%04x %02x ", ttl, rval, num);
245	for (i = 0; i < num; i++)
246		printf("%02x ", data[i]);
247	printf("\n");
248}
249#endif
250
251
252
253/*
254 * Check the hardware type of the Power Manager
255 */
256void
257pm_setup_adb()
258{
259	pmHardware = PM_HW_PB5XX;	/* XXX */
260}
261
262
263/*
264 * Check the existent ADB devices
265 */
266void
267pm_check_adb_devices(id)
268	int id;
269{
270	u_short ed = 0x1;
271
272	ed <<= id;
273	pm_existent_ADB_devices |= ed;
274}
275
276
277/*
278 * Wait until PM IC is busy
279 */
280int
281pm_wait_busy(delay)
282	int delay;
283{
284	while (PM_IS_ON) {
285#ifdef PM_GRAB_SI
286#if 0
287		zshard(0);		/* grab any serial interrupts */
288#else
289		(void)intr_dispatch(0x70);
290#endif
291#endif
292		if ((--delay) < 0)
293			return 1;	/* timeout */
294	}
295	return 0;
296}
297
298
299/*
300 * Wait until PM IC is free
301 */
302int
303pm_wait_free(delay)
304	int delay;
305{
306	while (PM_IS_OFF) {
307#ifdef PM_GRAB_SI
308#if 0
309		zshard(0);		/* grab any serial interrupts */
310#else
311		(void)intr_dispatch(0x70);
312#endif
313#endif
314		if ((--delay) < 0)
315			return 0;	/* timeout */
316	}
317	return 1;
318}
319
320
321
322/*
323 * Functions for the PB1XX series
324 */
325
326/*
327 * Receive data from PM for the PB1XX series
328 */
329int
330pm_receive_pm1(data)
331	u_char *data;
332{
333#if 0
334	int rval = 0xffffcd34;
335
336	via_reg(VIA2, vDirA) = 0x00;
337
338	switch (1) {
339		default:
340			if (pm_wait_busy(0x40) != 0)
341				break;			/* timeout */
342
343			PM_SET_STATE_ACKOFF();
344			*data = via_reg(VIA2, 0x200);
345
346			rval = 0xffffcd33;
347			if (pm_wait_free(0x40) == 0)
348				break;			/* timeout */
349
350			rval = 0x00;
351			break;
352	}
353
354	PM_SET_STATE_ACKON();
355	via_reg(VIA2, vDirA) = 0x00;
356
357	return rval;
358#else
359	panic("pm_receive_pm1");
360#endif
361}
362
363
364
365/*
366 * Send data to PM for the PB1XX series
367 */
368int
369pm_send_pm1(data, delay)
370	u_char data;
371	int delay;
372{
373#if 0
374	int rval;
375
376	via_reg(VIA2, vDirA) = 0xff;
377	via_reg(VIA2, 0x200) = data;
378
379	PM_SET_STATE_ACKOFF();
380	if (pm_wait_busy(0x400) != 0) {
381		PM_SET_STATE_ACKON();
382		via_reg(VIA2, vDirA) = 0x00;
383
384		return 0xffffcd36;
385	}
386
387	rval = 0x0;
388	PM_SET_STATE_ACKON();
389	if (pm_wait_free(0x40) == 0)
390		rval = 0xffffcd35;
391
392	PM_SET_STATE_ACKON();
393	via_reg(VIA2, vDirA) = 0x00;
394
395	return rval;
396#else
397	panic("pm_send_pm1");
398#endif
399}
400
401
402/*
403 * My PMgrOp routine for the PB1XX series
404 */
405int
406pm_pmgrop_pm1(pmdata)
407	PMData *pmdata;
408{
409#if 0
410	int i;
411	int s = 0x81815963;
412	u_char via1_vIER, via1_vDirA;
413	int rval = 0;
414	int num_pm_data = 0;
415	u_char pm_cmd;
416	u_char pm_data;
417	u_char *pm_buf;
418
419	/* disable all inetrrupts but PM */
420	via1_vIER = via_reg(VIA1, vIER);
421	PM_VIA_INTR_DISABLE();
422
423	via1_vDirA = via_reg(VIA1, vDirA);
424
425	switch (pmdata->command) {
426		default:
427			for (i = 0; i < 7; i++) {
428				via_reg(VIA2, vDirA) = 0x00;
429
430				/* wait until PM is free */
431				if (pm_wait_free(ADBDelay) == 0) {	/* timeout */
432					via_reg(VIA2, vDirA) = 0x00;
433					/* restore formar value */
434					via_reg(VIA1, vDirA) = via1_vDirA;
435					via_reg(VIA1, vIER) = via1_vIER;
436					return 0xffffcd38;
437				}
438
439				switch (mac68k_machine.machineid) {
440					case MACH_MACPB160:
441					case MACH_MACPB165:
442					case MACH_MACPB165C:
443					case MACH_MACPB180:
444					case MACH_MACPB180C:
445						{
446							int delay = ADBDelay * 16;
447
448							via_reg(VIA2, vDirA) = 0x00;
449							while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
450								delay--;
451
452							if (delay < 0) {	/* timeout */
453								via_reg(VIA2, vDirA) = 0x00;
454								/* restore formar value */
455								via_reg(VIA1, vIER) = via1_vIER;
456								return 0xffffcd38;
457							}
458						}
459				} /* end switch */
460
461				s = splhigh();
462
463				via1_vDirA = via_reg(VIA1, vDirA);
464				via_reg(VIA1, vDirA) &= 0x7f;
465
466				pm_cmd = (u_char)(pmdata->command & 0xff);
467				if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0)
468					break;	/* send command succeeded */
469
470				via_reg(VIA1, vDirA) = via1_vDirA;
471				splx(s);
472			} /* end for */
473
474			/* failed to send a command */
475			if (i == 7) {
476				via_reg(VIA2, vDirA) = 0x00;
477				/* restore formar value */
478				via_reg(VIA1, vDirA) = via1_vDirA;
479				via_reg(VIA1, vIER) = via1_vIER;
480				if (s != 0x81815963)
481					splx(s);
482				return 0xffffcd38;
483			}
484
485			/* send # of PM data */
486			num_pm_data = pmdata->num_data;
487			if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
488				break;			/* timeout */
489
490			/* send PM data */
491			pm_buf = (u_char *)pmdata->s_buf;
492			for (i = 0; i < num_pm_data; i++)
493				if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
494					break;		/* timeout */
495			if ((i != num_pm_data) && (num_pm_data != 0))
496				break;			/* timeout */
497
498			/* Will PM IC return data? */
499			if ((pm_cmd & 0x08) == 0) {
500				rval = 0;
501				break;			/* no returned data */
502			}
503
504			rval = 0xffffcd37;
505			if (pm_wait_busy(ADBDelay) != 0)
506				break;			/* timeout */
507
508			/* receive PM command */
509			if ((rval = pm_receive_pm1(&pm_data)) != 0)
510				break;
511
512			pmdata->command = pm_data;
513
514			/* receive number of PM data */
515			if ((rval = pm_receive_pm1(&pm_data)) != 0)
516				break;			/* timeout */
517			num_pm_data = pm_data;
518			pmdata->num_data = num_pm_data;
519
520			/* receive PM data */
521			pm_buf = (u_char *)pmdata->r_buf;
522			for (i = 0; i < num_pm_data; i++) {
523				if ((rval = pm_receive_pm1(&pm_data)) != 0)
524					break;		/* timeout */
525				pm_buf[i] = pm_data;
526			}
527
528			rval = 0;
529	}
530
531	via_reg(VIA2, vDirA) = 0x00;
532
533	/* restore formar value */
534	via_reg(VIA1, vDirA) = via1_vDirA;
535	via_reg(VIA1, vIER) = via1_vIER;
536	if (s != 0x81815963)
537		splx(s);
538
539	return rval;
540#else
541	panic("pm_pmgrop_pm1");
542#endif
543}
544
545
546/*
547 * My PM interrupt routine for PB1XX series
548 */
549void
550pm_intr_pm1()
551{
552#if 0
553	int s;
554	int rval;
555	PMData pmdata;
556
557	s = splhigh();
558
559	PM_VIA_CLR_INTR();				/* clear VIA1 interrupt */
560
561	/* ask PM what happend */
562	pmdata.command = 0x78;
563	pmdata.num_data = 0;
564	pmdata.data[0] = pmdata.data[1] = 0;
565	pmdata.s_buf = &pmdata.data[2];
566	pmdata.r_buf = &pmdata.data[2];
567	rval = pm_pmgrop_pm1(&pmdata);
568	if (rval != 0) {
569#ifdef ADB_DEBUG
570		if (adb_debug)
571			printf("pm: PM is not ready. error code=%08x\n", rval);
572#endif
573		splx(s);
574	}
575
576	if ((pmdata.data[2] & 0x10) == 0x10) {
577		if ((pmdata.data[2] & 0x0f) == 0) {
578			/* ADB data that were requested by TALK command */
579			pm_adb_get_TALK_result(&pmdata);
580		} else if ((pmdata.data[2] & 0x08) == 0x8) {
581			/* PM is requesting to poll  */
582			pm_adb_poll_next_device_pm1(&pmdata);
583		} else if ((pmdata.data[2] & 0x04) == 0x4) {
584			/* ADB device event */
585			pm_adb_get_ADB_data(&pmdata);
586		}
587	} else {
588#ifdef ADB_DEBUG
589		if (adb_debug)
590			pm_printerr("driver does not supported this event.",
591			    rval, pmdata.num_data, pmdata.data);
592#endif
593	}
594
595	splx(s);
596#else
597	panic("pm_intr_pm1");
598#endif
599}
600
601
602
603/*
604 * Functions for the PB Duo series and the PB 5XX series
605 */
606
607/*
608 * Receive data from PM for the PB Duo series and the PB 5XX series
609 */
610int
611pm_receive_pm2(data)
612	u_char *data;
613{
614	int i;
615	int rval;
616
617	rval = 0xffffcd34;
618
619	switch (1) {
620		default:
621			/* set VIA SR to input mode */
622			via_reg_or(VIA1, vACR, 0x0c);
623			via_reg_and(VIA1, vACR, ~0x10);
624			i = PM_SR();
625
626			PM_SET_STATE_ACKOFF();
627			if (pm_wait_busy((int)ADBDelay*32) != 0)
628				break;		/* timeout */
629
630			PM_SET_STATE_ACKON();
631			rval = 0xffffcd33;
632			if (pm_wait_free((int)ADBDelay*32) == 0)
633				break;		/* timeout */
634
635			*data = PM_SR();
636			rval = 0;
637
638			break;
639	}
640
641	PM_SET_STATE_ACKON();
642	via_reg_or(VIA1, vACR, 0x1c);
643
644	return rval;
645}
646
647
648
649/*
650 * Send data to PM for the PB Duo series and the PB 5XX series
651 */
652int
653pm_send_pm2(data)
654	u_char data;
655{
656	int rval;
657
658	via_reg_or(VIA1, vACR, 0x1c);
659	write_via_reg(VIA1, vSR, data);	/* PM_SR() = data; */
660
661	PM_SET_STATE_ACKOFF();
662	rval = 0xffffcd36;
663	if (pm_wait_busy((int)ADBDelay*32) != 0) {
664		PM_SET_STATE_ACKON();
665
666		via_reg_or(VIA1, vACR, 0x1c);
667
668		return rval;
669	}
670
671	PM_SET_STATE_ACKON();
672	rval = 0xffffcd35;
673	if (pm_wait_free((int)ADBDelay*32) != 0)
674		rval = 0;
675
676	PM_SET_STATE_ACKON();
677	via_reg_or(VIA1, vACR, 0x1c);
678
679	return rval;
680}
681
682
683
684/*
685 * My PMgrOp routine for the PB Duo series and the PB 5XX series
686 */
687int
688pm_pmgrop_pm2(pmdata)
689	PMData *pmdata;
690{
691	int i;
692	int s;
693	u_char via1_vIER;
694	int rval = 0;
695	int num_pm_data = 0;
696	u_char pm_cmd;
697	short pm_num_rx_data;
698	u_char pm_data;
699	u_char *pm_buf;
700
701	s = splhigh();
702
703	/* disable all inetrrupts but PM */
704	via1_vIER = 0x10;
705	via1_vIER &= read_via_reg(VIA1, vIER);
706	write_via_reg(VIA1, vIER, via1_vIER);
707	if (via1_vIER != 0x0)
708		via1_vIER |= 0x80;
709
710	switch (pmdata->command) {
711		default:
712			/* wait until PM is free */
713			pm_cmd = (u_char)(pmdata->command & 0xff);
714			rval = 0xcd38;
715			if (pm_wait_free(ADBDelay * 4) == 0)
716				break;			/* timeout */
717
718			if (HwCfgFlags3 & 0x00200000) {
719				/* PB 160, PB 165(c), PB 180(c)? */
720				int delay = ADBDelay * 16;
721
722				write_via_reg(VIA2, vDirA, 0x00);
723				while ((read_via_reg(VIA2, 0x200) == 0x07) &&
724				    (delay >= 0))
725					delay--;
726
727				if (delay < 0) {
728					rval = 0xffffcd38;
729					break;		/* timeout */
730				}
731			}
732
733			/* send PM command */
734			if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
735				break;				/* timeout */
736
737			/* send number of PM data */
738			num_pm_data = pmdata->num_data;
739			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
740				if (pm_send_cmd_type[pm_cmd] < 0) {
741					if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
742						break;		/* timeout */
743					pmdata->command = 0;
744				}
745			} else {				/* PB 1XX series ? */
746				if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
747					break;			/* timeout */
748			}
749			/* send PM data */
750			pm_buf = (u_char *)pmdata->s_buf;
751			for (i = 0 ; i < num_pm_data; i++)
752				if ((rval = pm_send_pm2(pm_buf[i])) != 0)
753					break;			/* timeout */
754			if (i != num_pm_data)
755				break;				/* timeout */
756
757
758			/* check if PM will send me data  */
759			pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
760			pmdata->num_data = pm_num_rx_data;
761			if (pm_num_rx_data == 0) {
762				rval = 0;
763				break;				/* no return data */
764			}
765
766			/* receive PM command */
767			pm_data = pmdata->command;
768			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
769				pm_num_rx_data--;
770				if (pm_num_rx_data == 0)
771					if ((rval = pm_receive_pm2(&pm_data)) != 0) {
772						rval = 0xffffcd37;
773						break;
774					}
775				pmdata->command = pm_data;
776			} else {				/* PB 1XX series ? */
777				if ((rval = pm_receive_pm2(&pm_data)) != 0) {
778					rval = 0xffffcd37;
779					break;
780				}
781				pmdata->command = pm_data;
782			}
783
784			/* receive number of PM data */
785			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
786				if (pm_num_rx_data < 0) {
787					if ((rval = pm_receive_pm2(&pm_data)) != 0)
788						break;		/* timeout */
789					num_pm_data = pm_data;
790				} else
791					num_pm_data = pm_num_rx_data;
792				pmdata->num_data = num_pm_data;
793			} else {				/* PB 1XX serias ? */
794				if ((rval = pm_receive_pm2(&pm_data)) != 0)
795					break;			/* timeout */
796				num_pm_data = pm_data;
797				pmdata->num_data = num_pm_data;
798			}
799
800			/* receive PM data */
801			pm_buf = (u_char *)pmdata->r_buf;
802			for (i = 0; i < num_pm_data; i++) {
803				if ((rval = pm_receive_pm2(&pm_data)) != 0)
804					break;			/* timeout */
805				pm_buf[i] = pm_data;
806			}
807
808			rval = 0;
809	}
810
811	/* restore former value */
812	write_via_reg(VIA1, vIER, via1_vIER);
813	splx(s);
814
815	return rval;
816}
817
818
819/*
820 * My PM interrupt routine for the PB Duo series and the PB 5XX series
821 */
822void
823pm_intr_pm2()
824{
825	int s;
826	int rval;
827	PMData pmdata;
828
829	s = splhigh();
830
831	PM_VIA_CLR_INTR();			/* clear VIA1 interrupt */
832						/* ask PM what happend */
833	pmdata.command = 0x78;
834	pmdata.num_data = 0;
835	pmdata.s_buf = &pmdata.data[2];
836	pmdata.r_buf = &pmdata.data[2];
837	rval = pm_pmgrop_pm2(&pmdata);
838	if (rval != 0) {
839#ifdef ADB_DEBUG
840		if (adb_debug)
841			printf("pm: PM is not ready. error code: %08x\n", rval);
842#endif
843		splx(s);
844	}
845
846	switch ((u_int)(pmdata.data[2] & 0xff)) {
847		case 0x00:			/* 1 sec interrupt? */
848			break;
849		case 0x80:			/* 1 sec interrupt? */
850			pm_counter++;
851			break;
852		case 0x08:			/* Brightness/Contrast button on LCD panel */
853			/* get brightness and contrast of the LCD */
854			pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
855			pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
856/*
857			pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
858			pmdata.command = 0x33;
859			pmdata.num_data = 1;
860			pmdata.s_buf = pmdata.data;
861			pmdata.r_buf = pmdata.data;
862			pmdata.data[0] = pm_LCD_contrast;
863			rval = pm_pmgrop_pm2(&pmdata);
864			pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
865*/
866			/* this is an experimental code */
867			pmdata.command = 0x41;
868			pmdata.num_data = 1;
869			pmdata.s_buf = pmdata.data;
870			pmdata.r_buf = pmdata.data;
871			pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
872			if (pm_LCD_brightness < 0x08)
873				pm_LCD_brightness = 0x08;
874			if (pm_LCD_brightness > 0x78)
875				pm_LCD_brightness = 0x78;
876			pmdata.data[0] = pm_LCD_brightness;
877			rval = pm_pmgrop_pm2(&pmdata);
878			break;
879		case 0x10:			/* ADB data that were requested by TALK command */
880		case 0x14:
881			pm_adb_get_TALK_result(&pmdata);
882			break;
883		case 0x16:			/* ADB device event */
884		case 0x18:
885		case 0x1e:
886			pm_adb_get_ADB_data(&pmdata);
887			break;
888		default:
889#ifdef ADB_DEBUG
890			if (adb_debug)
891				pm_printerr("driver does not supported this event.",
892				    pmdata.data[2], pmdata.num_data,
893				    pmdata.data);
894#endif
895			break;
896	}
897
898	splx(s);
899}
900
901
902/*
903 * My PMgrOp routine
904 */
905int
906pmgrop(pmdata)
907	PMData *pmdata;
908{
909	switch (pmHardware) {
910		case PM_HW_PB1XX:
911			return (pm_pmgrop_pm1(pmdata));
912			break;
913		case PM_HW_PB5XX:
914			return (pm_pmgrop_pm2(pmdata));
915			break;
916		default:
917			/* return (pmgrop_mrg(pmdata)); */
918			return 1;
919	}
920}
921
922
923/*
924 * My PM interrupt routine
925 */
926void
927pm_intr()
928{
929	switch (pmHardware) {
930		case PM_HW_PB1XX:
931			pm_intr_pm1();
932			break;
933		case PM_HW_PB5XX:
934			pm_intr_pm2();
935			break;
936		default:
937			break;
938	}
939}
940
941
942
943/*
944 * Synchronous ADBOp routine for the Power Manager
945 */
946int
947pm_adb_op(buffer, compRout, data, command)
948	u_char *buffer;
949	void *compRout;
950	void *data;
951	int command;
952{
953	int i;
954	int s;
955	int rval;
956	int timo;
957	PMData pmdata;
958	struct adbCommand packet;
959
960	if (adbWaiting == 1)
961		return 1;
962
963	s = splhigh();
964	write_via_reg(VIA1, vIER, 0x10);
965
966 	adbBuffer = buffer;
967	adbCompRout = compRout;
968	adbCompData = data;
969
970	pmdata.command = 0x20;
971	pmdata.s_buf = pmdata.data;
972	pmdata.r_buf = pmdata.data;
973
974	/* if the command is LISTEN, add number of ADB data to number of PM data */
975	if ((command & 0xc) == 0x8) {
976		if (buffer != (u_char *)0)
977			pmdata.num_data = buffer[0] + 3;
978	} else {
979		pmdata.num_data = 3;
980	}
981
982	pmdata.data[0] = (u_char)(command & 0xff);
983	pmdata.data[1] = 0;
984	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, copy ADB data to PM buffer */
985		if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
986			pmdata.data[2] = buffer[0];		/* number of data */
987			for (i = 0; i < buffer[0]; i++)
988				pmdata.data[3 + i] = buffer[1 + i];
989		} else
990			pmdata.data[2] = 0;
991	} else
992		pmdata.data[2] = 0;
993
994	if ((command & 0xc) != 0xc) {		/* if the command is not TALK */
995		/* set up stuff for adb_pass_up */
996		packet.data[0] = 1 + pmdata.data[2];
997		packet.data[1] = command;
998		for (i = 0; i < pmdata.data[2]; i++)
999			packet.data[i+2] = pmdata.data[i+3];
1000		packet.saveBuf = adbBuffer;
1001		packet.compRout = adbCompRout;
1002		packet.compData = adbCompData;
1003		packet.cmd = command;
1004		packet.unsol = 0;
1005		packet.ack_only = 1;
1006		adb_polling = 1;
1007		adb_pass_up(&packet);
1008		adb_polling = 0;
1009	}
1010
1011	rval = pmgrop(&pmdata);
1012	if (rval != 0) {
1013		splx(s);
1014		return 1;
1015	}
1016
1017	delay(10000);
1018
1019	adbWaiting = 1;
1020	adbWaitingCmd = command;
1021
1022	PM_VIA_INTR_ENABLE();
1023
1024	/* wait until the PM interrupt is occurred */
1025	timo = 0x80000;
1026	while (adbWaiting == 1) {
1027		if (read_via_reg(VIA1, vIFR) & 0x14)
1028			pm_intr();
1029#ifdef PM_GRAB_SI
1030#if 0
1031			zshard(0);		/* grab any serial interrupts */
1032#else
1033			(void)intr_dispatch(0x70);
1034#endif
1035#endif
1036		if ((--timo) < 0) {
1037			splx(s);
1038			return 1;
1039		}
1040	}
1041
1042	/* this command enables the interrupt by operating ADB devices */
1043	if (HwCfgFlags3 & 0x00020000) {		/* PB Duo series, PB 5XX series */
1044		pmdata.command = 0x20;
1045		pmdata.num_data = 4;
1046		pmdata.s_buf = pmdata.data;
1047		pmdata.r_buf = pmdata.data;
1048		pmdata.data[0] = 0x00;
1049		pmdata.data[1] = 0x86;	/* magic spell for awaking the PM */
1050		pmdata.data[2] = 0x00;
1051		pmdata.data[3] = 0x0c;	/* each bit may express the existent ADB device */
1052	} else {				/* PB 1XX series */
1053		pmdata.command = 0x20;
1054		pmdata.num_data = 3;
1055		pmdata.s_buf = pmdata.data;
1056		pmdata.r_buf = pmdata.data;
1057		pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1058		pmdata.data[1] = 0x04;
1059		pmdata.data[2] = 0x00;
1060	}
1061	rval = pmgrop(&pmdata);
1062
1063	splx(s);
1064	return rval;
1065}
1066
1067
1068void
1069pm_adb_get_TALK_result(pmdata)
1070	PMData *pmdata;
1071{
1072	int i;
1073	struct adbCommand packet;
1074
1075	/* set up data for adb_pass_up */
1076	packet.data[0] = pmdata->num_data-1;
1077	packet.data[1] = pmdata->data[3];
1078	for (i = 0; i <packet.data[0]-1; i++)
1079		packet.data[i+2] = pmdata->data[i+4];
1080
1081	packet.saveBuf = adbBuffer;
1082	packet.compRout = adbCompRout;
1083	packet.compData = adbCompData;
1084	packet.unsol = 0;
1085	packet.ack_only = 0;
1086	adb_polling = 1;
1087	adb_pass_up(&packet);
1088	adb_polling = 0;
1089
1090	adbWaiting = 0;
1091	adbBuffer = (long)0;
1092	adbCompRout = (long)0;
1093	adbCompData = (long)0;
1094}
1095
1096
1097void
1098pm_adb_get_ADB_data(pmdata)
1099	PMData *pmdata;
1100{
1101	int i;
1102	struct adbCommand packet;
1103
1104	/* set up data for adb_pass_up */
1105	packet.data[0] = pmdata->num_data-1;	/* number of raw data */
1106	packet.data[1] = pmdata->data[3];	/* ADB command */
1107	for (i = 0; i <packet.data[0]-1; i++)
1108		packet.data[i+2] = pmdata->data[i+4];
1109	packet.unsol = 1;
1110	packet.ack_only = 0;
1111	adb_pass_up(&packet);
1112}
1113
1114
1115void
1116pm_adb_poll_next_device_pm1(pmdata)
1117	PMData *pmdata;
1118{
1119	int i;
1120	int ndid;
1121	u_short bendid = 0x1;
1122	int rval;
1123	PMData tmp_pmdata;
1124
1125	/* find another existent ADB device to poll */
1126	for (i = 1; i < 16; i++) {
1127		ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf;
1128		bendid <<= ndid;
1129		if ((pm_existent_ADB_devices & bendid) != 0)
1130			break;
1131	}
1132
1133	/* poll the other device */
1134	tmp_pmdata.command = 0x20;
1135	tmp_pmdata.num_data = 3;
1136	tmp_pmdata.s_buf = tmp_pmdata.data;
1137	tmp_pmdata.r_buf = tmp_pmdata.data;
1138	tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1139	tmp_pmdata.data[1] = 0x04;	/* magic spell for awaking the PM */
1140	tmp_pmdata.data[2] = 0x00;
1141	rval = pmgrop(&tmp_pmdata);
1142}
1143
1144void
1145pm_adb_restart()
1146{
1147	PMData p;
1148
1149	p.command = PMU_RESET_CPU;
1150	p.num_data = 0;
1151	p.s_buf = p.data;
1152	p.r_buf = p.data;
1153	pmgrop(&p);
1154}
1155
1156void
1157pm_adb_poweroff()
1158{
1159	PMData p;
1160
1161	p.command = PMU_POWER_OFF;
1162	p.num_data = 4;
1163	p.s_buf = p.data;
1164	p.r_buf = p.data;
1165	strcpy(p.data, "MATT");
1166	pmgrop(&p);
1167}
1168
1169void
1170pm_read_date_time(time)
1171	u_long *time;
1172{
1173	PMData p;
1174
1175	p.command = PMU_READ_RTC;
1176	p.num_data = 0;
1177	p.s_buf = p.data;
1178	p.r_buf = p.data;
1179	pmgrop(&p);
1180
1181	memcpy(time, p.data, 4);
1182}
1183
1184void
1185pm_set_date_time(time)
1186	u_long time;
1187{
1188	PMData p;
1189
1190	p.command = PMU_SET_RTC;
1191	p.num_data = 4;
1192	p.s_buf = p.r_buf = p.data;
1193	memcpy(p.data, &time, 4);
1194	pmgrop(&p);
1195}
1196
1197int
1198pm_read_brightness()
1199{
1200	PMData p;
1201
1202	p.command = PMU_READ_BRIGHTNESS;
1203	p.num_data = 1;		/* XXX why 1? */
1204	p.s_buf = p.r_buf = p.data;
1205	p.data[0] = 0;
1206	pmgrop(&p);
1207
1208	return p.data[0];
1209}
1210
1211void
1212pm_set_brightness(val)
1213	int val;
1214{
1215	PMData p;
1216
1217	val = 0x7f - val / 2;
1218	if (val < 0x08)
1219		val = 0x08;
1220	if (val > 0x78)
1221		val = 0x78;
1222
1223	p.command = PMU_SET_BRIGHTNESS;
1224	p.num_data = 1;
1225	p.s_buf = p.r_buf = p.data;
1226	p.data[0] = val;
1227	pmgrop(&p);
1228}
1229
1230void
1231pm_init_brightness()
1232{
1233	int val;
1234
1235	val = pm_read_brightness();
1236	pm_set_brightness(val);
1237}
1238
1239void
1240pm_eject_pcmcia(slot)
1241	int slot;
1242{
1243	PMData p;
1244
1245	if (slot != 0 && slot != 1)
1246		return;
1247
1248	p.command = PMU_EJECT_PCMCIA;
1249	p.num_data = 1;
1250	p.s_buf = p.r_buf = p.data;
1251	p.data[0] = 5 + slot;	/* XXX */
1252	pmgrop(&p);
1253}
1254
1255int
1256pm_read_nvram(addr)
1257	int addr;
1258{
1259	PMData p;
1260
1261	p.command = PMU_READ_NVRAM;
1262	p.num_data = 2;
1263	p.s_buf = p.r_buf = p.data;
1264	p.data[0] = addr >> 8;
1265	p.data[1] = addr;
1266	pmgrop(&p);
1267
1268	return p.data[0];
1269}
1270
1271void
1272pm_write_nvram(addr, val)
1273	int addr, val;
1274{
1275	PMData p;
1276
1277	p.command = PMU_WRITE_NVRAM;
1278	p.num_data = 3;
1279	p.s_buf = p.r_buf = p.data;
1280	p.data[0] = addr >> 8;
1281	p.data[1] = addr;
1282	p.data[2] = val;
1283	pmgrop(&p);
1284}
1285