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