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