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