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