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