xref: /netbsd/sys/arch/mac68k/dev/pm_direct.c (revision c4a72b64)
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 */
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 		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  */
284 void
285 pm_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  */
298 int
299 pm_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  */
316 int
317 pm_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  */
339 int
340 pm_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  */
374 int
375 pm_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  */
409 int
410 pm_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  */
550 void
551 pm_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  */
608 int
609 pm_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  */
650 int
651 pm_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  */
681 int
682 pm_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  */
816 void
817 pm_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  */
900 int
901 pm_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  */
921 int
922 pmgrop(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  */
942 void
943 pm_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 
959 void
960 pm_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  */
980 int
981 pm_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 
1110 void
1111 pm_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 
1139 void
1140 pm_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 
1157 void
1158 pm_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