pm_direct.c revision 1.9
1/* $NetBSD: pm_direct.c,v 1.9 2000/06/08 22:10:46 tsubai Exp $ */ 2 3/* 4 * Copyright (C) 1997 Takashi Hamada 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Takashi Hamada 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32/* From: pm_direct.c 1.3 03/18/98 Takashi Hamada */ 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 54extern int adb_polling; /* Are we polling? (Debugger mode) */ 55 56/* hardware dependent values */ 57#define ADBDelay 100 /* XXX */ 58#define HwCfgFlags3 0x20000 /* XXX */ 59 60/* define the types of the Power Manager */ 61#define PM_HW_UNKNOWN 0x00 /* don't know */ 62#define PM_HW_PB1XX 0x01 /* PowerBook 1XX series */ 63#define PM_HW_PB5XX 0x02 /* PowerBook Duo and 5XX series */ 64 65/* useful macros */ 66#define PM_SR() read_via_reg(VIA1, vSR) 67#define PM_VIA_INTR_ENABLE() write_via_reg(VIA1, vIER, 0x90) 68#define PM_VIA_INTR_DISABLE() write_via_reg(VIA1, vIER, 0x10) 69#define PM_VIA_CLR_INTR() write_via_reg(VIA1, vIFR, 0x90) 70#if 0 71#define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x04) 72#define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x04) 73#define PM_IS_ON (0x02 == (read_via_reg(VIA2, vBufB) & 0x02)) 74#define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x02)) 75#else 76#define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x10) 77#define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x10) 78#define PM_IS_ON (0x08 == (read_via_reg(VIA2, vBufB) & 0x08)) 79#define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x08)) 80#endif 81 82/* 83 * Variables for internal use 84 */ 85int pmHardware = PM_HW_UNKNOWN; 86u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */ 87u_int pm_LCD_brightness = 0x0; 88u_int pm_LCD_contrast = 0x0; 89u_int pm_counter = 0; /* clock count */ 90 91/* these values shows that number of data returned after 'send' cmd is sent */ 92signed char pm_send_cmd_type[] = { 93 -1, -1, -1, -1, -1, -1, -1, -1, 94 -1, -1, -1, -1, -1, -1, -1, -1, 95 0x01, 0x01, -1, -1, -1, -1, -1, -1, 96 0x00, 0x00, -1, -1, -1, -1, -1, 0x00, 97 -1, 0x00, 0x02, 0x01, 0x01, -1, -1, -1, 98 0x00, -1, -1, -1, -1, -1, -1, -1, 99 0x04, 0x14, -1, 0x03, -1, -1, -1, -1, 100 0x00, 0x00, 0x02, 0x02, -1, -1, -1, -1, 101 0x01, 0x01, -1, -1, -1, -1, -1, -1, 102 0x00, 0x00, -1, -1, 0x01, -1, -1, -1, 103 0x01, 0x00, 0x02, 0x02, -1, 0x01, 0x03, 0x01, 104 0x00, 0x01, 0x00, 0x00, 0x00, -1, -1, -1, 105 0x02, -1, -1, -1, -1, -1, -1, -1, 106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, -1, 107 0x01, 0x01, 0x01, -1, -1, -1, -1, -1, 108 0x00, 0x00, -1, -1, -1, -1, 0x04, 0x04, 109 0x04, -1, 0x00, -1, -1, -1, -1, -1, 110 0x00, -1, -1, -1, -1, -1, -1, -1, 111 0x01, 0x02, -1, -1, -1, -1, -1, -1, 112 0x00, 0x00, -1, -1, -1, -1, -1, -1, 113 0x02, 0x02, 0x02, 0x04, -1, 0x00, -1, -1, 114 0x01, 0x01, 0x03, 0x02, -1, -1, -1, -1, 115 -1, -1, -1, -1, -1, -1, -1, -1, 116 -1, -1, -1, -1, -1, -1, -1, -1, 117 -1, -1, -1, -1, -1, -1, -1, -1, 118 -1, -1, -1, -1, -1, -1, -1, -1, 119 0x00, -1, -1, -1, -1, -1, -1, -1, 120 0x01, 0x01, -1, -1, 0x00, 0x00, -1, -1, 121 -1, 0x04, 0x00, -1, -1, -1, -1, -1, 122 0x03, -1, 0x00, -1, 0x00, -1, -1, 0x00, 123 -1, -1, -1, -1, -1, -1, -1, -1, 124 -1, -1, -1, -1, -1, -1, -1, -1 125}; 126 127/* these values shows that number of data returned after 'receive' cmd is sent */ 128signed char pm_receive_cmd_type[] = { 129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 130 -1, -1, -1, -1, -1, -1, -1, -1, 131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 132 0x02, 0x02, -1, -1, -1, -1, -1, 0x00, 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 0x05, 0x15, -1, 0x02, -1, -1, -1, -1, 137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 138 0x02, 0x02, -1, -1, -1, -1, -1, -1, 139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 140 0x02, 0x00, 0x03, 0x03, -1, -1, -1, -1, 141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 142 0x04, 0x04, 0x03, 0x09, -1, -1, -1, -1, 143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 144 -1, -1, -1, -1, -1, -1, 0x01, 0x01, 145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 146 0x06, -1, -1, -1, -1, -1, -1, -1, 147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 148 0x02, 0x02, -1, -1, -1, -1, -1, -1, 149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 150 0x02, 0x00, 0x00, 0x00, -1, -1, -1, -1, 151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 152 -1, -1, -1, -1, -1, -1, -1, -1, 153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 154 -1, -1, -1, -1, -1, -1, -1, -1, 155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 156 0x02, 0x02, -1, -1, 0x02, -1, -1, -1, 157 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 158 -1, -1, 0x02, -1, -1, -1, -1, 0x00, 159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 160 -1, -1, -1, -1, -1, -1, -1, -1, 161}; 162 163 164/* 165 * Define the private functions 166 */ 167 168/* for debugging */ 169#ifdef ADB_DEBUG 170void pm_printerr __P((char *, int, int, char *)); 171#endif 172 173int pm_wait_busy __P((int)); 174int pm_wait_free __P((int)); 175 176/* these functions are for the PB1XX series */ 177int pm_receive_pm1 __P((u_char *)); 178int pm_send_pm1 __P((u_char,int)); 179int pm_pmgrop_pm1 __P((PMData *)); 180void pm_intr_pm1 __P((void)); 181 182/* these functions are for the PB Duo series and the PB 5XX series */ 183int pm_receive_pm2 __P((u_char *)); 184int pm_send_pm2 __P((u_char)); 185int pm_pmgrop_pm2 __P((PMData *)); 186void pm_intr_pm2 __P((void)); 187 188/* this function is MRG-Based (for testing) */ 189int pm_pmgrop_mrg __P((PMData *)); 190 191/* these functions are called from adb_direct.c */ 192void pm_setup_adb __P((void)); 193void pm_check_adb_devices __P((int)); 194void pm_intr __P((void)); 195int pm_adb_op __P((u_char *, void *, void *, int)); 196 197/* these functions also use the variables of adb_direct.c */ 198void pm_adb_get_TALK_result __P((PMData *)); 199void pm_adb_get_ADB_data __P((PMData *)); 200void pm_adb_poll_next_device_pm1 __P((PMData *)); 201 202 203/* 204 * These variables are in adb_direct.c. 205 */ 206extern u_char *adbBuffer; /* pointer to user data area */ 207extern void *adbCompRout; /* pointer to the completion routine */ 208extern void *adbCompData; /* pointer to the completion routine data */ 209extern int adbWaiting; /* waiting for return data from the device */ 210extern int adbWaitingCmd; /* ADB command we are waiting for */ 211extern int adbStarting; /* doing ADB reinit, so do "polling" differently */ 212 213#define ADB_MAX_MSG_LENGTH 16 214#define ADB_MAX_HDR_LENGTH 8 215struct adbCommand { 216 u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */ 217 u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */ 218 u_char *saveBuf; /* where to save result */ 219 u_char *compRout; /* completion routine pointer */ 220 u_char *compData; /* completion routine data pointer */ 221 u_int cmd; /* the original command for this data */ 222 u_int unsol; /* 1 if packet was unsolicited */ 223 u_int ack_only; /* 1 for no special processing */ 224}; 225extern void adb_pass_up __P((struct adbCommand *)); 226 227#if 0 228/* 229 * Define the external functions 230 */ 231extern int zshard __P((int)); /* from zs.c */ 232#endif 233 234#ifdef ADB_DEBUG 235/* 236 * This function dumps contents of the PMData 237 */ 238void 239pm_printerr(ttl, rval, num, data) 240 char *ttl; 241 int rval; 242 int num; 243 char *data; 244{ 245 int i; 246 247 printf("pm: %s:%04x %02x ", ttl, rval, num); 248 for (i = 0; i < num; i++) 249 printf("%02x ", data[i]); 250 printf("\n"); 251} 252#endif 253 254 255 256/* 257 * Check the hardware type of the Power Manager 258 */ 259void 260pm_setup_adb() 261{ 262 pmHardware = PM_HW_PB5XX; /* XXX */ 263} 264 265 266/* 267 * Check the existent ADB devices 268 */ 269void 270pm_check_adb_devices(id) 271 int id; 272{ 273 u_short ed = 0x1; 274 275 ed <<= id; 276 pm_existent_ADB_devices |= ed; 277} 278 279 280/* 281 * Wait until PM IC is busy 282 */ 283int 284pm_wait_busy(delay) 285 int delay; 286{ 287 while (PM_IS_ON) { 288#ifdef PM_GRAB_SI 289#if 0 290 zshard(0); /* grab any serial interrupts */ 291#else 292 (void)intr_dispatch(0x70); 293#endif 294#endif 295 if ((--delay) < 0) 296 return 1; /* timeout */ 297 } 298 return 0; 299} 300 301 302/* 303 * Wait until PM IC is free 304 */ 305int 306pm_wait_free(delay) 307 int delay; 308{ 309 while (PM_IS_OFF) { 310#ifdef PM_GRAB_SI 311#if 0 312 zshard(0); /* grab any serial interrupts */ 313#else 314 (void)intr_dispatch(0x70); 315#endif 316#endif 317 if ((--delay) < 0) 318 return 0; /* timeout */ 319 } 320 return 1; 321} 322 323 324 325/* 326 * Functions for the PB1XX series 327 */ 328 329/* 330 * Receive data from PM for the PB1XX series 331 */ 332int 333pm_receive_pm1(data) 334 u_char *data; 335{ 336#if 0 337 int rval = 0xffffcd34; 338 339 via_reg(VIA2, vDirA) = 0x00; 340 341 switch (1) { 342 default: 343 if (pm_wait_busy(0x40) != 0) 344 break; /* timeout */ 345 346 PM_SET_STATE_ACKOFF(); 347 *data = via_reg(VIA2, 0x200); 348 349 rval = 0xffffcd33; 350 if (pm_wait_free(0x40) == 0) 351 break; /* timeout */ 352 353 rval = 0x00; 354 break; 355 } 356 357 PM_SET_STATE_ACKON(); 358 via_reg(VIA2, vDirA) = 0x00; 359 360 return rval; 361#else 362 panic("pm_receive_pm1"); 363#endif 364} 365 366 367 368/* 369 * Send data to PM for the PB1XX series 370 */ 371int 372pm_send_pm1(data, delay) 373 u_char data; 374 int delay; 375{ 376#if 0 377 int rval; 378 379 via_reg(VIA2, vDirA) = 0xff; 380 via_reg(VIA2, 0x200) = data; 381 382 PM_SET_STATE_ACKOFF(); 383 if (pm_wait_busy(0x400) != 0) { 384 PM_SET_STATE_ACKON(); 385 via_reg(VIA2, vDirA) = 0x00; 386 387 return 0xffffcd36; 388 } 389 390 rval = 0x0; 391 PM_SET_STATE_ACKON(); 392 if (pm_wait_free(0x40) == 0) 393 rval = 0xffffcd35; 394 395 PM_SET_STATE_ACKON(); 396 via_reg(VIA2, vDirA) = 0x00; 397 398 return rval; 399#else 400 panic("pm_send_pm1"); 401#endif 402} 403 404 405/* 406 * My PMgrOp routine for the PB1XX series 407 */ 408int 409pm_pmgrop_pm1(pmdata) 410 PMData *pmdata; 411{ 412#if 0 413 int i; 414 int s = 0x81815963; 415 u_char via1_vIER, via1_vDirA; 416 int rval = 0; 417 int num_pm_data = 0; 418 u_char pm_cmd; 419 u_char pm_data; 420 u_char *pm_buf; 421 422 /* disable all inetrrupts but PM */ 423 via1_vIER = via_reg(VIA1, vIER); 424 PM_VIA_INTR_DISABLE(); 425 426 via1_vDirA = via_reg(VIA1, vDirA); 427 428 switch (pmdata->command) { 429 default: 430 for (i = 0; i < 7; i++) { 431 via_reg(VIA2, vDirA) = 0x00; 432 433 /* wait until PM is free */ 434 if (pm_wait_free(ADBDelay) == 0) { /* timeout */ 435 via_reg(VIA2, vDirA) = 0x00; 436 /* restore formar value */ 437 via_reg(VIA1, vDirA) = via1_vDirA; 438 via_reg(VIA1, vIER) = via1_vIER; 439 return 0xffffcd38; 440 } 441 442 switch (mac68k_machine.machineid) { 443 case MACH_MACPB160: 444 case MACH_MACPB165: 445 case MACH_MACPB165C: 446 case MACH_MACPB180: 447 case MACH_MACPB180C: 448 { 449 int delay = ADBDelay * 16; 450 451 via_reg(VIA2, vDirA) = 0x00; 452 while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0)) 453 delay--; 454 455 if (delay < 0) { /* timeout */ 456 via_reg(VIA2, vDirA) = 0x00; 457 /* restore formar value */ 458 via_reg(VIA1, vIER) = via1_vIER; 459 return 0xffffcd38; 460 } 461 } 462 } /* end switch */ 463 464 s = splhigh(); 465 466 via1_vDirA = via_reg(VIA1, vDirA); 467 via_reg(VIA1, vDirA) &= 0x7f; 468 469 pm_cmd = (u_char)(pmdata->command & 0xff); 470 if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0) 471 break; /* send command succeeded */ 472 473 via_reg(VIA1, vDirA) = via1_vDirA; 474 splx(s); 475 } /* end for */ 476 477 /* failed to send a command */ 478 if (i == 7) { 479 via_reg(VIA2, vDirA) = 0x00; 480 /* restore formar value */ 481 via_reg(VIA1, vDirA) = via1_vDirA; 482 via_reg(VIA1, vIER) = via1_vIER; 483 if (s != 0x81815963) 484 splx(s); 485 return 0xffffcd38; 486 } 487 488 /* send # of PM data */ 489 num_pm_data = pmdata->num_data; 490 if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0) 491 break; /* timeout */ 492 493 /* send PM data */ 494 pm_buf = (u_char *)pmdata->s_buf; 495 for (i = 0; i < num_pm_data; i++) 496 if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0) 497 break; /* timeout */ 498 if ((i != num_pm_data) && (num_pm_data != 0)) 499 break; /* timeout */ 500 501 /* Will PM IC return data? */ 502 if ((pm_cmd & 0x08) == 0) { 503 rval = 0; 504 break; /* no returned data */ 505 } 506 507 rval = 0xffffcd37; 508 if (pm_wait_busy(ADBDelay) != 0) 509 break; /* timeout */ 510 511 /* receive PM command */ 512 if ((rval = pm_receive_pm1(&pm_data)) != 0) 513 break; 514 515 pmdata->command = pm_data; 516 517 /* receive number of PM data */ 518 if ((rval = pm_receive_pm1(&pm_data)) != 0) 519 break; /* timeout */ 520 num_pm_data = pm_data; 521 pmdata->num_data = num_pm_data; 522 523 /* receive PM data */ 524 pm_buf = (u_char *)pmdata->r_buf; 525 for (i = 0; i < num_pm_data; i++) { 526 if ((rval = pm_receive_pm1(&pm_data)) != 0) 527 break; /* timeout */ 528 pm_buf[i] = pm_data; 529 } 530 531 rval = 0; 532 } 533 534 via_reg(VIA2, vDirA) = 0x00; 535 536 /* restore formar value */ 537 via_reg(VIA1, vDirA) = via1_vDirA; 538 via_reg(VIA1, vIER) = via1_vIER; 539 if (s != 0x81815963) 540 splx(s); 541 542 return rval; 543#else 544 panic("pm_pmgrop_pm1"); 545#endif 546} 547 548 549/* 550 * My PM interrupt routine for PB1XX series 551 */ 552void 553pm_intr_pm1() 554{ 555#if 0 556 int s; 557 int rval; 558 PMData pmdata; 559 560 s = splhigh(); 561 562 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ 563 564 /* ask PM what happend */ 565 pmdata.command = 0x78; 566 pmdata.num_data = 0; 567 pmdata.data[0] = pmdata.data[1] = 0; 568 pmdata.s_buf = &pmdata.data[2]; 569 pmdata.r_buf = &pmdata.data[2]; 570 rval = pm_pmgrop_pm1(&pmdata); 571 if (rval != 0) { 572#ifdef ADB_DEBUG 573 if (adb_debug) 574 printf("pm: PM is not ready. error code=%08x\n", rval); 575#endif 576 splx(s); 577 } 578 579 if ((pmdata.data[2] & 0x10) == 0x10) { 580 if ((pmdata.data[2] & 0x0f) == 0) { 581 /* ADB data that were requested by TALK command */ 582 pm_adb_get_TALK_result(&pmdata); 583 } else if ((pmdata.data[2] & 0x08) == 0x8) { 584 /* PM is requesting to poll */ 585 pm_adb_poll_next_device_pm1(&pmdata); 586 } else if ((pmdata.data[2] & 0x04) == 0x4) { 587 /* ADB device event */ 588 pm_adb_get_ADB_data(&pmdata); 589 } 590 } else { 591#ifdef ADB_DEBUG 592 if (adb_debug) 593 pm_printerr("driver does not supported this event.", 594 rval, pmdata.num_data, pmdata.data); 595#endif 596 } 597 598 splx(s); 599#else 600 panic("pm_intr_pm1"); 601#endif 602} 603 604 605 606/* 607 * Functions for the PB Duo series and the PB 5XX series 608 */ 609 610/* 611 * Receive data from PM for the PB Duo series and the PB 5XX series 612 */ 613int 614pm_receive_pm2(data) 615 u_char *data; 616{ 617 int i; 618 int rval; 619 620 rval = 0xffffcd34; 621 622 switch (1) { 623 default: 624 /* set VIA SR to input mode */ 625 via_reg_or(VIA1, vACR, 0x0c); 626 via_reg_and(VIA1, vACR, ~0x10); 627 i = PM_SR(); 628 629 PM_SET_STATE_ACKOFF(); 630 if (pm_wait_busy((int)ADBDelay*32) != 0) 631 break; /* timeout */ 632 633 PM_SET_STATE_ACKON(); 634 rval = 0xffffcd33; 635 if (pm_wait_free((int)ADBDelay*32) == 0) 636 break; /* timeout */ 637 638 *data = PM_SR(); 639 rval = 0; 640 641 break; 642 } 643 644 PM_SET_STATE_ACKON(); 645 via_reg_or(VIA1, vACR, 0x1c); 646 647 return rval; 648} 649 650 651 652/* 653 * Send data to PM for the PB Duo series and the PB 5XX series 654 */ 655int 656pm_send_pm2(data) 657 u_char data; 658{ 659 int rval; 660 661 via_reg_or(VIA1, vACR, 0x1c); 662 write_via_reg(VIA1, vSR, data); /* PM_SR() = data; */ 663 664 PM_SET_STATE_ACKOFF(); 665 rval = 0xffffcd36; 666 if (pm_wait_busy((int)ADBDelay*32) != 0) { 667 PM_SET_STATE_ACKON(); 668 669 via_reg_or(VIA1, vACR, 0x1c); 670 671 return rval; 672 } 673 674 PM_SET_STATE_ACKON(); 675 rval = 0xffffcd35; 676 if (pm_wait_free((int)ADBDelay*32) != 0) 677 rval = 0; 678 679 PM_SET_STATE_ACKON(); 680 via_reg_or(VIA1, vACR, 0x1c); 681 682 return rval; 683} 684 685 686 687/* 688 * My PMgrOp routine for the PB Duo series and the PB 5XX series 689 */ 690int 691pm_pmgrop_pm2(pmdata) 692 PMData *pmdata; 693{ 694 int i; 695 int s; 696 u_char via1_vIER; 697 int rval = 0; 698 int num_pm_data = 0; 699 u_char pm_cmd; 700 short pm_num_rx_data; 701 u_char pm_data; 702 u_char *pm_buf; 703 704 s = splhigh(); 705 706 /* disable all inetrrupts but PM */ 707 via1_vIER = 0x10; 708 via1_vIER &= read_via_reg(VIA1, vIER); 709 write_via_reg(VIA1, vIER, via1_vIER); 710 if (via1_vIER != 0x0) 711 via1_vIER |= 0x80; 712 713 switch (pmdata->command) { 714 default: 715 /* wait until PM is free */ 716 pm_cmd = (u_char)(pmdata->command & 0xff); 717 rval = 0xcd38; 718 if (pm_wait_free(ADBDelay * 4) == 0) 719 break; /* timeout */ 720 721 if (HwCfgFlags3 & 0x00200000) { 722 /* PB 160, PB 165(c), PB 180(c)? */ 723 int delay = ADBDelay * 16; 724 725 write_via_reg(VIA2, vDirA, 0x00); 726 while ((read_via_reg(VIA2, 0x200) == 0x07) && 727 (delay >= 0)) 728 delay--; 729 730 if (delay < 0) { 731 rval = 0xffffcd38; 732 break; /* timeout */ 733 } 734 } 735 736 /* send PM command */ 737 if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff)))) 738 break; /* timeout */ 739 740 /* send number of PM data */ 741 num_pm_data = pmdata->num_data; 742 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 743 if (pm_send_cmd_type[pm_cmd] < 0) { 744 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0) 745 break; /* timeout */ 746 pmdata->command = 0; 747 } 748 } else { /* PB 1XX series ? */ 749 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0) 750 break; /* timeout */ 751 } 752 /* send PM data */ 753 pm_buf = (u_char *)pmdata->s_buf; 754 for (i = 0 ; i < num_pm_data; i++) 755 if ((rval = pm_send_pm2(pm_buf[i])) != 0) 756 break; /* timeout */ 757 if (i != num_pm_data) 758 break; /* timeout */ 759 760 761 /* check if PM will send me data */ 762 pm_num_rx_data = pm_receive_cmd_type[pm_cmd]; 763 pmdata->num_data = pm_num_rx_data; 764 if (pm_num_rx_data == 0) { 765 rval = 0; 766 break; /* no return data */ 767 } 768 769 /* receive PM command */ 770 pm_data = pmdata->command; 771 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 772 pm_num_rx_data--; 773 if (pm_num_rx_data == 0) 774 if ((rval = pm_receive_pm2(&pm_data)) != 0) { 775 rval = 0xffffcd37; 776 break; 777 } 778 pmdata->command = pm_data; 779 } else { /* PB 1XX series ? */ 780 if ((rval = pm_receive_pm2(&pm_data)) != 0) { 781 rval = 0xffffcd37; 782 break; 783 } 784 pmdata->command = pm_data; 785 } 786 787 /* receive number of PM data */ 788 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 789 if (pm_num_rx_data < 0) { 790 if ((rval = pm_receive_pm2(&pm_data)) != 0) 791 break; /* timeout */ 792 num_pm_data = pm_data; 793 } else 794 num_pm_data = pm_num_rx_data; 795 pmdata->num_data = num_pm_data; 796 } else { /* PB 1XX serias ? */ 797 if ((rval = pm_receive_pm2(&pm_data)) != 0) 798 break; /* timeout */ 799 num_pm_data = pm_data; 800 pmdata->num_data = num_pm_data; 801 } 802 803 /* receive PM data */ 804 pm_buf = (u_char *)pmdata->r_buf; 805 for (i = 0; i < num_pm_data; i++) { 806 if ((rval = pm_receive_pm2(&pm_data)) != 0) 807 break; /* timeout */ 808 pm_buf[i] = pm_data; 809 } 810 811 rval = 0; 812 } 813 814 /* restore former value */ 815 write_via_reg(VIA1, vIER, via1_vIER); 816 splx(s); 817 818 return rval; 819} 820 821 822/* 823 * My PM interrupt routine for the PB Duo series and the PB 5XX series 824 */ 825void 826pm_intr_pm2() 827{ 828 int s; 829 int rval; 830 PMData pmdata; 831 832 s = splhigh(); 833 834 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ 835 /* ask PM what happend */ 836 pmdata.command = 0x78; 837 pmdata.num_data = 0; 838 pmdata.s_buf = &pmdata.data[2]; 839 pmdata.r_buf = &pmdata.data[2]; 840 rval = pm_pmgrop_pm2(&pmdata); 841 if (rval != 0) { 842#ifdef ADB_DEBUG 843 if (adb_debug) 844 printf("pm: PM is not ready. error code: %08x\n", rval); 845#endif 846 splx(s); 847 } 848 849 switch ((u_int)(pmdata.data[2] & 0xff)) { 850 case 0x00: /* 1 sec interrupt? */ 851 break; 852 case 0x80: /* 1 sec interrupt? */ 853 pm_counter++; 854 break; 855 case 0x08: /* Brightness/Contrast button on LCD panel */ 856 /* get brightness and contrast of the LCD */ 857 pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff; 858 pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff; 859/* 860 pm_printerr("#08", rval, pmdata.num_data, pmdata.data); 861 pmdata.command = 0x33; 862 pmdata.num_data = 1; 863 pmdata.s_buf = pmdata.data; 864 pmdata.r_buf = pmdata.data; 865 pmdata.data[0] = pm_LCD_contrast; 866 rval = pm_pmgrop_pm2(&pmdata); 867 pm_printerr("#33", rval, pmdata.num_data, pmdata.data); 868*/ 869 /* this is an experimental code */ 870 pmdata.command = 0x41; 871 pmdata.num_data = 1; 872 pmdata.s_buf = pmdata.data; 873 pmdata.r_buf = pmdata.data; 874 pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2; 875 if (pm_LCD_brightness < 0x08) 876 pm_LCD_brightness = 0x08; 877 if (pm_LCD_brightness > 0x78) 878 pm_LCD_brightness = 0x78; 879 pmdata.data[0] = pm_LCD_brightness; 880 rval = pm_pmgrop_pm2(&pmdata); 881 break; 882 case 0x10: /* ADB data that were requested by TALK command */ 883 case 0x14: 884 pm_adb_get_TALK_result(&pmdata); 885 break; 886 case 0x16: /* ADB device event */ 887 case 0x18: 888 case 0x1e: 889 pm_adb_get_ADB_data(&pmdata); 890 break; 891 default: 892#ifdef ADB_DEBUG 893 if (adb_debug) 894 pm_printerr("driver does not supported this event.", 895 pmdata.data[2], pmdata.num_data, 896 pmdata.data); 897#endif 898 break; 899 } 900 901 splx(s); 902} 903 904 905#if 0 906/* 907 * MRG-based PMgrOp routine 908 */ 909int 910pm_pmgrop_mrg(pmdata) 911 PMData *pmdata; 912{ 913 u_int32_t rval=0; 914 915 asm(" 916 movl %1, a0 917 .word 0xa085 918 movl d0, %0" 919 : "=g" (rval) 920 : "g" (pmdata) 921 : "a0", "d0" ); 922 923 return rval; 924} 925#endif 926 927 928/* 929 * My PMgrOp routine 930 */ 931int 932pmgrop(pmdata) 933 PMData *pmdata; 934{ 935 switch (pmHardware) { 936 case PM_HW_PB1XX: 937 return (pm_pmgrop_pm1(pmdata)); 938 break; 939 case PM_HW_PB5XX: 940 return (pm_pmgrop_pm2(pmdata)); 941 break; 942 default: 943 /* return (pmgrop_mrg(pmdata)); */ 944 return 1; 945 } 946} 947 948 949/* 950 * My PM interrupt routine 951 */ 952void 953pm_intr() 954{ 955 switch (pmHardware) { 956 case PM_HW_PB1XX: 957 pm_intr_pm1(); 958 break; 959 case PM_HW_PB5XX: 960 pm_intr_pm2(); 961 break; 962 default: 963 break; 964 } 965} 966 967 968 969/* 970 * Synchronous ADBOp routine for the Power Manager 971 */ 972int 973pm_adb_op(buffer, compRout, data, command) 974 u_char *buffer; 975 void *compRout; 976 void *data; 977 int command; 978{ 979 int i; 980 int s; 981 int rval; 982 int delay; 983 PMData pmdata; 984 struct adbCommand packet; 985 986 if (adbWaiting == 1) 987 return 1; 988 989 s = splhigh(); 990 write_via_reg(VIA1, vIER, 0x10); 991 992 adbBuffer = buffer; 993 adbCompRout = compRout; 994 adbCompData = data; 995 996 pmdata.command = 0x20; 997 pmdata.s_buf = pmdata.data; 998 pmdata.r_buf = pmdata.data; 999 1000 /* if the command is LISTEN, add number of ADB data to number of PM data */ 1001 if ((command & 0xc) == 0x8) { 1002 if (buffer != (u_char *)0) 1003 pmdata.num_data = buffer[0] + 3; 1004 } else { 1005 pmdata.num_data = 3; 1006 } 1007 1008 pmdata.data[0] = (u_char)(command & 0xff); 1009 pmdata.data[1] = 0; 1010 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */ 1011 if ((buffer != (u_char *)0) && (buffer[0] <= 24)) { 1012 pmdata.data[2] = buffer[0]; /* number of data */ 1013 for (i = 0; i < buffer[0]; i++) 1014 pmdata.data[3 + i] = buffer[1 + i]; 1015 } else 1016 pmdata.data[2] = 0; 1017 } else 1018 pmdata.data[2] = 0; 1019 1020 if ((command & 0xc) != 0xc) { /* if the command is not TALK */ 1021 /* set up stuff for adb_pass_up */ 1022 packet.data[0] = 1 + pmdata.data[2]; 1023 packet.data[1] = command; 1024 for (i = 0; i < pmdata.data[2]; i++) 1025 packet.data[i+2] = pmdata.data[i+3]; 1026 packet.saveBuf = adbBuffer; 1027 packet.compRout = adbCompRout; 1028 packet.compData = adbCompData; 1029 packet.cmd = command; 1030 packet.unsol = 0; 1031 packet.ack_only = 1; 1032 adb_polling = 1; 1033 adb_pass_up(&packet); 1034 adb_polling = 0; 1035 } 1036 1037 rval = pmgrop(&pmdata); 1038 if (rval != 0) { 1039 splx(s); 1040 return 1; 1041 } 1042 1043 adbWaiting = 1; 1044 adbWaitingCmd = command; 1045 1046 PM_VIA_INTR_ENABLE(); 1047 1048 /* wait until the PM interrupt is occured */ 1049 delay = 0x80000; 1050 while (adbWaiting == 1) { 1051 if (read_via_reg(VIA1, vIFR) & 0x14) 1052 pm_intr(); 1053#ifdef PM_GRAB_SI 1054#if 0 1055 zshard(0); /* grab any serial interrupts */ 1056#else 1057 (void)intr_dispatch(0x70); 1058#endif 1059#endif 1060 if ((--delay) < 0) { 1061 splx(s); 1062 return 1; 1063 } 1064 } 1065 1066 /* this command enables the interrupt by operating ADB devices */ 1067 if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX series */ 1068 pmdata.command = 0x20; 1069 pmdata.num_data = 4; 1070 pmdata.s_buf = pmdata.data; 1071 pmdata.r_buf = pmdata.data; 1072 pmdata.data[0] = 0x00; 1073 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */ 1074 pmdata.data[2] = 0x00; 1075 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */ 1076 } else { /* PB 1XX series */ 1077 pmdata.command = 0x20; 1078 pmdata.num_data = 3; 1079 pmdata.s_buf = pmdata.data; 1080 pmdata.r_buf = pmdata.data; 1081 pmdata.data[0] = (u_char)(command & 0xf0) | 0xc; 1082 pmdata.data[1] = 0x04; 1083 pmdata.data[2] = 0x00; 1084 } 1085 rval = pmgrop(&pmdata); 1086 1087 splx(s); 1088 return rval; 1089} 1090 1091 1092void 1093pm_adb_get_TALK_result(pmdata) 1094 PMData *pmdata; 1095{ 1096 int i; 1097 struct adbCommand packet; 1098 1099 /* set up data for adb_pass_up */ 1100 packet.data[0] = pmdata->num_data-1; 1101 packet.data[1] = pmdata->data[3]; 1102 for (i = 0; i <packet.data[0]-1; i++) 1103 packet.data[i+2] = pmdata->data[i+4]; 1104 1105 packet.saveBuf = adbBuffer; 1106 packet.compRout = adbCompRout; 1107 packet.compData = adbCompData; 1108 packet.unsol = 0; 1109 packet.ack_only = 0; 1110 adb_polling = 1; 1111 adb_pass_up(&packet); 1112 adb_polling = 0; 1113 1114 adbWaiting = 0; 1115 adbBuffer = (long)0; 1116 adbCompRout = (long)0; 1117 adbCompData = (long)0; 1118} 1119 1120 1121void 1122pm_adb_get_ADB_data(pmdata) 1123 PMData *pmdata; 1124{ 1125 int i; 1126 struct adbCommand packet; 1127 1128 /* set up data for adb_pass_up */ 1129 packet.data[0] = pmdata->num_data-1; /* number of raw data */ 1130 packet.data[1] = pmdata->data[3]; /* ADB command */ 1131 for (i = 0; i <packet.data[0]-1; i++) 1132 packet.data[i+2] = pmdata->data[i+4]; 1133 packet.unsol = 1; 1134 packet.ack_only = 0; 1135 adb_pass_up(&packet); 1136} 1137 1138 1139void 1140pm_adb_poll_next_device_pm1(pmdata) 1141 PMData *pmdata; 1142{ 1143 int i; 1144 int ndid; 1145 u_short bendid = 0x1; 1146 int rval; 1147 PMData tmp_pmdata; 1148 1149 /* find another existent ADB device to poll */ 1150 for (i = 1; i < 16; i++) { 1151 ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf; 1152 bendid <<= ndid; 1153 if ((pm_existent_ADB_devices & bendid) != 0) 1154 break; 1155 } 1156 1157 /* poll the other device */ 1158 tmp_pmdata.command = 0x20; 1159 tmp_pmdata.num_data = 3; 1160 tmp_pmdata.s_buf = tmp_pmdata.data; 1161 tmp_pmdata.r_buf = tmp_pmdata.data; 1162 tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc; 1163 tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */ 1164 tmp_pmdata.data[2] = 0x00; 1165 rval = pmgrop(&tmp_pmdata); 1166} 1167 1168void 1169pm_adb_restart() 1170{ 1171 PMData p; 1172 1173 p.command = PMU_RESET_CPU; 1174 p.num_data = 0; 1175 p.s_buf = p.data; 1176 p.r_buf = p.data; 1177 pmgrop(&p); 1178} 1179 1180void 1181pm_adb_poweroff() 1182{ 1183 PMData p; 1184 1185 p.command = PMU_POWER_OFF; 1186 p.num_data = 4; 1187 p.s_buf = p.data; 1188 p.r_buf = p.data; 1189 strcpy(p.data, "MATT"); 1190 pmgrop(&p); 1191} 1192 1193void 1194pm_read_date_time(time) 1195 u_long *time; 1196{ 1197 PMData p; 1198 1199 p.command = PMU_READ_RTC; 1200 p.num_data = 0; 1201 p.s_buf = p.data; 1202 p.r_buf = p.data; 1203 pmgrop(&p); 1204 1205 bcopy(p.data, time, 4); 1206} 1207 1208void 1209pm_set_date_time(time) 1210 u_long time; 1211{ 1212 PMData p; 1213 1214 p.command = PMU_SET_RTC; 1215 p.num_data = 4; 1216 p.s_buf = p.r_buf = p.data; 1217 bcopy(&time, p.data, 4); 1218 pmgrop(&p); 1219} 1220 1221int 1222pm_read_brightness() 1223{ 1224 PMData p; 1225 1226 p.command = PMU_READ_BRIGHTNESS; 1227 p.num_data = 1; /* XXX why 1? */ 1228 p.s_buf = p.r_buf = p.data; 1229 p.data[0] = 0; 1230 pmgrop(&p); 1231 1232 return p.data[0]; 1233} 1234 1235void 1236pm_set_brightness(val) 1237 int val; 1238{ 1239 PMData p; 1240 1241 val = 0x7f - val / 2; 1242 if (val < 0x08) 1243 val = 0x08; 1244 if (val > 0x78) 1245 val = 0x78; 1246 1247 p.command = PMU_SET_BRIGHTNESS; 1248 p.num_data = 1; 1249 p.s_buf = p.r_buf = p.data; 1250 p.data[0] = val; 1251 pmgrop(&p); 1252} 1253 1254void 1255pm_init_brightness() 1256{ 1257 int val; 1258 1259 val = pm_read_brightness(); 1260 pm_set_brightness(val); 1261} 1262 1263void 1264pm_eject_pcmcia(slot) 1265 int slot; 1266{ 1267 PMData p; 1268 1269 if (slot != 0 && slot != 1) 1270 return; 1271 1272 p.command = PMU_EJECT_PCMCIA; 1273 p.num_data = 1; 1274 p.s_buf = p.r_buf = p.data; 1275 p.data[0] = 5 + slot; /* XXX */ 1276 pmgrop(&p); 1277} 1278 1279int 1280pm_read_nvram(addr) 1281 int addr; 1282{ 1283 PMData p; 1284 1285 p.command = PMU_READ_NVRAM; 1286 p.num_data = 2; 1287 p.s_buf = p.r_buf = p.data; 1288 p.data[0] = addr >> 8; 1289 p.data[1] = addr; 1290 pmgrop(&p); 1291 1292 return p.data[0]; 1293} 1294 1295void 1296pm_write_nvram(addr, val) 1297 int addr, val; 1298{ 1299 PMData p; 1300 1301 p.command = PMU_WRITE_NVRAM; 1302 p.num_data = 3; 1303 p.s_buf = p.r_buf = p.data; 1304 p.data[0] = addr >> 8; 1305 p.data[1] = addr; 1306 p.data[2] = val; 1307 pmgrop(&p); 1308} 1309