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