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