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