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