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 */ 58extern u_short ADBDelay; 59extern u_int32_t HwCfgFlags3; 60extern 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 */ 81int pmHardware = PM_HW_UNKNOWN; 82u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */ 83u_int pm_LCD_brightness = 0x0; 84u_int pm_LCD_contrast = 0x0; 85u_int pm_counter = 0; /* clock count */ 86 87/* these values shows that number of data returned after 'send' cmd is sent */ 88char 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 */ 108char 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 134void pm_printerr __P(( char *, int, int, char * )); 135#endif 136 137int pm_wait_busy __P((int)); 138int pm_wait_free __P((int)); 139 140/* these functions are for the PB1XX series */ 141int pm_receive_pm1 __P((u_char *)); 142int pm_send_pm1 __P((u_char,int)); 143int pm_pmgrop_pm1 __P((PMData *)); 144void pm_intr_pm1 __P((void)); 145 146/* these functions are for the PB Duo series and the PB 5XX series */ 147int pm_receive_pm2 __P((u_char *)); 148int pm_send_pm2 __P((u_char)); 149int pm_pmgrop_pm2 __P((PMData *)); 150void pm_intr_pm2 __P((void)); 151 152/* this function is MRG-Based (for testing) */ 153int pm_pmgrop_mrg __P((PMData *)); 154 155/* these functions are called from adb_direct.c */ 156void pm_setup_adb __P((void)); 157void pm_check_adb_devices __P((int)); 158void pm_intr __P((void)); 159int pm_adb_op __P((u_char *, void *, void *, int)); 160 161/* these functions also use the variables of adb_direct.c */ 162void pm_adb_get_TALK_result __P((PMData *)); 163void pm_adb_get_ADB_data __P((PMData *)); 164void pm_adb_poll_next_device_pm1 __P((PMData *)); 165 166 167/* 168 * These variables are in adb_direct.c. 169 */ 170extern u_char *adbBuffer; /* pointer to user data area */ 171#define MAX_ADB_MSG_LENGTH 20 172extern u_char adbInputBuffer[MAX_ADB_MSG_LENGTH]; /* data input buffer */ 173extern void *adbCompRout; /* pointer to the completion routine */ 174extern void *adbCompData; /* pointer to the completion routine data */ 175extern int adbWaiting; /* waiting for return data from the device */ 176extern int adbWaitingCmd; /* ADB command we are waiting for */ 177extern int adbStarting; /* doing ADB reinit, so do "polling" differently */ 178 179/* 180 * Define the external functions 181 */ 182extern int zshard(int); /* from zs.c */ 183extern 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 */ 190void 191pm_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 */ 211void 212pm_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 */ 244void 245pm_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 */ 258int 259pm_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 */ 276int 277pm_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 */ 299int 300pm_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 */ 334int 335pm_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 */ 367int 368pm_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 */ 505void 506pm_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 */ 559int 560pm_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 */ 601int 602pm_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 */ 636int 637pm_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 */ 769void 770pm_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 */ 860int 861pm_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 */ 881int 882pmgrop(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 */ 906void 907pm_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 */ 930int 931pm_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 1033void 1034pm_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 1064void 1065pm_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 1081void 1082pm_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