1 /* $OpenBSD: pm_direct.c,v 1.22 2007/02/18 19:33:48 gwk 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 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/cpu.h> 48 49 #include <dev/adb/adb.h> 50 #include <macppc/dev/adbvar.h> 51 #include <macppc/dev/pm_direct.h> 52 #include <macppc/dev/viareg.h> 53 54 /* hardware dependent values */ 55 #define ADBDelay 100 /* XXX */ 56 57 /* define the types of the Power Manager */ 58 #define PM_HW_UNKNOWN 0x00 /* don't know */ 59 #define PM_HW_PB5XX 0x02 /* PowerBook Duo and 5XX series */ 60 61 /* useful macros */ 62 #define PM_SR() read_via_reg(VIA1, vSR) 63 #define PM_VIA_INTR_ENABLE() write_via_reg(VIA1, vIER, 0x90) 64 #define PM_VIA_INTR_DISABLE() write_via_reg(VIA1, vIER, 0x10) 65 #define PM_VIA_CLR_INTR() write_via_reg(VIA1, vIFR, 0x90) 66 #if 0 67 #define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x04) 68 #define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x04) 69 #define PM_IS_ON (0x02 == (read_via_reg(VIA2, vBufB) & 0x02)) 70 #define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x02)) 71 #else 72 #define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x10) 73 #define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x10) 74 #define PM_IS_ON (0x08 == (read_via_reg(VIA2, vBufB) & 0x08)) 75 #define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x08)) 76 #endif 77 78 /* 79 * Variables for internal use 80 */ 81 int pmHardware = PM_HW_UNKNOWN; 82 83 /* these values shows that number of data returned after 'send' cmd is sent */ 84 signed char pm_send_cmd_type[] = { 85 -1, -1, -1, -1, -1, -1, -1, -1, 86 -1, -1, -1, -1, -1, -1, -1, -1, 87 0x01, 0x01, -1, -1, -1, -1, -1, -1, 88 0x00, 0x00, -1, -1, -1, -1, -1, 0x00, 89 -1, 0x00, 0x02, 0x01, 0x01, -1, -1, -1, 90 0x00, -1, -1, -1, -1, -1, -1, -1, 91 0x04, 0x14, -1, 0x03, -1, -1, -1, -1, 92 0x00, 0x00, 0x02, 0x02, -1, -1, -1, -1, 93 0x01, 0x01, -1, -1, -1, -1, -1, -1, 94 0x00, 0x00, -1, -1, 0x01, -1, -1, -1, 95 0x01, 0x00, 0x02, 0x02, -1, 0x01, 0x03, 0x01, 96 0x00, 0x01, 0x00, 0x00, 0x00, -1, -1, -1, 97 0x02, -1, -1, -1, -1, -1, -1, -1, 98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, -1, 99 0x01, 0x01, 0x01, -1, -1, -1, -1, -1, 100 0x00, 0x00, -1, -1, -1, -1, 0x04, 0x04, 101 0x04, -1, 0x00, -1, -1, -1, -1, -1, 102 0x00, -1, -1, -1, -1, -1, -1, -1, 103 0x01, 0x02, -1, -1, -1, -1, -1, -1, 104 0x00, 0x00, -1, -1, -1, -1, -1, -1, 105 0x02, 0x02, 0x02, 0x04, -1, 0x00, -1, -1, 106 0x01, 0x01, 0x03, 0x02, -1, -1, -1, -1, 107 -1, -1, -1, -1, -1, -1, -1, -1, 108 -1, -1, -1, -1, -1, -1, -1, -1, 109 -1, -1, -1, -1, -1, -1, -1, -1, 110 -1, -1, -1, -1, -1, -1, -1, -1, 111 0x00, -1, -1, -1, -1, -1, -1, -1, 112 0x01, 0x01, -1, -1, 0x00, 0x00, -1, -1, 113 -1, 0x04, 0x00, -1, -1, -1, -1, -1, 114 0x03, -1, 0x00, -1, 0x00, -1, -1, 0x00, 115 -1, -1, -1, -1, -1, -1, -1, -1, 116 -1, -1, -1, -1, -1, -1, -1, -1 117 }; 118 119 /* these values shows that number of data returned after 'receive' cmd is sent */ 120 signed char pm_receive_cmd_type[] = { 121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 122 -1, -1, -1, -1, -1, -1, -1, -1, 123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 124 0x02, 0x02, -1, -1, -1, -1, -1, 0x00, 125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 126 -1, -1, -1, -1, -1, -1, -1, -1, 127 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 128 0x05, 0x15, -1, 0x02, -1, -1, -1, -1, 129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 130 0x02, 0x02, -1, -1, -1, -1, -1, -1, 131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 132 0x02, 0x00, 0x03, 0x03, -1, -1, -1, -1, 133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 134 0x04, 0x04, 0x03, 0x09, -1, -1, -1, -1, 135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 136 -1, -1, -1, -1, -1, -1, 0x01, 0x01, 137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 138 0x06, -1, -1, -1, -1, -1, -1, -1, 139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 140 0x02, 0x02, -1, -1, -1, -1, -1, -1, 141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 142 0x02, 0x00, 0x00, 0x00, -1, -1, -1, -1, 143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 144 -1, -1, -1, -1, -1, -1, -1, -1, 145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 146 -1, -1, -1, -1, -1, -1, -1, -1, 147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 148 0x02, 0x02, -1, -1, 0x02, -1, -1, -1, 149 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 150 -1, -1, 0x02, -1, -1, -1, -1, 0x00, 151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 152 -1, -1, -1, -1, -1, -1, -1, -1, 153 }; 154 155 156 /* 157 * Define the private functions 158 */ 159 160 /* for debugging */ 161 #ifdef ADB_DEBUG 162 void pm_printerr(char *, int, int, char *); 163 #endif 164 165 int pm_wait_busy(int); 166 int pm_wait_free(int); 167 168 /* these functions are for the PB Duo series and the PB 5XX series */ 169 int pm_receive_pm2(u_char *); 170 int pm_send_pm2(u_char); 171 int pm_pmgrop_pm2(PMData *); 172 void pm_intr_pm2(void); 173 174 /* these functions also use the variables of adb_direct.c */ 175 void pm_adb_get_TALK_result(PMData *); 176 void pm_adb_get_ADB_data(PMData *); 177 178 179 /* 180 * These variables are in adb_direct.c. 181 */ 182 extern u_char *adbBuffer; /* pointer to user data area */ 183 extern void *adbCompRout; /* pointer to the completion routine */ 184 extern void *adbCompData; /* pointer to the completion routine data */ 185 extern int adbWaiting; /* waiting for return data from the device */ 186 extern int adbWaitingCmd; /* ADB command we are waiting for */ 187 extern int adbStarting; /* doing ADB reinit, so do "polling" differently */ 188 189 #define ADB_MAX_MSG_LENGTH 16 190 #define ADB_MAX_HDR_LENGTH 8 191 struct adbCommand { 192 u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */ 193 u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */ 194 u_char *saveBuf; /* where to save result */ 195 u_char *compRout; /* completion routine pointer */ 196 u_char *compData; /* completion routine data pointer */ 197 u_int cmd; /* the original command for this data */ 198 u_int unsol; /* 1 if packet was unsolicited */ 199 u_int ack_only; /* 1 for no special processing */ 200 }; 201 extern void adb_pass_up(struct adbCommand *); 202 203 204 #ifdef ADB_DEBUG 205 /* 206 * This function dumps contents of the PMData 207 */ 208 void 209 pm_printerr(ttl, rval, num, data) 210 char *ttl; 211 int rval; 212 int num; 213 char *data; 214 { 215 int i; 216 217 printf("pm: %s:%04x %02x ", ttl, rval, num); 218 for (i = 0; i < num; i++) 219 printf("%02x ", data[i]); 220 printf("\n"); 221 } 222 #endif 223 224 225 226 /* 227 * Check the hardware type of the Power Manager 228 */ 229 void 230 pm_setup_adb() 231 { 232 pmHardware = PM_HW_PB5XX; /* XXX */ 233 } 234 235 236 /* 237 * Wait until PM IC is busy 238 */ 239 int 240 pm_wait_busy(int delay) 241 { 242 while (PM_IS_ON) { 243 #ifdef PM_GRAB_SI 244 (void)intr_dispatch(0x70); 245 #endif 246 if ((--delay) < 0) 247 return 1; /* timeout */ 248 } 249 return 0; 250 } 251 252 253 /* 254 * Wait until PM IC is free 255 */ 256 int 257 pm_wait_free(int delay) 258 { 259 while (PM_IS_OFF) { 260 #ifdef PM_GRAB_SI 261 (void)intr_dispatch(0x70); 262 #endif 263 if ((--delay) < 0) 264 return 0; /* timeout */ 265 } 266 return 1; 267 } 268 269 /* 270 * Functions for the PB Duo series and the PB 5XX series 271 */ 272 273 /* 274 * Receive data from PM for the PB Duo series and the PB 5XX series 275 */ 276 int 277 pm_receive_pm2(u_char *data) 278 { 279 int i; 280 int rval; 281 282 rval = 0xffffcd34; 283 284 switch (1) { 285 default: 286 /* set VIA SR to input mode */ 287 via_reg_or(VIA1, vACR, 0x0c); 288 via_reg_and(VIA1, vACR, ~0x10); 289 i = PM_SR(); 290 291 PM_SET_STATE_ACKOFF(); 292 if (pm_wait_busy((int)ADBDelay*32) != 0) 293 break; /* timeout */ 294 295 PM_SET_STATE_ACKON(); 296 rval = 0xffffcd33; 297 if (pm_wait_free((int)ADBDelay*32) == 0) 298 break; /* timeout */ 299 300 *data = PM_SR(); 301 rval = 0; 302 303 break; 304 } 305 306 PM_SET_STATE_ACKON(); 307 via_reg_or(VIA1, vACR, 0x1c); 308 309 return rval; 310 } 311 312 /* 313 * Send data to PM for the PB Duo series and the PB 5XX series 314 */ 315 int 316 pm_send_pm2(data) 317 u_char data; 318 { 319 int rval; 320 321 via_reg_or(VIA1, vACR, 0x1c); 322 write_via_reg(VIA1, vSR, data); /* PM_SR() = data; */ 323 324 PM_SET_STATE_ACKOFF(); 325 rval = 0xffffcd36; 326 if (pm_wait_busy((int)ADBDelay*32) != 0) { 327 PM_SET_STATE_ACKON(); 328 via_reg_or(VIA1, vACR, 0x1c); 329 return rval; 330 } 331 332 PM_SET_STATE_ACKON(); 333 rval = 0xffffcd35; 334 if (pm_wait_free((int)ADBDelay*32) != 0) 335 rval = 0; 336 337 PM_SET_STATE_ACKON(); 338 via_reg_or(VIA1, vACR, 0x1c); 339 340 return rval; 341 } 342 343 344 345 /* 346 * My PMgrOp routine for the PB Duo series and the PB 5XX series 347 */ 348 int 349 pm_pmgrop_pm2(PMData *pmdata) 350 { 351 int i; 352 int s; 353 u_char via1_vIER; 354 int rval = 0; 355 int num_pm_data = 0; 356 u_char pm_cmd; 357 short pm_num_rx_data; 358 u_char pm_data; 359 u_char *pm_buf; 360 361 s = splhigh(); 362 363 /* disable all interrupts but PM */ 364 via1_vIER = 0x10; 365 via1_vIER &= read_via_reg(VIA1, vIER); 366 write_via_reg(VIA1, vIER, via1_vIER); 367 if (via1_vIER != 0x0) 368 via1_vIER |= 0x80; 369 370 switch (pmdata->command) { 371 default: 372 /* wait until PM is free */ 373 pm_cmd = (u_char)(pmdata->command & 0xff); 374 rval = 0xcd38; 375 if (pm_wait_free(ADBDelay * 4) == 0) 376 break; /* timeout */ 377 378 /* send PM command */ 379 if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff)))) 380 break; /* timeout */ 381 382 /* send number of PM data */ 383 num_pm_data = pmdata->num_data; 384 if (pm_send_cmd_type[pm_cmd] < 0) { 385 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0) 386 break; /* timeout */ 387 pmdata->command = 0; 388 } 389 /* send PM data */ 390 pm_buf = (u_char *)pmdata->s_buf; 391 for (i = 0 ; i < num_pm_data; i++) 392 if ((rval = pm_send_pm2(pm_buf[i])) != 0) 393 break; /* timeout */ 394 if (i != num_pm_data) 395 break; /* timeout */ 396 397 398 /* check if PM will send me data */ 399 pm_num_rx_data = pm_receive_cmd_type[pm_cmd]; 400 pmdata->num_data = pm_num_rx_data; 401 if (pm_num_rx_data == 0) { 402 rval = 0; 403 break; /* no return data */ 404 } 405 406 /* receive PM command */ 407 pm_data = pmdata->command; 408 pm_num_rx_data--; 409 if (pm_num_rx_data == 0) 410 if ((rval = pm_receive_pm2(&pm_data)) != 0) { 411 rval = 0xffffcd37; 412 break; 413 } 414 pmdata->command = pm_data; 415 416 /* receive number of PM data */ 417 if (pm_num_rx_data < 0) { 418 if ((rval = pm_receive_pm2(&pm_data)) != 0) 419 break; /* timeout */ 420 num_pm_data = pm_data; 421 } else 422 num_pm_data = pm_num_rx_data; 423 pmdata->num_data = num_pm_data; 424 425 /* receive PM data */ 426 pm_buf = (u_char *)pmdata->r_buf; 427 for (i = 0; i < num_pm_data; i++) { 428 if ((rval = pm_receive_pm2(&pm_data)) != 0) 429 break; /* timeout */ 430 pm_buf[i] = pm_data; 431 } 432 433 rval = 0; 434 } 435 436 /* restore former value */ 437 write_via_reg(VIA1, vIER, via1_vIER); 438 splx(s); 439 440 return rval; 441 } 442 443 444 /* 445 * My PM interrupt routine for the PB Duo series and the PB 5XX series 446 */ 447 void 448 pm_intr_pm2() 449 { 450 int s; 451 int rval; 452 PMData pmdata; 453 454 s = splhigh(); 455 456 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ 457 /* ask PM what happend */ 458 pmdata.command = 0x78; 459 pmdata.num_data = 0; 460 pmdata.s_buf = &pmdata.data[2]; 461 pmdata.r_buf = &pmdata.data[2]; 462 rval = pm_pmgrop_pm2(&pmdata); 463 if (rval != 0) { 464 #ifdef ADB_DEBUG 465 if (adb_debug) 466 printf("pm: PM is not ready. error code: %08x\n", rval); 467 #endif 468 splx(s); 469 return; 470 } 471 472 switch ((u_int)(pmdata.data[2] & 0xff)) { 473 case 0x00: /* 1 sec interrupt? */ 474 break; 475 case PMU_INT_TICK: /* 1 sec interrupt? */ 476 break; 477 case PMU_INT_SNDBRT: /* Brightness/Contrast button on LCD panel */ 478 break; 479 case PMU_INT_ADB: /* ADB data requested by TALK command */ 480 case PMU_INT_ADB|PMU_INT_ADB_AUTO: 481 pm_adb_get_TALK_result(&pmdata); 482 break; 483 case 0x16: /* ADB device event */ 484 case 0x18: 485 case 0x1e: 486 case PMU_INT_WAKEUP: 487 pm_adb_get_ADB_data(&pmdata); 488 break; 489 default: 490 #ifdef ADB_DEBUG 491 if (adb_debug) 492 pm_printerr("driver does not support this event.", 493 pmdata.data[2], pmdata.num_data, 494 pmdata.data); 495 #endif 496 break; 497 } 498 499 splx(s); 500 } 501 502 503 /* 504 * My PMgrOp routine 505 */ 506 int 507 pmgrop(PMData *pmdata) 508 { 509 switch (pmHardware) { 510 case PM_HW_PB5XX: 511 return (pm_pmgrop_pm2(pmdata)); 512 default: 513 /* return (pmgrop_mrg(pmdata)); */ 514 return 1; 515 } 516 } 517 518 519 /* 520 * My PM interrupt routine 521 */ 522 void 523 pm_intr() 524 { 525 switch (pmHardware) { 526 case PM_HW_PB5XX: 527 pm_intr_pm2(); 528 break; 529 default: 530 break; 531 } 532 } 533 534 535 536 /* 537 * Synchronous ADBOp routine for the Power Manager 538 */ 539 int 540 pm_adb_op(u_char *buffer, void *compRout, void *data, int command) 541 { 542 int i; 543 int s; 544 int rval; 545 int ndelay; 546 int waitfor; /* interrupts to poll for */ 547 int ifr; 548 #ifdef ADB_DEBUG 549 int oldifr; 550 #endif 551 PMData pmdata; 552 struct adbCommand packet; 553 extern int adbempty; 554 555 if (adbWaiting == 1) 556 return 1; 557 558 s = splhigh(); 559 write_via_reg(VIA1, vIER, 0x10); 560 561 adbBuffer = buffer; 562 adbCompRout = compRout; 563 adbCompData = data; 564 565 pmdata.command = 0x20; 566 pmdata.s_buf = pmdata.data; 567 pmdata.r_buf = pmdata.data; 568 569 /* 570 * if the command is LISTEN, 571 * add number of ADB data to number of PM data 572 */ 573 if ((command & 0xc) == 0x8) { 574 if (buffer != (u_char *)0) 575 pmdata.num_data = buffer[0] + 3; 576 } else 577 pmdata.num_data = 3; 578 579 /* 580 * Resetting adb on several models, such as 581 * - PowerBook3,* 582 * - PowerBook5,* 583 * - PowerMac10,1 584 * causes several pmu interrupts with ifr set to PMU_INT_SNDBRT. 585 * Not processing them prevents us from seeing the adb devices 586 * afterwards, so we have to expect it unless we know the adb 587 * bus is empty. 588 */ 589 if (command == PMU_RESET_ADB) { 590 waitfor = PMU_INT_ADB_AUTO | PMU_INT_ADB; 591 if (adbempty == 0) 592 waitfor |= PMU_INT_SNDBRT; 593 } else 594 waitfor = PMU_INT_ALL; 595 596 pmdata.data[0] = (u_char)(command & 0xff); 597 pmdata.data[1] = 0; 598 /* if the command is LISTEN, copy ADB data to PM buffer */ 599 if ((command & 0xc) == 0x8) { 600 if ((buffer != (u_char *)0) && (buffer[0] <= 24)) { 601 pmdata.data[2] = buffer[0]; /* number of data */ 602 for (i = 0; i < buffer[0]; i++) 603 pmdata.data[3 + i] = buffer[1 + i]; 604 } else 605 pmdata.data[2] = 0; 606 } else 607 pmdata.data[2] = 0; 608 609 if ((command & 0xc) != 0xc) { /* if the command is not TALK */ 610 /* set up stuff for adb_pass_up */ 611 packet.data[0] = 1 + pmdata.data[2]; 612 packet.data[1] = command; 613 for (i = 0; i < pmdata.data[2]; i++) 614 packet.data[i+2] = pmdata.data[i+3]; 615 packet.saveBuf = adbBuffer; 616 packet.compRout = adbCompRout; 617 packet.compData = adbCompData; 618 packet.cmd = command; 619 packet.unsol = 0; 620 packet.ack_only = 1; 621 adb_polling = 1; 622 adb_pass_up(&packet); 623 adb_polling = 0; 624 } 625 626 rval = pmgrop(&pmdata); 627 if (rval != 0) { 628 splx(s); 629 return 1; 630 } 631 632 delay (1000); 633 634 adbWaiting = 1; 635 adbWaitingCmd = command; 636 637 PM_VIA_INTR_ENABLE(); 638 639 /* wait until the PM interrupt is occurred */ 640 ndelay = 0x8000; 641 #ifdef ADB_DEBUG 642 oldifr = 0; 643 #endif 644 while (adbWaiting == 1) { 645 ifr = read_via_reg(VIA1, vIFR); 646 if (ifr & waitfor) { 647 pm_intr(); 648 #ifdef PM_GRAB_SI 649 (void)intr_dispatch(0x70); 650 #endif 651 #ifdef ADB_DEBUG 652 } else if (ifr != oldifr) { 653 if (adb_debug) 654 printf("pm_adb_op: ignoring ifr %02x" 655 ", expecting %02x\n", 656 (u_int)ifr, (u_int)waitfor); 657 oldifr = ifr; 658 #endif 659 } 660 if ((--ndelay) < 0) { 661 splx(s); 662 return 1; 663 } 664 delay(10); 665 } 666 667 /* this command enables the interrupt by operating ADB devices */ 668 pmdata.command = 0x20; 669 pmdata.num_data = 4; 670 pmdata.s_buf = pmdata.data; 671 pmdata.r_buf = pmdata.data; 672 pmdata.data[0] = 0x00; 673 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */ 674 pmdata.data[2] = 0x00; 675 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */ 676 rval = pmgrop(&pmdata); 677 678 splx(s); 679 return rval; 680 } 681 682 683 void 684 pm_adb_get_TALK_result(PMData *pmdata) 685 { 686 int i; 687 struct adbCommand packet; 688 689 /* set up data for adb_pass_up */ 690 packet.data[0] = pmdata->num_data-1; 691 packet.data[1] = pmdata->data[3]; 692 for (i = 0; i <packet.data[0]-1; i++) 693 packet.data[i+2] = pmdata->data[i+4]; 694 695 packet.saveBuf = adbBuffer; 696 packet.compRout = adbCompRout; 697 packet.compData = adbCompData; 698 packet.unsol = 0; 699 packet.ack_only = 0; 700 adb_polling = 1; 701 adb_pass_up(&packet); 702 adb_polling = 0; 703 704 adbWaiting = 0; 705 adbBuffer = (long)0; 706 adbCompRout = (long)0; 707 adbCompData = (long)0; 708 } 709 710 711 void 712 pm_adb_get_ADB_data(PMData *pmdata) 713 { 714 int i; 715 struct adbCommand packet; 716 717 /* set up data for adb_pass_up */ 718 packet.data[0] = pmdata->num_data-1; /* number of raw data */ 719 packet.data[1] = pmdata->data[3]; /* ADB command */ 720 for (i = 0; i <packet.data[0]-1; i++) 721 packet.data[i+2] = pmdata->data[i+4]; 722 packet.unsol = 1; 723 packet.ack_only = 0; 724 adb_pass_up(&packet); 725 } 726 727 void 728 pm_adb_restart() 729 { 730 PMData p; 731 732 p.command = PMU_RESET_CPU; 733 p.num_data = 0; 734 p.s_buf = p.data; 735 p.r_buf = p.data; 736 pmgrop(&p); 737 } 738 739 void 740 pm_adb_poweroff() 741 { 742 PMData p; 743 744 bzero(&p, sizeof p); 745 p.command = PMU_POWER_OFF; 746 p.num_data = 4; 747 p.s_buf = p.data; 748 p.r_buf = p.data; 749 strlcpy(p.data, "MATT", sizeof p.data); 750 pmgrop(&p); 751 } 752 753 void 754 pm_read_date_time(time_t *time) 755 { 756 PMData p; 757 758 p.command = PMU_READ_RTC; 759 p.num_data = 0; 760 p.s_buf = p.data; 761 p.r_buf = p.data; 762 pmgrop(&p); 763 764 bcopy(p.data, time, 4); 765 } 766 767 void 768 pm_set_date_time(time_t time) 769 { 770 PMData p; 771 772 p.command = PMU_SET_RTC; 773 p.num_data = 4; 774 p.s_buf = p.r_buf = p.data; 775 bcopy(&time, p.data, 4); 776 pmgrop(&p); 777 } 778 779 #if 0 780 void 781 pm_eject_pcmcia(int slot) 782 { 783 PMData p; 784 785 if (slot != 0 && slot != 1) 786 return; 787 788 p.command = PMU_EJECT_PCMCIA; 789 p.num_data = 1; 790 p.s_buf = p.r_buf = p.data; 791 p.data[0] = 5 + slot; /* XXX */ 792 pmgrop(&p); 793 } 794 #endif 795 796 797 /* 798 * Thanks to Paul Mackerras and Fabio Riccardi's Linux implementation 799 * for a clear description of the PMU results. 800 */ 801 802 int 803 pm_battery_info(int battery, struct pmu_battery_info *info) 804 { 805 PMData p; 806 807 p.command = PMU_SMART_BATTERY_STATE; 808 p.num_data = 1; 809 p.s_buf = p.r_buf = p.data; 810 p.data[0] = battery + 1; 811 pmgrop(&p); 812 813 info->flags = p.data[1]; 814 815 switch (p.data[0]) { 816 case 3: 817 case 4: 818 info->cur_charge = p.data[2]; 819 info->max_charge = p.data[3]; 820 info->draw = *((signed char *)&p.data[4]); 821 info->voltage = p.data[5]; 822 break; 823 case 5: 824 info->cur_charge = ((p.data[2] << 8) | (p.data[3])); 825 info->max_charge = ((p.data[4] << 8) | (p.data[5])); 826 info->draw = *((signed short *)&p.data[6]); 827 info->voltage = ((p.data[8] << 8) | (p.data[7])); 828 break; 829 default: 830 /* XXX - Error condition */ 831 info->cur_charge = 0; 832 info->max_charge = 0; 833 info->draw = 0; 834 info->voltage = 0; 835 break; 836 } 837 838 return 1; 839 } 840 841 void 842 pmu_fileserver_mode(int on) 843 { 844 PMData p; 845 846 p.command = PMU_POWER_EVENTS; 847 p.num_data = 1; 848 p.s_buf = p.r_buf = p.data; 849 p.data[0] = PMU_PWR_GET_POWERUP_EVENTS; 850 pmgrop(&p); 851 852 p.command = PMU_POWER_EVENTS; 853 p.num_data = 3; 854 p.s_buf = p.r_buf = p.data; 855 p.data[1] = p.data[0]; /* result from the get */ 856 if (on) { 857 p.data[0] = PMU_PWR_SET_POWERUP_EVENTS; 858 p.data[2] = PMU_WAKE_AC_LOSS; 859 } else { 860 p.data[0] = PMU_PWR_CLR_POWERUP_EVENTS; 861 p.data[2] = PMU_WAKE_AC_LOSS; 862 } 863 pmgrop(&p); 864 } 865