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