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