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