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