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