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