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