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