1 /* $NetBSD: pm_direct.c,v 1.17 2002/01/02 20:28:43 dbj 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 54 extern 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 */ 85 int pmHardware = PM_HW_UNKNOWN; 86 u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */ 87 u_int pm_LCD_brightness = 0x0; 88 u_int pm_LCD_contrast = 0x0; 89 u_int pm_counter = 0; /* clock count */ 90 91 /* these values shows that number of data returned after 'send' cmd is sent */ 92 signed 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 */ 128 signed 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 170 void pm_printerr __P((char *, int, int, char *)); 171 #endif 172 173 int pm_wait_busy __P((int)); 174 int pm_wait_free __P((int)); 175 176 /* these functions are for the PB1XX series */ 177 int pm_receive_pm1 __P((u_char *)); 178 int pm_send_pm1 __P((u_char,int)); 179 int pm_pmgrop_pm1 __P((PMData *)); 180 void pm_intr_pm1 __P((void)); 181 182 /* these functions are for the PB Duo series and the PB 5XX series */ 183 int pm_receive_pm2 __P((u_char *)); 184 int pm_send_pm2 __P((u_char)); 185 int pm_pmgrop_pm2 __P((PMData *)); 186 void pm_intr_pm2 __P((void)); 187 188 /* these functions are called from adb_direct.c */ 189 void pm_setup_adb __P((void)); 190 void pm_check_adb_devices __P((int)); 191 void pm_intr __P((void)); 192 int pm_adb_op __P((u_char *, void *, void *, int)); 193 194 /* these functions also use the variables of adb_direct.c */ 195 void pm_adb_get_TALK_result __P((PMData *)); 196 void pm_adb_get_ADB_data __P((PMData *)); 197 void pm_adb_poll_next_device_pm1 __P((PMData *)); 198 199 200 /* 201 * These variables are in adb_direct.c. 202 */ 203 extern u_char *adbBuffer; /* pointer to user data area */ 204 extern void *adbCompRout; /* pointer to the completion routine */ 205 extern void *adbCompData; /* pointer to the completion routine data */ 206 extern int adbWaiting; /* waiting for return data from the device */ 207 extern int adbWaitingCmd; /* ADB command we are waiting for */ 208 extern int adbStarting; /* doing ADB reinit, so do "polling" differently */ 209 210 #define ADB_MAX_MSG_LENGTH 16 211 #define ADB_MAX_HDR_LENGTH 8 212 struct 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 }; 222 extern void adb_pass_up __P((struct adbCommand *)); 223 224 #if 0 225 /* 226 * Define the external functions 227 */ 228 extern int zshard __P((int)); /* from zs.c */ 229 #endif 230 231 #ifdef ADB_DEBUG 232 /* 233 * This function dumps contents of the PMData 234 */ 235 void 236 pm_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 */ 256 void 257 pm_setup_adb() 258 { 259 pmHardware = PM_HW_PB5XX; /* XXX */ 260 } 261 262 263 /* 264 * Check the existent ADB devices 265 */ 266 void 267 pm_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 */ 280 int 281 pm_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 */ 302 int 303 pm_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 */ 329 int 330 pm_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 */ 368 int 369 pm_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 */ 405 int 406 pm_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 */ 549 void 550 pm_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 */ 610 int 611 pm_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 */ 652 int 653 pm_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 */ 687 int 688 pm_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 */ 822 void 823 pm_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 */ 905 int 906 pmgrop(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 */ 926 void 927 pm_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 */ 946 int 947 pm_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 has occurred */ 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 /* Try to take an interrupt anyway, just in case. 1038 * This has been observed to happen on my ibook 1039 * when i press a key after boot and before adb 1040 * is attached; For example, when booting with -d. 1041 */ 1042 pm_intr(); 1043 if (adbWaiting) { 1044 printf("pm_adb_op: timeout. command = 0x%x\n",command); 1045 splx(s); 1046 return 1; 1047 } 1048 #ifdef ADB_DEBUG 1049 else { 1050 printf("pm_adb_op: missed interrupt. cmd=0x%x\n",command); 1051 } 1052 #endif 1053 } 1054 } 1055 1056 /* this command enables the interrupt by operating ADB devices */ 1057 if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX series */ 1058 pmdata.command = 0x20; 1059 pmdata.num_data = 4; 1060 pmdata.s_buf = pmdata.data; 1061 pmdata.r_buf = pmdata.data; 1062 pmdata.data[0] = 0x00; 1063 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */ 1064 pmdata.data[2] = 0x00; 1065 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */ 1066 } else { /* PB 1XX series */ 1067 pmdata.command = 0x20; 1068 pmdata.num_data = 3; 1069 pmdata.s_buf = pmdata.data; 1070 pmdata.r_buf = pmdata.data; 1071 pmdata.data[0] = (u_char)(command & 0xf0) | 0xc; 1072 pmdata.data[1] = 0x04; 1073 pmdata.data[2] = 0x00; 1074 } 1075 rval = pmgrop(&pmdata); 1076 1077 splx(s); 1078 return rval; 1079 } 1080 1081 1082 void 1083 pm_adb_get_TALK_result(pmdata) 1084 PMData *pmdata; 1085 { 1086 int i; 1087 struct adbCommand packet; 1088 1089 /* set up data for adb_pass_up */ 1090 packet.data[0] = pmdata->num_data-1; 1091 packet.data[1] = pmdata->data[3]; 1092 for (i = 0; i <packet.data[0]-1; i++) 1093 packet.data[i+2] = pmdata->data[i+4]; 1094 1095 packet.saveBuf = adbBuffer; 1096 packet.compRout = adbCompRout; 1097 packet.compData = adbCompData; 1098 packet.unsol = 0; 1099 packet.ack_only = 0; 1100 adb_polling = 1; 1101 adb_pass_up(&packet); 1102 adb_polling = 0; 1103 1104 adbWaiting = 0; 1105 adbBuffer = (long)0; 1106 adbCompRout = (long)0; 1107 adbCompData = (long)0; 1108 } 1109 1110 1111 void 1112 pm_adb_get_ADB_data(pmdata) 1113 PMData *pmdata; 1114 { 1115 int i; 1116 struct adbCommand packet; 1117 1118 /* set up data for adb_pass_up */ 1119 packet.data[0] = pmdata->num_data-1; /* number of raw data */ 1120 packet.data[1] = pmdata->data[3]; /* ADB command */ 1121 for (i = 0; i <packet.data[0]-1; i++) 1122 packet.data[i+2] = pmdata->data[i+4]; 1123 packet.unsol = 1; 1124 packet.ack_only = 0; 1125 adb_pass_up(&packet); 1126 } 1127 1128 1129 void 1130 pm_adb_poll_next_device_pm1(pmdata) 1131 PMData *pmdata; 1132 { 1133 int i; 1134 int ndid; 1135 u_short bendid = 0x1; 1136 int rval; 1137 PMData tmp_pmdata; 1138 1139 /* find another existent ADB device to poll */ 1140 for (i = 1; i < 16; i++) { 1141 ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf; 1142 bendid <<= ndid; 1143 if ((pm_existent_ADB_devices & bendid) != 0) 1144 break; 1145 } 1146 1147 /* poll the other device */ 1148 tmp_pmdata.command = 0x20; 1149 tmp_pmdata.num_data = 3; 1150 tmp_pmdata.s_buf = tmp_pmdata.data; 1151 tmp_pmdata.r_buf = tmp_pmdata.data; 1152 tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc; 1153 tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */ 1154 tmp_pmdata.data[2] = 0x00; 1155 rval = pmgrop(&tmp_pmdata); 1156 } 1157 1158 void 1159 pm_adb_restart() 1160 { 1161 PMData p; 1162 1163 p.command = PMU_RESET_CPU; 1164 p.num_data = 0; 1165 p.s_buf = p.data; 1166 p.r_buf = p.data; 1167 pmgrop(&p); 1168 } 1169 1170 void 1171 pm_adb_poweroff() 1172 { 1173 PMData p; 1174 1175 p.command = PMU_POWER_OFF; 1176 p.num_data = 4; 1177 p.s_buf = p.data; 1178 p.r_buf = p.data; 1179 strcpy(p.data, "MATT"); 1180 pmgrop(&p); 1181 } 1182 1183 void 1184 pm_read_date_time(time) 1185 u_long *time; 1186 { 1187 PMData p; 1188 1189 p.command = PMU_READ_RTC; 1190 p.num_data = 0; 1191 p.s_buf = p.data; 1192 p.r_buf = p.data; 1193 pmgrop(&p); 1194 1195 memcpy(time, p.data, 4); 1196 } 1197 1198 void 1199 pm_set_date_time(time) 1200 u_long time; 1201 { 1202 PMData p; 1203 1204 p.command = PMU_SET_RTC; 1205 p.num_data = 4; 1206 p.s_buf = p.r_buf = p.data; 1207 memcpy(p.data, &time, 4); 1208 pmgrop(&p); 1209 } 1210 1211 int 1212 pm_read_brightness() 1213 { 1214 PMData p; 1215 1216 p.command = PMU_READ_BRIGHTNESS; 1217 p.num_data = 1; /* XXX why 1? */ 1218 p.s_buf = p.r_buf = p.data; 1219 p.data[0] = 0; 1220 pmgrop(&p); 1221 1222 return p.data[0]; 1223 } 1224 1225 void 1226 pm_set_brightness(val) 1227 int val; 1228 { 1229 PMData p; 1230 1231 val = 0x7f - val / 2; 1232 if (val < 0x08) 1233 val = 0x08; 1234 if (val > 0x78) 1235 val = 0x78; 1236 1237 p.command = PMU_SET_BRIGHTNESS; 1238 p.num_data = 1; 1239 p.s_buf = p.r_buf = p.data; 1240 p.data[0] = val; 1241 pmgrop(&p); 1242 } 1243 1244 void 1245 pm_init_brightness() 1246 { 1247 int val; 1248 1249 val = pm_read_brightness(); 1250 pm_set_brightness(val); 1251 } 1252 1253 void 1254 pm_eject_pcmcia(slot) 1255 int slot; 1256 { 1257 PMData p; 1258 1259 if (slot != 0 && slot != 1) 1260 return; 1261 1262 p.command = PMU_EJECT_PCMCIA; 1263 p.num_data = 1; 1264 p.s_buf = p.r_buf = p.data; 1265 p.data[0] = 5 + slot; /* XXX */ 1266 pmgrop(&p); 1267 } 1268 1269 int 1270 pm_read_nvram(addr) 1271 int addr; 1272 { 1273 PMData p; 1274 1275 p.command = PMU_READ_NVRAM; 1276 p.num_data = 2; 1277 p.s_buf = p.r_buf = p.data; 1278 p.data[0] = addr >> 8; 1279 p.data[1] = addr; 1280 pmgrop(&p); 1281 1282 return p.data[0]; 1283 } 1284 1285 void 1286 pm_write_nvram(addr, val) 1287 int addr, val; 1288 { 1289 PMData p; 1290 1291 p.command = PMU_WRITE_NVRAM; 1292 p.num_data = 3; 1293 p.s_buf = p.r_buf = p.data; 1294 p.data[0] = addr >> 8; 1295 p.data[1] = addr; 1296 p.data[2] = val; 1297 pmgrop(&p); 1298 } 1299