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