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