Annotation of sys/arch/macppc/dev/pm_direct.c, Revision 1.1.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