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