Home | History | Annotate | Line # | Download | only in dev
pm_direct.c revision 1.7
      1 /*	$NetBSD: pm_direct.c,v 1.7 1998/10/23 01:16:24 ender 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_MACPB180:
    459 					case MACH_MACPB180C:
    460 						{
    461 							int delay = ADBDelay * 16;
    462 
    463 							via_reg(VIA2, vDirA) = 0x00;
    464 							while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
    465 								delay--;
    466 
    467 							if (delay < 0) {	/* timeout */
    468 								via_reg(VIA2, vDirA) = 0x00;
    469 								/* restore formar value */
    470 								via_reg(VIA1, vIER) = via1_vIER;
    471 								return 0xffffcd38;
    472 							}
    473 						}
    474 				} /* end switch */
    475 
    476 				s = splhigh();
    477 
    478 				via1_vDirA = via_reg(VIA1, vDirA);
    479 				via_reg(VIA1, vDirA) &= 0x7f;
    480 
    481 				pm_cmd = (u_char)(pmdata->command & 0xff);
    482 				if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0)
    483 					break;	/* send command succeeded */
    484 
    485 				via_reg(VIA1, vDirA) = via1_vDirA;
    486 				splx(s);
    487 			} /* end for */
    488 
    489 			/* failed to send a command */
    490 			if (i == 7) {
    491 				via_reg(VIA2, vDirA) = 0x00;
    492 				/* restore formar value */
    493 				via_reg(VIA1, vDirA) = via1_vDirA;
    494 				via_reg(VIA1, vIER) = via1_vIER;
    495 					return 0xffffcd38;
    496 			}
    497 
    498 			/* send # of PM data */
    499 			num_pm_data = pmdata->num_data;
    500 			if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
    501 				break;			/* timeout */
    502 
    503 			/* send PM data */
    504 			pm_buf = (u_char *)pmdata->s_buf;
    505 			for (i = 0; i < num_pm_data; i++)
    506 				if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
    507 					break;		/* timeout */
    508 			if ((i != num_pm_data) && (num_pm_data != 0))
    509 				break;			/* timeout */
    510 
    511 			/* Will PM IC return data? */
    512 			if ((pm_cmd & 0x08) == 0) {
    513 				rval = 0;
    514 				break;			/* no returned data */
    515 			}
    516 
    517 			rval = 0xffffcd37;
    518 			if (pm_wait_busy(ADBDelay) != 0)
    519 				break;			/* timeout */
    520 
    521 			/* receive PM command */
    522 			if ((rval = pm_receive_pm1(&pm_data)) != 0)
    523 				break;
    524 
    525 			pmdata->command = pm_data;
    526 
    527 			/* receive number of PM data */
    528 			if ((rval = pm_receive_pm1(&pm_data)) != 0)
    529 				break;			/* timeout */
    530 			num_pm_data = pm_data;
    531 			pmdata->num_data = num_pm_data;
    532 
    533 			/* receive PM data */
    534 			pm_buf = (u_char *)pmdata->r_buf;
    535 			for (i = 0; i < num_pm_data; i++) {
    536 				if ((rval = pm_receive_pm1(&pm_data)) != 0)
    537 					break;				/* timeout */
    538 				pm_buf[i] = pm_data;
    539 			}
    540 
    541 			rval = 0;
    542 	}
    543 
    544 	via_reg(VIA2, vDirA) = 0x00;
    545 
    546 	/* restore formar value */
    547 	via_reg(VIA1, vDirA) = via1_vDirA;
    548 	via_reg(VIA1, vIER) = via1_vIER;
    549 	if (s != 0x81815963)
    550 		splx(s);
    551 
    552 	return rval;
    553 }
    554 
    555 
    556 /*
    557  * My PM interrupt routine for PB1XX series
    558  */
    559 void
    560 pm_intr_pm1()
    561 {
    562 	int s;
    563 	int rval;
    564 	PMData pmdata;
    565 
    566 	s = splhigh();
    567 
    568 	PM_VIA_CLR_INTR();				/* clear VIA1 interrupt */
    569 
    570 	/* ask PM what happend */
    571 	pmdata.command = 0x78;
    572 	pmdata.num_data = 0;
    573 	pmdata.data[0] = pmdata.data[1] = 0;
    574 	pmdata.s_buf = &pmdata.data[2];
    575 	pmdata.r_buf = &pmdata.data[2];
    576 	rval = pm_pmgrop_pm1(&pmdata);
    577 	if (rval != 0) {
    578 #ifdef ADB_DEBUG
    579 		if (adb_debug)
    580 			printf("pm: PM is not ready. error code=%08x\n", rval);
    581 #endif
    582 		splx(s);
    583 	}
    584 
    585 	if ((pmdata.data[2] & 0x10) == 0x10) {
    586 		if ((pmdata.data[2] & 0x0f) == 0) {
    587 			/* ADB data that were requested by TALK command */
    588 			pm_adb_get_TALK_result(&pmdata);
    589 		} else if ((pmdata.data[2] & 0x08) == 0x8) {
    590 			/* PM is requesting to poll  */
    591 			pm_adb_poll_next_device_pm1(&pmdata);
    592 		} else if ((pmdata.data[2] & 0x04) == 0x4) {
    593 			/* ADB device event */
    594 			pm_adb_get_ADB_data(&pmdata);
    595 		}
    596 	} else {
    597 #ifdef ADB_DEBUG
    598 		if (adb_debug)
    599 			pm_printerr("driver does not supported this event.",
    600 			    rval, pmdata.num_data, pmdata.data);
    601 #endif
    602 	}
    603 
    604 	splx(s);
    605 }
    606 
    607 
    608 
    609 /*
    610  * Functions for the PB Duo series and the PB 5XX series
    611  */
    612 
    613 /*
    614  * Receive data from PM for the PB Duo series and the PB 5XX series
    615  */
    616 int
    617 pm_receive_pm2(data)
    618 	u_char *data;
    619 {
    620 	int i;
    621 	int rval;
    622 
    623 	rval = 0xffffcd34;
    624 
    625 	switch (1) {
    626 		default:
    627 			/* set VIA SR to input mode */
    628 			via_reg(VIA1, vACR) |= 0x0c;
    629 			via_reg(VIA1, vACR) &= ~0x10;
    630 			i = PM_SR();
    631 
    632 			PM_SET_STATE_ACKOFF();
    633 			if (pm_wait_busy((int)ADBDelay*32) != 0)
    634 				break;		/* timeout */
    635 
    636 			PM_SET_STATE_ACKON();
    637 			rval = 0xffffcd33;
    638 			if (pm_wait_free((int)ADBDelay*32) == 0)
    639 				break;		/* timeout */
    640 
    641 			*data = PM_SR();
    642 			rval = 0;
    643 
    644 			break;
    645 	}
    646 
    647 	PM_SET_STATE_ACKON();
    648 	via_reg(VIA1, vACR) |= 0x1c;
    649 
    650 	return rval;
    651 }
    652 
    653 
    654 
    655 /*
    656  * Send data to PM for the PB Duo series and the PB 5XX series
    657  */
    658 int
    659 pm_send_pm2(data)
    660 	u_char data;
    661 {
    662 	int rval;
    663 
    664 	via_reg(VIA1, vACR) |= 0x1c;
    665 	PM_SR() = data;
    666 
    667 	PM_SET_STATE_ACKOFF();
    668 	rval = 0xffffcd36;
    669 	if (pm_wait_busy((int)ADBDelay*32) != 0) {
    670 		PM_SET_STATE_ACKON();
    671 
    672 		via_reg(VIA1, vACR) |= 0x1c;
    673 
    674 		return rval;
    675 	}
    676 
    677 	PM_SET_STATE_ACKON();
    678 	rval = 0xffffcd35;
    679 	if (pm_wait_free((int)ADBDelay*32) != 0)
    680 		rval = 0;
    681 
    682 	PM_SET_STATE_ACKON();
    683 	via_reg(VIA1, vACR) |= 0x1c;
    684 
    685 	return rval;
    686 }
    687 
    688 
    689 
    690 /*
    691  * My PMgrOp routine for the PB Duo series and the PB 5XX series
    692  */
    693 int
    694 pm_pmgrop_pm2(pmdata)
    695 	PMData *pmdata;
    696 {
    697 	int i;
    698 	int s;
    699 	u_char via1_vIER;
    700 	int rval = 0;
    701 	int num_pm_data = 0;
    702 	u_char pm_cmd;
    703 	short pm_num_rx_data;
    704 	u_char pm_data;
    705 	u_char *pm_buf;
    706 
    707 	s = splhigh();
    708 
    709 	/* disable all inetrrupts but PM */
    710 	via1_vIER = 0x10;
    711 	via1_vIER &= via_reg(VIA1, vIER);
    712 	via_reg(VIA1, vIER) = via1_vIER;
    713 	if (via1_vIER != 0x0)
    714 		via1_vIER |= 0x80;
    715 
    716 	switch (pmdata->command) {
    717 		default:
    718 			/* wait until PM is free */
    719 			pm_cmd = (u_char)(pmdata->command & 0xff);
    720 			rval = 0xcd38;
    721 			if (pm_wait_free(ADBDelay * 4) == 0)
    722 				break;			/* timeout */
    723 
    724 			if (HwCfgFlags3 & 0x00200000) {
    725 				/* PB 160, PB 165(c), PB 180(c)? */
    726 				int delay = ADBDelay * 16;
    727 
    728 				via_reg(VIA2, vDirA) = 0x00;
    729 				while ((via_reg(VIA2, 0x200) == 0x07) &&
    730 				    (delay >= 0))
    731 					delay--;
    732 
    733 				if (delay < 0) {
    734 					rval = 0xffffcd38;
    735 					break;		/* timeout */
    736 				}
    737 			}
    738 
    739 			/* send PM command */
    740 			if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
    741 				break;				/* timeout */
    742 
    743 			/* send number of PM data */
    744 			num_pm_data = pmdata->num_data;
    745 			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
    746 				if (pm_send_cmd_type[pm_cmd] < 0) {
    747 					if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
    748 						break;		/* timeout */
    749 					pmdata->command = 0;
    750 				}
    751 			} else {				/* PB 1XX series ? */
    752 				if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
    753 					break;			/* timeout */
    754 			}
    755 			/* send PM data */
    756 			pm_buf = (u_char *)pmdata->s_buf;
    757 			for (i = 0 ; i < num_pm_data; i++)
    758 				if ((rval = pm_send_pm2(pm_buf[i])) != 0)
    759 					break;			/* timeout */
    760 			if (i != num_pm_data)
    761 				break;				/* timeout */
    762 
    763 
    764 			/* check if PM will send me data  */
    765 			pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
    766 			pmdata->num_data = pm_num_rx_data;
    767 			if (pm_num_rx_data == 0) {
    768 				rval = 0;
    769 				break;				/* no return data */
    770 			}
    771 
    772 			/* receive PM command */
    773 			pm_data = pmdata->command;
    774 			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
    775 				pm_num_rx_data--;
    776 				if (pm_num_rx_data == 0)
    777 					if ((rval = pm_receive_pm2(&pm_data)) != 0) {
    778 						rval = 0xffffcd37;
    779 						break;
    780 					}
    781 				pmdata->command = pm_data;
    782 			} else {				/* PB 1XX series ? */
    783 				if ((rval = pm_receive_pm2(&pm_data)) != 0) {
    784 					rval = 0xffffcd37;
    785 					break;
    786 				}
    787 				pmdata->command = pm_data;
    788 			}
    789 
    790 			/* receive number of PM data */
    791 			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
    792 				if (pm_num_rx_data < 0) {
    793 					if ((rval = pm_receive_pm2(&pm_data)) != 0)
    794 						break;		/* timeout */
    795 					num_pm_data = pm_data;
    796 				} else
    797 					num_pm_data = pm_num_rx_data;
    798 				pmdata->num_data = num_pm_data;
    799 			} else {				/* PB 1XX serias ? */
    800 				if ((rval = pm_receive_pm2(&pm_data)) != 0)
    801 					break;			/* timeout */
    802 				num_pm_data = pm_data;
    803 				pmdata->num_data = num_pm_data;
    804 			}
    805 
    806 			/* receive PM data */
    807 			pm_buf = (u_char *)pmdata->r_buf;
    808 			for (i = 0; i < num_pm_data; i++) {
    809 				if ((rval = pm_receive_pm2(&pm_data)) != 0)
    810 					break;			/* timeout */
    811 				pm_buf[i] = pm_data;
    812 			}
    813 
    814 			rval = 0;
    815 	}
    816 
    817 	/* restore former value */
    818 	via_reg(VIA1, vIER) = via1_vIER;
    819 	splx(s);
    820 
    821 	return rval;
    822 }
    823 
    824 
    825 /*
    826  * My PM interrupt routine for the PB Duo series and the PB 5XX series
    827  */
    828 void
    829 pm_intr_pm2()
    830 {
    831 	int s;
    832 	int rval;
    833 	PMData pmdata;
    834 
    835 	s = splhigh();
    836 
    837 	PM_VIA_CLR_INTR();			/* clear VIA1 interrupt */
    838 						/* ask PM what happend */
    839 	pmdata.command = 0x78;
    840 	pmdata.num_data = 0;
    841 	pmdata.s_buf = &pmdata.data[2];
    842 	pmdata.r_buf = &pmdata.data[2];
    843 	rval = pm_pmgrop_pm2(&pmdata);
    844 	if (rval != 0) {
    845 #ifdef ADB_DEBUG
    846 		if (adb_debug)
    847 			printf("pm: PM is not ready. error code: %08x\n", rval);
    848 #endif
    849 		splx(s);
    850 	}
    851 
    852 	switch ((u_int)(pmdata.data[2] & 0xff)) {
    853 		case 0x00:			/* 1 sec interrupt? */
    854 			break;
    855 		case 0x80:			/* 1 sec interrupt? */
    856 			pm_counter++;
    857 			break;
    858 		case 0x08:			/* Brightness/Contrast button on LCD panel */
    859 			/* get brightness and contrast of the LCD */
    860 			pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
    861 			pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
    862 /*
    863 			pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
    864 			pmdata.command = 0x33;
    865 			pmdata.num_data = 1;
    866 			pmdata.s_buf = pmdata.data;
    867 			pmdata.r_buf = pmdata.data;
    868 			pmdata.data[0] = pm_LCD_contrast;
    869 			rval = pm_pmgrop_pm2(&pmdata);
    870 			pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
    871 */
    872 			/* this is an experimental code */
    873 			pmdata.command = 0x41;
    874 			pmdata.num_data = 1;
    875 			pmdata.s_buf = pmdata.data;
    876 			pmdata.r_buf = pmdata.data;
    877 			pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
    878 			if (pm_LCD_brightness < 0x25)
    879 				pm_LCD_brightness = 0x25;
    880 			if (pm_LCD_brightness > 0x5a)
    881 				pm_LCD_brightness = 0x7f;
    882 			pmdata.data[0] = pm_LCD_brightness;
    883 			rval = pm_pmgrop_pm2(&pmdata);
    884 			break;
    885 		case 0x10:			/* ADB data that were requested by TALK command */
    886 		case 0x14:
    887 			pm_adb_get_TALK_result(&pmdata);
    888 			break;
    889 		case 0x16:			/* ADB device event */
    890 		case 0x18:
    891 		case 0x1e:
    892 			pm_adb_get_ADB_data(&pmdata);
    893 			break;
    894 		default:
    895 #ifdef ADB_DEBUG
    896 			if (adb_debug)
    897 				pm_printerr("driver does not supported this event.",
    898 				    pmdata.data[2], pmdata.num_data,
    899 				    pmdata.data);
    900 #endif
    901 			break;
    902 	}
    903 
    904 	splx(s);
    905 }
    906 
    907 
    908 /*
    909  * MRG-based PMgrOp routine
    910  */
    911 int
    912 pm_pmgrop_mrg(pmdata)
    913 	PMData *pmdata;
    914 {
    915 	u_int32_t rval=0;
    916 
    917 	asm("
    918 		movl	%1, a0
    919 		.word	0xa085
    920 		movl	d0, %0"
    921 		: "=g" (rval)
    922 		: "g" (pmdata)
    923 		: "a0", "d0" );
    924 
    925 	return rval;
    926 }
    927 
    928 
    929 /*
    930  * My PMgrOp routine
    931  */
    932 int
    933 pmgrop(pmdata)
    934 	PMData *pmdata;
    935 {
    936 	switch (pmHardware) {
    937 		case PM_HW_PB1XX:
    938 			return (pm_pmgrop_pm1(pmdata));
    939 			break;
    940 		case PM_HW_PB5XX:
    941 			return (pm_pmgrop_pm2(pmdata));
    942 			break;
    943 		default:
    944 			/* return (pmgrop_mrg(pmdata)); */
    945 			return 1;
    946 	}
    947 }
    948 
    949 
    950 /*
    951  * My PM interrupt routine
    952  */
    953 void
    954 pm_intr()
    955 {
    956 	switch (pmHardware) {
    957 		case PM_HW_PB1XX:
    958 			pm_intr_pm1();
    959 			break;
    960 		case PM_HW_PB5XX:
    961 			pm_intr_pm2();
    962 			break;
    963 		default:
    964 			break;
    965 	}
    966 }
    967 
    968 
    969 
    970 /*
    971  * Synchronous ADBOp routine for the Power Manager
    972  */
    973 int
    974 pm_adb_op(buffer, compRout, data, command)
    975 	u_char *buffer;
    976 	void *compRout;
    977 	void *data;
    978 	int command;
    979 {
    980 	int i;
    981 	int s;
    982 	int rval;
    983 	int delay;
    984 	PMData pmdata;
    985 	struct adbCommand packet;
    986 
    987 	if (adbWaiting == 1)
    988 		return 1;
    989 
    990 	s = splhigh();
    991 	via_reg(VIA1, vIER) = 0x10;
    992 
    993  	adbBuffer = buffer;
    994 	adbCompRout = compRout;
    995 	adbCompData = data;
    996 
    997 	pmdata.command = 0x20;
    998 	pmdata.s_buf = pmdata.data;
    999 	pmdata.r_buf = pmdata.data;
   1000 
   1001 	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, add number of ADB data to number of PM data */
   1002 		if (buffer != (u_char *)0)
   1003 			pmdata.num_data = buffer[0] + 3;
   1004 	} else {
   1005 		pmdata.num_data = 3;
   1006 	}
   1007 
   1008 	pmdata.data[0] = (u_char)(command & 0xff);
   1009 	pmdata.data[1] = 0;
   1010 	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, copy ADB data to PM buffer */
   1011 		if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
   1012 			pmdata.data[2] = buffer[0];		/* number of data */
   1013 			for (i = 0; i < buffer[0]; i++)
   1014 				pmdata.data[3 + i] = buffer[1 + i];
   1015 		} else
   1016 			pmdata.data[2] = 0;
   1017 	} else
   1018 		pmdata.data[2] = 0;
   1019 
   1020 	if ((command & 0xc) != 0xc) {		/* if the command is not TALK */
   1021 		/* set up stuff for adb_pass_up */
   1022 		packet.data[0] = 1 + pmdata.data[2];
   1023 		packet.data[1] = command;
   1024 		for (i = 0; i < pmdata.data[2]; i++)
   1025 			packet.data[i+2] = pmdata.data[i+3];
   1026 		packet.saveBuf = adbBuffer;
   1027 		packet.compRout = adbCompRout;
   1028 		packet.compData = adbCompData;
   1029 		packet.cmd = command;
   1030 		packet.unsol = 0;
   1031 		packet.ack_only = 1;
   1032 		ite_polling = 1;
   1033 		adb_pass_up(&packet);
   1034 		ite_polling = 0;
   1035 	}
   1036 
   1037 	rval = pmgrop(&pmdata);
   1038 	if (rval != 0)
   1039 		return 1;
   1040 
   1041 	adbWaiting = 1;
   1042 	adbWaitingCmd = command;
   1043 
   1044 	PM_VIA_INTR_ENABLE();
   1045 
   1046 	/* wait until the PM interrupt is occured */
   1047 	delay = 0x80000;
   1048 	while (adbWaiting == 1) {
   1049 		if ((via_reg(VIA1, vIFR) & 0x10) == 0x10)
   1050 			pm_intr();
   1051 #ifdef PM_GRAB_SI
   1052 #if 0
   1053 			zshard(0);		/* grab any serial interrupts */
   1054 #else
   1055 			(void)intr_dispatch(0x70);
   1056 #endif
   1057 #endif
   1058 		if ((--delay) < 0)
   1059 			return 1;
   1060 	}
   1061 
   1062 	/* this command enables the interrupt by operating ADB devices */
   1063 	if (HwCfgFlags3 & 0x00020000) {		/* PB Duo series, PB 5XX series */
   1064 		pmdata.command = 0x20;
   1065 		pmdata.num_data = 4;
   1066 		pmdata.s_buf = pmdata.data;
   1067 		pmdata.r_buf = pmdata.data;
   1068 		pmdata.data[0] = 0x00;
   1069 		pmdata.data[1] = 0x86;	/* magic spell for awaking the PM */
   1070 		pmdata.data[2] = 0x00;
   1071 		pmdata.data[3] = 0x0c;	/* each bit may express the existent ADB device */
   1072 	} else {				/* PB 1XX series */
   1073 		pmdata.command = 0x20;
   1074 		pmdata.num_data = 3;
   1075 		pmdata.s_buf = pmdata.data;
   1076 		pmdata.r_buf = pmdata.data;
   1077 		pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
   1078 		pmdata.data[1] = 0x04;
   1079 		pmdata.data[2] = 0x00;
   1080 	}
   1081 	rval = pmgrop(&pmdata);
   1082 
   1083 	splx(s);
   1084 	return rval;
   1085 }
   1086 
   1087 
   1088 void
   1089 pm_adb_get_TALK_result(pmdata)
   1090 	PMData *pmdata;
   1091 {
   1092 	int i;
   1093 	struct adbCommand packet;
   1094 
   1095 	/* set up data for adb_pass_up */
   1096 	packet.data[0] = pmdata->num_data-1;
   1097 	packet.data[1] = pmdata->data[3];
   1098 	for (i = 0; i <packet.data[0]-1; i++)
   1099 		packet.data[i+2] = pmdata->data[i+4];
   1100 
   1101 	packet.saveBuf = adbBuffer;
   1102 	packet.compRout = adbCompRout;
   1103 	packet.compData = adbCompData;
   1104 	packet.unsol = 0;
   1105 	packet.ack_only = 0;
   1106 	ite_polling = 1;
   1107 	adb_pass_up(&packet);
   1108 	ite_polling = 0;
   1109 
   1110 	adbWaiting = 0;
   1111 	adbBuffer = (long)0;
   1112 	adbCompRout = (long)0;
   1113 	adbCompData = (long)0;
   1114 }
   1115 
   1116 
   1117 void
   1118 pm_adb_get_ADB_data(pmdata)
   1119 	PMData *pmdata;
   1120 {
   1121 	int i;
   1122 	struct adbCommand packet;
   1123 
   1124 	/* set up data for adb_pass_up */
   1125 	packet.data[0] = pmdata->num_data-1;	/* number of raw data */
   1126 	packet.data[1] = pmdata->data[3];	/* ADB command */
   1127 	for (i = 0; i <packet.data[0]-1; i++)
   1128 		packet.data[i+2] = pmdata->data[i+4];
   1129 	packet.unsol = 1;
   1130 	packet.ack_only = 0;
   1131 	adb_pass_up(&packet);
   1132 }
   1133 
   1134 
   1135 void
   1136 pm_adb_poll_next_device_pm1(pmdata)
   1137 	PMData *pmdata;
   1138 {
   1139 	int i;
   1140 	int ndid;
   1141 	u_short bendid = 0x1;
   1142 	int rval;
   1143 	PMData tmp_pmdata;
   1144 
   1145 	/* find another existent ADB device to poll */
   1146 	for (i = 1; i < 16; i++) {
   1147 		ndid = (((pmdata->data[3] & 0xf0) >> 4) + i) & 0xf;
   1148 		bendid <<= ndid;
   1149 		if ((pm_existent_ADB_devices & bendid) != 0)
   1150 			break;
   1151 	}
   1152 
   1153 	/* poll the other device */
   1154 	tmp_pmdata.command = 0x20;
   1155 	tmp_pmdata.num_data = 3;
   1156 	tmp_pmdata.s_buf = tmp_pmdata.data;
   1157 	tmp_pmdata.r_buf = tmp_pmdata.data;
   1158 	tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
   1159 	tmp_pmdata.data[1] = 0x04;	/* magic spell for awaking the PM */
   1160 	tmp_pmdata.data[2] = 0x00;
   1161 	rval = pmgrop(&tmp_pmdata);
   1162 }
   1163 
   1164 
   1165 
   1166