1 /* $NetBSD: pm_direct.c,v 1.36 2009/03/14 21:04:11 dsl Exp $ */
4 * Copyright (C) 1997 Takashi Hamada
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
32 /* From: pm_direct.c 1.3 03/18/98 Takashi Hamada */
35 * TODO : Check bounds on PMData in pmgrop
36 * callers should specify how much room for data is in the buffer
37 * and that should be respected by the pmgrop
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: pm_direct.c,v 1.36 2009/03/14 21:04:11 dsl Exp $");
49 /* #define PM_GRAB_SI 1 */
51 #include <sys/param.h>
52 #include <sys/device.h>
53 #include <sys/systm.h>
55 #include <machine/adbsys.h>
56 #include <machine/autoconf.h>
57 #include <machine/cpu.h>
58 #include <machine/pio.h>
60 #include <dev/ofw/openfirm.h>
62 #include <macppc/dev/adbvar.h>
63 #include <macppc/dev/pm_direct.h>
64 #include <macppc/dev/viareg.h>
66 extern int adb_polling
; /* Are we polling? (Debugger mode) */
68 /* hardware dependent values */
69 #define ADBDelay 100 /* XXX */
72 #define PM_SR() read_via_reg(VIA1, vSR)
73 #define PM_VIA_INTR_ENABLE() write_via_reg(VIA1, vIER, 0x90)
74 #define PM_VIA_INTR_DISABLE() write_via_reg(VIA1, vIER, 0x10)
75 #define PM_VIA_CLR_INTR() write_via_reg(VIA1, vIFR, 0x90)
77 #define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x10)
78 #define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x10)
79 #define PM_IS_ON (0x08 == (read_via_reg(VIA2, vBufB) & 0x08))
80 #define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x08))
83 * Variables for internal use
85 u_short pm_existent_ADB_devices
= 0x0; /* each bit expresses the existent ADB device */
86 u_int pm_LCD_brightness
= 0x0;
87 u_int pm_LCD_contrast
= 0x0;
88 u_int pm_counter
= 0; /* clock count */
90 static enum batt_type
{ BATT_COMET
, BATT_HOOPER
, BATT_SMART
} pmu_batt_type
;
92 static int strinlist(const char *, char *, int);
93 static enum pmu_type
{ PMU_UNKNOWN
, PMU_OHARE
, PMU_G3
, PMU_KEYLARGO
} pmu_type
;
95 /* these values shows that number of data returned after 'send' cmd is sent */
96 signed char pm_send_cmd_type
[] = {
97 -1, -1, -1, -1, -1, -1, -1, -1,
98 -1, -1, -1, -1, -1, -1, -1, -1,
99 0x01, 0x01, -1, -1, -1, -1, -1, -1,
100 0x00, 0x00, -1, -1, -1, -1, -1, 0x00,
101 -1, 0x00, 0x02, 0x01, 0x01, -1, -1, -1,
102 0x00, -1, -1, -1, -1, -1, -1, -1,
103 0x04, 0x14, -1, 0x03, -1, -1, -1, -1,
104 0x00, 0x00, 0x02, 0x02, -1, -1, -1, -1,
105 0x01, 0x01, -1, -1, -1, -1, -1, -1,
106 0x00, 0x00, -1, -1, 0x01, -1, -1, -1,
107 0x01, 0x00, 0x02, 0x02, -1, 0x01, 0x03, 0x01,
108 0x00, 0x01, 0x00, 0x00, 0x00, -1, -1, -1,
109 0x02, -1, -1, -1, -1, -1, -1, -1,
110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, -1,
111 0x01, 0x01, 0x01, -1, -1, -1, -1, -1,
112 0x00, 0x00, -1, -1, -1, -1, 0x04, 0x04,
113 0x04, -1, 0x00, -1, -1, -1, -1, -1,
114 0x00, -1, -1, -1, -1, -1, -1, -1,
115 0x01, 0x02, -1, -1, -1, -1, -1, -1,
116 0x00, 0x00, -1, -1, -1, -1, -1, -1,
117 0x02, 0x02, 0x02, 0x04, -1, 0x00, -1, -1,
118 0x01, 0x01, 0x03, 0x02, -1, -1, -1, -1,
119 -1, -1, -1, -1, -1, -1, -1, -1,
120 -1, -1, -1, -1, -1, -1, -1, -1,
121 -1, -1, -1, -1, -1, -1, -1, -1,
122 -1, -1, -1, -1, -1, -1, -1, -1,
123 0x00, -1, -1, -1, -1, -1, -1, -1,
124 0x01, 0x01, -1, -1, 0x00, 0x00, -1, -1,
125 -1, 0x04, 0x00, -1, -1, -1, -1, -1,
126 0x03, -1, 0x00, -1, 0x00, -1, -1, 0x00,
127 -1, -1, -1, -1, -1, -1, -1, -1,
128 -1, -1, -1, -1, -1, -1, -1, -1
131 /* these values shows that number of data returned after 'receive' cmd is sent */
132 signed char pm_receive_cmd_type
[] = {
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134 -1, -1, -1, -1, -1, -1, -1, -1,
135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136 0x02, 0x02, -1, -1, -1, -1, -1, 0x00,
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138 -1, -1, -1, -1, -1, -1, -1, -1,
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140 0x05, 0x15, -1, 0x02, -1, -1, -1, -1,
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142 0x02, 0x02, -1, -1, -1, -1, -1, -1,
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 0x02, 0x00, 0x03, 0x03, -1, -1, -1, -1,
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146 0x04, 0x04, 0x03, 0x09, -1, -1, -1, -1,
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148 -1, -1, -1, -1, -1, -1, 0x01, 0x01,
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150 0x06, -1, -1, -1, -1, -1, -1, -1,
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152 0x02, 0x02, -1, -1, -1, -1, -1, -1,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 0x02, 0x00, 0x00, 0x00, -1, -1, -1, -1,
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156 -1, -1, -1, -1, -1, -1, -1, -1,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 -1, -1, -1, -1, -1, -1, -1, -1,
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160 0x02, 0x02, -1, -1, 0x02, -1, -1, -1,
161 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
162 -1, -1, 0x02, -1, -1, -1, -1, 0x00,
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164 -1, -1, -1, -1, -1, -1, -1, -1,
169 * Define the private functions
174 void pm_printerr(const char *, int, int, const char *);
177 int pm_wait_busy(int);
178 int pm_wait_free(int);
180 static int pm_receive(u_char
*);
181 static int pm_send(u_char
);
183 /* these functions are called from adb_direct.c */
184 void pm_setup_adb(void);
185 void pm_check_adb_devices(int);
186 int pm_adb_op(u_char
*, adbComp
*, volatile int *, int);
188 /* these functions also use the variables of adb_direct.c */
189 void pm_adb_get_TALK_result(PMData
*);
190 void pm_adb_get_ADB_data(PMData
*);
194 * These variables are in adb_direct.c.
196 extern u_char
*adbBuffer
; /* pointer to user data area */
197 extern adbComp
*adbCompRout
; /* pointer to the completion routine */
198 extern volatile int *adbCompData
; /* pointer to the completion routine data */
199 extern int adbWaiting
; /* waiting for return data from the device */
200 extern int adbWaitingCmd
; /* ADB command we are waiting for */
201 extern int adbStarting
; /* doing ADB reinit, so do "polling" differently */
203 #define ADB_MAX_MSG_LENGTH 16
204 #define ADB_MAX_HDR_LENGTH 8
206 u_char header
[ADB_MAX_HDR_LENGTH
]; /* not used yet */
207 u_char data
[ADB_MAX_MSG_LENGTH
]; /* packet data only */
208 u_char
*saveBuf
; /* where to save result */
209 adbComp
*compRout
; /* completion routine pointer */
210 volatile int *compData
; /* completion routine data pointer */
211 u_int cmd
; /* the original command for this data */
212 u_int unsol
; /* 1 if packet was unsolicited */
213 u_int ack_only
; /* 1 for no special processing */
215 extern void adb_pass_up(struct adbCommand
*);
219 * Define the external functions
221 extern int zshard(int); /* from zs.c */
226 * This function dumps contents of the PMData
229 pm_printerr(const char *ttl
, int rval
, int num
, const char *data
)
233 printf("pm: %s:%04x %02x ", ttl
, rval
, num
);
234 for (i
= 0; i
< num
; i
++)
235 printf("%02x ", data
[i
]);
243 * Check the hardware type of the Power Manager
251 * Search for targ in list. list is an area of listlen bytes
252 * containing null-terminated strings.
255 strinlist(const char *targ
, char *list
, int listlen
)
262 targlen
= strlen(targ
);
263 while (listlen
> 0) {
265 if (sl
== targlen
&& (strncmp(targ
, str
, sl
) == 0))
274 * Check the hardware type of the Power Manager
282 int clen
, node
, pm_imask
;
286 printf("pmu: Failed to get root");
289 clen
= OF_getprop(node
, "compatible", compat
, sizeof(compat
));
291 printf("pmu: failed to read root compatible data %d\n", clen
);
296 PMU_INT_PCEJECT
| PMU_INT_SNDBRT
| PMU_INT_ADB
| PMU_INT_TICK
;
298 if (strinlist("AAPL,3500", compat
, clen
) ||
299 strinlist("AAPL,3400/2400", compat
, clen
)) {
300 /* How to distinguish BATT_COMET? */
302 pmu_batt_type
= BATT_HOOPER
;
303 pmu_type
= PMU_OHARE
;
304 } else if (strinlist("AAPL,PowerBook1998", compat
, clen
) ||
305 strinlist("PowerBook1,1", compat
, clen
)) {
307 pmu_batt_type
= BATT_SMART
;
311 pmu_batt_type
= BATT_SMART
;
312 pmu_type
= PMU_KEYLARGO
;
313 node
= of_getnode_byname(0, "power-mgt");
315 printf("pmu: can't find power-mgt\n");
318 clen
= OF_getprop(node
, "prim-info", regs
, sizeof(regs
));
320 printf("pmu: failed to read prim-info\n");
323 pmu_nbatt
= regs
[6] >> 16;
326 pmdata
.command
= PMU_SET_IMASK
;
328 pmdata
.s_buf
= pmdata
.data
;
329 pmdata
.r_buf
= pmdata
.data
;
330 pmdata
.data
[0] = pm_imask
;
336 * Check the existent ADB devices
339 pm_check_adb_devices(int id
)
344 pm_existent_ADB_devices
|= ed
;
349 * Wait until PM IC is busy
352 pm_wait_busy(int delaycycles
)
357 zshard(0); /* grab any serial interrupts */
359 (void)intr_dispatch(0x70);
362 if ((--delaycycles
) < 0)
363 return 1; /* timeout */
370 * Wait until PM IC is free
373 pm_wait_free(int delaycycles
)
378 zshard(0); /* grab any serial interrupts */
380 (void)intr_dispatch(0x70);
383 if ((--delaycycles
) < 0)
384 return 0; /* timeout */
392 * Receive data from PMU
395 pm_receive(u_char
*data
)
404 /* set VIA SR to input mode */
405 via_reg_or(VIA1
, vACR
, 0x0c);
406 via_reg_and(VIA1
, vACR
, ~0x10);
409 PM_SET_STATE_ACKOFF();
410 if (pm_wait_busy((int)ADBDelay
*32) != 0)
413 PM_SET_STATE_ACKON();
415 if (pm_wait_free((int)ADBDelay
*32) == 0)
424 PM_SET_STATE_ACKON();
425 via_reg_or(VIA1
, vACR
, 0x1c);
440 via_reg_or(VIA1
, vACR
, 0x1c);
441 write_via_reg(VIA1
, vSR
, data
); /* PM_SR() = data; */
443 PM_SET_STATE_ACKOFF();
445 if (pm_wait_busy((int)ADBDelay
*32) != 0) {
446 PM_SET_STATE_ACKON();
448 via_reg_or(VIA1
, vACR
, 0x1c);
453 PM_SET_STATE_ACKON();
455 if (pm_wait_free((int)ADBDelay
*32) != 0)
458 PM_SET_STATE_ACKON();
459 via_reg_or(VIA1
, vACR
, 0x1c);
470 pmgrop(PMData
*pmdata
)
478 short pm_num_rx_data
;
484 /* disable all inetrrupts but PM */
486 via1_vIER
&= read_via_reg(VIA1
, vIER
);
487 write_via_reg(VIA1
, vIER
, via1_vIER
);
488 if (via1_vIER
!= 0x0)
491 switch (pmdata
->command
) {
493 /* wait until PM is free */
494 pm_cmd
= (u_char
)(pmdata
->command
& 0xff);
496 if (pm_wait_free(ADBDelay
* 4) == 0)
499 /* send PM command */
500 if ((rval
= pm_send((u_char
)(pm_cmd
& 0xff))))
503 /* send number of PM data */
504 num_pm_data
= pmdata
->num_data
;
505 if (pm_send_cmd_type
[pm_cmd
] < 0) {
506 if ((rval
= pm_send((u_char
)(num_pm_data
& 0xff))) != 0)
511 pm_buf
= (u_char
*)pmdata
->s_buf
;
512 for (i
= 0 ; i
< num_pm_data
; i
++)
513 if ((rval
= pm_send(pm_buf
[i
])) != 0)
515 if (i
!= num_pm_data
)
519 /* check if PM will send me data */
520 pm_num_rx_data
= pm_receive_cmd_type
[pm_cmd
];
521 pmdata
->num_data
= pm_num_rx_data
;
522 if (pm_num_rx_data
== 0) {
524 break; /* no return data */
527 /* receive PM command */
528 pm_data
= pmdata
->command
;
530 if (pm_num_rx_data
== 0)
531 if ((rval
= pm_receive(&pm_data
)) != 0) {
535 pmdata
->command
= pm_data
;
537 /* receive number of PM data */
538 if (pm_num_rx_data
< 0) {
539 if ((rval
= pm_receive(&pm_data
)) != 0)
541 num_pm_data
= pm_data
;
543 num_pm_data
= pm_num_rx_data
;
544 pmdata
->num_data
= num_pm_data
;
546 /* receive PM data */
547 pm_buf
= (u_char
*)pmdata
->r_buf
;
548 for (i
= 0; i
< num_pm_data
; i
++) {
549 if ((rval
= pm_receive(&pm_data
)) != 0)
557 /* restore former value */
558 write_via_reg(VIA1
, vIER
, via1_vIER
);
566 * My PMU interrupt routine
577 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
578 /* ask PM what happend */
579 pmdata
.command
= PMU_INT_ACK
;
581 pmdata
.s_buf
= &pmdata
.data
[2];
582 pmdata
.r_buf
= &pmdata
.data
[2];
583 rval
= pmgrop(&pmdata
);
587 printf("pm: PM is not ready. error code: %08x\n", rval
);
593 switch ((u_int
)(pmdata
.data
[2] & 0xff)) {
594 case 0x00: /* no event pending? */
596 case 0x80: /* 1 sec interrupt? */
599 case 0x08: /* Brightness/Contrast button on LCD panel */
600 /* get brightness and contrast of the LCD */
601 pm_LCD_brightness
= (u_int
)pmdata
.data
[3] & 0xff;
602 pm_LCD_contrast
= (u_int
)pmdata
.data
[4] & 0xff;
604 /* this is experimental code */
605 pmdata
.command
= PMU_SET_BRIGHTNESS
;
607 pmdata
.s_buf
= pmdata
.data
;
608 pmdata
.r_buf
= pmdata
.data
;
609 pm_LCD_brightness
= 0x7f - pm_LCD_brightness
/ 2;
610 if (pm_LCD_brightness
< 0x08)
611 pm_LCD_brightness
= 0x08;
612 if (pm_LCD_brightness
> 0x78)
613 pm_LCD_brightness
= 0x78;
614 pmdata
.data
[0] = pm_LCD_brightness
;
615 rval
= pmgrop(&pmdata
);
618 case 0x10: /* ADB data requested by TALK command */
620 pm_adb_get_TALK_result(&pmdata
);
622 case 0x16: /* ADB device event */
625 pm_adb_get_ADB_data(&pmdata
);
630 pm_printerr("driver does not support this event.",
631 pmdata
.data
[2], pmdata
.num_data
,
644 * Synchronous ADBOp routine for the Power Manager
647 pm_adb_op(u_char
*buffer
, adbComp
*compRout
, volatile int *data
, int command
)
654 struct adbCommand packet
;
660 write_via_reg(VIA1
, vIER
, 0x10);
663 adbCompRout
= compRout
;
666 pmdata
.command
= PMU_ADB_CMD
;
667 pmdata
.s_buf
= pmdata
.data
;
668 pmdata
.r_buf
= pmdata
.data
;
670 /* if the command is LISTEN, add number of ADB data to number of PM data */
671 if ((command
& 0xc) == 0x8) {
672 if (buffer
!= (u_char
*)0)
673 pmdata
.num_data
= buffer
[0] + 3;
678 pmdata
.data
[0] = (u_char
)(command
& 0xff);
680 if ((command
& 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */
681 if ((buffer
!= (u_char
*)0) && (buffer
[0] <= 24)) {
682 pmdata
.data
[2] = buffer
[0]; /* number of data */
683 for (i
= 0; i
< buffer
[0]; i
++)
684 pmdata
.data
[3 + i
] = buffer
[1 + i
];
690 if ((command
& 0xc) != 0xc) { /* if the command is not TALK */
691 /* set up stuff for adb_pass_up */
692 packet
.data
[0] = 1 + pmdata
.data
[2];
693 packet
.data
[1] = command
;
694 for (i
= 0; i
< pmdata
.data
[2]; i
++)
695 packet
.data
[i
+2] = pmdata
.data
[i
+3];
696 packet
.saveBuf
= adbBuffer
;
697 packet
.compRout
= adbCompRout
;
698 packet
.compData
= adbCompData
;
699 packet
.cmd
= command
;
703 adb_pass_up(&packet
);
707 rval
= pmgrop(&pmdata
);
716 adbWaitingCmd
= command
;
718 PM_VIA_INTR_ENABLE();
720 /* wait until the PM interrupt has occurred */
722 while (adbWaiting
== 1) {
723 if (read_via_reg(VIA1
, vIFR
) & 0x14)
727 zshard(0); /* grab any serial interrupts */
729 (void)intr_dispatch(0x70);
733 /* Try to take an interrupt anyway, just in case.
734 * This has been observed to happen on my ibook
735 * when i press a key after boot and before adb
736 * is attached; For example, when booting with -d.
740 printf("pm_adb_op: timeout. command = 0x%x\n",command
);
746 printf("pm_adb_op: missed interrupt. cmd=0x%x\n",command
);
752 /* this command enables the interrupt by operating ADB devices */
753 pmdata
.command
= PMU_ADB_CMD
;
755 pmdata
.s_buf
= pmdata
.data
;
756 pmdata
.r_buf
= pmdata
.data
;
757 pmdata
.data
[0] = 0x00;
758 pmdata
.data
[1] = 0x86; /* magic spell for awaking the PM */
759 pmdata
.data
[2] = 0x00;
760 pmdata
.data
[3] = 0x0c; /* each bit may express the existent ADB device */
761 rval
= pmgrop(&pmdata
);
769 pm_adb_get_TALK_result(PMData
*pmdata
)
772 struct adbCommand packet
;
774 /* set up data for adb_pass_up */
775 packet
.data
[0] = pmdata
->num_data
-1;
776 packet
.data
[1] = pmdata
->data
[3];
777 for (i
= 0; i
<packet
.data
[0]-1; i
++)
778 packet
.data
[i
+2] = pmdata
->data
[i
+4];
780 packet
.saveBuf
= adbBuffer
;
781 packet
.compRout
= adbCompRout
;
782 packet
.compData
= adbCompData
;
786 adb_pass_up(&packet
);
791 adbCompRout
= (long)0;
792 adbCompData
= (long)0;
797 pm_adb_get_ADB_data(PMData
*pmdata
)
800 struct adbCommand packet
;
802 if (pmu_type
== PMU_OHARE
&& pmdata
->num_data
== 4 &&
803 pmdata
->data
[1] == 0x2c && pmdata
->data
[3] == 0xff &&
804 ((pmdata
->data
[2] & ~1) == 0xf4)) {
805 if (pmdata
->data
[2] == 0xf4) {
812 /* set up data for adb_pass_up */
813 packet
.data
[0] = pmdata
->num_data
-1; /* number of raw data */
814 packet
.data
[1] = pmdata
->data
[3]; /* ADB command */
815 for (i
= 0; i
<packet
.data
[0]-1; i
++)
816 packet
.data
[i
+2] = pmdata
->data
[i
+4];
819 adb_pass_up(&packet
);
828 p
.command
= PMU_RESET_CPU
;
836 pm_adb_poweroff(void)
840 p
.command
= PMU_POWER_OFF
;
844 strcpy(p
.data
, "MATT");
849 pm_read_date_time(u_long
*t
)
853 p
.command
= PMU_READ_RTC
;
859 memcpy(t
, p
.data
, 4);
863 pm_set_date_time(u_long t
)
867 p
.command
= PMU_SET_RTC
;
869 p
.s_buf
= p
.r_buf
= p
.data
;
870 memcpy(p
.data
, &t
, 4);
875 pm_read_brightness(void)
879 p
.command
= PMU_READ_BRIGHTNESS
;
880 p
.num_data
= 1; /* XXX why 1? */
881 p
.s_buf
= p
.r_buf
= p
.data
;
889 pm_set_brightness(int val
)
893 val
= 0x7f - val
/ 2;
899 p
.command
= PMU_SET_BRIGHTNESS
;
901 p
.s_buf
= p
.r_buf
= p
.data
;
907 pm_init_brightness(void)
911 val
= pm_read_brightness();
912 pm_set_brightness(val
);
916 pm_eject_pcmcia(int slot
)
920 if (slot
!= 0 && slot
!= 1)
923 p
.command
= PMU_EJECT_PCMCIA
;
925 p
.s_buf
= p
.r_buf
= p
.data
;
926 p
.data
[0] = 5 + slot
; /* XXX */
931 * Thanks to Paul Mackerras and Fabio Riccardi's Linux implementation
932 * for a clear description of the PMU results.
935 pm_battery_info_smart(int battery
, struct pmu_battery_info
*info
)
939 p
.command
= PMU_SMART_BATTERY_STATE
;
941 p
.s_buf
= p
.r_buf
= p
.data
;
942 p
.data
[0] = battery
+ 1;
945 info
->flags
= p
.data
[1];
947 info
->secs_remaining
= 0;
951 info
->cur_charge
= p
.data
[2];
952 info
->max_charge
= p
.data
[3];
953 info
->draw
= *((signed char *)&p
.data
[4]);
954 info
->voltage
= p
.data
[5];
957 info
->cur_charge
= ((p
.data
[2] << 8) | (p
.data
[3]));
958 info
->max_charge
= ((p
.data
[4] << 8) | (p
.data
[5]));
959 info
->draw
= *((signed short *)&p
.data
[6]);
960 info
->voltage
= ((p
.data
[8] << 8) | (p
.data
[7]));
963 /* XXX - Error condition */
964 info
->cur_charge
= 0;
965 info
->max_charge
= 0;
971 if (info
->flags
& PMU_PWR_AC_PRESENT
&& info
->draw
> 0) {
972 info
->secs_remaining
=
973 ((info
->max_charge
- info
->cur_charge
) * 3600)
976 info
->secs_remaining
=
977 (info
->cur_charge
* 3600) / -info
->draw
;
985 pm_battery_info_legacy(int battery
, struct pmu_battery_info
*info
, int ty
)
988 long pcharge
=0, charge
, vb
, vmax
, chargemax
;
989 long vmax_charging
, vmax_charged
, amperage
, voltage
;
991 p
.command
= PMU_BATTERY_STATE
;
993 p
.s_buf
= p
.r_buf
= p
.data
;
996 info
->flags
= p
.data
[0];
998 if (info
->flags
& PMU_PWR_BATT_PRESENT
) {
999 if (ty
== BATT_COMET
) {
1000 vmax_charging
= 213;
1004 /* Experimental values */
1005 vmax_charging
= 365;
1009 vmax
= vmax_charged
;
1010 vb
= (p
.data
[1] << 8) | p
.data
[2];
1011 voltage
= (vb
* 256 + 72665) / 10;
1012 amperage
= (unsigned char) p
.data
[5];
1013 if ((info
->flags
& PMU_PWR_AC_PRESENT
) == 0) {
1015 vb
+= ((amperage
- 200) * 15)/100;
1016 } else if (info
->flags
& PMU_PWR_BATT_CHARGING
) {
1017 vb
= (vb
* 97) / 100;
1018 vmax
= vmax_charging
;
1020 charge
= (100 * vb
) / vmax
;
1021 if (info
->flags
& PMU_PWR_PCHARGE_RESET
) {
1022 pcharge
= (p
.data
[6] << 8) | p
.data
[7];
1023 if (pcharge
> chargemax
)
1024 pcharge
= chargemax
;
1026 pcharge
= 100 - pcharge
/ chargemax
;
1027 if (pcharge
< charge
)
1030 info
->cur_charge
= charge
;
1031 info
->max_charge
= 100;
1032 info
->draw
= -amperage
;
1033 info
->voltage
= voltage
;
1035 info
->secs_remaining
= (charge
* 16440) / amperage
;
1037 info
->secs_remaining
= 0;
1039 info
->cur_charge
= 0;
1040 info
->max_charge
= 0;
1043 info
->secs_remaining
= 0;
1050 pm_battery_info(int battery
, struct pmu_battery_info
*info
)
1053 if (battery
> pmu_nbatt
)
1056 switch (pmu_batt_type
) {
1059 return pm_battery_info_legacy(battery
, info
, pmu_batt_type
);
1062 return pm_battery_info_smart(battery
, info
);
1069 pm_read_nvram(int addr
)
1073 p
.command
= PMU_READ_NVRAM
;
1075 p
.s_buf
= p
.r_buf
= p
.data
;
1076 p
.data
[0] = addr
>> 8;
1084 pm_write_nvram(int addr
, int val
)
1088 p
.command
= PMU_WRITE_NVRAM
;
1090 p
.s_buf
= p
.r_buf
= p
.data
;
1091 p
.data
[0] = addr
>> 8;