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