pm_direct.c revision 1.6
1/*	$NetBSD: pm_direct.c,v 1.6 1998/08/12 05:42:44 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
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_MACPB180:
458					case MACH_MACPB180C:
459						{
460							int delay = ADBDelay * 16;
461
462							via_reg(VIA2, vDirA) = 0x00;
463							while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
464								delay--;
465
466							if (delay < 0) {	/* timeout */
467								via_reg(VIA2, vDirA) = 0x00;
468								/* restore formar value */
469								via_reg(VIA1, vIER) = via1_vIER;
470								return 0xffffcd38;
471							}
472						}
473				} /* end switch */
474
475				s = splhigh();
476
477				via1_vDirA = via_reg(VIA1, vDirA);
478				via_reg(VIA1, vDirA) &= 0x7f;
479
480				pm_cmd = (u_char)(pmdata->command & 0xff);
481				if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0)
482					break;	/* send command succeeded */
483
484				via_reg(VIA1, vDirA) = via1_vDirA;
485				splx(s);
486			} /* end for */
487
488			/* failed to send a command */
489			if (i == 7) {
490				via_reg(VIA2, vDirA) = 0x00;
491				/* restore formar value */
492				via_reg(VIA1, vDirA) = via1_vDirA;
493				via_reg(VIA1, vIER) = via1_vIER;
494					return 0xffffcd38;
495			}
496
497			/* send # of PM data */
498			num_pm_data = pmdata->num_data;
499			if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
500				break;			/* timeout */
501
502			/* send PM data */
503			pm_buf = (u_char *)pmdata->s_buf;
504			for (i = 0; i < num_pm_data; i++)
505				if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
506					break;		/* timeout */
507			if ((i != num_pm_data) && (num_pm_data != 0))
508				break;			/* timeout */
509
510			/* Will PM IC return data? */
511			if ((pm_cmd & 0x08) == 0) {
512				rval = 0;
513				break;			/* no returned data */
514			}
515
516			rval = 0xffffcd37;
517			if (pm_wait_busy(ADBDelay) != 0)
518				break;			/* timeout */
519
520			/* receive PM command */
521			if ((rval = pm_receive_pm1(&pm_data)) != 0)
522				break;
523
524			pmdata->command = pm_data;
525
526			/* receive number of PM data */
527			if ((rval = pm_receive_pm1(&pm_data)) != 0)
528				break;			/* timeout */
529			num_pm_data = pm_data;
530			pmdata->num_data = num_pm_data;
531
532			/* receive PM data */
533			pm_buf = (u_char *)pmdata->r_buf;
534			for (i = 0; i < num_pm_data; i++) {
535				if ((rval = pm_receive_pm1(&pm_data)) != 0)
536					break;				/* timeout */
537				pm_buf[i] = pm_data;
538			}
539
540			rval = 0;
541	}
542
543	via_reg(VIA2, vDirA) = 0x00;
544
545	/* restore formar value */
546	via_reg(VIA1, vDirA) = via1_vDirA;
547	via_reg(VIA1, vIER) = via1_vIER;
548	if (s != 0x81815963)
549		splx(s);
550
551	return rval;
552}
553
554
555/*
556 * My PM interrupt routine for PB1XX series
557 */
558void
559pm_intr_pm1()
560{
561	int s;
562	int rval;
563	PMData pmdata;
564
565	s = splhigh();
566
567	PM_VIA_CLR_INTR();				/* clear VIA1 interrupt */
568
569	/* ask PM what happend */
570	pmdata.command = 0x78;
571	pmdata.num_data = 0;
572	pmdata.data[0] = pmdata.data[1] = 0;
573	pmdata.s_buf = &pmdata.data[2];
574	pmdata.r_buf = &pmdata.data[2];
575	rval = pm_pmgrop_pm1(&pmdata);
576	if (rval != 0) {
577#ifdef ADB_DEBUG
578		if (adb_debug)
579			printf("pm: PM is not ready. error code=%08x\n", rval);
580#endif
581		splx(s);
582	}
583
584	if ((pmdata.data[2] & 0x10) == 0x10) {
585		if ((pmdata.data[2] & 0x0f) == 0) {
586			/* ADB data that were requested by TALK command */
587			pm_adb_get_TALK_result(&pmdata);
588		} else if ((pmdata.data[2] & 0x08) == 0x8) {
589			/* PM is requesting to poll  */
590			pm_adb_poll_next_device_pm1(&pmdata);
591		} else if ((pmdata.data[2] & 0x04) == 0x4) {
592			/* ADB device event */
593			pm_adb_get_ADB_data(&pmdata);
594		}
595	} else {
596#ifdef ADB_DEBUG
597		if (adb_debug)
598			pm_printerr("driver does not supported this event.",
599			    rval, pmdata.num_data, pmdata.data);
600#endif
601	}
602
603	splx(s);
604}
605
606
607
608/*
609 * Functions for the PB Duo series and the PB 5XX series
610 */
611
612/*
613 * Receive data from PM for the PB Duo series and the PB 5XX series
614 */
615int
616pm_receive_pm2(data)
617	u_char *data;
618{
619	int i;
620	int rval;
621
622	rval = 0xffffcd34;
623
624	switch (1) {
625		default:
626			/* set VIA SR to input mode */
627			via_reg(VIA1, vACR) |= 0x0c;
628			via_reg(VIA1, vACR) &= ~0x10;
629			i = PM_SR();
630
631			PM_SET_STATE_ACKOFF();
632			if (pm_wait_busy((int)ADBDelay*32) != 0)
633				break;		/* timeout */
634
635			PM_SET_STATE_ACKON();
636			rval = 0xffffcd33;
637			if (pm_wait_free((int)ADBDelay*32) == 0)
638				break;		/* timeout */
639
640			*data = PM_SR();
641			rval = 0;
642
643			break;
644	}
645
646	PM_SET_STATE_ACKON();
647	via_reg(VIA1, vACR) |= 0x1c;
648
649	return rval;
650}
651
652
653
654/*
655 * Send data to PM for the PB Duo series and the PB 5XX series
656 */
657int
658pm_send_pm2(data)
659	u_char data;
660{
661	int rval;
662
663	via_reg(VIA1, vACR) |= 0x1c;
664	PM_SR() = data;
665
666	PM_SET_STATE_ACKOFF();
667	rval = 0xffffcd36;
668	if (pm_wait_busy((int)ADBDelay*32) != 0) {
669		PM_SET_STATE_ACKON();
670
671		via_reg(VIA1, vACR) |= 0x1c;
672
673		return rval;
674	}
675
676	PM_SET_STATE_ACKON();
677	rval = 0xffffcd35;
678	if (pm_wait_free((int)ADBDelay*32) != 0)
679		rval = 0;
680
681	PM_SET_STATE_ACKON();
682	via_reg(VIA1, vACR) |= 0x1c;
683
684	return rval;
685}
686
687
688
689/*
690 * My PMgrOp routine for the PB Duo series and the PB 5XX series
691 */
692int
693pm_pmgrop_pm2(pmdata)
694	PMData *pmdata;
695{
696	int i;
697	int s;
698	u_char via1_vIER;
699	int rval = 0;
700	int num_pm_data = 0;
701	u_char pm_cmd;
702	short pm_num_rx_data;
703	u_char pm_data;
704	u_char *pm_buf;
705
706	s = splhigh();
707
708	/* disable all inetrrupts but PM */
709	via1_vIER = 0x10;
710	via1_vIER &= via_reg(VIA1, vIER);
711	via_reg(VIA1, vIER) = via1_vIER;
712	if (via1_vIER != 0x0)
713		via1_vIER |= 0x80;
714
715	switch (pmdata->command) {
716		default:
717			/* wait until PM is free */
718			pm_cmd = (u_char)(pmdata->command & 0xff);
719			rval = 0xcd38;
720			if (pm_wait_free(ADBDelay * 4) == 0)
721				break;			/* timeout */
722
723			if (HwCfgFlags3 & 0x00200000) {
724				/* PB 160, PB 165(c), PB 180(c)? */
725				int delay = ADBDelay * 16;
726
727				via_reg(VIA2, vDirA) = 0x00;
728				while ((via_reg(VIA2, 0x200) == 0x07) &&
729				    (delay >= 0))
730					delay--;
731
732				if (delay < 0) {
733					rval = 0xffffcd38;
734					break;		/* timeout */
735				}
736			}
737
738			/* send PM command */
739			if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
740				break;				/* timeout */
741
742			/* send number of PM data */
743			num_pm_data = pmdata->num_data;
744			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
745				if (pm_send_cmd_type[pm_cmd] < 0) {
746					if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
747						break;		/* timeout */
748					pmdata->command = 0;
749				}
750			} else {				/* PB 1XX series ? */
751				if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
752					break;			/* timeout */
753			}
754			/* send PM data */
755			pm_buf = (u_char *)pmdata->s_buf;
756			for (i = 0 ; i < num_pm_data; i++)
757				if ((rval = pm_send_pm2(pm_buf[i])) != 0)
758					break;			/* timeout */
759			if (i != num_pm_data)
760				break;				/* timeout */
761
762
763			/* check if PM will send me data  */
764			pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
765			pmdata->num_data = pm_num_rx_data;
766			if (pm_num_rx_data == 0) {
767				rval = 0;
768				break;				/* no return data */
769			}
770
771			/* receive PM command */
772			pm_data = pmdata->command;
773			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
774				pm_num_rx_data--;
775				if (pm_num_rx_data == 0)
776					if ((rval = pm_receive_pm2(&pm_data)) != 0) {
777						rval = 0xffffcd37;
778						break;
779					}
780				pmdata->command = pm_data;
781			} else {				/* PB 1XX series ? */
782				if ((rval = pm_receive_pm2(&pm_data)) != 0) {
783					rval = 0xffffcd37;
784					break;
785				}
786				pmdata->command = pm_data;
787			}
788
789			/* receive number of PM data */
790			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
791				if (pm_num_rx_data < 0) {
792					if ((rval = pm_receive_pm2(&pm_data)) != 0)
793						break;		/* timeout */
794					num_pm_data = pm_data;
795				} else
796					num_pm_data = pm_num_rx_data;
797				pmdata->num_data = num_pm_data;
798			} else {				/* PB 1XX serias ? */
799				if ((rval = pm_receive_pm2(&pm_data)) != 0)
800					break;			/* timeout */
801				num_pm_data = pm_data;
802				pmdata->num_data = num_pm_data;
803			}
804
805			/* receive PM data */
806			pm_buf = (u_char *)pmdata->r_buf;
807			for (i = 0; i < num_pm_data; i++) {
808				if ((rval = pm_receive_pm2(&pm_data)) != 0)
809					break;			/* timeout */
810				pm_buf[i] = pm_data;
811			}
812
813			rval = 0;
814	}
815
816	/* restore former value */
817	via_reg(VIA1, vIER) = via1_vIER;
818	splx(s);
819
820	return rval;
821}
822
823
824/*
825 * My PM interrupt routine for the PB Duo series and the PB 5XX series
826 */
827void
828pm_intr_pm2()
829{
830	int s;
831	int rval;
832	PMData pmdata;
833
834	s = splhigh();
835
836	PM_VIA_CLR_INTR();			/* clear VIA1 interrupt */
837						/* ask PM what happend */
838	pmdata.command = 0x78;
839	pmdata.num_data = 0;
840	pmdata.s_buf = &pmdata.data[2];
841	pmdata.r_buf = &pmdata.data[2];
842	rval = pm_pmgrop_pm2(&pmdata);
843	if (rval != 0) {
844#ifdef ADB_DEBUG
845		if (adb_debug)
846			printf("pm: PM is not ready. error code: %08x\n", rval);
847#endif
848		splx(s);
849	}
850
851	switch ((u_int)(pmdata.data[2] & 0xff)) {
852		case 0x00:			/* 1 sec interrupt? */
853			break;
854		case 0x80:			/* 1 sec interrupt? */
855			pm_counter++;
856			break;
857		case 0x08:			/* Brightness/Contrast button on LCD panel */
858			/* get brightness and contrast of the LCD */
859			pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
860			pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
861/*
862			pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
863			pmdata.command = 0x33;
864			pmdata.num_data = 1;
865			pmdata.s_buf = pmdata.data;
866			pmdata.r_buf = pmdata.data;
867			pmdata.data[0] = pm_LCD_contrast;
868			rval = pm_pmgrop_pm2(&pmdata);
869			pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
870*/
871			/* this is an experimental code */
872			pmdata.command = 0x41;
873			pmdata.num_data = 1;
874			pmdata.s_buf = pmdata.data;
875			pmdata.r_buf = pmdata.data;
876			pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
877			if (pm_LCD_brightness < 0x25)
878				pm_LCD_brightness = 0x25;
879			if (pm_LCD_brightness > 0x5a)
880				pm_LCD_brightness = 0x7f;
881			pmdata.data[0] = pm_LCD_brightness;
882			rval = pm_pmgrop_pm2(&pmdata);
883			break;
884		case 0x10:			/* ADB data that were requested by TALK command */
885		case 0x14:
886			pm_adb_get_TALK_result(&pmdata);
887			break;
888		case 0x16:			/* ADB device event */
889		case 0x18:
890		case 0x1e:
891			pm_adb_get_ADB_data(&pmdata);
892			break;
893		default:
894#ifdef ADB_DEBUG
895			if (adb_debug)
896				pm_printerr("driver does not supported this event.",
897				    pmdata.data[2], pmdata.num_data,
898				    pmdata.data);
899#endif
900			break;
901	}
902
903	splx(s);
904}
905
906
907/*
908 * MRG-based PMgrOp routine
909 */
910int
911pm_pmgrop_mrg(pmdata)
912	PMData *pmdata;
913{
914	u_int32_t rval=0;
915
916	asm("
917		movl	%1, a0
918		.word	0xa085
919		movl	d0, %0"
920		: "=g" (rval)
921		: "g" (pmdata)
922		: "a0", "d0" );
923
924	return rval;
925}
926
927
928/*
929 * My PMgrOp routine
930 */
931int
932pmgrop(pmdata)
933	PMData *pmdata;
934{
935	switch (pmHardware) {
936		case PM_HW_PB1XX:
937			return (pm_pmgrop_pm1(pmdata));
938			break;
939		case PM_HW_PB5XX:
940			return (pm_pmgrop_pm2(pmdata));
941			break;
942		default:
943			/* return (pmgrop_mrg(pmdata)); */
944			return 1;
945	}
946}
947
948
949/*
950 * My PM interrupt routine
951 */
952void
953pm_intr()
954{
955	switch (pmHardware) {
956		case PM_HW_PB1XX:
957			pm_intr_pm1();
958			break;
959		case PM_HW_PB5XX:
960			pm_intr_pm2();
961			break;
962		default:
963			break;
964	}
965}
966
967
968
969/*
970 * Synchronous ADBOp routine for the Power Manager
971 */
972int
973pm_adb_op(buffer, compRout, data, command)
974	u_char *buffer;
975	void *compRout;
976	void *data;
977	int command;
978{
979	int i;
980	int s;
981	int rval;
982	int delay;
983	PMData pmdata;
984	struct adbCommand packet;
985
986	if (adbWaiting == 1)
987		return 1;
988
989	s = splhigh();
990	via_reg(VIA1, vIER) = 0x10;
991
992 	adbBuffer = buffer;
993	adbCompRout = compRout;
994	adbCompData = data;
995
996	pmdata.command = 0x20;
997	pmdata.s_buf = pmdata.data;
998	pmdata.r_buf = pmdata.data;
999
1000	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, add number of ADB data to number of PM data */
1001		if (buffer != (u_char *)0)
1002			pmdata.num_data = buffer[0] + 3;
1003	} else {
1004		pmdata.num_data = 3;
1005	}
1006
1007	pmdata.data[0] = (u_char)(command & 0xff);
1008	pmdata.data[1] = 0;
1009	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, copy ADB data to PM buffer */
1010		if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
1011			pmdata.data[2] = buffer[0];		/* number of data */
1012			for (i = 0; i < buffer[0]; i++)
1013				pmdata.data[3 + i] = buffer[1 + i];
1014		} else
1015			pmdata.data[2] = 0;
1016	} else
1017		pmdata.data[2] = 0;
1018
1019	if ((command & 0xc) != 0xc) {		/* if the command is not TALK */
1020		/* set up stuff for adb_pass_up */
1021		packet.data[0] = 1 + pmdata.data[2];
1022		packet.data[1] = command;
1023		for (i = 0; i < pmdata.data[2]; i++)
1024			packet.data[i+2] = pmdata.data[i+3];
1025		packet.saveBuf = adbBuffer;
1026		packet.compRout = adbCompRout;
1027		packet.compData = adbCompData;
1028		packet.cmd = command;
1029		packet.unsol = 0;
1030		packet.ack_only = 1;
1031		adb_polling = 1;
1032		adb_pass_up(&packet);
1033		adb_polling = 0;
1034	}
1035
1036	rval = pmgrop(&pmdata);
1037	if (rval != 0)
1038		return 1;
1039
1040	adbWaiting = 1;
1041	adbWaitingCmd = command;
1042
1043	PM_VIA_INTR_ENABLE();
1044
1045	/* wait until the PM interrupt is occured */
1046	delay = 0x80000;
1047	while (adbWaiting == 1) {
1048		if ((via_reg(VIA1, vIFR) & 0x10) == 0x10)
1049			pm_intr();
1050#ifdef PM_GRAB_SI
1051#if 0
1052			zshard(0);		/* grab any serial interrupts */
1053#else
1054			(void)intr_dispatch(0x70);
1055#endif
1056#endif
1057		if ((--delay) < 0)
1058			return 1;
1059	}
1060
1061	/* this command enables the interrupt by operating ADB devices */
1062	if (HwCfgFlags3 & 0x00020000) {		/* PB Duo series, PB 5XX series */
1063		pmdata.command = 0x20;
1064		pmdata.num_data = 4;
1065		pmdata.s_buf = pmdata.data;
1066		pmdata.r_buf = pmdata.data;
1067		pmdata.data[0] = 0x00;
1068		pmdata.data[1] = 0x86;	/* magic spell for awaking the PM */
1069		pmdata.data[2] = 0x00;
1070		pmdata.data[3] = 0x0c;	/* each bit may express the existent ADB device */
1071	} else {				/* PB 1XX series */
1072		pmdata.command = 0x20;
1073		pmdata.num_data = 3;
1074		pmdata.s_buf = pmdata.data;
1075		pmdata.r_buf = pmdata.data;
1076		pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1077		pmdata.data[1] = 0x04;
1078		pmdata.data[2] = 0x00;
1079	}
1080	rval = pmgrop(&pmdata);
1081
1082	splx(s);
1083	return rval;
1084}
1085
1086
1087void
1088pm_adb_get_TALK_result(pmdata)
1089	PMData *pmdata;
1090{
1091	int i;
1092	struct adbCommand packet;
1093
1094	/* set up data for adb_pass_up */
1095	packet.data[0] = pmdata->num_data-1;
1096	packet.data[1] = pmdata->data[3];
1097	for (i = 0; i <packet.data[0]-1; i++)
1098		packet.data[i+2] = pmdata->data[i+4];
1099
1100	packet.saveBuf = adbBuffer;
1101	packet.compRout = adbCompRout;
1102	packet.compData = adbCompData;
1103	packet.unsol = 0;
1104	packet.ack_only = 0;
1105	adb_polling = 1;
1106	adb_pass_up(&packet);
1107	adb_polling = 0;
1108
1109	adbWaiting = 0;
1110	adbBuffer = (long)0;
1111	adbCompRout = (long)0;
1112	adbCompData = (long)0;
1113}
1114
1115
1116void
1117pm_adb_get_ADB_data(pmdata)
1118	PMData *pmdata;
1119{
1120	int i;
1121	struct adbCommand packet;
1122
1123	/* set up data for adb_pass_up */
1124	packet.data[0] = pmdata->num_data-1;	/* number of raw data */
1125	packet.data[1] = pmdata->data[3];	/* ADB command */
1126	for (i = 0; i <packet.data[0]-1; i++)
1127		packet.data[i+2] = pmdata->data[i+4];
1128	packet.unsol = 1;
1129	packet.ack_only = 0;
1130	adb_pass_up(&packet);
1131}
1132
1133
1134void
1135pm_adb_poll_next_device_pm1(pmdata)
1136	PMData *pmdata;
1137{
1138	int i;
1139	int ndid;
1140	u_short bendid = 0x1;
1141	int rval;
1142	PMData tmp_pmdata;
1143
1144	/* find another existent ADB device to poll */
1145	for (i = 1; i < 16; i++) {
1146		ndid = (((pmdata->data[3] & 0xf0) >> 4) + i) & 0xf;
1147		bendid <<= ndid;
1148		if ((pm_existent_ADB_devices & bendid) != 0)
1149			break;
1150	}
1151
1152	/* poll the other device */
1153	tmp_pmdata.command = 0x20;
1154	tmp_pmdata.num_data = 3;
1155	tmp_pmdata.s_buf = tmp_pmdata.data;
1156	tmp_pmdata.r_buf = tmp_pmdata.data;
1157	tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1158	tmp_pmdata.data[1] = 0x04;	/* magic spell for awaking the PM */
1159	tmp_pmdata.data[2] = 0x00;
1160	rval = pmgrop(&tmp_pmdata);
1161}
1162
1163
1164
1165