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