Home | History | Annotate | Line # | Download | only in dev
pm_direct.c revision 1.4
      1 /*	$NetBSD: pm_direct.c,v 1.4 1998/02/23 03:11:26 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.22 01/09/97 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 #define MAX_ADB_MSG_LENGTH	20
    204 extern u_char	adbInputBuffer[MAX_ADB_MSG_LENGTH];      /* data input buffer */
    205 extern void	*adbCompRout;	/* pointer to the completion routine */
    206 extern void	*adbCompData;	/* pointer to the completion routine data */
    207 extern int	adbWaiting;	/* waiting for return data from the device */
    208 extern int	adbWaitingCmd;	/* ADB command we are waiting for */
    209 extern int	adbStarting;	/* doing ADB reinit, so do "polling" differently */
    210 
    211 /*
    212  * Define the external functions
    213  */
    214 extern int	zshard __P((int));		/* from zs.c */
    215 extern void	adb_comp_exec __P((void));	/* from adb_direct.c */
    216 
    217 
    218 #ifdef ADB_DEBUG
    219 /*
    220  * This function dumps contents of the PMData
    221  */
    222 void
    223 pm_printerr(ttl, rval, num, data)
    224 	char *ttl;
    225 	int rval;
    226 	int num;
    227 	char *data;
    228 {
    229 	int i;
    230 
    231 	printf("pm: %s:%04x %02x ", ttl, rval, num);
    232 	for (i = 0; i < num; i++)
    233 		printf("%02x ", data[i]);
    234 	printf("\n");
    235 }
    236 #endif
    237 
    238 
    239 
    240 /*
    241  * Check the hardware type of the Power Manager
    242  */
    243 void
    244 pm_setup_adb()
    245 {
    246 	switch (mac68k_machine.machineid) {
    247 		case MACH_MACPB140:
    248 		case MACH_MACPB145:
    249 		case MACH_MACPB150:
    250 		case MACH_MACPB160:
    251 		case MACH_MACPB165:
    252 		case MACH_MACPB165C:
    253 		case MACH_MACPB170:
    254 		case MACH_MACPB180:
    255 		case MACH_MACPB180C:
    256 			pmHardware = PM_HW_PB1XX;
    257 			break;
    258 		case MACH_MACPB210:
    259 		case MACH_MACPB230:
    260 		case MACH_MACPB250:
    261 		case MACH_MACPB270:
    262 		case MACH_MACPB280:
    263 		case MACH_MACPB280C:
    264 		case MACH_MACPB500:
    265 			pmHardware = PM_HW_PB5XX;
    266 			break;
    267 		default:
    268 			break;
    269 	}
    270 }
    271 
    272 
    273 /*
    274  * Check the existent ADB devices
    275  */
    276 void
    277 pm_check_adb_devices(id)
    278 	int id;
    279 {
    280 	u_short ed = 0x1;
    281 
    282 	ed <<= id;
    283 	pm_existent_ADB_devices |= ed;
    284 }
    285 
    286 
    287 /*
    288  * Wait until PM IC is busy
    289  */
    290 int
    291 pm_wait_busy(delay)
    292 	int delay;
    293 {
    294 	while (PM_IS_ON) {
    295 #ifdef PM_GRAB_SI
    296 		zshard(0);		/* grab any serial interrupts */
    297 #endif
    298 		if ((--delay) < 0)
    299 			return (1);	/* timeout */
    300 	}
    301 	return (0);
    302 }
    303 
    304 
    305 /*
    306  * Wait until PM IC is free
    307  */
    308 int
    309 pm_wait_free(delay)
    310 	int delay;
    311 {
    312 	while (PM_IS_OFF) {
    313 #ifdef PM_GRAB_SI
    314 		zshard(0);		/* grab any serial interrupts */
    315 #endif
    316 		if ((--delay) < 0)
    317 			return (0);	/* timeout */
    318 	}
    319 	return (1);
    320 }
    321 
    322 
    323 
    324 /*
    325  * Functions for the PB1XX series
    326  */
    327 
    328 /*
    329  * Receive data from PM for the PB1XX series
    330  */
    331 int
    332 pm_receive_pm1(data)
    333 	u_char *data;
    334 {
    335 	int rval = 0xffffcd34;
    336 
    337 	via_reg(VIA2, vDirA) = 0x00;
    338 
    339 	switch (1) {
    340 		default:
    341 			if (pm_wait_busy(0x40) != 0)
    342 				break;			/* timeout */
    343 
    344 			PM_SET_STATE_ACKOFF();
    345 			*data = via_reg(VIA2, 0x200);
    346 
    347 			rval = 0xffffcd33;
    348 			if (pm_wait_free(0x40) == 0)
    349 				break;			/* timeout */
    350 
    351 			rval = 0x00;
    352 			break;
    353 	}
    354 
    355 	PM_SET_STATE_ACKON();
    356 	via_reg(VIA2, vDirA) = 0x00;
    357 
    358 	return (rval);
    359 }
    360 
    361 
    362 
    363 /*
    364  * Send data to PM for the PB1XX series
    365  */
    366 int
    367 pm_send_pm1(data, delay)
    368 	u_char data;
    369 	int delay;
    370 {
    371 	int rval;
    372 
    373 	via_reg(VIA2, vDirA) = 0xff;
    374 	via_reg(VIA2, 0x200) = data;
    375 
    376 	PM_SET_STATE_ACKOFF();
    377 	if (pm_wait_busy(0x400) != 0) {
    378 		PM_SET_STATE_ACKON();
    379 		via_reg(VIA2, vDirA) = 0x00;
    380 
    381 		return (0xffffcd36);
    382 	}
    383 
    384 	rval = 0x0;
    385 	PM_SET_STATE_ACKON();
    386 	if (pm_wait_free(0x40) == 0)
    387 		rval = 0xffffcd35;
    388 
    389 	PM_SET_STATE_ACKON();
    390 	via_reg(VIA2, vDirA) = 0x00;
    391 
    392 	return (rval);
    393 }
    394 
    395 
    396 /*
    397  * My PMgrOp routine for the PB1XX series
    398  */
    399 int
    400 pm_pmgrop_pm1(pmdata)
    401 	PMData *pmdata;
    402 {
    403 	int i;
    404 	int s = 0x81815963;
    405 	u_char via1_vIER, via1_vDirA;
    406 	int rval = 0;
    407 	int num_pm_data = 0;
    408 	u_char pm_cmd;
    409 	u_char pm_data;
    410 	u_char *pm_buf;
    411 
    412 	/* disable all inetrrupts but PM */
    413 	via1_vIER = via_reg(VIA1, vIER);
    414 	PM_VIA_INTR_DISABLE();
    415 
    416 	via1_vDirA = via_reg(VIA1, vDirA);
    417 
    418 	switch (pmdata->command) {
    419 		default:
    420 			for (i = 0; i < 7; i++) {
    421 				via_reg(VIA2, vDirA) = 0x00;
    422 
    423 				/* wait until PM is free */
    424 				if (pm_wait_free(ADBDelay) == 0) {	/* timeout */
    425 					via_reg(VIA2, vDirA) = 0x00;
    426 					/* restore formar value */
    427 					via_reg(VIA1, vDirA) = via1_vDirA;
    428 					via_reg(VIA1, vIER) = via1_vIER;
    429 					return (0xffffcd38);
    430 				}
    431 
    432 				switch (mac68k_machine.machineid) {
    433 					case MACH_MACPB160:
    434 					case MACH_MACPB165:
    435 					case MACH_MACPB165C:
    436 					case MACH_MACPB180:
    437 					case MACH_MACPB180C:
    438 						{
    439 							int delay = ADBDelay * 16;
    440 
    441 							via_reg(VIA2, vDirA) = 0x00;
    442 							while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
    443 								delay--;
    444 
    445 							if (delay < 0) {	/* timeout */
    446 								via_reg(VIA2, vDirA) = 0x00;
    447 								/* restore formar value */
    448 								via_reg(VIA1, vIER) = via1_vIER;
    449 								return (0xffffcd38);
    450 							}
    451 						}
    452 				} /* end switch */
    453 
    454 				s = splhigh();
    455 
    456 				via1_vDirA = via_reg(VIA1, vDirA);
    457 				via_reg(VIA1, vDirA) &= 0x7f;
    458 
    459 				pm_cmd = (u_char)(pmdata->command & 0xff);
    460 				if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0)
    461 					break;	/* send command succeeded */
    462 
    463 				via_reg(VIA1, vDirA) = via1_vDirA;
    464 				splx(s);
    465 			} /* end for */
    466 
    467 			/* failed to send a command */
    468 			if (i == 7) {
    469 				via_reg(VIA2, vDirA) = 0x00;
    470 				/* restore formar value */
    471 				via_reg(VIA1, vDirA) = via1_vDirA;
    472 				via_reg(VIA1, vIER) = via1_vIER;
    473 					return (0xffffcd38);
    474 			}
    475 
    476 			/* send # of PM data */
    477 			num_pm_data = pmdata->num_data;
    478 			if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
    479 				break;			/* timeout */
    480 
    481 			/* send PM data */
    482 			pm_buf = (u_char *)pmdata->s_buf;
    483 			for (i = 0; i < num_pm_data; i++)
    484 				if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
    485 					break;		/* timeout */
    486 			if ((i != num_pm_data) && (num_pm_data != 0))
    487 				break;			/* timeout */
    488 
    489 			/* Will PM IC return data? */
    490 			if ((pm_cmd & 0x08) == 0) {
    491 				rval = 0;
    492 				break;			/* no returned data */
    493 			}
    494 
    495 			rval = 0xffffcd37;
    496 			if (pm_wait_busy(ADBDelay) != 0)
    497 				break;			/* timeout */
    498 
    499 			/* receive PM command */
    500 			if ((rval = pm_receive_pm1(&pm_data)) != 0)
    501 				break;
    502 
    503 			pmdata->command = pm_data;
    504 
    505 			/* receive number of PM data */
    506 			if ((rval = pm_receive_pm1(&pm_data)) != 0)
    507 				break;			/* timeout */
    508 			num_pm_data = pm_data;
    509 			pmdata->num_data = num_pm_data;
    510 
    511 			/* receive PM data */
    512 			pm_buf = (u_char *)pmdata->r_buf;
    513 			for (i = 0; i < num_pm_data; i++) {
    514 				if ((rval = pm_receive_pm1(&pm_data)) != 0)
    515 					break;				/* timeout */
    516 				pm_buf[i] = pm_data;
    517 			}
    518 
    519 			rval = 0;
    520 	}
    521 
    522 	via_reg(VIA2, vDirA) = 0x00;
    523 
    524 	/* restore formar value */
    525 	via_reg(VIA1, vDirA) = via1_vDirA;
    526 	via_reg(VIA1, vIER) = via1_vIER;
    527 	if (s != 0x81815963)
    528 		splx(s);
    529 
    530 	return (rval);
    531 }
    532 
    533 
    534 /*
    535  * My PM interrupt routine for PB100-series
    536  */
    537 void
    538 pm_intr_pm1()
    539 {
    540 	int s;
    541 	int rval;
    542 	PMData pmdata;
    543 
    544 	s = splhigh();
    545 
    546 	PM_VIA_CLR_INTR();				/* clear VIA1 interrupt */
    547 
    548 	/* ask PM what happend */
    549 	pmdata.command = 0x78;
    550 	pmdata.num_data = 0;
    551 	pmdata.data[0] = pmdata.data[1] = 0;
    552 	pmdata.s_buf = &pmdata.data[2];
    553 	pmdata.r_buf = &pmdata.data[2];
    554 	rval = pm_pmgrop_pm1(&pmdata);
    555 	if (rval != 0) {
    556 #ifdef ADB_DEBUG
    557 		if (adb_debug)
    558 			printf("pm: PM is not ready. error code=%08x\n", rval);
    559 #endif
    560 		splx(s);
    561 	}
    562 
    563 	if ((pmdata.data[2] & 0x10) == 0x10) {
    564 		if ((pmdata.data[2] & 0x0f) == 0) {
    565 			/* ADB data that were requested by TALK command */
    566 			pm_adb_get_TALK_result(&pmdata);
    567 		} else if ((pmdata.data[2] & 0x08) == 0x8) {
    568 			/* PM is requesting to poll  */
    569 			pm_adb_poll_next_device_pm1(&pmdata);
    570 		} else if ((pmdata.data[2] & 0x04) == 0x4) {
    571 			/* ADB device event */
    572 			pm_adb_get_ADB_data(&pmdata);
    573 		}
    574 	} else {
    575 #ifdef ADB_DEBUG
    576 		if (adb_debug)
    577 			pm_printerr("driver does not supported this event.",
    578 			    rval, pmdata.num_data, pmdata.data);
    579 #endif
    580 	}
    581 
    582 	splx(s);
    583 }
    584 
    585 
    586 
    587 /*
    588  * Functions for the PB Duo series and the PB 5XX series
    589  */
    590 
    591 /*
    592  * Receive data from PM for the PB Duo series and the PB 5XX series
    593  */
    594 int
    595 pm_receive_pm2(data)
    596 	u_char *data;
    597 {
    598 	int i;
    599 	int rval;
    600 
    601 	rval = 0xffffcd34;
    602 
    603 	switch (1) {
    604 		default:
    605 			/* set VIA SR to input mode */
    606 			via_reg(VIA1, vACR) |= 0x0c;
    607 			via_reg(VIA1, vACR) &= ~0x10;
    608 			i = PM_SR();
    609 
    610 			PM_SET_STATE_ACKOFF();
    611 			if (pm_wait_busy((int)ADBDelay*32) != 0)
    612 				break;		/* timeout */
    613 
    614 			PM_SET_STATE_ACKON();
    615 			rval = 0xffffcd33;
    616 			if (pm_wait_free((int)ADBDelay*32) == 0)
    617 				break;		/* timeout */
    618 
    619 			*data = PM_SR();
    620 			rval = 0;
    621 
    622 			break;
    623 	}
    624 
    625 	PM_SET_STATE_ACKON();
    626 	via_reg(VIA1, vACR) |= 0x1c;
    627 
    628 	return (rval);
    629 }
    630 
    631 
    632 
    633 /*
    634  * Send data to PM for the PB Duo series and the PB 5XX series
    635  */
    636 int
    637 pm_send_pm2(data)
    638 	u_char data;
    639 {
    640 	int rval;
    641 
    642 	via_reg(VIA1, vACR) |= 0x1c;
    643 	PM_SR() = data;
    644 
    645 	PM_SET_STATE_ACKOFF();
    646 	rval = 0xffffcd36;
    647 	if (pm_wait_busy((int)ADBDelay*32) != 0) {
    648 		PM_SET_STATE_ACKON();
    649 
    650 		via_reg(VIA1, vACR) |= 0x1c;
    651 
    652 		return (rval);
    653 	}
    654 
    655 	PM_SET_STATE_ACKON();
    656 	rval = 0xffffcd35;
    657 	if (pm_wait_free((int)ADBDelay*32) != 0)
    658 		rval = 0;
    659 
    660 	PM_SET_STATE_ACKON();
    661 	via_reg(VIA1, vACR) |= 0x1c;
    662 
    663 	return (rval);
    664 }
    665 
    666 
    667 
    668 /*
    669  * My PMgrOp routine for the PB Duo series and the PB 5XX series
    670  */
    671 int
    672 pm_pmgrop_pm2(pmdata)
    673 	PMData *pmdata;
    674 {
    675 	int i;
    676 	int s;
    677 	u_char via1_vIER;
    678 	int rval = 0;
    679 	int num_pm_data = 0;
    680 	u_char pm_cmd;
    681 	short pm_num_rx_data;
    682 	u_char pm_data;
    683 	u_char *pm_buf;
    684 
    685 	s = splhigh();
    686 
    687 	/* disable all inetrrupts but PM */
    688 	via1_vIER = 0x10;
    689 	via1_vIER &= via_reg(VIA1, vIER);
    690 	via_reg(VIA1, vIER) = via1_vIER;
    691 	if (via1_vIER != 0x0)
    692 		via1_vIER |= 0x80;
    693 
    694 	switch (pmdata->command) {
    695 		default:
    696 			/* wait until PM is free */
    697 			pm_cmd = (u_char)(pmdata->command & 0xff);
    698 			rval = 0xcd38;
    699 			if (pm_wait_free(ADBDelay * 4) == 0)
    700 				break;			/* timeout */
    701 
    702 			if (HwCfgFlags3 & 0x00200000) {
    703 				/* PB 160, PB 165(c), PB 180(c)? */
    704 				int delay = ADBDelay * 16;
    705 
    706 				via_reg(VIA2, vDirA) = 0x00;
    707 				while ((via_reg(VIA2, 0x200) == 0x07) &&
    708 				    (delay >= 0))
    709 					delay--;
    710 
    711 				if (delay < 0) {
    712 					rval = 0xffffcd38;
    713 					break;		/* timeout */
    714 				}
    715 			}
    716 
    717 			/* send PM command */
    718 			if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
    719 				break;				/* timeout */
    720 
    721 			/* send number of PM data */
    722 			num_pm_data = pmdata->num_data;
    723 			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
    724 				if (pm_send_cmd_type[pm_cmd] < 0) {
    725 					if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
    726 						break;		/* timeout */
    727 					pmdata->command = 0;
    728 				}
    729 			} else {				/* PB 1XX series ? */
    730 				if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
    731 					break;			/* timeout */
    732 			}
    733 			/* send PM data */
    734 			pm_buf = (u_char *)pmdata->s_buf;
    735 			for (i = 0 ; i < num_pm_data; i++)
    736 				if ((rval = pm_send_pm2(pm_buf[i])) != 0)
    737 					break;			/* timeout */
    738 			if (i != num_pm_data)
    739 				break;				/* timeout */
    740 
    741 
    742 			/* check if PM will send me data  */
    743 			pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
    744 			pmdata->num_data = pm_num_rx_data;
    745 			if (pm_num_rx_data == 0) {
    746 				rval = 0;
    747 				break;				/* no return data */
    748 			}
    749 
    750 			/* receive PM command */
    751 			pm_data = pmdata->command;
    752 			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
    753 				pm_num_rx_data--;
    754 				if (pm_num_rx_data == 0)
    755 					if ((rval = pm_receive_pm2(&pm_data)) != 0) {
    756 						rval = 0xffffcd37;
    757 						break;
    758 					}
    759 				pmdata->command = pm_data;
    760 			} else {				/* PB 1XX series ? */
    761 				if ((rval = pm_receive_pm2(&pm_data)) != 0) {
    762 					rval = 0xffffcd37;
    763 					break;
    764 				}
    765 				pmdata->command = pm_data;
    766 			}
    767 
    768 			/* receive number of PM data */
    769 			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
    770 				if (pm_num_rx_data < 0) {
    771 					if ((rval = pm_receive_pm2(&pm_data)) != 0)
    772 						break;		/* timeout */
    773 					num_pm_data = pm_data;
    774 				} else
    775 					num_pm_data = pm_num_rx_data;
    776 				pmdata->num_data = num_pm_data;
    777 			} else {				/* PB 1XX serias ? */
    778 				if ((rval = pm_receive_pm2(&pm_data)) != 0)
    779 					break;			/* timeout */
    780 				num_pm_data = pm_data;
    781 				pmdata->num_data = num_pm_data;
    782 			}
    783 
    784 			/* receive PM data */
    785 			pm_buf = (u_char *)pmdata->r_buf;
    786 			for (i = 0; i < num_pm_data; i++) {
    787 				if ((rval = pm_receive_pm2(&pm_data)) != 0)
    788 					break;			/* timeout */
    789 				pm_buf[i] = pm_data;
    790 			}
    791 
    792 			rval = 0;
    793 	}
    794 
    795 	/* restore former value */
    796 	via_reg(VIA1, vIER) = via1_vIER;
    797 	splx(s);
    798 
    799 	return (rval);
    800 }
    801 
    802 
    803 /*
    804  * My PM interrupt routine for the PB Duo series and the PB 5XX series
    805  */
    806 void
    807 pm_intr_pm2()
    808 {
    809 	int s;
    810 	int rval;
    811 	PMData pmdata;
    812 
    813 	s = splhigh();
    814 
    815 	PM_VIA_CLR_INTR();			/* clear VIA1 interrupt */
    816 						/* ask PM what happend */
    817 	pmdata.command = 0x78;
    818 	pmdata.num_data = 0;
    819 	pmdata.s_buf = &pmdata.data[2];
    820 	pmdata.r_buf = &pmdata.data[2];
    821 	rval = pm_pmgrop_pm2(&pmdata);
    822 	if (rval != 0) {
    823 #ifdef ADB_DEBUG
    824 		if (adb_debug)
    825 			printf("pm: PM is not ready. error code: %08x\n", rval);
    826 #endif
    827 		splx(s);
    828 	}
    829 
    830 	switch ((u_int)(pmdata.data[2] & 0xff)) {
    831 		case 0x00:			/* 1 sec interrupt? */
    832 			break;
    833 		case 0x80:			/* 1 sec interrupt? */
    834 			pm_counter++;
    835 			break;
    836 		case 0x08:			/* Brightness/Contrast button on LCD panel */
    837 			/* get brightness and contrast of the LCD */
    838 			pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
    839 			pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
    840 /*
    841 			pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
    842 			pmdata.command = 0x33;
    843 			pmdata.num_data = 1;
    844 			pmdata.s_buf = pmdata.data;
    845 			pmdata.r_buf = pmdata.data;
    846 			pmdata.data[0] = pm_LCD_contrast;
    847 			rval = pm_pmgrop_pm2(&pmdata);
    848 			pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
    849 */
    850 			/* this is an experimental code */
    851 			pmdata.command = 0x41;
    852 			pmdata.num_data = 1;
    853 			pmdata.s_buf = pmdata.data;
    854 			pmdata.r_buf = pmdata.data;
    855 			pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
    856 			if (pm_LCD_brightness < 0x25)
    857 				pm_LCD_brightness = 0x25;
    858 			if (pm_LCD_brightness > 0x5a)
    859 				pm_LCD_brightness = 0x7f;
    860 			pmdata.data[0] = pm_LCD_brightness;
    861 			rval = pm_pmgrop_pm2(&pmdata);
    862 			break;
    863 		case 0x10:			/* ADB data that were requested by TALK command */
    864 		case 0x14:
    865 			pm_adb_get_TALK_result(&pmdata);
    866 			break;
    867 		case 0x16:			/* ADB device event */
    868 		case 0x18:
    869 		case 0x1e:
    870 			pm_adb_get_ADB_data(&pmdata);
    871 			break;
    872 		default:
    873 #ifdef ADB_DEBUG
    874 			if (adb_debug)
    875 				pm_printerr("driver does not supported this event.",
    876 				    pmdata.data[2], pmdata.num_data,
    877 				    pmdata.data);
    878 #endif
    879 			break;
    880 	}
    881 
    882 	splx(s);
    883 }
    884 
    885 
    886 /*
    887  * MRG-based PMgrOp routine
    888  */
    889 int
    890 pm_pmgrop_mrg(pmdata)
    891 	PMData *pmdata;
    892 {
    893 	u_int32_t rval=0;
    894 
    895 	asm("
    896 		movl	%1, a0
    897 		.word   0xa085
    898 		movl	d0, %0"
    899 		: "=g" (rval)
    900 		: "g" (pmdata)
    901 		: "a0", "d0" );
    902 
    903 	return rval;
    904 }
    905 
    906 
    907 /*
    908  * My PMgrOp routine
    909  */
    910 int
    911 pmgrop(pmdata)
    912 	PMData *pmdata;
    913 {
    914 	switch (pmHardware) {
    915 		case PM_HW_PB1XX:
    916 			return (pm_pmgrop_pm1(pmdata));
    917 			break;
    918 		case PM_HW_PB5XX:
    919 			return (pm_pmgrop_pm2(pmdata));
    920 			break;
    921 		default:
    922 			/* return (pmgrop_mrg(pmdata)); */
    923 			return (-1);
    924 	}
    925 }
    926 
    927 
    928 /*
    929  * My PM interrupt routine
    930  */
    931 void
    932 pm_intr()
    933 {
    934 	switch (pmHardware) {
    935 		case PM_HW_PB1XX:
    936 			pm_intr_pm1();
    937 			break;
    938 		case PM_HW_PB5XX:
    939 			pm_intr_pm2();
    940 			break;
    941 		default:
    942 			break;
    943 	}
    944 }
    945 
    946 
    947 
    948 /*
    949  * Synchronous ADBOp routine for the Power Manager
    950  */
    951 int
    952 pm_adb_op(buffer, compRout, data, command)
    953 	u_char *buffer;
    954 	void *compRout;
    955 	void *data;
    956 	int command;
    957 {
    958 	int i, len;
    959 	int s;
    960 	int rval;
    961 	int delay;
    962 	PMData pmdata;
    963 
    964 	if (adbWaiting == 1)
    965 		return (-1);
    966 
    967 	s = splhigh();
    968 	via_reg(VIA1, vIER) = 0x10;
    969 
    970  	adbBuffer = buffer;
    971 	adbCompRout = compRout;
    972 	adbCompData = data;
    973 
    974 	pmdata.command = 0x20;
    975 	pmdata.s_buf = pmdata.data;
    976 	pmdata.r_buf = pmdata.data;
    977 
    978 	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, add number of ADB data to number of PM data */
    979 		if (buffer != (u_char *)0)
    980 			pmdata.num_data = buffer[0] + 3;
    981 	} else {
    982 		pmdata.num_data = 3;
    983 	}
    984 
    985 	pmdata.data[0] = (u_char)(command & 0xff);
    986 	pmdata.data[1] = 0;
    987 	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, copy ADB data to PM buffer */
    988 		if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
    989 			pmdata.data[2] = buffer[0];		/* number of data */
    990 			for (i = 0; i < buffer[0]; i++)
    991 				pmdata.data[3 + i] = buffer[1 + i];
    992 		} else
    993 			pmdata.data[2] = 0;
    994 	} else
    995 		pmdata.data[2] = 0;
    996 
    997 	rval = pmgrop(&pmdata);
    998 	if (rval != 0)
    999 		return (-1);
   1000 
   1001 	if (adbWaiting == 0) {
   1002 		adbWaiting = 1;
   1003 		adbWaitingCmd = command;
   1004 	}
   1005 
   1006 	PM_VIA_INTR_ENABLE();
   1007 
   1008 	/* wait until the PM interrupt is occured */
   1009 	delay = 0x80000;
   1010 	while (adbWaiting == 1) {
   1011 		if ((via_reg(VIA1, vIFR) & 0x10) == 0x10)
   1012 			pm_intr();
   1013 #ifdef PM_GRAB_SI
   1014 			zshard(0);		/* grab any serial interrupts */
   1015 #endif
   1016 		if ((--delay) < 0)
   1017 			return (-1);
   1018 	}
   1019 
   1020 	if (buffer != (u_char *)0) {
   1021 		len = adbInputBuffer[3];
   1022 		for (i=0; i<=len; i++)
   1023 				buffer[i] = adbInputBuffer[3 + i];
   1024 		if (len < 0)
   1025 			buffer[0] = 0;
   1026 	}
   1027 
   1028 	/* this command enables the interrupt by operating ADB devices */
   1029 	if (HwCfgFlags3 & 0x00020000) {		/* PB Duo series, PB 500 series */
   1030 		pmdata.command = 0x20;
   1031 		pmdata.num_data = 4;
   1032 		pmdata.s_buf = pmdata.data;
   1033 		pmdata.r_buf = pmdata.data;
   1034 		pmdata.data[0] = 0x00;
   1035 		pmdata.data[1] = 0x86;	/* magic spell for awaking the PM */
   1036 		pmdata.data[2] = 0x00;
   1037 		pmdata.data[3] = 0x0c;	/* each bit may express the existent ADB device */
   1038 	} else {				/* PB 100-series */
   1039 		pmdata.command = 0x20;
   1040 		pmdata.num_data = 3;
   1041 		pmdata.s_buf = pmdata.data;
   1042 		pmdata.r_buf = pmdata.data;
   1043 		pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
   1044 		pmdata.data[1] = 0x04;
   1045 		pmdata.data[2] = 0x00;
   1046 	}
   1047 	rval = pmgrop(&pmdata);
   1048 
   1049 	splx(s);
   1050 	return (rval);
   1051 }
   1052 
   1053 
   1054 void
   1055 pm_adb_get_TALK_result(pmdata)
   1056 	PMData *pmdata;
   1057 {
   1058 	int i;
   1059 	int rx_pm_adb_cmd;
   1060 
   1061 	rx_pm_adb_cmd = (u_int)pmdata->data[3] & 0xff;
   1062 
   1063 	pmdata->data[2] &= 0xf;
   1064 	pmdata->data[1] = pmdata->data[3];
   1065 	pmdata->data[3] = pmdata->num_data - 2;
   1066 
   1067 	adbInputBuffer[0] = pmdata->num_data + 1;
   1068 	for (i = 1; i < pmdata->num_data + 2; i++)
   1069 		adbInputBuffer[i] = pmdata->data[i];
   1070 
   1071 	if ((adbWaiting == 1) && (rx_pm_adb_cmd == adbWaitingCmd)) {
   1072 		if (adbStarting == 0)
   1073 			adb_complete(&pmdata->data[3], (long)0, adbWaitingCmd);
   1074 		adbWaitingCmd = 0x0;
   1075 
   1076 		adbWaiting = 0;
   1077 		adb_comp_exec();
   1078 		adbBuffer = (long)0;
   1079 		adbCompRout = (long)0;
   1080 		adbCompData = (long)0;
   1081 	}
   1082 }
   1083 
   1084 
   1085 void
   1086 pm_adb_get_ADB_data(pmdata)
   1087 	PMData *pmdata;
   1088 {
   1089 	int i;
   1090 
   1091 	i = (u_int)pmdata->data[3] & 0xff;
   1092 	pmdata->data[2] &= 0xf;
   1093 	pmdata->data[1] = pmdata->data[3];
   1094 	pmdata->data[3] = pmdata->num_data - 2;
   1095 
   1096 	adbInputBuffer[0] = pmdata->num_data + 1;
   1097 	if (adbStarting == 0)
   1098 		adb_complete(&pmdata->data[3], (long)0, i);
   1099 }
   1100 
   1101 
   1102 void
   1103 pm_adb_poll_next_device_pm1(pmdata)
   1104 	PMData *pmdata;
   1105 {
   1106 	int i;
   1107 	int ndid;
   1108 	u_short bendid = 0x1;
   1109 	int rval;
   1110 	PMData tmp_pmdata;
   1111 
   1112 	/* find another existent ADB device to poll */
   1113 	for (i = 1; i < 16; i++) {
   1114 		ndid = (((pmdata->data[3] & 0xf0) >> 4) + i) & 0xf;
   1115 		bendid <<= ndid;
   1116 		if ((pm_existent_ADB_devices & bendid) != 0)
   1117 			break;
   1118 	}
   1119 
   1120 	/* poll the other device */
   1121 	tmp_pmdata.command = 0x20;
   1122 	tmp_pmdata.num_data = 3;
   1123 	tmp_pmdata.s_buf = tmp_pmdata.data;
   1124 	tmp_pmdata.r_buf = tmp_pmdata.data;
   1125 	tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
   1126 	tmp_pmdata.data[1] = 0x04;	/* magic spell for awaking the PM */
   1127 	tmp_pmdata.data[2] = 0x00;
   1128 	rval = pmgrop(&tmp_pmdata);
   1129 }
   1130 
   1131 
   1132