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