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