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