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