pm_direct.c revision 1.11
1/*	$NetBSD: pm_direct.c,v 1.11 2000/03/19 07:37:58 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, delay)
389	u_char data;
390	int delay;
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 (pm_wait_busy(0x400) != 0) {
399		PM_SET_STATE_ACKON();
400		via_reg(VIA2, vDirA) = 0x00;
401
402		return 0xffffcd36;
403	}
404
405	rval = 0x0;
406	PM_SET_STATE_ACKON();
407	if (pm_wait_free(0x40) == 0)
408		rval = 0xffffcd35;
409
410	PM_SET_STATE_ACKON();
411	via_reg(VIA2, vDirA) = 0x00;
412
413	return rval;
414}
415
416
417/*
418 * My PMgrOp routine for the PB1XX series
419 */
420int
421pm_pmgrop_pm1(pmdata)
422	PMData *pmdata;
423{
424	int i;
425	int s = 0x81815963;
426	u_char via1_vIER, via1_vDirA;
427	int rval = 0;
428	int num_pm_data = 0;
429	u_char pm_cmd;
430	u_char pm_data;
431	u_char *pm_buf;
432
433	/* disable all inetrrupts but PM */
434	via1_vIER = via_reg(VIA1, vIER);
435	PM_VIA_INTR_DISABLE();
436
437	via1_vDirA = via_reg(VIA1, vDirA);
438
439	switch (pmdata->command) {
440		default:
441			for (i = 0; i < 7; i++) {
442				via_reg(VIA2, vDirA) = 0x00;
443
444				/* wait until PM is free */
445				if (pm_wait_free(ADBDelay) == 0) {	/* timeout */
446					via_reg(VIA2, vDirA) = 0x00;
447					/* restore formar value */
448					via_reg(VIA1, vDirA) = via1_vDirA;
449					via_reg(VIA1, vIER) = via1_vIER;
450					return 0xffffcd38;
451				}
452
453				switch (mac68k_machine.machineid) {
454					case MACH_MACPB160:
455					case MACH_MACPB165:
456					case MACH_MACPB165C:
457					case MACH_MACPB170:
458					case MACH_MACPB180:
459					case MACH_MACPB180C:
460						{
461							int delay = ADBDelay * 16;
462
463							via_reg(VIA2, vDirA) = 0x00;
464							while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
465								delay--;
466
467							if (delay < 0) {	/* timeout */
468								via_reg(VIA2, vDirA) = 0x00;
469								/* restore formar value */
470								via_reg(VIA1, vIER) = via1_vIER;
471								return 0xffffcd38;
472							}
473						}
474				} /* end switch */
475
476				s = splhigh();
477
478				via1_vDirA = via_reg(VIA1, vDirA);
479				via_reg(VIA1, vDirA) &= 0x7f;
480
481				pm_cmd = (u_char)(pmdata->command & 0xff);
482				if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0)
483					break;	/* send command succeeded */
484
485				via_reg(VIA1, vDirA) = via1_vDirA;
486				splx(s);
487			} /* end for */
488
489			/* failed to send a command */
490			if (i == 7) {
491				via_reg(VIA2, vDirA) = 0x00;
492				/* restore formar value */
493				via_reg(VIA1, vDirA) = via1_vDirA;
494				via_reg(VIA1, vIER) = via1_vIER;
495					return 0xffffcd38;
496			}
497
498			/* send # of PM data */
499			num_pm_data = pmdata->num_data;
500			if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
501				break;			/* timeout */
502
503			/* send PM data */
504			pm_buf = (u_char *)pmdata->s_buf;
505			for (i = 0; i < num_pm_data; i++)
506				if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
507					break;		/* timeout */
508			if ((i != num_pm_data) && (num_pm_data != 0))
509				break;			/* timeout */
510
511			/* Will PM IC return data? */
512			if ((pm_cmd & 0x08) == 0) {
513				rval = 0;
514				break;			/* no returned data */
515			}
516
517			rval = 0xffffcd37;
518			if (pm_wait_busy(ADBDelay) != 0)
519				break;			/* timeout */
520
521			/* receive PM command */
522			if ((rval = pm_receive_pm1(&pm_data)) != 0)
523				break;
524
525			pmdata->command = pm_data;
526
527			/* receive number of PM data */
528			if ((rval = pm_receive_pm1(&pm_data)) != 0)
529				break;			/* timeout */
530			num_pm_data = pm_data;
531			pmdata->num_data = num_pm_data;
532
533			/* receive PM data */
534			pm_buf = (u_char *)pmdata->r_buf;
535			for (i = 0; i < num_pm_data; i++) {
536				if ((rval = pm_receive_pm1(&pm_data)) != 0)
537					break;				/* timeout */
538				pm_buf[i] = pm_data;
539			}
540
541			rval = 0;
542	}
543
544	via_reg(VIA2, vDirA) = 0x00;
545
546	/* restore formar value */
547	via_reg(VIA1, vDirA) = via1_vDirA;
548	via_reg(VIA1, vIER) = via1_vIER;
549	if (s != 0x81815963)
550		splx(s);
551
552	return rval;
553}
554
555
556/*
557 * My PM interrupt routine for PB1XX series
558 */
559void
560pm_intr_pm1(arg)
561	void *arg;
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(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		return 1;
1060
1061	adbWaiting = 1;
1062	adbWaitingCmd = command;
1063
1064	PM_VIA_INTR_ENABLE();
1065
1066	/* wait until the PM interrupt is occured */
1067	delay = 0x80000;
1068	while (adbWaiting == 1) {
1069		if ((via_reg(VIA1, vIFR) & 0x10) == 0x10)
1070			pm_intr((void *)0);
1071#ifdef PM_GRAB_SI
1072#if 0
1073			zshard(0);		/* grab any serial interrupts */
1074#else
1075			(void)intr_dispatch(0x70);
1076#endif
1077#endif
1078		if ((--delay) < 0)
1079			return 1;
1080	}
1081
1082	/* this command enables the interrupt by operating ADB devices */
1083	if (HwCfgFlags3 & 0x00020000) {		/* PB Duo series, PB 5XX series */
1084		pmdata.command = 0x20;
1085		pmdata.num_data = 4;
1086		pmdata.s_buf = pmdata.data;
1087		pmdata.r_buf = pmdata.data;
1088		pmdata.data[0] = 0x00;
1089		pmdata.data[1] = 0x86;	/* magic spell for awaking the PM */
1090		pmdata.data[2] = 0x00;
1091		pmdata.data[3] = 0x0c;	/* each bit may express the existent ADB device */
1092	} else {				/* PB 1XX series */
1093		pmdata.command = 0x20;
1094		pmdata.num_data = 3;
1095		pmdata.s_buf = pmdata.data;
1096		pmdata.r_buf = pmdata.data;
1097		pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1098		pmdata.data[1] = 0x04;
1099		pmdata.data[2] = 0x00;
1100	}
1101	rval = pmgrop(&pmdata);
1102
1103	splx(s);
1104	return rval;
1105}
1106
1107
1108void
1109pm_adb_get_TALK_result(pmdata)
1110	PMData *pmdata;
1111{
1112	int i;
1113	struct adbCommand packet;
1114
1115	/* set up data for adb_pass_up */
1116	packet.data[0] = pmdata->num_data-1;
1117	packet.data[1] = pmdata->data[3];
1118	for (i = 0; i <packet.data[0]-1; i++)
1119		packet.data[i+2] = pmdata->data[i+4];
1120
1121	packet.saveBuf = adbBuffer;
1122	packet.compRout = adbCompRout;
1123	packet.compData = adbCompData;
1124	packet.unsol = 0;
1125	packet.ack_only = 0;
1126	adb_polling = 1;
1127	adb_pass_up(&packet);
1128	adb_polling = 0;
1129
1130	adbWaiting = 0;
1131	adbBuffer = (long)0;
1132	adbCompRout = (long)0;
1133	adbCompData = (long)0;
1134}
1135
1136
1137void
1138pm_adb_get_ADB_data(pmdata)
1139	PMData *pmdata;
1140{
1141	int i;
1142	struct adbCommand packet;
1143
1144	/* set up data for adb_pass_up */
1145	packet.data[0] = pmdata->num_data-1;	/* number of raw data */
1146	packet.data[1] = pmdata->data[3];	/* ADB command */
1147	for (i = 0; i <packet.data[0]-1; i++)
1148		packet.data[i+2] = pmdata->data[i+4];
1149	packet.unsol = 1;
1150	packet.ack_only = 0;
1151	adb_pass_up(&packet);
1152}
1153
1154
1155void
1156pm_adb_poll_next_device_pm1(pmdata)
1157	PMData *pmdata;
1158{
1159	int i;
1160	int ndid;
1161	u_short bendid = 0x1;
1162	int rval;
1163	PMData tmp_pmdata;
1164
1165	/* find another existent ADB device to poll */
1166	for (i = 1; i < 16; i++) {
1167		ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf;
1168		bendid <<= ndid;
1169		if ((pm_existent_ADB_devices & bendid) != 0)
1170			break;
1171	}
1172
1173	/* poll the other device */
1174	tmp_pmdata.command = 0x20;
1175	tmp_pmdata.num_data = 3;
1176	tmp_pmdata.s_buf = tmp_pmdata.data;
1177	tmp_pmdata.r_buf = tmp_pmdata.data;
1178	tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1179	tmp_pmdata.data[1] = 0x04;	/* magic spell for awaking the PM */
1180	tmp_pmdata.data[2] = 0x00;
1181	rval = pmgrop(&tmp_pmdata);
1182}
1183
1184
1185
1186