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