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