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