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