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