Annotation of sys/arch/macppc/dev/pm_direct.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pm_direct.c,v 1.22 2007/02/18 19:33:48 gwk Exp $ */
! 2: /* $NetBSD: pm_direct.c,v 1.9 2000/06/08 22:10:46 tsubai Exp $ */
! 3:
! 4: /*
! 5: * Copyright (C) 1997 Takashi Hamada
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. All advertising materials mentioning features or use of this software
! 17: * must display the following acknowledgement:
! 18: * This product includes software developed by Takashi Hamada
! 19: * 4. The name of the author may not be used to endorse or promote products
! 20: * derived from this software without specific prior written permission.
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
! 31: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 32: */
! 33:
! 34: #ifdef DEBUG
! 35: #ifndef ADB_DEBUG
! 36: #define ADB_DEBUG
! 37: #endif
! 38: #endif
! 39:
! 40: /* #define PM_GRAB_SI 1 */
! 41:
! 42: #include <sys/param.h>
! 43: #include <sys/cdefs.h>
! 44: #include <sys/device.h>
! 45: #include <sys/systm.h>
! 46:
! 47: #include <machine/cpu.h>
! 48:
! 49: #include <dev/adb/adb.h>
! 50: #include <macppc/dev/adbvar.h>
! 51: #include <macppc/dev/pm_direct.h>
! 52: #include <macppc/dev/viareg.h>
! 53:
! 54: /* hardware dependent values */
! 55: #define ADBDelay 100 /* XXX */
! 56:
! 57: /* define the types of the Power Manager */
! 58: #define PM_HW_UNKNOWN 0x00 /* don't know */
! 59: #define PM_HW_PB5XX 0x02 /* PowerBook Duo and 5XX series */
! 60:
! 61: /* useful macros */
! 62: #define PM_SR() read_via_reg(VIA1, vSR)
! 63: #define PM_VIA_INTR_ENABLE() write_via_reg(VIA1, vIER, 0x90)
! 64: #define PM_VIA_INTR_DISABLE() write_via_reg(VIA1, vIER, 0x10)
! 65: #define PM_VIA_CLR_INTR() write_via_reg(VIA1, vIFR, 0x90)
! 66: #if 0
! 67: #define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x04)
! 68: #define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x04)
! 69: #define PM_IS_ON (0x02 == (read_via_reg(VIA2, vBufB) & 0x02))
! 70: #define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x02))
! 71: #else
! 72: #define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x10)
! 73: #define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x10)
! 74: #define PM_IS_ON (0x08 == (read_via_reg(VIA2, vBufB) & 0x08))
! 75: #define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x08))
! 76: #endif
! 77:
! 78: /*
! 79: * Variables for internal use
! 80: */
! 81: int pmHardware = PM_HW_UNKNOWN;
! 82:
! 83: /* these values shows that number of data returned after 'send' cmd is sent */
! 84: signed char pm_send_cmd_type[] = {
! 85: -1, -1, -1, -1, -1, -1, -1, -1,
! 86: -1, -1, -1, -1, -1, -1, -1, -1,
! 87: 0x01, 0x01, -1, -1, -1, -1, -1, -1,
! 88: 0x00, 0x00, -1, -1, -1, -1, -1, 0x00,
! 89: -1, 0x00, 0x02, 0x01, 0x01, -1, -1, -1,
! 90: 0x00, -1, -1, -1, -1, -1, -1, -1,
! 91: 0x04, 0x14, -1, 0x03, -1, -1, -1, -1,
! 92: 0x00, 0x00, 0x02, 0x02, -1, -1, -1, -1,
! 93: 0x01, 0x01, -1, -1, -1, -1, -1, -1,
! 94: 0x00, 0x00, -1, -1, 0x01, -1, -1, -1,
! 95: 0x01, 0x00, 0x02, 0x02, -1, 0x01, 0x03, 0x01,
! 96: 0x00, 0x01, 0x00, 0x00, 0x00, -1, -1, -1,
! 97: 0x02, -1, -1, -1, -1, -1, -1, -1,
! 98: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, -1,
! 99: 0x01, 0x01, 0x01, -1, -1, -1, -1, -1,
! 100: 0x00, 0x00, -1, -1, -1, -1, 0x04, 0x04,
! 101: 0x04, -1, 0x00, -1, -1, -1, -1, -1,
! 102: 0x00, -1, -1, -1, -1, -1, -1, -1,
! 103: 0x01, 0x02, -1, -1, -1, -1, -1, -1,
! 104: 0x00, 0x00, -1, -1, -1, -1, -1, -1,
! 105: 0x02, 0x02, 0x02, 0x04, -1, 0x00, -1, -1,
! 106: 0x01, 0x01, 0x03, 0x02, -1, -1, -1, -1,
! 107: -1, -1, -1, -1, -1, -1, -1, -1,
! 108: -1, -1, -1, -1, -1, -1, -1, -1,
! 109: -1, -1, -1, -1, -1, -1, -1, -1,
! 110: -1, -1, -1, -1, -1, -1, -1, -1,
! 111: 0x00, -1, -1, -1, -1, -1, -1, -1,
! 112: 0x01, 0x01, -1, -1, 0x00, 0x00, -1, -1,
! 113: -1, 0x04, 0x00, -1, -1, -1, -1, -1,
! 114: 0x03, -1, 0x00, -1, 0x00, -1, -1, 0x00,
! 115: -1, -1, -1, -1, -1, -1, -1, -1,
! 116: -1, -1, -1, -1, -1, -1, -1, -1
! 117: };
! 118:
! 119: /* these values shows that number of data returned after 'receive' cmd is sent */
! 120: signed char pm_receive_cmd_type[] = {
! 121: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 122: -1, -1, -1, -1, -1, -1, -1, -1,
! 123: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 124: 0x02, 0x02, -1, -1, -1, -1, -1, 0x00,
! 125: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 126: -1, -1, -1, -1, -1, -1, -1, -1,
! 127: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 128: 0x05, 0x15, -1, 0x02, -1, -1, -1, -1,
! 129: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 130: 0x02, 0x02, -1, -1, -1, -1, -1, -1,
! 131: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 132: 0x02, 0x00, 0x03, 0x03, -1, -1, -1, -1,
! 133: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 134: 0x04, 0x04, 0x03, 0x09, -1, -1, -1, -1,
! 135: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 136: -1, -1, -1, -1, -1, -1, 0x01, 0x01,
! 137: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 138: 0x06, -1, -1, -1, -1, -1, -1, -1,
! 139: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 140: 0x02, 0x02, -1, -1, -1, -1, -1, -1,
! 141: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 142: 0x02, 0x00, 0x00, 0x00, -1, -1, -1, -1,
! 143: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 144: -1, -1, -1, -1, -1, -1, -1, -1,
! 145: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 146: -1, -1, -1, -1, -1, -1, -1, -1,
! 147: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 148: 0x02, 0x02, -1, -1, 0x02, -1, -1, -1,
! 149: 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
! 150: -1, -1, 0x02, -1, -1, -1, -1, 0x00,
! 151: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 152: -1, -1, -1, -1, -1, -1, -1, -1,
! 153: };
! 154:
! 155:
! 156: /*
! 157: * Define the private functions
! 158: */
! 159:
! 160: /* for debugging */
! 161: #ifdef ADB_DEBUG
! 162: void pm_printerr(char *, int, int, char *);
! 163: #endif
! 164:
! 165: int pm_wait_busy(int);
! 166: int pm_wait_free(int);
! 167:
! 168: /* these functions are for the PB Duo series and the PB 5XX series */
! 169: int pm_receive_pm2(u_char *);
! 170: int pm_send_pm2(u_char);
! 171: int pm_pmgrop_pm2(PMData *);
! 172: void pm_intr_pm2(void);
! 173:
! 174: /* these functions also use the variables of adb_direct.c */
! 175: void pm_adb_get_TALK_result(PMData *);
! 176: void pm_adb_get_ADB_data(PMData *);
! 177:
! 178:
! 179: /*
! 180: * These variables are in adb_direct.c.
! 181: */
! 182: extern u_char *adbBuffer; /* pointer to user data area */
! 183: extern void *adbCompRout; /* pointer to the completion routine */
! 184: extern void *adbCompData; /* pointer to the completion routine data */
! 185: extern int adbWaiting; /* waiting for return data from the device */
! 186: extern int adbWaitingCmd; /* ADB command we are waiting for */
! 187: extern int adbStarting; /* doing ADB reinit, so do "polling" differently */
! 188:
! 189: #define ADB_MAX_MSG_LENGTH 16
! 190: #define ADB_MAX_HDR_LENGTH 8
! 191: struct adbCommand {
! 192: u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */
! 193: u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */
! 194: u_char *saveBuf; /* where to save result */
! 195: u_char *compRout; /* completion routine pointer */
! 196: u_char *compData; /* completion routine data pointer */
! 197: u_int cmd; /* the original command for this data */
! 198: u_int unsol; /* 1 if packet was unsolicited */
! 199: u_int ack_only; /* 1 for no special processing */
! 200: };
! 201: extern void adb_pass_up(struct adbCommand *);
! 202:
! 203:
! 204: #ifdef ADB_DEBUG
! 205: /*
! 206: * This function dumps contents of the PMData
! 207: */
! 208: void
! 209: pm_printerr(ttl, rval, num, data)
! 210: char *ttl;
! 211: int rval;
! 212: int num;
! 213: char *data;
! 214: {
! 215: int i;
! 216:
! 217: printf("pm: %s:%04x %02x ", ttl, rval, num);
! 218: for (i = 0; i < num; i++)
! 219: printf("%02x ", data[i]);
! 220: printf("\n");
! 221: }
! 222: #endif
! 223:
! 224:
! 225:
! 226: /*
! 227: * Check the hardware type of the Power Manager
! 228: */
! 229: void
! 230: pm_setup_adb()
! 231: {
! 232: pmHardware = PM_HW_PB5XX; /* XXX */
! 233: }
! 234:
! 235:
! 236: /*
! 237: * Wait until PM IC is busy
! 238: */
! 239: int
! 240: pm_wait_busy(int delay)
! 241: {
! 242: while (PM_IS_ON) {
! 243: #ifdef PM_GRAB_SI
! 244: (void)intr_dispatch(0x70);
! 245: #endif
! 246: if ((--delay) < 0)
! 247: return 1; /* timeout */
! 248: }
! 249: return 0;
! 250: }
! 251:
! 252:
! 253: /*
! 254: * Wait until PM IC is free
! 255: */
! 256: int
! 257: pm_wait_free(int delay)
! 258: {
! 259: while (PM_IS_OFF) {
! 260: #ifdef PM_GRAB_SI
! 261: (void)intr_dispatch(0x70);
! 262: #endif
! 263: if ((--delay) < 0)
! 264: return 0; /* timeout */
! 265: }
! 266: return 1;
! 267: }
! 268:
! 269: /*
! 270: * Functions for the PB Duo series and the PB 5XX series
! 271: */
! 272:
! 273: /*
! 274: * Receive data from PM for the PB Duo series and the PB 5XX series
! 275: */
! 276: int
! 277: pm_receive_pm2(u_char *data)
! 278: {
! 279: int i;
! 280: int rval;
! 281:
! 282: rval = 0xffffcd34;
! 283:
! 284: switch (1) {
! 285: default:
! 286: /* set VIA SR to input mode */
! 287: via_reg_or(VIA1, vACR, 0x0c);
! 288: via_reg_and(VIA1, vACR, ~0x10);
! 289: i = PM_SR();
! 290:
! 291: PM_SET_STATE_ACKOFF();
! 292: if (pm_wait_busy((int)ADBDelay*32) != 0)
! 293: break; /* timeout */
! 294:
! 295: PM_SET_STATE_ACKON();
! 296: rval = 0xffffcd33;
! 297: if (pm_wait_free((int)ADBDelay*32) == 0)
! 298: break; /* timeout */
! 299:
! 300: *data = PM_SR();
! 301: rval = 0;
! 302:
! 303: break;
! 304: }
! 305:
! 306: PM_SET_STATE_ACKON();
! 307: via_reg_or(VIA1, vACR, 0x1c);
! 308:
! 309: return rval;
! 310: }
! 311:
! 312: /*
! 313: * Send data to PM for the PB Duo series and the PB 5XX series
! 314: */
! 315: int
! 316: pm_send_pm2(data)
! 317: u_char data;
! 318: {
! 319: int rval;
! 320:
! 321: via_reg_or(VIA1, vACR, 0x1c);
! 322: write_via_reg(VIA1, vSR, data); /* PM_SR() = data; */
! 323:
! 324: PM_SET_STATE_ACKOFF();
! 325: rval = 0xffffcd36;
! 326: if (pm_wait_busy((int)ADBDelay*32) != 0) {
! 327: PM_SET_STATE_ACKON();
! 328: via_reg_or(VIA1, vACR, 0x1c);
! 329: return rval;
! 330: }
! 331:
! 332: PM_SET_STATE_ACKON();
! 333: rval = 0xffffcd35;
! 334: if (pm_wait_free((int)ADBDelay*32) != 0)
! 335: rval = 0;
! 336:
! 337: PM_SET_STATE_ACKON();
! 338: via_reg_or(VIA1, vACR, 0x1c);
! 339:
! 340: return rval;
! 341: }
! 342:
! 343:
! 344:
! 345: /*
! 346: * My PMgrOp routine for the PB Duo series and the PB 5XX series
! 347: */
! 348: int
! 349: pm_pmgrop_pm2(PMData *pmdata)
! 350: {
! 351: int i;
! 352: int s;
! 353: u_char via1_vIER;
! 354: int rval = 0;
! 355: int num_pm_data = 0;
! 356: u_char pm_cmd;
! 357: short pm_num_rx_data;
! 358: u_char pm_data;
! 359: u_char *pm_buf;
! 360:
! 361: s = splhigh();
! 362:
! 363: /* disable all interrupts but PM */
! 364: via1_vIER = 0x10;
! 365: via1_vIER &= read_via_reg(VIA1, vIER);
! 366: write_via_reg(VIA1, vIER, via1_vIER);
! 367: if (via1_vIER != 0x0)
! 368: via1_vIER |= 0x80;
! 369:
! 370: switch (pmdata->command) {
! 371: default:
! 372: /* wait until PM is free */
! 373: pm_cmd = (u_char)(pmdata->command & 0xff);
! 374: rval = 0xcd38;
! 375: if (pm_wait_free(ADBDelay * 4) == 0)
! 376: break; /* timeout */
! 377:
! 378: /* send PM command */
! 379: if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
! 380: break; /* timeout */
! 381:
! 382: /* send number of PM data */
! 383: num_pm_data = pmdata->num_data;
! 384: if (pm_send_cmd_type[pm_cmd] < 0) {
! 385: if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
! 386: break; /* timeout */
! 387: pmdata->command = 0;
! 388: }
! 389: /* send PM data */
! 390: pm_buf = (u_char *)pmdata->s_buf;
! 391: for (i = 0 ; i < num_pm_data; i++)
! 392: if ((rval = pm_send_pm2(pm_buf[i])) != 0)
! 393: break; /* timeout */
! 394: if (i != num_pm_data)
! 395: break; /* timeout */
! 396:
! 397:
! 398: /* check if PM will send me data */
! 399: pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
! 400: pmdata->num_data = pm_num_rx_data;
! 401: if (pm_num_rx_data == 0) {
! 402: rval = 0;
! 403: break; /* no return data */
! 404: }
! 405:
! 406: /* receive PM command */
! 407: pm_data = pmdata->command;
! 408: pm_num_rx_data--;
! 409: if (pm_num_rx_data == 0)
! 410: if ((rval = pm_receive_pm2(&pm_data)) != 0) {
! 411: rval = 0xffffcd37;
! 412: break;
! 413: }
! 414: pmdata->command = pm_data;
! 415:
! 416: /* receive number of PM data */
! 417: if (pm_num_rx_data < 0) {
! 418: if ((rval = pm_receive_pm2(&pm_data)) != 0)
! 419: break; /* timeout */
! 420: num_pm_data = pm_data;
! 421: } else
! 422: num_pm_data = pm_num_rx_data;
! 423: pmdata->num_data = num_pm_data;
! 424:
! 425: /* receive PM data */
! 426: pm_buf = (u_char *)pmdata->r_buf;
! 427: for (i = 0; i < num_pm_data; i++) {
! 428: if ((rval = pm_receive_pm2(&pm_data)) != 0)
! 429: break; /* timeout */
! 430: pm_buf[i] = pm_data;
! 431: }
! 432:
! 433: rval = 0;
! 434: }
! 435:
! 436: /* restore former value */
! 437: write_via_reg(VIA1, vIER, via1_vIER);
! 438: splx(s);
! 439:
! 440: return rval;
! 441: }
! 442:
! 443:
! 444: /*
! 445: * My PM interrupt routine for the PB Duo series and the PB 5XX series
! 446: */
! 447: void
! 448: pm_intr_pm2()
! 449: {
! 450: int s;
! 451: int rval;
! 452: PMData pmdata;
! 453:
! 454: s = splhigh();
! 455:
! 456: PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
! 457: /* ask PM what happend */
! 458: pmdata.command = 0x78;
! 459: pmdata.num_data = 0;
! 460: pmdata.s_buf = &pmdata.data[2];
! 461: pmdata.r_buf = &pmdata.data[2];
! 462: rval = pm_pmgrop_pm2(&pmdata);
! 463: if (rval != 0) {
! 464: #ifdef ADB_DEBUG
! 465: if (adb_debug)
! 466: printf("pm: PM is not ready. error code: %08x\n", rval);
! 467: #endif
! 468: splx(s);
! 469: return;
! 470: }
! 471:
! 472: switch ((u_int)(pmdata.data[2] & 0xff)) {
! 473: case 0x00: /* 1 sec interrupt? */
! 474: break;
! 475: case PMU_INT_TICK: /* 1 sec interrupt? */
! 476: break;
! 477: case PMU_INT_SNDBRT: /* Brightness/Contrast button on LCD panel */
! 478: break;
! 479: case PMU_INT_ADB: /* ADB data requested by TALK command */
! 480: case PMU_INT_ADB|PMU_INT_ADB_AUTO:
! 481: pm_adb_get_TALK_result(&pmdata);
! 482: break;
! 483: case 0x16: /* ADB device event */
! 484: case 0x18:
! 485: case 0x1e:
! 486: case PMU_INT_WAKEUP:
! 487: pm_adb_get_ADB_data(&pmdata);
! 488: break;
! 489: default:
! 490: #ifdef ADB_DEBUG
! 491: if (adb_debug)
! 492: pm_printerr("driver does not support this event.",
! 493: pmdata.data[2], pmdata.num_data,
! 494: pmdata.data);
! 495: #endif
! 496: break;
! 497: }
! 498:
! 499: splx(s);
! 500: }
! 501:
! 502:
! 503: /*
! 504: * My PMgrOp routine
! 505: */
! 506: int
! 507: pmgrop(PMData *pmdata)
! 508: {
! 509: switch (pmHardware) {
! 510: case PM_HW_PB5XX:
! 511: return (pm_pmgrop_pm2(pmdata));
! 512: default:
! 513: /* return (pmgrop_mrg(pmdata)); */
! 514: return 1;
! 515: }
! 516: }
! 517:
! 518:
! 519: /*
! 520: * My PM interrupt routine
! 521: */
! 522: void
! 523: pm_intr()
! 524: {
! 525: switch (pmHardware) {
! 526: case PM_HW_PB5XX:
! 527: pm_intr_pm2();
! 528: break;
! 529: default:
! 530: break;
! 531: }
! 532: }
! 533:
! 534:
! 535:
! 536: /*
! 537: * Synchronous ADBOp routine for the Power Manager
! 538: */
! 539: int
! 540: pm_adb_op(u_char *buffer, void *compRout, void *data, int command)
! 541: {
! 542: int i;
! 543: int s;
! 544: int rval;
! 545: int ndelay;
! 546: int waitfor; /* interrupts to poll for */
! 547: int ifr;
! 548: #ifdef ADB_DEBUG
! 549: int oldifr;
! 550: #endif
! 551: PMData pmdata;
! 552: struct adbCommand packet;
! 553: extern int adbempty;
! 554:
! 555: if (adbWaiting == 1)
! 556: return 1;
! 557:
! 558: s = splhigh();
! 559: write_via_reg(VIA1, vIER, 0x10);
! 560:
! 561: adbBuffer = buffer;
! 562: adbCompRout = compRout;
! 563: adbCompData = data;
! 564:
! 565: pmdata.command = 0x20;
! 566: pmdata.s_buf = pmdata.data;
! 567: pmdata.r_buf = pmdata.data;
! 568:
! 569: /*
! 570: * if the command is LISTEN,
! 571: * add number of ADB data to number of PM data
! 572: */
! 573: if ((command & 0xc) == 0x8) {
! 574: if (buffer != (u_char *)0)
! 575: pmdata.num_data = buffer[0] + 3;
! 576: } else
! 577: pmdata.num_data = 3;
! 578:
! 579: /*
! 580: * Resetting adb on several models, such as
! 581: * - PowerBook3,*
! 582: * - PowerBook5,*
! 583: * - PowerMac10,1
! 584: * causes several pmu interrupts with ifr set to PMU_INT_SNDBRT.
! 585: * Not processing them prevents us from seeing the adb devices
! 586: * afterwards, so we have to expect it unless we know the adb
! 587: * bus is empty.
! 588: */
! 589: if (command == PMU_RESET_ADB) {
! 590: waitfor = PMU_INT_ADB_AUTO | PMU_INT_ADB;
! 591: if (adbempty == 0)
! 592: waitfor |= PMU_INT_SNDBRT;
! 593: } else
! 594: waitfor = PMU_INT_ALL;
! 595:
! 596: pmdata.data[0] = (u_char)(command & 0xff);
! 597: pmdata.data[1] = 0;
! 598: /* if the command is LISTEN, copy ADB data to PM buffer */
! 599: if ((command & 0xc) == 0x8) {
! 600: if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
! 601: pmdata.data[2] = buffer[0]; /* number of data */
! 602: for (i = 0; i < buffer[0]; i++)
! 603: pmdata.data[3 + i] = buffer[1 + i];
! 604: } else
! 605: pmdata.data[2] = 0;
! 606: } else
! 607: pmdata.data[2] = 0;
! 608:
! 609: if ((command & 0xc) != 0xc) { /* if the command is not TALK */
! 610: /* set up stuff for adb_pass_up */
! 611: packet.data[0] = 1 + pmdata.data[2];
! 612: packet.data[1] = command;
! 613: for (i = 0; i < pmdata.data[2]; i++)
! 614: packet.data[i+2] = pmdata.data[i+3];
! 615: packet.saveBuf = adbBuffer;
! 616: packet.compRout = adbCompRout;
! 617: packet.compData = adbCompData;
! 618: packet.cmd = command;
! 619: packet.unsol = 0;
! 620: packet.ack_only = 1;
! 621: adb_polling = 1;
! 622: adb_pass_up(&packet);
! 623: adb_polling = 0;
! 624: }
! 625:
! 626: rval = pmgrop(&pmdata);
! 627: if (rval != 0) {
! 628: splx(s);
! 629: return 1;
! 630: }
! 631:
! 632: delay (1000);
! 633:
! 634: adbWaiting = 1;
! 635: adbWaitingCmd = command;
! 636:
! 637: PM_VIA_INTR_ENABLE();
! 638:
! 639: /* wait until the PM interrupt is occurred */
! 640: ndelay = 0x8000;
! 641: #ifdef ADB_DEBUG
! 642: oldifr = 0;
! 643: #endif
! 644: while (adbWaiting == 1) {
! 645: ifr = read_via_reg(VIA1, vIFR);
! 646: if (ifr & waitfor) {
! 647: pm_intr();
! 648: #ifdef PM_GRAB_SI
! 649: (void)intr_dispatch(0x70);
! 650: #endif
! 651: #ifdef ADB_DEBUG
! 652: } else if (ifr != oldifr) {
! 653: if (adb_debug)
! 654: printf("pm_adb_op: ignoring ifr %02x"
! 655: ", expecting %02x\n",
! 656: (u_int)ifr, (u_int)waitfor);
! 657: oldifr = ifr;
! 658: #endif
! 659: }
! 660: if ((--ndelay) < 0) {
! 661: splx(s);
! 662: return 1;
! 663: }
! 664: delay(10);
! 665: }
! 666:
! 667: /* this command enables the interrupt by operating ADB devices */
! 668: pmdata.command = 0x20;
! 669: pmdata.num_data = 4;
! 670: pmdata.s_buf = pmdata.data;
! 671: pmdata.r_buf = pmdata.data;
! 672: pmdata.data[0] = 0x00;
! 673: pmdata.data[1] = 0x86; /* magic spell for awaking the PM */
! 674: pmdata.data[2] = 0x00;
! 675: pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */
! 676: rval = pmgrop(&pmdata);
! 677:
! 678: splx(s);
! 679: return rval;
! 680: }
! 681:
! 682:
! 683: void
! 684: pm_adb_get_TALK_result(PMData *pmdata)
! 685: {
! 686: int i;
! 687: struct adbCommand packet;
! 688:
! 689: /* set up data for adb_pass_up */
! 690: packet.data[0] = pmdata->num_data-1;
! 691: packet.data[1] = pmdata->data[3];
! 692: for (i = 0; i <packet.data[0]-1; i++)
! 693: packet.data[i+2] = pmdata->data[i+4];
! 694:
! 695: packet.saveBuf = adbBuffer;
! 696: packet.compRout = adbCompRout;
! 697: packet.compData = adbCompData;
! 698: packet.unsol = 0;
! 699: packet.ack_only = 0;
! 700: adb_polling = 1;
! 701: adb_pass_up(&packet);
! 702: adb_polling = 0;
! 703:
! 704: adbWaiting = 0;
! 705: adbBuffer = (long)0;
! 706: adbCompRout = (long)0;
! 707: adbCompData = (long)0;
! 708: }
! 709:
! 710:
! 711: void
! 712: pm_adb_get_ADB_data(PMData *pmdata)
! 713: {
! 714: int i;
! 715: struct adbCommand packet;
! 716:
! 717: /* set up data for adb_pass_up */
! 718: packet.data[0] = pmdata->num_data-1; /* number of raw data */
! 719: packet.data[1] = pmdata->data[3]; /* ADB command */
! 720: for (i = 0; i <packet.data[0]-1; i++)
! 721: packet.data[i+2] = pmdata->data[i+4];
! 722: packet.unsol = 1;
! 723: packet.ack_only = 0;
! 724: adb_pass_up(&packet);
! 725: }
! 726:
! 727: void
! 728: pm_adb_restart()
! 729: {
! 730: PMData p;
! 731:
! 732: p.command = PMU_RESET_CPU;
! 733: p.num_data = 0;
! 734: p.s_buf = p.data;
! 735: p.r_buf = p.data;
! 736: pmgrop(&p);
! 737: }
! 738:
! 739: void
! 740: pm_adb_poweroff()
! 741: {
! 742: PMData p;
! 743:
! 744: bzero(&p, sizeof p);
! 745: p.command = PMU_POWER_OFF;
! 746: p.num_data = 4;
! 747: p.s_buf = p.data;
! 748: p.r_buf = p.data;
! 749: strlcpy(p.data, "MATT", sizeof p.data);
! 750: pmgrop(&p);
! 751: }
! 752:
! 753: void
! 754: pm_read_date_time(time_t *time)
! 755: {
! 756: PMData p;
! 757:
! 758: p.command = PMU_READ_RTC;
! 759: p.num_data = 0;
! 760: p.s_buf = p.data;
! 761: p.r_buf = p.data;
! 762: pmgrop(&p);
! 763:
! 764: bcopy(p.data, time, 4);
! 765: }
! 766:
! 767: void
! 768: pm_set_date_time(time_t time)
! 769: {
! 770: PMData p;
! 771:
! 772: p.command = PMU_SET_RTC;
! 773: p.num_data = 4;
! 774: p.s_buf = p.r_buf = p.data;
! 775: bcopy(&time, p.data, 4);
! 776: pmgrop(&p);
! 777: }
! 778:
! 779: #if 0
! 780: void
! 781: pm_eject_pcmcia(int slot)
! 782: {
! 783: PMData p;
! 784:
! 785: if (slot != 0 && slot != 1)
! 786: return;
! 787:
! 788: p.command = PMU_EJECT_PCMCIA;
! 789: p.num_data = 1;
! 790: p.s_buf = p.r_buf = p.data;
! 791: p.data[0] = 5 + slot; /* XXX */
! 792: pmgrop(&p);
! 793: }
! 794: #endif
! 795:
! 796:
! 797: /*
! 798: * Thanks to Paul Mackerras and Fabio Riccardi's Linux implementation
! 799: * for a clear description of the PMU results.
! 800: */
! 801:
! 802: int
! 803: pm_battery_info(int battery, struct pmu_battery_info *info)
! 804: {
! 805: PMData p;
! 806:
! 807: p.command = PMU_SMART_BATTERY_STATE;
! 808: p.num_data = 1;
! 809: p.s_buf = p.r_buf = p.data;
! 810: p.data[0] = battery + 1;
! 811: pmgrop(&p);
! 812:
! 813: info->flags = p.data[1];
! 814:
! 815: switch (p.data[0]) {
! 816: case 3:
! 817: case 4:
! 818: info->cur_charge = p.data[2];
! 819: info->max_charge = p.data[3];
! 820: info->draw = *((signed char *)&p.data[4]);
! 821: info->voltage = p.data[5];
! 822: break;
! 823: case 5:
! 824: info->cur_charge = ((p.data[2] << 8) | (p.data[3]));
! 825: info->max_charge = ((p.data[4] << 8) | (p.data[5]));
! 826: info->draw = *((signed short *)&p.data[6]);
! 827: info->voltage = ((p.data[8] << 8) | (p.data[7]));
! 828: break;
! 829: default:
! 830: /* XXX - Error condition */
! 831: info->cur_charge = 0;
! 832: info->max_charge = 0;
! 833: info->draw = 0;
! 834: info->voltage = 0;
! 835: break;
! 836: }
! 837:
! 838: return 1;
! 839: }
! 840:
! 841: void
! 842: pmu_fileserver_mode(int on)
! 843: {
! 844: PMData p;
! 845:
! 846: p.command = PMU_POWER_EVENTS;
! 847: p.num_data = 1;
! 848: p.s_buf = p.r_buf = p.data;
! 849: p.data[0] = PMU_PWR_GET_POWERUP_EVENTS;
! 850: pmgrop(&p);
! 851:
! 852: p.command = PMU_POWER_EVENTS;
! 853: p.num_data = 3;
! 854: p.s_buf = p.r_buf = p.data;
! 855: p.data[1] = p.data[0]; /* result from the get */
! 856: if (on) {
! 857: p.data[0] = PMU_PWR_SET_POWERUP_EVENTS;
! 858: p.data[2] = PMU_WAKE_AC_LOSS;
! 859: } else {
! 860: p.data[0] = PMU_PWR_CLR_POWERUP_EVENTS;
! 861: p.data[2] = PMU_WAKE_AC_LOSS;
! 862: }
! 863: pmgrop(&p);
! 864: }
CVSweb