pm_direct.c revision 1.13
1/* $OpenBSD: pm_direct.c,v 1.13 2003/10/16 03:54:48 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/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 * Send data to PM for the PB Duo series and the PB 5XX series 333 */ 334int 335pm_send_pm2(data) 336 u_char data; 337{ 338 int rval; 339 340 via_reg_or(VIA1, vACR, 0x1c); 341 write_via_reg(VIA1, vSR, data); /* PM_SR() = data; */ 342 343 PM_SET_STATE_ACKOFF(); 344 rval = 0xffffcd36; 345 if (pm_wait_busy((int)ADBDelay*32) != 0) { 346 PM_SET_STATE_ACKON(); 347 via_reg_or(VIA1, vACR, 0x1c); 348 return rval; 349 } 350 351 PM_SET_STATE_ACKON(); 352 rval = 0xffffcd35; 353 if (pm_wait_free((int)ADBDelay*32) != 0) 354 rval = 0; 355 356 PM_SET_STATE_ACKON(); 357 via_reg_or(VIA1, vACR, 0x1c); 358 359 return rval; 360} 361 362 363 364/* 365 * My PMgrOp routine for the PB Duo series and the PB 5XX series 366 */ 367int 368pm_pmgrop_pm2(PMData *pmdata) 369{ 370 int i; 371 int s; 372 u_char via1_vIER; 373 int rval = 0; 374 int num_pm_data = 0; 375 u_char pm_cmd; 376 short pm_num_rx_data; 377 u_char pm_data; 378 u_char *pm_buf; 379 380 s = splhigh(); 381 382 /* disable all inetrrupts but PM */ 383 via1_vIER = 0x10; 384 via1_vIER &= read_via_reg(VIA1, vIER); 385 write_via_reg(VIA1, vIER, via1_vIER); 386 if (via1_vIER != 0x0) 387 via1_vIER |= 0x80; 388 389 switch (pmdata->command) { 390 default: 391 /* wait until PM is free */ 392 pm_cmd = (u_char)(pmdata->command & 0xff); 393 rval = 0xcd38; 394 if (pm_wait_free(ADBDelay * 4) == 0) 395 break; /* timeout */ 396 397 /* send PM command */ 398 if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff)))) 399 break; /* timeout */ 400 401 /* send number of PM data */ 402 num_pm_data = pmdata->num_data; 403 if (pm_send_cmd_type[pm_cmd] < 0) { 404 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0) 405 break; /* timeout */ 406 pmdata->command = 0; 407 } 408 /* send PM data */ 409 pm_buf = (u_char *)pmdata->s_buf; 410 for (i = 0 ; i < num_pm_data; i++) 411 if ((rval = pm_send_pm2(pm_buf[i])) != 0) 412 break; /* timeout */ 413 if (i != num_pm_data) 414 break; /* timeout */ 415 416 417 /* check if PM will send me data */ 418 pm_num_rx_data = pm_receive_cmd_type[pm_cmd]; 419 pmdata->num_data = pm_num_rx_data; 420 if (pm_num_rx_data == 0) { 421 rval = 0; 422 break; /* no return data */ 423 } 424 425 /* receive PM command */ 426 pm_data = pmdata->command; 427 pm_num_rx_data--; 428 if (pm_num_rx_data == 0) 429 if ((rval = pm_receive_pm2(&pm_data)) != 0) { 430 rval = 0xffffcd37; 431 break; 432 } 433 pmdata->command = pm_data; 434 435 /* receive number of PM data */ 436 if (pm_num_rx_data < 0) { 437 if ((rval = pm_receive_pm2(&pm_data)) != 0) 438 break; /* timeout */ 439 num_pm_data = pm_data; 440 } else 441 num_pm_data = pm_num_rx_data; 442 pmdata->num_data = num_pm_data; 443 444 /* receive PM data */ 445 pm_buf = (u_char *)pmdata->r_buf; 446 for (i = 0; i < num_pm_data; i++) { 447 if ((rval = pm_receive_pm2(&pm_data)) != 0) 448 break; /* timeout */ 449 pm_buf[i] = pm_data; 450 } 451 452 rval = 0; 453 } 454 455 /* restore former value */ 456 write_via_reg(VIA1, vIER, via1_vIER); 457 splx(s); 458 459 return rval; 460} 461 462 463/* 464 * My PM interrupt routine for the PB Duo series and the PB 5XX series 465 */ 466void 467pm_intr_pm2() 468{ 469 int s; 470 int rval; 471 PMData pmdata; 472 473 s = splhigh(); 474 475 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ 476 /* ask PM what happend */ 477 pmdata.command = 0x78; 478 pmdata.num_data = 0; 479 pmdata.s_buf = &pmdata.data[2]; 480 pmdata.r_buf = &pmdata.data[2]; 481 rval = pm_pmgrop_pm2(&pmdata); 482 if (rval != 0) { 483#ifdef ADB_DEBUG 484 if (adb_debug) 485 printf("pm: PM is not ready. error code: %08x\n", rval); 486#endif 487 splx(s); 488 return; 489 } 490 491 switch ((u_int)(pmdata.data[2] & 0xff)) { 492 case 0x00: /* 1 sec interrupt? */ 493 break; 494 case PMU_INT_TICK: /* 1 sec interrupt? */ 495 break; 496 case PMU_INT_SNDBRT: /* Brightness/Contrast button on LCD panel */ 497 break; 498 case PMU_INT_ADB: /* ADB data requested by TALK command */ 499 case PMU_INT_ADB|PMU_INT_ADB_AUTO: 500 pm_adb_get_TALK_result(&pmdata); 501 break; 502 case 0x16: /* ADB device event */ 503 case 0x18: 504 case 0x1e: 505 case PMU_INT_WAKEUP: 506 pm_adb_get_ADB_data(&pmdata); 507 break; 508 default: 509#ifdef ADB_DEBUG 510 if (adb_debug) 511 pm_printerr("driver does not support this event.", 512 pmdata.data[2], pmdata.num_data, 513 pmdata.data); 514#endif 515 break; 516 } 517 518 splx(s); 519} 520 521 522/* 523 * My PMgrOp routine 524 */ 525int 526pmgrop(PMData *pmdata) 527{ 528 switch (pmHardware) { 529 case PM_HW_PB5XX: 530 return (pm_pmgrop_pm2(pmdata)); 531 default: 532 /* return (pmgrop_mrg(pmdata)); */ 533 return 1; 534 } 535} 536 537 538/* 539 * My PM interrupt routine 540 */ 541void 542pm_intr() 543{ 544 switch (pmHardware) { 545 case PM_HW_PB5XX: 546 pm_intr_pm2(); 547 break; 548 default: 549 break; 550 } 551} 552 553 554 555/* 556 * Synchronous ADBOp routine for the Power Manager 557 */ 558int 559pm_adb_op(u_char *buffer, void *compRout, void *data, int command) 560{ 561 int i; 562 int s; 563 int rval; 564 int ndelay; 565 PMData pmdata; 566 struct adbCommand packet; 567 568 if (adbWaiting == 1) 569 return 1; 570 571 s = splhigh(); 572 write_via_reg(VIA1, vIER, 0x10); 573 574 adbBuffer = buffer; 575 adbCompRout = compRout; 576 adbCompData = data; 577 578 pmdata.command = 0x20; 579 pmdata.s_buf = pmdata.data; 580 pmdata.r_buf = pmdata.data; 581 582 /* 583 * if the command is LISTEN, 584 * add number of ADB data to number of PM data 585 */ 586 if ((command & 0xc) == 0x8) { 587 if (buffer != (u_char *)0) 588 pmdata.num_data = buffer[0] + 3; 589 } else 590 pmdata.num_data = 3; 591 592 pmdata.data[0] = (u_char)(command & 0xff); 593 pmdata.data[1] = 0; 594 /* if the command is LISTEN, copy ADB data to PM buffer */ 595 if ((command & 0xc) == 0x8) { 596 if ((buffer != (u_char *)0) && (buffer[0] <= 24)) { 597 pmdata.data[2] = buffer[0]; /* number of data */ 598 for (i = 0; i < buffer[0]; i++) 599 pmdata.data[3 + i] = buffer[1 + i]; 600 } else 601 pmdata.data[2] = 0; 602 } else 603 pmdata.data[2] = 0; 604 605 if ((command & 0xc) != 0xc) { /* if the command is not TALK */ 606 /* set up stuff for adb_pass_up */ 607 packet.data[0] = 1 + pmdata.data[2]; 608 packet.data[1] = command; 609 for (i = 0; i < pmdata.data[2]; i++) 610 packet.data[i+2] = pmdata.data[i+3]; 611 packet.saveBuf = adbBuffer; 612 packet.compRout = adbCompRout; 613 packet.compData = adbCompData; 614 packet.cmd = command; 615 packet.unsol = 0; 616 packet.ack_only = 1; 617 adb_polling = 1; 618 adb_pass_up(&packet); 619 adb_polling = 0; 620 } 621 622 rval = pmgrop(&pmdata); 623 if (rval != 0) { 624 splx(s); 625 return 1; 626 } 627 628 delay (1000); 629 630 adbWaiting = 1; 631 adbWaitingCmd = command; 632 633 PM_VIA_INTR_ENABLE(); 634 635 /* wait until the PM interrupt is occurred */ 636 ndelay = 0x8000; 637 while (adbWaiting == 1) { 638 if (read_via_reg(VIA1, vIFR) != 0) 639 pm_intr(); 640#ifdef PM_GRAB_SI 641 (void)intr_dispatch(0x70); 642#endif 643 if ((--ndelay) < 0) { 644 splx(s); 645 return 1; 646 } 647 delay(10); 648 } 649 650 /* this command enables the interrupt by operating ADB devices */ 651 pmdata.command = 0x20; 652 pmdata.num_data = 4; 653 pmdata.s_buf = pmdata.data; 654 pmdata.r_buf = pmdata.data; 655 pmdata.data[0] = 0x00; 656 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */ 657 pmdata.data[2] = 0x00; 658 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */ 659 rval = pmgrop(&pmdata); 660 661 splx(s); 662 return rval; 663} 664 665 666void 667pm_adb_get_TALK_result(PMData *pmdata) 668{ 669 int i; 670 struct adbCommand packet; 671 672 /* set up data for adb_pass_up */ 673 packet.data[0] = pmdata->num_data-1; 674 packet.data[1] = pmdata->data[3]; 675 for (i = 0; i <packet.data[0]-1; i++) 676 packet.data[i+2] = pmdata->data[i+4]; 677 678 packet.saveBuf = adbBuffer; 679 packet.compRout = adbCompRout; 680 packet.compData = adbCompData; 681 packet.unsol = 0; 682 packet.ack_only = 0; 683 adb_polling = 1; 684 adb_pass_up(&packet); 685 adb_polling = 0; 686 687 adbWaiting = 0; 688 adbBuffer = (long)0; 689 adbCompRout = (long)0; 690 adbCompData = (long)0; 691} 692 693 694void 695pm_adb_get_ADB_data(PMData *pmdata) 696{ 697 int i; 698 struct adbCommand packet; 699 700 /* set up data for adb_pass_up */ 701 packet.data[0] = pmdata->num_data-1; /* number of raw data */ 702 packet.data[1] = pmdata->data[3]; /* ADB command */ 703 for (i = 0; i <packet.data[0]-1; i++) 704 packet.data[i+2] = pmdata->data[i+4]; 705 packet.unsol = 1; 706 packet.ack_only = 0; 707 adb_pass_up(&packet); 708} 709 710void 711pm_adb_restart() 712{ 713 PMData p; 714 715 p.command = PMU_RESET_CPU; 716 p.num_data = 0; 717 p.s_buf = p.data; 718 p.r_buf = p.data; 719 pmgrop(&p); 720} 721 722void 723pm_adb_poweroff() 724{ 725 PMData p; 726 727 bzero(&p, sizeof p); 728 p.command = PMU_POWER_OFF; 729 p.num_data = 4; 730 p.s_buf = p.data; 731 p.r_buf = p.data; 732 strlcpy(p.data, "MATT", sizeof p.data); 733 pmgrop(&p); 734} 735 736void 737pm_read_date_time(u_long *time) 738{ 739 PMData p; 740 741 p.command = PMU_READ_RTC; 742 p.num_data = 0; 743 p.s_buf = p.data; 744 p.r_buf = p.data; 745 pmgrop(&p); 746 747 bcopy(p.data, time, 4); 748} 749 750void 751pm_set_date_time(u_long time) 752{ 753 PMData p; 754 755 p.command = PMU_SET_RTC; 756 p.num_data = 4; 757 p.s_buf = p.r_buf = p.data; 758 bcopy(&time, p.data, 4); 759 pmgrop(&p); 760} 761 762int 763pm_read_brightness() 764{ 765 PMData p; 766 767 p.command = PMU_READ_BRIGHTNESS; 768 p.num_data = 1; /* XXX why 1? */ 769 p.s_buf = p.r_buf = p.data; 770 p.data[0] = 0; 771 pmgrop(&p); 772 773 return p.data[0]; 774} 775 776void 777pm_set_brightness(int val) 778{ 779 PMData p; 780 781 val = 0x7f - val / 2; 782 if (val < 0x08) 783 val = 0x08; 784 if (val > 0x78) 785 val = 0x78; 786 787 p.command = PMU_SET_BRIGHTNESS; 788 p.num_data = 1; 789 p.s_buf = p.r_buf = p.data; 790 p.data[0] = val; 791 pmgrop(&p); 792} 793 794void 795pm_init_brightness() 796{ 797 int val; 798 799 val = pm_read_brightness(); 800 pm_set_brightness(val); 801} 802 803void 804pm_eject_pcmcia(int slot) 805{ 806 PMData p; 807 808 if (slot != 0 && slot != 1) 809 return; 810 811 p.command = PMU_EJECT_PCMCIA; 812 p.num_data = 1; 813 p.s_buf = p.r_buf = p.data; 814 p.data[0] = 5 + slot; /* XXX */ 815 pmgrop(&p); 816} 817 818 819/* 820 * Thanks to Paul Mackerras and Fabio Riccardi's Linux implementation 821 * for a clear description of the PMU results. 822 */ 823 824int 825pm_battery_info(int battery, struct pmu_battery_info *info) 826{ 827 PMData p; 828 829 p.command = PMU_SMART_BATTERY_STATE; 830 p.num_data = 1; 831 p.s_buf = p.r_buf = p.data; 832 p.data[0] = battery + 1; 833 pmgrop(&p); 834 835 info->flags = p.data[1]; 836 837 switch (p.data[0]) { 838 case 3: 839 case 4: 840 info->cur_charge = p.data[2]; 841 info->max_charge = p.data[3]; 842 info->draw = *((signed char *)&p.data[4]); 843 info->voltage = p.data[5]; 844 break; 845 case 5: 846 info->cur_charge = ((p.data[2] << 8) | (p.data[3])); 847 info->max_charge = ((p.data[4] << 8) | (p.data[5])); 848 info->draw = *((signed short *)&p.data[6]); 849 info->voltage = ((p.data[8] << 8) | (p.data[7])); 850 break; 851 default: 852 /* XXX - Error condition */ 853 info->cur_charge = 0; 854 info->max_charge = 0; 855 info->draw = 0; 856 info->voltage = 0; 857 break; 858 } 859 860 return 1; 861} 862 863 864 865int 866pm_read_nvram(int addr) 867{ 868 PMData p; 869 870 p.command = PMU_READ_NVRAM; 871 p.num_data = 2; 872 p.s_buf = p.r_buf = p.data; 873 p.data[0] = addr >> 8; 874 p.data[1] = addr; 875 pmgrop(&p); 876 877 return p.data[0]; 878} 879 880void 881pm_write_nvram(int addr, int val) 882{ 883 PMData p; 884 885 p.command = PMU_WRITE_NVRAM; 886 p.num_data = 3; 887 p.s_buf = p.r_buf = p.data; 888 p.data[0] = addr >> 8; 889 p.data[1] = addr; 890 p.data[2] = val; 891 pmgrop(&p); 892} 893