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