pm_direct.c revision 1.4
1/* $NetBSD: pm_direct.c,v 1.4 1998/02/23 03:11:26 scottr 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.22 01/09/97 Takashi Hamada */ 33 34#include "opt_adb.h" 35 36#ifdef DEBUG 37#ifndef ADB_DEBUG 38#define ADB_DEBUG 39#endif 40#endif 41 42/* #define PM_GRAB_SI 1 */ 43 44#include <sys/types.h> 45#include <sys/cdefs.h> 46#include <sys/systm.h> 47 48#include <machine/viareg.h> 49#include <machine/param.h> 50#include <machine/cpu.h> 51#include <machine/adbsys.h> 52 53#include <mac68k/mac68k/macrom.h> 54#include <mac68k/dev/adbvar.h> 55#include <mac68k/dev/pm_direct.h> 56 57/* hardware dependent values */ 58extern u_short ADBDelay; 59extern u_int32_t HwCfgFlags3; 60extern struct mac68k_machine_S mac68k_machine; 61 62 63/* define the types of the Power Manager */ 64#define PM_HW_UNKNOWN 0x00 /* don't know */ 65#define PM_HW_PB1XX 0x01 /* PowerBook 1XX series */ 66#define PM_HW_PB5XX 0x02 /* PowerBook Duo and 5XX series */ 67 68/* useful macros */ 69#define PM_SR() via_reg(VIA1, vSR) 70#define PM_VIA_INTR_ENABLE() via_reg(VIA1, vIER) = 0x90 71#define PM_VIA_INTR_DISABLE() via_reg(VIA1, vIER) = 0x10 72#define PM_VIA_CLR_INTR() via_reg(VIA1, vIFR) = 0x90 73#define PM_SET_STATE_ACKON() via_reg(VIA2, vBufB) |= 0x04 74#define PM_SET_STATE_ACKOFF() via_reg(VIA2, vBufB) &= ~0x04 75#define PM_IS_ON (0x02 == (via_reg(VIA2, vBufB) & 0x02)) 76#define PM_IS_OFF (0x00 == (via_reg(VIA2, vBufB) & 0x02)) 77 78/* 79 * Variables for internal use 80 */ 81int pmHardware = PM_HW_UNKNOWN; 82u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */ 83u_int pm_LCD_brightness = 0x0; 84u_int pm_LCD_contrast = 0x0; 85u_int pm_counter = 0; /* clock count */ 86 87/* these values shows that number of data returned after 'send' cmd is sent */ 88char pm_send_cmd_type[] = { 89 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 90 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 91 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 92 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 93 0xff, 0x00, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 94 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 95 0x04, 0x14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 96 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 97 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 98 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 99 0x01, 0x00, 0x02, 0x02, 0xff, 0x01, 0x03, 0x01, 100 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 101 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 103 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 104 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x04, 0x04, 105 0x04, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 106 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 107 0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 108 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 109 0x02, 0x02, 0x02, 0x04, 0xff, 0x00, 0xff, 0xff, 110 0x01, 0x01, 0x03, 0x02, 0xff, 0xff, 0xff, 0xff, 111 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 112 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 113 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 114 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 115 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 116 0x01, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 117 0xff, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 118 0x03, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 119 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 120 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 121}; 122 123/* these values shows that number of data returned after 'receive' cmd is sent */ 124char pm_receive_cmd_type[] = { 125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 126 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 127 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 128 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 130 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 132 0x05, 0x15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 134 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 136 0x02, 0x00, 0x03, 0x03, 0xff, 0xff, 0xff, 0xff, 137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 138 0x04, 0x04, 0x03, 0x09, 0xff, 0xff, 0xff, 0xff, 139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 140 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 142 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 144 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 146 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 148 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 150 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 152 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 153 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 154 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0xff, 0x00, 155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 156 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 157}; 158 159 160/* 161 * Define the private functions 162 */ 163 164/* for debugging */ 165#ifdef ADB_DEBUG 166void pm_printerr __P((char *, int, int, char *)); 167#endif 168 169int pm_wait_busy __P((int)); 170int pm_wait_free __P((int)); 171 172/* these functions are for the PB1XX series */ 173int pm_receive_pm1 __P((u_char *)); 174int pm_send_pm1 __P((u_char,int)); 175int pm_pmgrop_pm1 __P((PMData *)); 176void pm_intr_pm1 __P((void)); 177 178/* these functions are for the PB Duo series and the PB 5XX series */ 179int pm_receive_pm2 __P((u_char *)); 180int pm_send_pm2 __P((u_char)); 181int pm_pmgrop_pm2 __P((PMData *)); 182void pm_intr_pm2 __P((void)); 183 184/* this function is MRG-Based (for testing) */ 185int pm_pmgrop_mrg __P((PMData *)); 186 187/* these functions are called from adb_direct.c */ 188void pm_setup_adb __P((void)); 189void pm_check_adb_devices __P((int)); 190void pm_intr __P((void)); 191int pm_adb_op __P((u_char *, void *, void *, int)); 192 193/* these functions also use the variables of adb_direct.c */ 194void pm_adb_get_TALK_result __P((PMData *)); 195void pm_adb_get_ADB_data __P((PMData *)); 196void pm_adb_poll_next_device_pm1 __P((PMData *)); 197 198 199/* 200 * These variables are in adb_direct.c. 201 */ 202extern u_char *adbBuffer; /* pointer to user data area */ 203#define MAX_ADB_MSG_LENGTH 20 204extern u_char adbInputBuffer[MAX_ADB_MSG_LENGTH]; /* data input buffer */ 205extern void *adbCompRout; /* pointer to the completion routine */ 206extern void *adbCompData; /* pointer to the completion routine data */ 207extern int adbWaiting; /* waiting for return data from the device */ 208extern int adbWaitingCmd; /* ADB command we are waiting for */ 209extern int adbStarting; /* doing ADB reinit, so do "polling" differently */ 210 211/* 212 * Define the external functions 213 */ 214extern int zshard __P((int)); /* from zs.c */ 215extern void adb_comp_exec __P((void)); /* from adb_direct.c */ 216 217 218#ifdef ADB_DEBUG 219/* 220 * This function dumps contents of the PMData 221 */ 222void 223pm_printerr(ttl, rval, num, data) 224 char *ttl; 225 int rval; 226 int num; 227 char *data; 228{ 229 int i; 230 231 printf("pm: %s:%04x %02x ", ttl, rval, num); 232 for (i = 0; i < num; i++) 233 printf("%02x ", data[i]); 234 printf("\n"); 235} 236#endif 237 238 239 240/* 241 * Check the hardware type of the Power Manager 242 */ 243void 244pm_setup_adb() 245{ 246 switch (mac68k_machine.machineid) { 247 case MACH_MACPB140: 248 case MACH_MACPB145: 249 case MACH_MACPB150: 250 case MACH_MACPB160: 251 case MACH_MACPB165: 252 case MACH_MACPB165C: 253 case MACH_MACPB170: 254 case MACH_MACPB180: 255 case MACH_MACPB180C: 256 pmHardware = PM_HW_PB1XX; 257 break; 258 case MACH_MACPB210: 259 case MACH_MACPB230: 260 case MACH_MACPB250: 261 case MACH_MACPB270: 262 case MACH_MACPB280: 263 case MACH_MACPB280C: 264 case MACH_MACPB500: 265 pmHardware = PM_HW_PB5XX; 266 break; 267 default: 268 break; 269 } 270} 271 272 273/* 274 * Check the existent ADB devices 275 */ 276void 277pm_check_adb_devices(id) 278 int id; 279{ 280 u_short ed = 0x1; 281 282 ed <<= id; 283 pm_existent_ADB_devices |= ed; 284} 285 286 287/* 288 * Wait until PM IC is busy 289 */ 290int 291pm_wait_busy(delay) 292 int delay; 293{ 294 while (PM_IS_ON) { 295#ifdef PM_GRAB_SI 296 zshard(0); /* grab any serial interrupts */ 297#endif 298 if ((--delay) < 0) 299 return (1); /* timeout */ 300 } 301 return (0); 302} 303 304 305/* 306 * Wait until PM IC is free 307 */ 308int 309pm_wait_free(delay) 310 int delay; 311{ 312 while (PM_IS_OFF) { 313#ifdef PM_GRAB_SI 314 zshard(0); /* grab any serial interrupts */ 315#endif 316 if ((--delay) < 0) 317 return (0); /* timeout */ 318 } 319 return (1); 320} 321 322 323 324/* 325 * Functions for the PB1XX series 326 */ 327 328/* 329 * Receive data from PM for the PB1XX series 330 */ 331int 332pm_receive_pm1(data) 333 u_char *data; 334{ 335 int rval = 0xffffcd34; 336 337 via_reg(VIA2, vDirA) = 0x00; 338 339 switch (1) { 340 default: 341 if (pm_wait_busy(0x40) != 0) 342 break; /* timeout */ 343 344 PM_SET_STATE_ACKOFF(); 345 *data = via_reg(VIA2, 0x200); 346 347 rval = 0xffffcd33; 348 if (pm_wait_free(0x40) == 0) 349 break; /* timeout */ 350 351 rval = 0x00; 352 break; 353 } 354 355 PM_SET_STATE_ACKON(); 356 via_reg(VIA2, vDirA) = 0x00; 357 358 return (rval); 359} 360 361 362 363/* 364 * Send data to PM for the PB1XX series 365 */ 366int 367pm_send_pm1(data, delay) 368 u_char data; 369 int delay; 370{ 371 int rval; 372 373 via_reg(VIA2, vDirA) = 0xff; 374 via_reg(VIA2, 0x200) = data; 375 376 PM_SET_STATE_ACKOFF(); 377 if (pm_wait_busy(0x400) != 0) { 378 PM_SET_STATE_ACKON(); 379 via_reg(VIA2, vDirA) = 0x00; 380 381 return (0xffffcd36); 382 } 383 384 rval = 0x0; 385 PM_SET_STATE_ACKON(); 386 if (pm_wait_free(0x40) == 0) 387 rval = 0xffffcd35; 388 389 PM_SET_STATE_ACKON(); 390 via_reg(VIA2, vDirA) = 0x00; 391 392 return (rval); 393} 394 395 396/* 397 * My PMgrOp routine for the PB1XX series 398 */ 399int 400pm_pmgrop_pm1(pmdata) 401 PMData *pmdata; 402{ 403 int i; 404 int s = 0x81815963; 405 u_char via1_vIER, via1_vDirA; 406 int rval = 0; 407 int num_pm_data = 0; 408 u_char pm_cmd; 409 u_char pm_data; 410 u_char *pm_buf; 411 412 /* disable all inetrrupts but PM */ 413 via1_vIER = via_reg(VIA1, vIER); 414 PM_VIA_INTR_DISABLE(); 415 416 via1_vDirA = via_reg(VIA1, vDirA); 417 418 switch (pmdata->command) { 419 default: 420 for (i = 0; i < 7; i++) { 421 via_reg(VIA2, vDirA) = 0x00; 422 423 /* wait until PM is free */ 424 if (pm_wait_free(ADBDelay) == 0) { /* timeout */ 425 via_reg(VIA2, vDirA) = 0x00; 426 /* restore formar value */ 427 via_reg(VIA1, vDirA) = via1_vDirA; 428 via_reg(VIA1, vIER) = via1_vIER; 429 return (0xffffcd38); 430 } 431 432 switch (mac68k_machine.machineid) { 433 case MACH_MACPB160: 434 case MACH_MACPB165: 435 case MACH_MACPB165C: 436 case MACH_MACPB180: 437 case MACH_MACPB180C: 438 { 439 int delay = ADBDelay * 16; 440 441 via_reg(VIA2, vDirA) = 0x00; 442 while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0)) 443 delay--; 444 445 if (delay < 0) { /* timeout */ 446 via_reg(VIA2, vDirA) = 0x00; 447 /* restore formar value */ 448 via_reg(VIA1, vIER) = via1_vIER; 449 return (0xffffcd38); 450 } 451 } 452 } /* end switch */ 453 454 s = splhigh(); 455 456 via1_vDirA = via_reg(VIA1, vDirA); 457 via_reg(VIA1, vDirA) &= 0x7f; 458 459 pm_cmd = (u_char)(pmdata->command & 0xff); 460 if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0) 461 break; /* send command succeeded */ 462 463 via_reg(VIA1, vDirA) = via1_vDirA; 464 splx(s); 465 } /* end for */ 466 467 /* failed to send a command */ 468 if (i == 7) { 469 via_reg(VIA2, vDirA) = 0x00; 470 /* restore formar value */ 471 via_reg(VIA1, vDirA) = via1_vDirA; 472 via_reg(VIA1, vIER) = via1_vIER; 473 return (0xffffcd38); 474 } 475 476 /* send # of PM data */ 477 num_pm_data = pmdata->num_data; 478 if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0) 479 break; /* timeout */ 480 481 /* send PM data */ 482 pm_buf = (u_char *)pmdata->s_buf; 483 for (i = 0; i < num_pm_data; i++) 484 if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0) 485 break; /* timeout */ 486 if ((i != num_pm_data) && (num_pm_data != 0)) 487 break; /* timeout */ 488 489 /* Will PM IC return data? */ 490 if ((pm_cmd & 0x08) == 0) { 491 rval = 0; 492 break; /* no returned data */ 493 } 494 495 rval = 0xffffcd37; 496 if (pm_wait_busy(ADBDelay) != 0) 497 break; /* timeout */ 498 499 /* receive PM command */ 500 if ((rval = pm_receive_pm1(&pm_data)) != 0) 501 break; 502 503 pmdata->command = pm_data; 504 505 /* receive number of PM data */ 506 if ((rval = pm_receive_pm1(&pm_data)) != 0) 507 break; /* timeout */ 508 num_pm_data = pm_data; 509 pmdata->num_data = num_pm_data; 510 511 /* receive PM data */ 512 pm_buf = (u_char *)pmdata->r_buf; 513 for (i = 0; i < num_pm_data; i++) { 514 if ((rval = pm_receive_pm1(&pm_data)) != 0) 515 break; /* timeout */ 516 pm_buf[i] = pm_data; 517 } 518 519 rval = 0; 520 } 521 522 via_reg(VIA2, vDirA) = 0x00; 523 524 /* restore formar value */ 525 via_reg(VIA1, vDirA) = via1_vDirA; 526 via_reg(VIA1, vIER) = via1_vIER; 527 if (s != 0x81815963) 528 splx(s); 529 530 return (rval); 531} 532 533 534/* 535 * My PM interrupt routine for PB100-series 536 */ 537void 538pm_intr_pm1() 539{ 540 int s; 541 int rval; 542 PMData pmdata; 543 544 s = splhigh(); 545 546 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ 547 548 /* ask PM what happend */ 549 pmdata.command = 0x78; 550 pmdata.num_data = 0; 551 pmdata.data[0] = pmdata.data[1] = 0; 552 pmdata.s_buf = &pmdata.data[2]; 553 pmdata.r_buf = &pmdata.data[2]; 554 rval = pm_pmgrop_pm1(&pmdata); 555 if (rval != 0) { 556#ifdef ADB_DEBUG 557 if (adb_debug) 558 printf("pm: PM is not ready. error code=%08x\n", rval); 559#endif 560 splx(s); 561 } 562 563 if ((pmdata.data[2] & 0x10) == 0x10) { 564 if ((pmdata.data[2] & 0x0f) == 0) { 565 /* ADB data that were requested by TALK command */ 566 pm_adb_get_TALK_result(&pmdata); 567 } else if ((pmdata.data[2] & 0x08) == 0x8) { 568 /* PM is requesting to poll */ 569 pm_adb_poll_next_device_pm1(&pmdata); 570 } else if ((pmdata.data[2] & 0x04) == 0x4) { 571 /* ADB device event */ 572 pm_adb_get_ADB_data(&pmdata); 573 } 574 } else { 575#ifdef ADB_DEBUG 576 if (adb_debug) 577 pm_printerr("driver does not supported this event.", 578 rval, pmdata.num_data, pmdata.data); 579#endif 580 } 581 582 splx(s); 583} 584 585 586 587/* 588 * Functions for the PB Duo series and the PB 5XX series 589 */ 590 591/* 592 * Receive data from PM for the PB Duo series and the PB 5XX series 593 */ 594int 595pm_receive_pm2(data) 596 u_char *data; 597{ 598 int i; 599 int rval; 600 601 rval = 0xffffcd34; 602 603 switch (1) { 604 default: 605 /* set VIA SR to input mode */ 606 via_reg(VIA1, vACR) |= 0x0c; 607 via_reg(VIA1, vACR) &= ~0x10; 608 i = PM_SR(); 609 610 PM_SET_STATE_ACKOFF(); 611 if (pm_wait_busy((int)ADBDelay*32) != 0) 612 break; /* timeout */ 613 614 PM_SET_STATE_ACKON(); 615 rval = 0xffffcd33; 616 if (pm_wait_free((int)ADBDelay*32) == 0) 617 break; /* timeout */ 618 619 *data = PM_SR(); 620 rval = 0; 621 622 break; 623 } 624 625 PM_SET_STATE_ACKON(); 626 via_reg(VIA1, vACR) |= 0x1c; 627 628 return (rval); 629} 630 631 632 633/* 634 * Send data to PM for the PB Duo series and the PB 5XX series 635 */ 636int 637pm_send_pm2(data) 638 u_char data; 639{ 640 int rval; 641 642 via_reg(VIA1, vACR) |= 0x1c; 643 PM_SR() = data; 644 645 PM_SET_STATE_ACKOFF(); 646 rval = 0xffffcd36; 647 if (pm_wait_busy((int)ADBDelay*32) != 0) { 648 PM_SET_STATE_ACKON(); 649 650 via_reg(VIA1, vACR) |= 0x1c; 651 652 return (rval); 653 } 654 655 PM_SET_STATE_ACKON(); 656 rval = 0xffffcd35; 657 if (pm_wait_free((int)ADBDelay*32) != 0) 658 rval = 0; 659 660 PM_SET_STATE_ACKON(); 661 via_reg(VIA1, vACR) |= 0x1c; 662 663 return (rval); 664} 665 666 667 668/* 669 * My PMgrOp routine for the PB Duo series and the PB 5XX series 670 */ 671int 672pm_pmgrop_pm2(pmdata) 673 PMData *pmdata; 674{ 675 int i; 676 int s; 677 u_char via1_vIER; 678 int rval = 0; 679 int num_pm_data = 0; 680 u_char pm_cmd; 681 short pm_num_rx_data; 682 u_char pm_data; 683 u_char *pm_buf; 684 685 s = splhigh(); 686 687 /* disable all inetrrupts but PM */ 688 via1_vIER = 0x10; 689 via1_vIER &= via_reg(VIA1, vIER); 690 via_reg(VIA1, vIER) = via1_vIER; 691 if (via1_vIER != 0x0) 692 via1_vIER |= 0x80; 693 694 switch (pmdata->command) { 695 default: 696 /* wait until PM is free */ 697 pm_cmd = (u_char)(pmdata->command & 0xff); 698 rval = 0xcd38; 699 if (pm_wait_free(ADBDelay * 4) == 0) 700 break; /* timeout */ 701 702 if (HwCfgFlags3 & 0x00200000) { 703 /* PB 160, PB 165(c), PB 180(c)? */ 704 int delay = ADBDelay * 16; 705 706 via_reg(VIA2, vDirA) = 0x00; 707 while ((via_reg(VIA2, 0x200) == 0x07) && 708 (delay >= 0)) 709 delay--; 710 711 if (delay < 0) { 712 rval = 0xffffcd38; 713 break; /* timeout */ 714 } 715 } 716 717 /* send PM command */ 718 if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff)))) 719 break; /* timeout */ 720 721 /* send number of PM data */ 722 num_pm_data = pmdata->num_data; 723 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 724 if (pm_send_cmd_type[pm_cmd] < 0) { 725 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0) 726 break; /* timeout */ 727 pmdata->command = 0; 728 } 729 } else { /* PB 1XX series ? */ 730 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0) 731 break; /* timeout */ 732 } 733 /* send PM data */ 734 pm_buf = (u_char *)pmdata->s_buf; 735 for (i = 0 ; i < num_pm_data; i++) 736 if ((rval = pm_send_pm2(pm_buf[i])) != 0) 737 break; /* timeout */ 738 if (i != num_pm_data) 739 break; /* timeout */ 740 741 742 /* check if PM will send me data */ 743 pm_num_rx_data = pm_receive_cmd_type[pm_cmd]; 744 pmdata->num_data = pm_num_rx_data; 745 if (pm_num_rx_data == 0) { 746 rval = 0; 747 break; /* no return data */ 748 } 749 750 /* receive PM command */ 751 pm_data = pmdata->command; 752 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 753 pm_num_rx_data--; 754 if (pm_num_rx_data == 0) 755 if ((rval = pm_receive_pm2(&pm_data)) != 0) { 756 rval = 0xffffcd37; 757 break; 758 } 759 pmdata->command = pm_data; 760 } else { /* PB 1XX series ? */ 761 if ((rval = pm_receive_pm2(&pm_data)) != 0) { 762 rval = 0xffffcd37; 763 break; 764 } 765 pmdata->command = pm_data; 766 } 767 768 /* receive number of PM data */ 769 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 770 if (pm_num_rx_data < 0) { 771 if ((rval = pm_receive_pm2(&pm_data)) != 0) 772 break; /* timeout */ 773 num_pm_data = pm_data; 774 } else 775 num_pm_data = pm_num_rx_data; 776 pmdata->num_data = num_pm_data; 777 } else { /* PB 1XX serias ? */ 778 if ((rval = pm_receive_pm2(&pm_data)) != 0) 779 break; /* timeout */ 780 num_pm_data = pm_data; 781 pmdata->num_data = num_pm_data; 782 } 783 784 /* receive PM data */ 785 pm_buf = (u_char *)pmdata->r_buf; 786 for (i = 0; i < num_pm_data; i++) { 787 if ((rval = pm_receive_pm2(&pm_data)) != 0) 788 break; /* timeout */ 789 pm_buf[i] = pm_data; 790 } 791 792 rval = 0; 793 } 794 795 /* restore former value */ 796 via_reg(VIA1, vIER) = via1_vIER; 797 splx(s); 798 799 return (rval); 800} 801 802 803/* 804 * My PM interrupt routine for the PB Duo series and the PB 5XX series 805 */ 806void 807pm_intr_pm2() 808{ 809 int s; 810 int rval; 811 PMData pmdata; 812 813 s = splhigh(); 814 815 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ 816 /* ask PM what happend */ 817 pmdata.command = 0x78; 818 pmdata.num_data = 0; 819 pmdata.s_buf = &pmdata.data[2]; 820 pmdata.r_buf = &pmdata.data[2]; 821 rval = pm_pmgrop_pm2(&pmdata); 822 if (rval != 0) { 823#ifdef ADB_DEBUG 824 if (adb_debug) 825 printf("pm: PM is not ready. error code: %08x\n", rval); 826#endif 827 splx(s); 828 } 829 830 switch ((u_int)(pmdata.data[2] & 0xff)) { 831 case 0x00: /* 1 sec interrupt? */ 832 break; 833 case 0x80: /* 1 sec interrupt? */ 834 pm_counter++; 835 break; 836 case 0x08: /* Brightness/Contrast button on LCD panel */ 837 /* get brightness and contrast of the LCD */ 838 pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff; 839 pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff; 840/* 841 pm_printerr("#08", rval, pmdata.num_data, pmdata.data); 842 pmdata.command = 0x33; 843 pmdata.num_data = 1; 844 pmdata.s_buf = pmdata.data; 845 pmdata.r_buf = pmdata.data; 846 pmdata.data[0] = pm_LCD_contrast; 847 rval = pm_pmgrop_pm2(&pmdata); 848 pm_printerr("#33", rval, pmdata.num_data, pmdata.data); 849*/ 850 /* this is an experimental code */ 851 pmdata.command = 0x41; 852 pmdata.num_data = 1; 853 pmdata.s_buf = pmdata.data; 854 pmdata.r_buf = pmdata.data; 855 pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2; 856 if (pm_LCD_brightness < 0x25) 857 pm_LCD_brightness = 0x25; 858 if (pm_LCD_brightness > 0x5a) 859 pm_LCD_brightness = 0x7f; 860 pmdata.data[0] = pm_LCD_brightness; 861 rval = pm_pmgrop_pm2(&pmdata); 862 break; 863 case 0x10: /* ADB data that were requested by TALK command */ 864 case 0x14: 865 pm_adb_get_TALK_result(&pmdata); 866 break; 867 case 0x16: /* ADB device event */ 868 case 0x18: 869 case 0x1e: 870 pm_adb_get_ADB_data(&pmdata); 871 break; 872 default: 873#ifdef ADB_DEBUG 874 if (adb_debug) 875 pm_printerr("driver does not supported this event.", 876 pmdata.data[2], pmdata.num_data, 877 pmdata.data); 878#endif 879 break; 880 } 881 882 splx(s); 883} 884 885 886/* 887 * MRG-based PMgrOp routine 888 */ 889int 890pm_pmgrop_mrg(pmdata) 891 PMData *pmdata; 892{ 893 u_int32_t rval=0; 894 895 asm(" 896 movl %1, a0 897 .word 0xa085 898 movl d0, %0" 899 : "=g" (rval) 900 : "g" (pmdata) 901 : "a0", "d0" ); 902 903 return rval; 904} 905 906 907/* 908 * My PMgrOp routine 909 */ 910int 911pmgrop(pmdata) 912 PMData *pmdata; 913{ 914 switch (pmHardware) { 915 case PM_HW_PB1XX: 916 return (pm_pmgrop_pm1(pmdata)); 917 break; 918 case PM_HW_PB5XX: 919 return (pm_pmgrop_pm2(pmdata)); 920 break; 921 default: 922 /* return (pmgrop_mrg(pmdata)); */ 923 return (-1); 924 } 925} 926 927 928/* 929 * My PM interrupt routine 930 */ 931void 932pm_intr() 933{ 934 switch (pmHardware) { 935 case PM_HW_PB1XX: 936 pm_intr_pm1(); 937 break; 938 case PM_HW_PB5XX: 939 pm_intr_pm2(); 940 break; 941 default: 942 break; 943 } 944} 945 946 947 948/* 949 * Synchronous ADBOp routine for the Power Manager 950 */ 951int 952pm_adb_op(buffer, compRout, data, command) 953 u_char *buffer; 954 void *compRout; 955 void *data; 956 int command; 957{ 958 int i, len; 959 int s; 960 int rval; 961 int delay; 962 PMData pmdata; 963 964 if (adbWaiting == 1) 965 return (-1); 966 967 s = splhigh(); 968 via_reg(VIA1, vIER) = 0x10; 969 970 adbBuffer = buffer; 971 adbCompRout = compRout; 972 adbCompData = data; 973 974 pmdata.command = 0x20; 975 pmdata.s_buf = pmdata.data; 976 pmdata.r_buf = pmdata.data; 977 978 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, add number of ADB data to number of PM data */ 979 if (buffer != (u_char *)0) 980 pmdata.num_data = buffer[0] + 3; 981 } else { 982 pmdata.num_data = 3; 983 } 984 985 pmdata.data[0] = (u_char)(command & 0xff); 986 pmdata.data[1] = 0; 987 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */ 988 if ((buffer != (u_char *)0) && (buffer[0] <= 24)) { 989 pmdata.data[2] = buffer[0]; /* number of data */ 990 for (i = 0; i < buffer[0]; i++) 991 pmdata.data[3 + i] = buffer[1 + i]; 992 } else 993 pmdata.data[2] = 0; 994 } else 995 pmdata.data[2] = 0; 996 997 rval = pmgrop(&pmdata); 998 if (rval != 0) 999 return (-1); 1000 1001 if (adbWaiting == 0) { 1002 adbWaiting = 1; 1003 adbWaitingCmd = command; 1004 } 1005 1006 PM_VIA_INTR_ENABLE(); 1007 1008 /* wait until the PM interrupt is occured */ 1009 delay = 0x80000; 1010 while (adbWaiting == 1) { 1011 if ((via_reg(VIA1, vIFR) & 0x10) == 0x10) 1012 pm_intr(); 1013#ifdef PM_GRAB_SI 1014 zshard(0); /* grab any serial interrupts */ 1015#endif 1016 if ((--delay) < 0) 1017 return (-1); 1018 } 1019 1020 if (buffer != (u_char *)0) { 1021 len = adbInputBuffer[3]; 1022 for (i=0; i<=len; i++) 1023 buffer[i] = adbInputBuffer[3 + i]; 1024 if (len < 0) 1025 buffer[0] = 0; 1026 } 1027 1028 /* this command enables the interrupt by operating ADB devices */ 1029 if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 500 series */ 1030 pmdata.command = 0x20; 1031 pmdata.num_data = 4; 1032 pmdata.s_buf = pmdata.data; 1033 pmdata.r_buf = pmdata.data; 1034 pmdata.data[0] = 0x00; 1035 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */ 1036 pmdata.data[2] = 0x00; 1037 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */ 1038 } else { /* PB 100-series */ 1039 pmdata.command = 0x20; 1040 pmdata.num_data = 3; 1041 pmdata.s_buf = pmdata.data; 1042 pmdata.r_buf = pmdata.data; 1043 pmdata.data[0] = (u_char)(command & 0xf0) | 0xc; 1044 pmdata.data[1] = 0x04; 1045 pmdata.data[2] = 0x00; 1046 } 1047 rval = pmgrop(&pmdata); 1048 1049 splx(s); 1050 return (rval); 1051} 1052 1053 1054void 1055pm_adb_get_TALK_result(pmdata) 1056 PMData *pmdata; 1057{ 1058 int i; 1059 int rx_pm_adb_cmd; 1060 1061 rx_pm_adb_cmd = (u_int)pmdata->data[3] & 0xff; 1062 1063 pmdata->data[2] &= 0xf; 1064 pmdata->data[1] = pmdata->data[3]; 1065 pmdata->data[3] = pmdata->num_data - 2; 1066 1067 adbInputBuffer[0] = pmdata->num_data + 1; 1068 for (i = 1; i < pmdata->num_data + 2; i++) 1069 adbInputBuffer[i] = pmdata->data[i]; 1070 1071 if ((adbWaiting == 1) && (rx_pm_adb_cmd == adbWaitingCmd)) { 1072 if (adbStarting == 0) 1073 adb_complete(&pmdata->data[3], (long)0, adbWaitingCmd); 1074 adbWaitingCmd = 0x0; 1075 1076 adbWaiting = 0; 1077 adb_comp_exec(); 1078 adbBuffer = (long)0; 1079 adbCompRout = (long)0; 1080 adbCompData = (long)0; 1081 } 1082} 1083 1084 1085void 1086pm_adb_get_ADB_data(pmdata) 1087 PMData *pmdata; 1088{ 1089 int i; 1090 1091 i = (u_int)pmdata->data[3] & 0xff; 1092 pmdata->data[2] &= 0xf; 1093 pmdata->data[1] = pmdata->data[3]; 1094 pmdata->data[3] = pmdata->num_data - 2; 1095 1096 adbInputBuffer[0] = pmdata->num_data + 1; 1097 if (adbStarting == 0) 1098 adb_complete(&pmdata->data[3], (long)0, i); 1099} 1100 1101 1102void 1103pm_adb_poll_next_device_pm1(pmdata) 1104 PMData *pmdata; 1105{ 1106 int i; 1107 int ndid; 1108 u_short bendid = 0x1; 1109 int rval; 1110 PMData tmp_pmdata; 1111 1112 /* find another existent ADB device to poll */ 1113 for (i = 1; i < 16; i++) { 1114 ndid = (((pmdata->data[3] & 0xf0) >> 4) + i) & 0xf; 1115 bendid <<= ndid; 1116 if ((pm_existent_ADB_devices & bendid) != 0) 1117 break; 1118 } 1119 1120 /* poll the other device */ 1121 tmp_pmdata.command = 0x20; 1122 tmp_pmdata.num_data = 3; 1123 tmp_pmdata.s_buf = tmp_pmdata.data; 1124 tmp_pmdata.r_buf = tmp_pmdata.data; 1125 tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc; 1126 tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */ 1127 tmp_pmdata.data[2] = 0x00; 1128 rval = pmgrop(&tmp_pmdata); 1129} 1130 1131 1132