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