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