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 */ 51extern u_short ADBDelay; 52extern u_int32_t HwCfgFlags3; 53extern 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 */ 74int pmHardware = PM_HW_UNKNOWN; 75u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */ 76u_int pm_LCD_brightness = 0x0; 77u_int pm_LCD_contrast = 0x0; 78u_int pm_counter = 0; /* clock count */ 79 80/* these values shows that number of data returned after 'send' cmd is sent */ 81char 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 */ 101char 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 127void pm_printerr __P(( char *, int, int, char * )); 128#endif 129 130int pm_wait_busy __P((int)); 131int pm_wait_free __P((int)); 132 133/* these functions are for the PB1XX series */ 134int pm_receive_pm1 __P((u_char *)); 135int pm_send_pm1 __P((u_char,int)); 136int pm_pmgrop_pm1 __P((PMData *)); 137void pm_intr_pm1 __P((void)); 138 139/* these functions are for the PB Duo series and the PB 5XX series */ 140int pm_receive_pm2 __P((u_char *)); 141int pm_send_pm2 __P((u_char)); 142int pm_pmgrop_pm2 __P((PMData *)); 143void pm_intr_pm2 __P((void)); 144 145/* this function is MRG-Based (for testing) */ 146int pm_pmgrop_mrg __P((PMData *)); 147 148/* these functions are called from adb_direct.c */ 149void pm_setup_adb __P((void)); 150void pm_check_adb_devices __P((int)); 151void pm_intr __P((void)); 152int pm_adb_op __P((u_char *, void *, void *, int)); 153 154/* these functions also use the variables of adb_direct.c */ 155void pm_adb_get_TALK_result __P((PMData *)); 156void pm_adb_get_ADB_data __P((PMData *)); 157void pm_adb_poll_next_device_pm1 __P((PMData *)); 158 159 160/* 161 * These variables are in adb_direct.c. 162 */ 163extern u_char *adbBuffer; /* pointer to user data area */ 164#define MAX_ADB_MSG_LENGTH 20 165extern u_char adbInputBuffer[MAX_ADB_MSG_LENGTH]; /* data input buffer */ 166extern void *adbCompRout; /* pointer to the completion routine */ 167extern void *adbCompData; /* pointer to the completion routine data */ 168extern int adbWaiting; /* waiting for return data from the device */ 169extern int adbWaitingCmd; /* ADB command we are waiting for */ 170extern int adbStarting; /* doing ADB reinit, so do "polling" differently */ 171 172/* 173 * Define the external functions 174 */ 175extern int zshard(int); /* from zs.c */ 176extern 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 */ 183void 184pm_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 */ 204void 205pm_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 */ 237void 238pm_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 */ 251int 252pm_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 */ 269int 270pm_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 */ 292int 293pm_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 */ 327int 328pm_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 */ 360int 361pm_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 */ 498void 499pm_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 */ 549int 550pm_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 */ 591int 592pm_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 */ 626int 627pm_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 */ 759void 760pm_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 */ 846int 847pm_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 */ 867int 868pmgrop(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 */ 892void 893pm_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 */ 916int 917pm_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 1019void 1020pm_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 1050void 1051pm_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 1067void 1068pm_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