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