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