pm_direct.c revision 1.14
1/*	$NetBSD: pm_direct.c,v 1.14 2000/07/03 08:59:27 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));
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
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	switch (mac68k_machine.machineid) {
260		case MACH_MACPB140:
261		case MACH_MACPB145:
262		case MACH_MACPB150:
263		case MACH_MACPB160:
264		case MACH_MACPB165:
265		case MACH_MACPB165C:
266		case MACH_MACPB170:
267		case MACH_MACPB180:
268		case MACH_MACPB180C:
269			pmHardware = PM_HW_PB1XX;
270			break;
271		case MACH_MACPB210:
272		case MACH_MACPB230:
273		case MACH_MACPB250:
274		case MACH_MACPB270:
275		case MACH_MACPB280:
276		case MACH_MACPB280C:
277		case MACH_MACPB500:
278			pmHardware = PM_HW_PB5XX;
279			break;
280		default:
281			break;
282	}
283}
284
285
286/*
287 * Check the existent ADB devices
288 */
289void
290pm_check_adb_devices(id)
291	int id;
292{
293	u_short ed = 0x1;
294
295	ed <<= id;
296	pm_existent_ADB_devices |= ed;
297}
298
299
300/*
301 * Wait until PM IC is busy
302 */
303int
304pm_wait_busy(delay)
305	int delay;
306{
307	while (PM_IS_ON) {
308#ifdef PM_GRAB_SI
309#if 0
310		zshard(0);		/* grab any serial interrupts */
311#else
312		(void)intr_dispatch(0x70);
313#endif
314#endif
315		if ((--delay) < 0)
316			return 1;	/* timeout */
317	}
318	return 0;
319}
320
321
322/*
323 * Wait until PM IC is free
324 */
325int
326pm_wait_free(delay)
327	int delay;
328{
329	while (PM_IS_OFF) {
330#ifdef PM_GRAB_SI
331#if 0
332		zshard(0);		/* grab any serial interrupts */
333#else
334		(void)intr_dispatch(0x70);
335#endif
336#endif
337		if ((--delay) < 0)
338			return 0;	/* timeout */
339	}
340	return 1;
341}
342
343
344
345/*
346 * Functions for the PB1XX series
347 */
348
349/*
350 * Receive data from PM for the PB1XX series
351 */
352int
353pm_receive_pm1(data)
354	u_char *data;
355{
356	int rval = 0xffffcd34;
357
358	via_reg(VIA2, vDirA) = 0x00;
359
360	switch (1) {
361		default:
362			if (pm_wait_busy(0x40) != 0)
363				break;			/* timeout */
364
365			PM_SET_STATE_ACKOFF();
366			*data = via_reg(VIA2, 0x200);
367
368			rval = 0xffffcd33;
369			if (pm_wait_free(0x40) == 0)
370				break;			/* timeout */
371
372			rval = 0x00;
373			break;
374	}
375
376	PM_SET_STATE_ACKON();
377	via_reg(VIA2, vDirA) = 0x00;
378
379	return rval;
380}
381
382
383
384/*
385 * Send data to PM for the PB1XX series
386 */
387int
388pm_send_pm1(data, timo)
389	u_char data;
390	int timo;
391{
392	int rval;
393
394	via_reg(VIA2, vDirA) = 0xff;
395	via_reg(VIA2, 0x200) = data;
396
397	PM_SET_STATE_ACKOFF();
398#if 0
399	if (pm_wait_busy(0x400) == 0) {
400#else
401	if (pm_wait_busy(timo) == 0) {
402#endif
403		PM_SET_STATE_ACKON();
404		if (pm_wait_free(0x40) != 0)
405			rval = 0x0;
406		else
407			rval = 0xffffcd35;
408	} else {
409		rval = 0xffffcd36;
410	}
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				if (s != 0x81815963)
498					splx(s);
499				return 0xffffcd38;
500			}
501
502			/* send # of PM data */
503			num_pm_data = pmdata->num_data;
504			if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
505				break;			/* timeout */
506
507			/* send PM data */
508			pm_buf = (u_char *)pmdata->s_buf;
509			for (i = 0; i < num_pm_data; i++)
510				if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
511					break;		/* timeout */
512			if ((i != num_pm_data) && (num_pm_data != 0))
513				break;			/* timeout */
514
515			/* Will PM IC return data? */
516			if ((pm_cmd & 0x08) == 0) {
517				rval = 0;
518				break;			/* no returned data */
519			}
520
521			rval = 0xffffcd37;
522			if (pm_wait_busy(ADBDelay) != 0)
523				break;			/* timeout */
524
525			/* receive PM command */
526			if ((rval = pm_receive_pm1(&pm_data)) != 0)
527				break;
528
529			pmdata->command = pm_data;
530
531			/* receive number of PM data */
532			if ((rval = pm_receive_pm1(&pm_data)) != 0)
533				break;			/* timeout */
534			num_pm_data = pm_data;
535			pmdata->num_data = num_pm_data;
536
537			/* receive PM data */
538			pm_buf = (u_char *)pmdata->r_buf;
539			for (i = 0; i < num_pm_data; i++) {
540				if ((rval = pm_receive_pm1(&pm_data)) != 0)
541					break;		/* timeout */
542				pm_buf[i] = pm_data;
543			}
544
545			rval = 0;
546	}
547
548	via_reg(VIA2, vDirA) = 0x00;
549
550	/* restore formar value */
551	via_reg(VIA1, vDirA) = via1_vDirA;
552	via_reg(VIA1, vIER) = via1_vIER;
553	if (s != 0x81815963)
554		splx(s);
555
556	return rval;
557}
558
559
560/*
561 * My PM interrupt routine for PB1XX series
562 */
563void
564pm_intr_pm1(arg)
565	void *arg;
566{
567	int s;
568	int rval;
569	PMData pmdata;
570
571	s = splhigh();
572
573	PM_VIA_CLR_INTR();				/* clear VIA1 interrupt */
574
575	/* ask PM what happend */
576	pmdata.command = 0x78;
577	pmdata.num_data = 0;
578	pmdata.data[0] = pmdata.data[1] = 0;
579	pmdata.s_buf = &pmdata.data[2];
580	pmdata.r_buf = &pmdata.data[2];
581	rval = pm_pmgrop_pm1(&pmdata);
582	if (rval != 0) {
583#ifdef ADB_DEBUG
584		if (adb_debug)
585			printf("pm: PM is not ready. error code=%08x\n", rval);
586#endif
587		splx(s);
588	}
589
590	if ((pmdata.data[2] & 0x10) == 0x10) {
591		if ((pmdata.data[2] & 0x0f) == 0) {
592			/* ADB data that were requested by TALK command */
593			pm_adb_get_TALK_result(&pmdata);
594		} else if ((pmdata.data[2] & 0x08) == 0x8) {
595			/* PM is requesting to poll  */
596			pm_adb_poll_next_device_pm1(&pmdata);
597		} else if ((pmdata.data[2] & 0x04) == 0x4) {
598			/* ADB device event */
599			pm_adb_get_ADB_data(&pmdata);
600		}
601	} else {
602#ifdef ADB_DEBUG
603		if (adb_debug)
604			pm_printerr("driver does not supported this event.",
605			    rval, pmdata.num_data, pmdata.data);
606#endif
607	}
608
609	splx(s);
610}
611
612
613
614/*
615 * Functions for the PB Duo series and the PB 5XX series
616 */
617
618/*
619 * Receive data from PM for the PB Duo series and the PB 5XX series
620 */
621int
622pm_receive_pm2(data)
623	u_char *data;
624{
625	int i;
626	int rval;
627
628	rval = 0xffffcd34;
629
630	switch (1) {
631		default:
632			/* set VIA SR to input mode */
633			via_reg(VIA1, vACR) |= 0x0c;
634			via_reg(VIA1, vACR) &= ~0x10;
635			i = PM_SR();
636
637			PM_SET_STATE_ACKOFF();
638			if (pm_wait_busy((int)ADBDelay*32) != 0)
639				break;		/* timeout */
640
641			PM_SET_STATE_ACKON();
642			rval = 0xffffcd33;
643			if (pm_wait_free((int)ADBDelay*32) == 0)
644				break;		/* timeout */
645
646			*data = PM_SR();
647			rval = 0;
648
649			break;
650	}
651
652	PM_SET_STATE_ACKON();
653	via_reg(VIA1, vACR) |= 0x1c;
654
655	return rval;
656}
657
658
659
660/*
661 * Send data to PM for the PB Duo series and the PB 5XX series
662 */
663int
664pm_send_pm2(data)
665	u_char data;
666{
667	int rval;
668
669	via_reg(VIA1, vACR) |= 0x1c;
670	PM_SR() = data;
671
672	PM_SET_STATE_ACKOFF();
673	if (pm_wait_busy((int)ADBDelay*32) == 0) {
674		PM_SET_STATE_ACKON();
675		if (pm_wait_free((int)ADBDelay*32) != 0)
676			rval = 0;
677		else
678			rval = 0xffffcd35;
679	} else {
680		rval = 0xffffcd36;
681	}
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(arg)
831	void *arg;
832{
833	int s;
834	int rval;
835	PMData pmdata;
836
837	s = splhigh();
838
839	PM_VIA_CLR_INTR();			/* clear VIA1 interrupt */
840						/* ask PM what happend */
841	pmdata.command = 0x78;
842	pmdata.num_data = 0;
843	pmdata.s_buf = &pmdata.data[2];
844	pmdata.r_buf = &pmdata.data[2];
845	rval = pm_pmgrop_pm2(&pmdata);
846	if (rval != 0) {
847#ifdef ADB_DEBUG
848		if (adb_debug)
849			printf("pm: PM is not ready. error code: %08x\n", rval);
850#endif
851		splx(s);
852	}
853
854	switch ((u_int)(pmdata.data[2] & 0xff)) {
855		case 0x00:			/* 1 sec interrupt? */
856			break;
857		case 0x80:			/* 1 sec interrupt? */
858			pm_counter++;
859			break;
860		case 0x08:			/* Brightness/Contrast button on LCD panel */
861			/* get brightness and contrast of the LCD */
862			pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
863			pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
864/*
865			pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
866			pmdata.command = 0x33;
867			pmdata.num_data = 1;
868			pmdata.s_buf = pmdata.data;
869			pmdata.r_buf = pmdata.data;
870			pmdata.data[0] = pm_LCD_contrast;
871			rval = pm_pmgrop_pm2(&pmdata);
872			pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
873*/
874			/* this is an experimental code */
875			pmdata.command = 0x41;
876			pmdata.num_data = 1;
877			pmdata.s_buf = pmdata.data;
878			pmdata.r_buf = pmdata.data;
879			pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
880			if (pm_LCD_brightness < 0x25)
881				pm_LCD_brightness = 0x25;
882			if (pm_LCD_brightness > 0x5a)
883				pm_LCD_brightness = 0x7f;
884			pmdata.data[0] = pm_LCD_brightness;
885			rval = pm_pmgrop_pm2(&pmdata);
886			break;
887		case 0x10:			/* ADB data that were requested by TALK command */
888		case 0x14:
889			pm_adb_get_TALK_result(&pmdata);
890			break;
891		case 0x16:			/* ADB device event */
892		case 0x18:
893		case 0x1e:
894			pm_adb_get_ADB_data(&pmdata);
895			break;
896		default:
897#ifdef ADB_DEBUG
898			if (adb_debug)
899				pm_printerr("driver does not supported this event.",
900				    pmdata.data[2], pmdata.num_data,
901				    pmdata.data);
902#endif
903			break;
904	}
905
906	splx(s);
907}
908
909
910/*
911 * MRG-based PMgrOp routine
912 */
913int
914pm_pmgrop_mrg(pmdata)
915	PMData *pmdata;
916{
917	u_int32_t rval=0;
918
919	asm("
920		movl	%1, a0
921		.word	0xa085
922		movl	d0, %0"
923		: "=g" (rval)
924		: "g" (pmdata)
925		: "a0", "d0" );
926
927	return rval;
928}
929
930
931/*
932 * My PMgrOp routine
933 */
934int
935pmgrop(pmdata)
936	PMData *pmdata;
937{
938	switch (pmHardware) {
939		case PM_HW_PB1XX:
940			return (pm_pmgrop_pm1(pmdata));
941			break;
942		case PM_HW_PB5XX:
943			return (pm_pmgrop_pm2(pmdata));
944			break;
945		default:
946			/* return (pmgrop_mrg(pmdata)); */
947			return 1;
948	}
949}
950
951
952/*
953 * My PM interrupt routine
954 */
955void
956pm_intr(arg)
957	void *arg;
958{
959	switch (pmHardware) {
960		case PM_HW_PB1XX:
961			pm_intr_pm1(arg);
962			break;
963		case PM_HW_PB5XX:
964			pm_intr_pm2(arg);
965			break;
966		default:
967			break;
968	}
969}
970
971
972void
973pm_hw_setup()
974{
975	switch (pmHardware) {
976		case PM_HW_PB1XX:
977			via1_register_irq(4, pm_intr_pm1, (void *)0);
978			PM_VIA_CLR_INTR();
979			break;
980		case PM_HW_PB5XX:
981			via1_register_irq(4, pm_intr_pm2, (void *)0);
982			PM_VIA_CLR_INTR();
983			break;
984		default:
985			break;
986	}
987}
988
989
990/*
991 * Synchronous ADBOp routine for the Power Manager
992 */
993int
994pm_adb_op(buffer, compRout, data, command)
995	u_char *buffer;
996	void *compRout;
997	void *data;
998	int command;
999{
1000	int i;
1001	int s;
1002	int rval;
1003	int delay;
1004	PMData pmdata;
1005	struct adbCommand packet;
1006
1007	if (adbWaiting == 1)
1008		return 1;
1009
1010	s = splhigh();
1011	via_reg(VIA1, vIER) = 0x10;
1012
1013 	adbBuffer = buffer;
1014	adbCompRout = compRout;
1015	adbCompData = data;
1016
1017	pmdata.command = 0x20;
1018	pmdata.s_buf = pmdata.data;
1019	pmdata.r_buf = pmdata.data;
1020
1021	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, add number of ADB data to number of PM data */
1022		if (buffer != (u_char *)0)
1023			pmdata.num_data = buffer[0] + 3;
1024	} else {
1025		pmdata.num_data = 3;
1026	}
1027
1028	pmdata.data[0] = (u_char)(command & 0xff);
1029	pmdata.data[1] = 0;
1030	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, copy ADB data to PM buffer */
1031		if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
1032			pmdata.data[2] = buffer[0];		/* number of data */
1033			for (i = 0; i < buffer[0]; i++)
1034				pmdata.data[3 + i] = buffer[1 + i];
1035		} else
1036			pmdata.data[2] = 0;
1037	} else
1038		pmdata.data[2] = 0;
1039
1040	if ((command & 0xc) != 0xc) {		/* if the command is not TALK */
1041		/* set up stuff fNULLor adb_pass_up */
1042		packet.data[0] = 1 + pmdata.data[2];
1043		packet.data[1] = command;
1044		for (i = 0; i < pmdata.data[2]; i++)
1045			packet.data[i+2] = pmdata.data[i+3];
1046		packet.saveBuf = adbBuffer;
1047		packet.compRout = adbCompRout;
1048		packet.compData = adbCompData;
1049		packet.cmd = command;
1050		packet.unsol = 0;
1051		packet.ack_only = 1;
1052		adb_polling = 1;
1053		adb_pass_up(&packet);
1054		adb_polling = 0;
1055	}
1056
1057	rval = pmgrop(&pmdata);
1058	if (rval != 0) {
1059		splx(s);
1060		return 1;
1061	}
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			splx(s);
1082			return 1;
1083		}
1084	}
1085
1086	/* this command enables the interrupt by operating ADB devices */
1087	if (HwCfgFlags3 & 0x00020000) {		/* PB Duo series, PB 5XX series */
1088		pmdata.command = 0x20;
1089		pmdata.num_data = 4;
1090		pmdata.s_buf = pmdata.data;
1091		pmdata.r_buf = pmdata.data;
1092		pmdata.data[0] = 0x00;
1093		pmdata.data[1] = 0x86;	/* magic spell for awaking the PM */
1094		pmdata.data[2] = 0x00;
1095		pmdata.data[3] = 0x0c;	/* each bit may express the existent ADB device */
1096	} else {				/* PB 1XX series */
1097		pmdata.command = 0x20;
1098		pmdata.num_data = 3;
1099		pmdata.s_buf = pmdata.data;
1100		pmdata.r_buf = pmdata.data;
1101		pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1102		pmdata.data[1] = 0x04;
1103		pmdata.data[2] = 0x00;
1104	}
1105	rval = pmgrop(&pmdata);
1106
1107	splx(s);
1108	return rval;
1109}
1110
1111
1112void
1113pm_adb_get_TALK_result(pmdata)
1114	PMData *pmdata;
1115{
1116	int i;
1117	struct adbCommand packet;
1118
1119	/* set up data for adb_pass_up */
1120	packet.data[0] = pmdata->num_data-1;
1121	packet.data[1] = pmdata->data[3];
1122	for (i = 0; i <packet.data[0]-1; i++)
1123		packet.data[i+2] = pmdata->data[i+4];
1124
1125	packet.saveBuf = adbBuffer;
1126	packet.compRout = adbCompRout;
1127	packet.compData = adbCompData;
1128	packet.unsol = 0;
1129	packet.ack_only = 0;
1130	adb_polling = 1;
1131	adb_pass_up(&packet);
1132	adb_polling = 0;
1133
1134	adbWaiting = 0;
1135	adbBuffer = (long)0;
1136	adbCompRout = (long)0;
1137	adbCompData = (long)0;
1138}
1139
1140
1141void
1142pm_adb_get_ADB_data(pmdata)
1143	PMData *pmdata;
1144{
1145	int i;
1146	struct adbCommand packet;
1147
1148	/* set up data for adb_pass_up */
1149	packet.data[0] = pmdata->num_data-1;	/* number of raw data */
1150	packet.data[1] = pmdata->data[3];	/* ADB command */
1151	for (i = 0; i <packet.data[0]-1; i++)
1152		packet.data[i+2] = pmdata->data[i+4];
1153	packet.unsol = 1;
1154	packet.ack_only = 0;
1155	adb_pass_up(&packet);
1156}
1157
1158
1159void
1160pm_adb_poll_next_device_pm1(pmdata)
1161	PMData *pmdata;
1162{
1163	int i;
1164	int ndid;
1165	u_short bendid = 0x1;
1166	int rval;
1167	PMData tmp_pmdata;
1168
1169	/* find another existent ADB device to poll */
1170	for (i = 1; i < 16; i++) {
1171		ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf;
1172		bendid <<= ndid;
1173		if ((pm_existent_ADB_devices & bendid) != 0)
1174			break;
1175	}
1176
1177	/* poll the other device */
1178	tmp_pmdata.command = 0x20;
1179	tmp_pmdata.num_data = 3;
1180	tmp_pmdata.s_buf = tmp_pmdata.data;
1181	tmp_pmdata.r_buf = tmp_pmdata.data;
1182	tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1183	tmp_pmdata.data[1] = 0x04;	/* magic spell for awaking the PM */
1184	tmp_pmdata.data[2] = 0x00;
1185	rval = pmgrop(&tmp_pmdata);
1186}
1187
1188
1189
1190