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