pm_direct.c revision 1.3
1/* $OpenBSD: pm_direct.c,v 1.3 2001/09/20 17:02:30 mpech Exp $ */ 2/* $NetBSD: pm_direct.c,v 1.9 2000/06/08 22:10:46 tsubai Exp $ */ 3 4/* 5 * Copyright (C) 1997 Takashi Hamada 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Takashi Hamada 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33/* From: pm_direct.c 1.3 03/18/98 Takashi Hamada */ 34 35#ifdef DEBUG 36#ifndef ADB_DEBUG 37#define ADB_DEBUG 38#endif 39#endif 40 41/* #define PM_GRAB_SI 1 */ 42 43#include <sys/param.h> 44#include <sys/cdefs.h> 45#include <sys/device.h> 46#include <sys/systm.h> 47 48#include <machine/adbsys.h> 49#include <machine/cpu.h> 50 51#include <macppc/dev/adbvar.h> 52#include <macppc/dev/pm_direct.h> 53#include <macppc/dev/viareg.h> 54 55extern int adb_polling; /* Are we polling? (Debugger mode) */ 56 57/* hardware dependent values */ 58#define ADBDelay 100 /* XXX */ 59#define HwCfgFlags3 0x20000 /* XXX */ 60 61/* define the types of the Power Manager */ 62#define PM_HW_UNKNOWN 0x00 /* don't know */ 63#define PM_HW_PB1XX 0x01 /* PowerBook 1XX series */ 64#define PM_HW_PB5XX 0x02 /* PowerBook Duo and 5XX series */ 65 66/* useful macros */ 67#define PM_SR() read_via_reg(VIA1, vSR) 68#define PM_VIA_INTR_ENABLE() write_via_reg(VIA1, vIER, 0x90) 69#define PM_VIA_INTR_DISABLE() write_via_reg(VIA1, vIER, 0x10) 70#define PM_VIA_CLR_INTR() write_via_reg(VIA1, vIFR, 0x90) 71#if 0 72#define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x04) 73#define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x04) 74#define PM_IS_ON (0x02 == (read_via_reg(VIA2, vBufB) & 0x02)) 75#define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x02)) 76#else 77#define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x10) 78#define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x10) 79#define PM_IS_ON (0x08 == (read_via_reg(VIA2, vBufB) & 0x08)) 80#define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x08)) 81#endif 82 83/* 84 * Variables for internal use 85 */ 86int pmHardware = PM_HW_UNKNOWN; 87u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */ 88u_int pm_LCD_brightness = 0x0; 89u_int pm_LCD_contrast = 0x0; 90u_int pm_counter = 0; /* clock count */ 91 92/* these values shows that number of data returned after 'send' cmd is sent */ 93signed char pm_send_cmd_type[] = { 94 -1, -1, -1, -1, -1, -1, -1, -1, 95 -1, -1, -1, -1, -1, -1, -1, -1, 96 0x01, 0x01, -1, -1, -1, -1, -1, -1, 97 0x00, 0x00, -1, -1, -1, -1, -1, 0x00, 98 -1, 0x00, 0x02, 0x01, 0x01, -1, -1, -1, 99 0x00, -1, -1, -1, -1, -1, -1, -1, 100 0x04, 0x14, -1, 0x03, -1, -1, -1, -1, 101 0x00, 0x00, 0x02, 0x02, -1, -1, -1, -1, 102 0x01, 0x01, -1, -1, -1, -1, -1, -1, 103 0x00, 0x00, -1, -1, 0x01, -1, -1, -1, 104 0x01, 0x00, 0x02, 0x02, -1, 0x01, 0x03, 0x01, 105 0x00, 0x01, 0x00, 0x00, 0x00, -1, -1, -1, 106 0x02, -1, -1, -1, -1, -1, -1, -1, 107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, -1, 108 0x01, 0x01, 0x01, -1, -1, -1, -1, -1, 109 0x00, 0x00, -1, -1, -1, -1, 0x04, 0x04, 110 0x04, -1, 0x00, -1, -1, -1, -1, -1, 111 0x00, -1, -1, -1, -1, -1, -1, -1, 112 0x01, 0x02, -1, -1, -1, -1, -1, -1, 113 0x00, 0x00, -1, -1, -1, -1, -1, -1, 114 0x02, 0x02, 0x02, 0x04, -1, 0x00, -1, -1, 115 0x01, 0x01, 0x03, 0x02, -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 -1, -1, -1, -1, -1, -1, -1, -1, 120 0x00, -1, -1, -1, -1, -1, -1, -1, 121 0x01, 0x01, -1, -1, 0x00, 0x00, -1, -1, 122 -1, 0x04, 0x00, -1, -1, -1, -1, -1, 123 0x03, -1, 0x00, -1, 0x00, -1, -1, 0x00, 124 -1, -1, -1, -1, -1, -1, -1, -1, 125 -1, -1, -1, -1, -1, -1, -1, -1 126}; 127 128/* these values shows that number of data returned after 'receive' cmd is sent */ 129signed char pm_receive_cmd_type[] = { 130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 131 -1, -1, -1, -1, -1, -1, -1, -1, 132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 133 0x02, 0x02, -1, -1, -1, -1, -1, 0x00, 134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 135 -1, -1, -1, -1, -1, -1, -1, -1, 136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 137 0x05, 0x15, -1, 0x02, -1, -1, -1, -1, 138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 139 0x02, 0x02, -1, -1, -1, -1, -1, -1, 140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 141 0x02, 0x00, 0x03, 0x03, -1, -1, -1, -1, 142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 143 0x04, 0x04, 0x03, 0x09, -1, -1, -1, -1, 144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 145 -1, -1, -1, -1, -1, -1, 0x01, 0x01, 146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 147 0x06, -1, -1, -1, -1, -1, -1, -1, 148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 149 0x02, 0x02, -1, -1, -1, -1, -1, -1, 150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 151 0x02, 0x00, 0x00, 0x00, -1, -1, -1, -1, 152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 153 -1, -1, -1, -1, -1, -1, -1, -1, 154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 155 -1, -1, -1, -1, -1, -1, -1, -1, 156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 157 0x02, 0x02, -1, -1, 0x02, -1, -1, -1, 158 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 159 -1, -1, 0x02, -1, -1, -1, -1, 0x00, 160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 161 -1, -1, -1, -1, -1, -1, -1, -1, 162}; 163 164 165/* 166 * Define the private functions 167 */ 168 169/* for debugging */ 170#ifdef ADB_DEBUG 171void pm_printerr __P((char *, int, int, char *)); 172#endif 173 174int pm_wait_busy __P((int)); 175int pm_wait_free __P((int)); 176 177/* these functions are for the PB1XX series */ 178int pm_receive_pm1 __P((u_char *)); 179int pm_send_pm1 __P((u_char,int)); 180int pm_pmgrop_pm1 __P((PMData *)); 181void pm_intr_pm1 __P((void)); 182 183/* these functions are for the PB Duo series and the PB 5XX series */ 184int pm_receive_pm2 __P((u_char *)); 185int pm_send_pm2 __P((u_char)); 186int pm_pmgrop_pm2 __P((PMData *)); 187void pm_intr_pm2 __P((void)); 188 189/* this function is MRG-Based (for testing) */ 190int pm_pmgrop_mrg __P((PMData *)); 191 192/* these functions are called from adb_direct.c */ 193void pm_setup_adb __P((void)); 194void pm_check_adb_devices __P((int)); 195void pm_intr __P((void)); 196int pm_adb_op __P((u_char *, void *, void *, int)); 197 198/* these functions also use the variables of adb_direct.c */ 199void pm_adb_get_TALK_result __P((PMData *)); 200void pm_adb_get_ADB_data __P((PMData *)); 201void pm_adb_poll_next_device_pm1 __P((PMData *)); 202 203 204/* 205 * These variables are in adb_direct.c. 206 */ 207extern u_char *adbBuffer; /* pointer to user data area */ 208extern void *adbCompRout; /* pointer to the completion routine */ 209extern void *adbCompData; /* pointer to the completion routine data */ 210extern int adbWaiting; /* waiting for return data from the device */ 211extern int adbWaitingCmd; /* ADB command we are waiting for */ 212extern int adbStarting; /* doing ADB reinit, so do "polling" differently */ 213 214#define ADB_MAX_MSG_LENGTH 16 215#define ADB_MAX_HDR_LENGTH 8 216struct adbCommand { 217 u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */ 218 u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */ 219 u_char *saveBuf; /* where to save result */ 220 u_char *compRout; /* completion routine pointer */ 221 u_char *compData; /* completion routine data pointer */ 222 u_int cmd; /* the original command for this data */ 223 u_int unsol; /* 1 if packet was unsolicited */ 224 u_int ack_only; /* 1 for no special processing */ 225}; 226extern void adb_pass_up __P((struct adbCommand *)); 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 if (s != 0x81815963) 485 splx(s); 486 return 0xffffcd38; 487 } 488 489 /* send # of PM data */ 490 num_pm_data = pmdata->num_data; 491 if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0) 492 break; /* timeout */ 493 494 /* send PM data */ 495 pm_buf = (u_char *)pmdata->s_buf; 496 for (i = 0; i < num_pm_data; i++) 497 if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0) 498 break; /* timeout */ 499 if ((i != num_pm_data) && (num_pm_data != 0)) 500 break; /* timeout */ 501 502 /* Will PM IC return data? */ 503 if ((pm_cmd & 0x08) == 0) { 504 rval = 0; 505 break; /* no returned data */ 506 } 507 508 rval = 0xffffcd37; 509 if (pm_wait_busy(ADBDelay) != 0) 510 break; /* timeout */ 511 512 /* receive PM command */ 513 if ((rval = pm_receive_pm1(&pm_data)) != 0) 514 break; 515 516 pmdata->command = pm_data; 517 518 /* receive number of PM data */ 519 if ((rval = pm_receive_pm1(&pm_data)) != 0) 520 break; /* timeout */ 521 num_pm_data = pm_data; 522 pmdata->num_data = num_pm_data; 523 524 /* receive PM data */ 525 pm_buf = (u_char *)pmdata->r_buf; 526 for (i = 0; i < num_pm_data; i++) { 527 if ((rval = pm_receive_pm1(&pm_data)) != 0) 528 break; /* timeout */ 529 pm_buf[i] = pm_data; 530 } 531 532 rval = 0; 533 } 534 535 via_reg(VIA2, vDirA) = 0x00; 536 537 /* restore formar value */ 538 via_reg(VIA1, vDirA) = via1_vDirA; 539 via_reg(VIA1, vIER) = via1_vIER; 540 if (s != 0x81815963) 541 splx(s); 542 543 return rval; 544#else 545 panic("pm_pmgrop_pm1"); 546#endif 547} 548 549 550/* 551 * My PM interrupt routine for PB1XX series 552 */ 553void 554pm_intr_pm1() 555{ 556#if 0 557 int s; 558 int rval; 559 PMData pmdata; 560 561 s = splhigh(); 562 563 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ 564 565 /* ask PM what happend */ 566 pmdata.command = 0x78; 567 pmdata.num_data = 0; 568 pmdata.data[0] = pmdata.data[1] = 0; 569 pmdata.s_buf = &pmdata.data[2]; 570 pmdata.r_buf = &pmdata.data[2]; 571 rval = pm_pmgrop_pm1(&pmdata); 572 if (rval != 0) { 573#ifdef ADB_DEBUG 574 if (adb_debug) 575 printf("pm: PM is not ready. error code=%08x\n", rval); 576#endif 577 splx(s); 578 return; 579 } 580 581 if ((pmdata.data[2] & 0x10) == 0x10) { 582 if ((pmdata.data[2] & 0x0f) == 0) { 583 /* ADB data that were requested by TALK command */ 584 pm_adb_get_TALK_result(&pmdata); 585 } else if ((pmdata.data[2] & 0x08) == 0x8) { 586 /* PM is requesting to poll */ 587 pm_adb_poll_next_device_pm1(&pmdata); 588 } else if ((pmdata.data[2] & 0x04) == 0x4) { 589 /* ADB device event */ 590 pm_adb_get_ADB_data(&pmdata); 591 } 592 } else { 593#ifdef ADB_DEBUG 594 if (adb_debug) 595 pm_printerr("driver does not supported this event.", 596 rval, pmdata.num_data, pmdata.data); 597#endif 598 } 599 600 splx(s); 601#else 602 panic("pm_intr_pm1"); 603#endif 604} 605 606 607 608/* 609 * Functions for the PB Duo series and the PB 5XX series 610 */ 611 612/* 613 * Receive data from PM for the PB Duo series and the PB 5XX series 614 */ 615int 616pm_receive_pm2(data) 617 u_char *data; 618{ 619 int i; 620 int rval; 621 622 rval = 0xffffcd34; 623 624 switch (1) { 625 default: 626 /* set VIA SR to input mode */ 627 via_reg_or(VIA1, vACR, 0x0c); 628 via_reg_and(VIA1, vACR, ~0x10); 629 i = PM_SR(); 630 631 PM_SET_STATE_ACKOFF(); 632 if (pm_wait_busy((int)ADBDelay*32) != 0) 633 break; /* timeout */ 634 635 PM_SET_STATE_ACKON(); 636 rval = 0xffffcd33; 637 if (pm_wait_free((int)ADBDelay*32) == 0) 638 break; /* timeout */ 639 640 *data = PM_SR(); 641 rval = 0; 642 643 break; 644 } 645 646 PM_SET_STATE_ACKON(); 647 via_reg_or(VIA1, vACR, 0x1c); 648 649 return rval; 650} 651 652 653 654/* 655 * Send data to PM for the PB Duo series and the PB 5XX series 656 */ 657int 658pm_send_pm2(data) 659 u_char data; 660{ 661 int rval; 662 663 via_reg_or(VIA1, vACR, 0x1c); 664 write_via_reg(VIA1, vSR, data); /* PM_SR() = data; */ 665 666 PM_SET_STATE_ACKOFF(); 667 rval = 0xffffcd36; 668 if (pm_wait_busy((int)ADBDelay*32) != 0) { 669 PM_SET_STATE_ACKON(); 670 671 via_reg_or(VIA1, vACR, 0x1c); 672 673 return rval; 674 } 675 676 PM_SET_STATE_ACKON(); 677 rval = 0xffffcd35; 678 if (pm_wait_free((int)ADBDelay*32) != 0) 679 rval = 0; 680 681 PM_SET_STATE_ACKON(); 682 via_reg_or(VIA1, vACR, 0x1c); 683 684 return rval; 685} 686 687 688 689/* 690 * My PMgrOp routine for the PB Duo series and the PB 5XX series 691 */ 692int 693pm_pmgrop_pm2(pmdata) 694 PMData *pmdata; 695{ 696 int i; 697 int s; 698 u_char via1_vIER; 699 int rval = 0; 700 int num_pm_data = 0; 701 u_char pm_cmd; 702 short pm_num_rx_data; 703 u_char pm_data; 704 u_char *pm_buf; 705 706 s = splhigh(); 707 708 /* disable all inetrrupts but PM */ 709 via1_vIER = 0x10; 710 via1_vIER &= read_via_reg(VIA1, vIER); 711 write_via_reg(VIA1, vIER, via1_vIER); 712 if (via1_vIER != 0x0) 713 via1_vIER |= 0x80; 714 715 switch (pmdata->command) { 716 default: 717 /* wait until PM is free */ 718 pm_cmd = (u_char)(pmdata->command & 0xff); 719 rval = 0xcd38; 720 if (pm_wait_free(ADBDelay * 4) == 0) 721 break; /* timeout */ 722 723 if (HwCfgFlags3 & 0x00200000) { 724 /* PB 160, PB 165(c), PB 180(c)? */ 725 int delay = ADBDelay * 16; 726 727 write_via_reg(VIA2, vDirA, 0x00); 728 while ((read_via_reg(VIA2, 0x200) == 0x07) && 729 (delay >= 0)) 730 delay--; 731 732 if (delay < 0) { 733 rval = 0xffffcd38; 734 break; /* timeout */ 735 } 736 } 737 738 /* send PM command */ 739 if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff)))) 740 break; /* timeout */ 741 742 /* send number of PM data */ 743 num_pm_data = pmdata->num_data; 744 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 745 if (pm_send_cmd_type[pm_cmd] < 0) { 746 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0) 747 break; /* timeout */ 748 pmdata->command = 0; 749 } 750 } else { /* PB 1XX series ? */ 751 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0) 752 break; /* timeout */ 753 } 754 /* send PM data */ 755 pm_buf = (u_char *)pmdata->s_buf; 756 for (i = 0 ; i < num_pm_data; i++) 757 if ((rval = pm_send_pm2(pm_buf[i])) != 0) 758 break; /* timeout */ 759 if (i != num_pm_data) 760 break; /* timeout */ 761 762 763 /* check if PM will send me data */ 764 pm_num_rx_data = pm_receive_cmd_type[pm_cmd]; 765 pmdata->num_data = pm_num_rx_data; 766 if (pm_num_rx_data == 0) { 767 rval = 0; 768 break; /* no return data */ 769 } 770 771 /* receive PM command */ 772 pm_data = pmdata->command; 773 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 774 pm_num_rx_data--; 775 if (pm_num_rx_data == 0) 776 if ((rval = pm_receive_pm2(&pm_data)) != 0) { 777 rval = 0xffffcd37; 778 break; 779 } 780 pmdata->command = pm_data; 781 } else { /* PB 1XX series ? */ 782 if ((rval = pm_receive_pm2(&pm_data)) != 0) { 783 rval = 0xffffcd37; 784 break; 785 } 786 pmdata->command = pm_data; 787 } 788 789 /* receive number of PM data */ 790 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 791 if (pm_num_rx_data < 0) { 792 if ((rval = pm_receive_pm2(&pm_data)) != 0) 793 break; /* timeout */ 794 num_pm_data = pm_data; 795 } else 796 num_pm_data = pm_num_rx_data; 797 pmdata->num_data = num_pm_data; 798 } else { /* PB 1XX serias ? */ 799 if ((rval = pm_receive_pm2(&pm_data)) != 0) 800 break; /* timeout */ 801 num_pm_data = pm_data; 802 pmdata->num_data = num_pm_data; 803 } 804 805 /* receive PM data */ 806 pm_buf = (u_char *)pmdata->r_buf; 807 for (i = 0; i < num_pm_data; i++) { 808 if ((rval = pm_receive_pm2(&pm_data)) != 0) 809 break; /* timeout */ 810 pm_buf[i] = pm_data; 811 } 812 813 rval = 0; 814 } 815 816 /* restore former value */ 817 write_via_reg(VIA1, vIER, via1_vIER); 818 splx(s); 819 820 return rval; 821} 822 823 824/* 825 * My PM interrupt routine for the PB Duo series and the PB 5XX series 826 */ 827void 828pm_intr_pm2() 829{ 830 int s; 831 int rval; 832 PMData pmdata; 833 834 s = splhigh(); 835 836 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ 837 /* ask PM what happend */ 838 pmdata.command = 0x78; 839 pmdata.num_data = 0; 840 pmdata.s_buf = &pmdata.data[2]; 841 pmdata.r_buf = &pmdata.data[2]; 842 rval = pm_pmgrop_pm2(&pmdata); 843 if (rval != 0) { 844#ifdef ADB_DEBUG 845 if (adb_debug) 846 printf("pm: PM is not ready. error code: %08x\n", rval); 847#endif 848 splx(s); 849 return; 850 } 851 852 switch ((u_int)(pmdata.data[2] & 0xff)) { 853 case 0x00: /* 1 sec interrupt? */ 854 break; 855 case 0x80: /* 1 sec interrupt? */ 856 pm_counter++; 857 break; 858 case 0x08: /* Brightness/Contrast button on LCD panel */ 859 /* get brightness and contrast of the LCD */ 860 pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff; 861 pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff; 862/* 863 pm_printerr("#08", rval, pmdata.num_data, pmdata.data); 864 pmdata.command = 0x33; 865 pmdata.num_data = 1; 866 pmdata.s_buf = pmdata.data; 867 pmdata.r_buf = pmdata.data; 868 pmdata.data[0] = pm_LCD_contrast; 869 rval = pm_pmgrop_pm2(&pmdata); 870 pm_printerr("#33", rval, pmdata.num_data, pmdata.data); 871*/ 872 /* this is an experimental code */ 873 pmdata.command = 0x41; 874 pmdata.num_data = 1; 875 pmdata.s_buf = pmdata.data; 876 pmdata.r_buf = pmdata.data; 877 pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2; 878 if (pm_LCD_brightness < 0x08) 879 pm_LCD_brightness = 0x08; 880 if (pm_LCD_brightness > 0x78) 881 pm_LCD_brightness = 0x78; 882 pmdata.data[0] = pm_LCD_brightness; 883 rval = pm_pmgrop_pm2(&pmdata); 884 break; 885 case 0x10: /* ADB data that were requested by TALK command */ 886 case 0x14: 887 pm_adb_get_TALK_result(&pmdata); 888 break; 889 case 0x16: /* ADB device event */ 890 case 0x18: 891 case 0x1e: 892 case PMU_INT_WAKEUP: 893 pm_adb_get_ADB_data(&pmdata); 894 break; 895 default: 896#ifdef ADB_DEBUG 897 if (adb_debug) 898 pm_printerr("driver does not supported this event.", 899 pmdata.data[2], pmdata.num_data, 900 pmdata.data); 901#endif 902 break; 903 } 904 905 splx(s); 906} 907 908 909#if 0 910/* 911 * MRG-based PMgrOp routine 912 */ 913int 914pm_pmgrop_mrg(pmdata) 915 PMData *pmdata; 916{ 917 u_int32_t rval=0; 918 919 asm(" 920 movl %1, a0 921 .word 0xa085 922 movl d0, %0" 923 : "=g" (rval) 924 : "g" (pmdata) 925 : "a0", "d0" ); 926 927 return rval; 928} 929#endif 930 931 932/* 933 * My PMgrOp routine 934 */ 935int 936pmgrop(pmdata) 937 PMData *pmdata; 938{ 939 switch (pmHardware) { 940 case PM_HW_PB1XX: 941 return (pm_pmgrop_pm1(pmdata)); 942 break; 943 case PM_HW_PB5XX: 944 return (pm_pmgrop_pm2(pmdata)); 945 break; 946 default: 947 /* return (pmgrop_mrg(pmdata)); */ 948 return 1; 949 } 950} 951 952 953/* 954 * My PM interrupt routine 955 */ 956void 957pm_intr() 958{ 959 switch (pmHardware) { 960 case PM_HW_PB1XX: 961 pm_intr_pm1(); 962 break; 963 case PM_HW_PB5XX: 964 pm_intr_pm2(); 965 break; 966 default: 967 break; 968 } 969} 970 971 972 973/* 974 * Synchronous ADBOp routine for the Power Manager 975 */ 976int 977pm_adb_op(buffer, compRout, data, command) 978 u_char *buffer; 979 void *compRout; 980 void *data; 981 int command; 982{ 983 int i; 984 int s; 985 int rval; 986 int ndelay; 987 PMData pmdata; 988 struct adbCommand packet; 989 990 if (adbWaiting == 1) 991 return 1; 992 993 s = splhigh(); 994 write_via_reg(VIA1, vIER, 0x10); 995 996 adbBuffer = buffer; 997 adbCompRout = compRout; 998 adbCompData = data; 999 1000 pmdata.command = 0x20; 1001 pmdata.s_buf = pmdata.data; 1002 pmdata.r_buf = pmdata.data; 1003 1004 /* if the command is LISTEN, add number of ADB data to number of PM data */ 1005 if ((command & 0xc) == 0x8) { 1006 if (buffer != (u_char *)0) 1007 pmdata.num_data = buffer[0] + 3; 1008 } else { 1009 pmdata.num_data = 3; 1010 } 1011 1012 pmdata.data[0] = (u_char)(command & 0xff); 1013 pmdata.data[1] = 0; 1014 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */ 1015 if ((buffer != (u_char *)0) && (buffer[0] <= 24)) { 1016 pmdata.data[2] = buffer[0]; /* number of data */ 1017 for (i = 0; i < buffer[0]; i++) 1018 pmdata.data[3 + i] = buffer[1 + i]; 1019 } else 1020 pmdata.data[2] = 0; 1021 } else 1022 pmdata.data[2] = 0; 1023 1024 if ((command & 0xc) != 0xc) { /* if the command is not TALK */ 1025 /* set up stuff for adb_pass_up */ 1026 packet.data[0] = 1 + pmdata.data[2]; 1027 packet.data[1] = command; 1028 for (i = 0; i < pmdata.data[2]; i++) 1029 packet.data[i+2] = pmdata.data[i+3]; 1030 packet.saveBuf = adbBuffer; 1031 packet.compRout = adbCompRout; 1032 packet.compData = adbCompData; 1033 packet.cmd = command; 1034 packet.unsol = 0; 1035 packet.ack_only = 1; 1036 adb_polling = 1; 1037 adb_pass_up(&packet); 1038 adb_polling = 0; 1039 } 1040 1041 rval = pmgrop(&pmdata); 1042 if (rval != 0) { 1043 splx(s); 1044 return 1; 1045 } 1046 1047 delay(10000); 1048 1049 adbWaiting = 1; 1050 adbWaitingCmd = command; 1051 1052 PM_VIA_INTR_ENABLE(); 1053 1054 /* wait until the PM interrupt is occurred */ 1055 ndelay = 0x80000; 1056 while (adbWaiting == 1) { 1057 if (read_via_reg(VIA1, vIFR) & 0x14) 1058 pm_intr(); 1059#ifdef PM_GRAB_SI 1060#if 0 1061 zshard(0); /* grab any serial interrupts */ 1062#else 1063 (void)intr_dispatch(0x70); 1064#endif 1065#endif 1066 if ((--ndelay) < 0) { 1067 splx(s); 1068 return 1; 1069 } 1070 } 1071 1072 /* this command enables the interrupt by operating ADB devices */ 1073 if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX series */ 1074 pmdata.command = 0x20; 1075 pmdata.num_data = 4; 1076 pmdata.s_buf = pmdata.data; 1077 pmdata.r_buf = pmdata.data; 1078 pmdata.data[0] = 0x00; 1079 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */ 1080 pmdata.data[2] = 0x00; 1081 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */ 1082 } else { /* PB 1XX series */ 1083 pmdata.command = 0x20; 1084 pmdata.num_data = 3; 1085 pmdata.s_buf = pmdata.data; 1086 pmdata.r_buf = pmdata.data; 1087 pmdata.data[0] = (u_char)(command & 0xf0) | 0xc; 1088 pmdata.data[1] = 0x04; 1089 pmdata.data[2] = 0x00; 1090 } 1091 rval = pmgrop(&pmdata); 1092 1093 splx(s); 1094 return rval; 1095} 1096 1097 1098void 1099pm_adb_get_TALK_result(pmdata) 1100 PMData *pmdata; 1101{ 1102 int i; 1103 struct adbCommand packet; 1104 1105 /* set up data for adb_pass_up */ 1106 packet.data[0] = pmdata->num_data-1; 1107 packet.data[1] = pmdata->data[3]; 1108 for (i = 0; i <packet.data[0]-1; i++) 1109 packet.data[i+2] = pmdata->data[i+4]; 1110 1111 packet.saveBuf = adbBuffer; 1112 packet.compRout = adbCompRout; 1113 packet.compData = adbCompData; 1114 packet.unsol = 0; 1115 packet.ack_only = 0; 1116 adb_polling = 1; 1117 adb_pass_up(&packet); 1118 adb_polling = 0; 1119 1120 adbWaiting = 0; 1121 adbBuffer = (long)0; 1122 adbCompRout = (long)0; 1123 adbCompData = (long)0; 1124} 1125 1126 1127void 1128pm_adb_get_ADB_data(pmdata) 1129 PMData *pmdata; 1130{ 1131 int i; 1132 struct adbCommand packet; 1133 1134 /* set up data for adb_pass_up */ 1135 packet.data[0] = pmdata->num_data-1; /* number of raw data */ 1136 packet.data[1] = pmdata->data[3]; /* ADB command */ 1137 for (i = 0; i <packet.data[0]-1; i++) 1138 packet.data[i+2] = pmdata->data[i+4]; 1139 packet.unsol = 1; 1140 packet.ack_only = 0; 1141 adb_pass_up(&packet); 1142} 1143 1144 1145void 1146pm_adb_poll_next_device_pm1(pmdata) 1147 PMData *pmdata; 1148{ 1149 int i; 1150 int ndid; 1151 u_short bendid = 0x1; 1152 int rval; 1153 PMData tmp_pmdata; 1154 1155 /* find another existent ADB device to poll */ 1156 for (i = 1; i < 16; i++) { 1157 ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf; 1158 bendid <<= ndid; 1159 if ((pm_existent_ADB_devices & bendid) != 0) 1160 break; 1161 } 1162 1163 /* poll the other device */ 1164 tmp_pmdata.command = 0x20; 1165 tmp_pmdata.num_data = 3; 1166 tmp_pmdata.s_buf = tmp_pmdata.data; 1167 tmp_pmdata.r_buf = tmp_pmdata.data; 1168 tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc; 1169 tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */ 1170 tmp_pmdata.data[2] = 0x00; 1171 rval = pmgrop(&tmp_pmdata); 1172} 1173 1174void 1175pm_adb_restart() 1176{ 1177 PMData p; 1178 1179 p.command = PMU_RESET_CPU; 1180 p.num_data = 0; 1181 p.s_buf = p.data; 1182 p.r_buf = p.data; 1183 pmgrop(&p); 1184} 1185 1186void 1187pm_adb_poweroff() 1188{ 1189 PMData p; 1190 1191 p.command = PMU_POWER_OFF; 1192 p.num_data = 4; 1193 p.s_buf = p.data; 1194 p.r_buf = p.data; 1195 strcpy(p.data, "MATT"); 1196 pmgrop(&p); 1197} 1198 1199void 1200pm_read_date_time(time) 1201 u_long *time; 1202{ 1203 PMData p; 1204 1205 p.command = PMU_READ_RTC; 1206 p.num_data = 0; 1207 p.s_buf = p.data; 1208 p.r_buf = p.data; 1209 pmgrop(&p); 1210 1211 bcopy(p.data, time, 4); 1212} 1213 1214void 1215pm_set_date_time(time) 1216 u_long time; 1217{ 1218 PMData p; 1219 1220 p.command = PMU_SET_RTC; 1221 p.num_data = 4; 1222 p.s_buf = p.r_buf = p.data; 1223 bcopy(&time, p.data, 4); 1224 pmgrop(&p); 1225} 1226 1227int 1228pm_read_brightness() 1229{ 1230 PMData p; 1231 1232 p.command = PMU_READ_BRIGHTNESS; 1233 p.num_data = 1; /* XXX why 1? */ 1234 p.s_buf = p.r_buf = p.data; 1235 p.data[0] = 0; 1236 pmgrop(&p); 1237 1238 return p.data[0]; 1239} 1240 1241void 1242pm_set_brightness(val) 1243 int val; 1244{ 1245 PMData p; 1246 1247 val = 0x7f - val / 2; 1248 if (val < 0x08) 1249 val = 0x08; 1250 if (val > 0x78) 1251 val = 0x78; 1252 1253 p.command = PMU_SET_BRIGHTNESS; 1254 p.num_data = 1; 1255 p.s_buf = p.r_buf = p.data; 1256 p.data[0] = val; 1257 pmgrop(&p); 1258} 1259 1260void 1261pm_init_brightness() 1262{ 1263 int val; 1264 1265 val = pm_read_brightness(); 1266 pm_set_brightness(val); 1267} 1268 1269void 1270pm_eject_pcmcia(slot) 1271 int slot; 1272{ 1273 PMData p; 1274 1275 if (slot != 0 && slot != 1) 1276 return; 1277 1278 p.command = PMU_EJECT_PCMCIA; 1279 p.num_data = 1; 1280 p.s_buf = p.r_buf = p.data; 1281 p.data[0] = 5 + slot; /* XXX */ 1282 pmgrop(&p); 1283} 1284 1285int 1286pm_read_nvram(addr) 1287 int addr; 1288{ 1289 PMData p; 1290 1291 p.command = PMU_READ_NVRAM; 1292 p.num_data = 2; 1293 p.s_buf = p.r_buf = p.data; 1294 p.data[0] = addr >> 8; 1295 p.data[1] = addr; 1296 pmgrop(&p); 1297 1298 return p.data[0]; 1299} 1300 1301void 1302pm_write_nvram(addr, val) 1303 int addr, val; 1304{ 1305 PMData p; 1306 1307 p.command = PMU_WRITE_NVRAM; 1308 p.num_data = 3; 1309 p.s_buf = p.r_buf = p.data; 1310 p.data[0] = addr >> 8; 1311 p.data[1] = addr; 1312 p.data[2] = val; 1313 pmgrop(&p); 1314} 1315