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