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