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