Re: Poweron timer on iBook G3 (PPC_RTAS?)
Benjamin Herrenschmidt wrote:
[...]
> There is no general interface. If you figure out the proper command to send
> to the PMU, then we can add the option to /proc/pmu/options
An easy way to get the information is to 'boot' into Open Firmware.
First I want to add two hints:
Apple's Technotes 'TN2004: Debugging Open Firmware Using Telnet' and
'TN2023: Open Firmware Ethernet Debugging II: Telnet downloading' are
very usefull.
There is a short Forth tutorial on Apple's pci page:
<http://developer.apple.com/hardware/pci/>
Here is a fragment of such a session:
(It is an iBook 2.2)
| Script started on Mon Jun 7 23:43:00 2004
| frank@debian:~$ telnet 192.168.0.3
| Trying 192.168.0.3...
| Connected to 192.168.0.3.
| Escape character is '^]'.
| ok
| 0 > dev rtc
| 0 > pwd
| 0 > /pci@f2000000/mac-io@17/via-pmu@16000/rtc ok
| 0 > words
| More [<space>,<cr>,q,a] ?
| open set-time get-time oneminute shutdowntimer
| write-pua disableboottimer enableboottimer setboottimer
| read-boot disablewakeup write-wake write-rtc write-time
| read-wake read-rtc read-time rtc-bfr ok
'oneminute' will set the boot timer one minute in the future and
shutdown the Mac.
| 0 > see oneminute
| : oneminute
| 3c shutdowntimer ; ok
| 0 > see shutdowntimer
| : shutdowntimer
| read-rtc + write-pua shut-down ; ok
| 0 > see write-pua
| : write-pua
| enableboottimer ; ok
The 'read-rtc' command puts the current time on the data-stack
| 0 > read-rtc . [enter]
leads to:
| 0 > read-rtc bcea937e ok
The following line would set the boot timer one minute in the
future:
| 0 > read-rtc 3c + enableboottimer [enter]
| 0 > see enableboottimer
| : enableboottimer
| 8e rtc-bfr c! 5 rtc-bfr char+ c! 0 rtc-bfr wa1+ c!
| rtc-bfr 3 + 4c!-be
| rtc-bfr 7 " write" _pmu-ihandle $call-method drop
| rtc-bfr 7 + 1 " read"
| _pmu-ihandle $call-method drop ; ok
[Sorry for the line breaks]
In short words:
A sequence of 7 bytes is assembled somewhere in the memory
(The position is determined by rtc-bfr) and sent to the pmu.
These 7 bytes are: '0x8e 0x05 0x00 x3 x2 x1 x0'.
An answer of the pmu of length of one byte is then expected.
Here 'x3 x2 x1 x0' is a 32-bit value. (Which is the time of
which the boot timer will be set.)
To read the boot timer (commando 'read-boot') the
sequence '0x8e 0x01 0x01' is sent to the pmu and a sequence of
6 bytes is expected as answer.
Some more commands:
| 0 > see write-wake
| : write-time
| 80 write-time ; ok
| 0 >
| 0 > see write-time
| : >r rtc-bfr 4c!-be 0 0 rtc-bfr 4 r> " pmu-op"
| _pmu-ihandle $call-method drop ; ok
Here '0x80 y3 y2 y1 y0' is sent to the pmu.
(I haven't looked for the meaning of the other two
arguments '00 00'.)
| 0 > see read-wake
| : 88 read-time ; ok
| 0 >
| 0 > see read-time
| : read-time
| >r rtc-bfr 5 0 0 r> " pmu-op" _pmu-ihandle $call-method drop
| >rtc-bfr 4c@-be ; ok
Here '0x88' is send to the pmu.
There is also a command 'setboottimer' in this node, but it is not
clear to me what the command will do.
One node above '/pci@f2000000/mac-io@17/via-pmu@16000' there are more
commands, e.g
| 0 > see shutdown
| : shutdown
| 0 0 " MATT" poweroffcmd pmu-op drop
| begin
| again
| ; ok
More interesting a lot of command bytes are defined here, e.g.
'poweroffcmd'.
****************************************
There is already a program called 'pmacpow' written by Takashi
Oe, which can set the wakeup time for cuda-based Macs.
The idea is to write a sequence of command bytes to '/dev/adb'.
I have tested to write sequences like:
"PMU_PACKET 0x38" ('read-rtc').
[PMU_PACKET is definend in <linux/adb.h>]
And then I read back as many bytes as possible from '/dev/adb'.
"PMU_PACKET 0x38" 'read-rtc' succesfull
"PMU_PACKET 0x88" 'read-wake' succesfull
"PMU_PACKET 0x8e 0x01 0x01" 'read-boot' succesfull
"PMU_PACKET 0x80 y3 y2 y1 y0" 'write-wake' succesfull
"PMU_PACKET 0x8e 0x05 0x00 y3 y2 y1 y0 " 'enableboottimer' no luck
In '$linux/drivers/macintosh/via-pmu.c' (I'm using 2.4.22-ben2) there
is an array 'pmu_data_len[256][2]' (line 255 ff.) which says something
about the length of the data of a command and something about the
length of the reply of the pmu.
Hence '0x8e ...' is a variable lenght command and the second byte is
the count of the bytes _after_ the second byte.
So I suppose there is a mistake in the pmu-code or I am using
'/dev/adb' in a wrong way.
Frank
****************
To be complete here is an example:
> cat pmu_read_boot.c
/*
* pmacpow.c - set the next power up time on VIA-CUDA.
*
*
* Copyright (C) 1999 Takashi Oe. All rights reserved.
* Parts of the code are from clock.c and bat.c
* by Paul Mackerras.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* cc -o pmu_read_boot pmu_read_boot.c
*/
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <getopt.h>
#include <time.h>
#include <sys/time.h>
#include <linux/adb.h>
#include <linux/pmu.h>
unsigned char reqt[4] =
{ PMU_PACKET, 0x8e, 0x01, 0x01};
unsigned char reply[32];
static char *program_name;
void dump(unsigned char *buf, int n)
{
int i;
for (i = 0; i < n; ++i)
fprintf(stderr, " %.2x", buf[i]);
fprintf(stderr, "\n");
}
void usage(void) {
fprintf(stderr,
"%s TBA \n", program_name);
exit(1);
}
int get_rtc_time(int fd)
{
int n;
n = write(fd, reqt, sizeof(reqt));
if (n != sizeof(reqt)) {
fprintf(stderr, "%s: write returned %d\n", program_name, n);
return -1;
}
if ((n = read(fd, reply, sizeof(reply))) < 0) {
perror("read");
return -1;
}
dump(reply, n);
fprintf(stderr, "%s: command returned\n", program_name);
return 0;
}
int main(int argc, char **argv)
{
int fd, arg, hour, min;
long cur, sec, uptime;
char *timestr, *tmp;
extern int optind;
program_name = (char *)basename(argv[0]);
if (getuid()) {
fprintf(stderr, "Sorry, must be root to set power up time\n");
return 1;
}
if ((fd = open("/dev/adb", O_RDWR)) < 0) {
perror("open");
return 1;
}
get_rtc_time(fd);
close(fd);
return 0;
}
Reply to: