QUOTE(mrbelvedere @ Jan 14 2008, 10:26 PM)

Looks good, I'll play with it when I get home. Any idea about controlling the led's on the front of the console?
CODE
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <getopt.h>
#include <string.h>
#define SMC_FILENAME "/dev/smc"
int smc_fd;
void query_poweron_type(unsigned char *msg)
{
msg[0] = 0x01;
}
void query_rtc(unsigned char *msg)
{
msg[0] = 0x04;
}
void query_sensor(unsigned char *msg)
{
msg[0] = 0x07;
}
void query_tray(unsigned char *msg)
{
msg[0] = 0x0A;
}
void query_avpack(unsigned char *msg)
{
msg[0] = 0x0F;
}
void query_version(unsigned char *msg)
{
msg[0] = 0x12;
}
void query_ir_address(unsigned char *msg)
{
msg[0] = 0x16;
}
void query_tilt_sensor(unsigned char *msg)
{
msg[0] = 0x17;
}
void set_standby(unsigned char *msg)
{
msg[0] = 0x82;
// TODO: other parameters
}
void set_time(unsigned char *msg, int time)
{
msg[0] = 0x85;
// msg[1] = ...
}
void set_fan_algorithm(unsigned char *msg, int algorithm)
{
msg[0] = 0x88;
msg[1] = algorithm;
}
void set_fan_speed(unsigned char *msg, int cpugpu, int speed)
{
msg[0] = cpugpu ? 0x94 : 0x89;
msg[1] = speed | 0x80;
}
void set_dvd_tray(unsigned char *msg, int state)
{
msg[0] = 0x8B;
msg[1] = state ? 0x60 : 0x62;
}
void set_power_led(unsigned char *msg, int override, int state, int startanim)
{
msg[0] = 0x8C;
msg[1] = (override ? 1 : 0) | (state ? 0 : 2);
msg[2] = startanim;
}
void set_audio_mute(unsigned char *msg, int mute)
{
msg[0] = 0x8D;
msg[1] = mute;
}
void set_ir_address(unsigned char *msg, int ir_address)
{
msg[0] = 0x95;
msg[1] = ir_address;
}
void set_dvd_tray_secure(unsigned char *msg)
{
msg[0] = 0x98;
}
void set_leds(unsigned char *msg, int enable, int red, int green)
{
msg[0] = 0x99;
msg[1] = enable;
msg[2] = red | (green << 4);
}
void set_rtc_wake(unsigned char *msg, int time)
{
msg[0] = 0x9a;
// todo
}
void hexdump(unsigned char *msg)
{
int i;
for (i=0; i<0x10; ++i)
printf("%02x ", msg[i]);
printf("\n");
}
void show_tilt(unsigned char *msg)
{
if (*msg == 0x83)
msg++;
printf("tilt: %s\n", (msg[1]&1) ? "vertical" : "horizontal");
}
void show_tray(unsigned char *msg)
{
char *states[] = {"open", "opening", "closed", "closing", "pushed"};
printf("tray: %s\n", states[(msg[1] & 0xF) % 5]);
}
void show_ir(unsigned char *msg)
{
printf("IR code: %02x\n", msg[3]);
}
void show_avpack(unsigned char *msg)
{
if (*msg == 0x83)
++msg;
printf("AV pack type: %02x\n", msg[1]);
}
void show_poweron_type(unsigned char *msg)
{
printf("poweron type: %02x\n", msg[1]);
}
void show_rtc(unsigned char *msg)
{
int rtc = msg[1] | (msg[2] << 8) | (msg[3] << 16) | (msg[4] << 24);
printf("rtc: %d.%03d\n", rtc / 1000, rtc % 1000);
}
void show_sensor(unsigned char *msg)
{
printf("sensor data: ");
int i;
for (i=0; i<4; ++i)
{
float s = (msg[i * 2 + 1] | (msg[i * 2 + 2] << 8)) / 256.0;
printf("%3.1f C, ", s);
}
printf("\n");
}
void show_version(unsigned char *msg)
{
printf("version: %d.%d\n", msg[2], msg[3]);
}
void show_ir_address(unsigned char *msg)
{
printf("ir address: %d\n", msg[1]);
}
void show_response(unsigned char *msg)
{
switch (msg[0])
{
case 0x83:
switch (msg[1])
{
case 0x11:
printf("poweroff occuring\n");
break;
case 0x14:
show_tilt(msg);
break;
case 0x60 ... 0x65:
show_tray(msg);
break;
case 0x23:
show_ir(msg);
break;
case 0x40:
show_avpack(msg);
break;
default:
hexdump(msg);
break;
}
break;
case 0x01:
show_poweron_type(msg);
break;
case 0x04:
show_rtc(msg);
break;
case 0x07:
show_sensor(msg);
break;
case 0x0a:
show_tray(msg);
break;
case 0x0F:
show_avpack(msg);
break;
case 0x12:
show_version(msg);
break;
case 0x16:
show_ir_address(msg);
break;
case 0x17:
show_tilt(msg);
break;
default:
hexdump(msg);
break;
}
}
int main(int argc, char **argv)
{
int first = 1;
/* try open SMC. if this doesn't work, bail out. */
smc_fd = open(SMC_FILENAME, O_RDWR);
if (smc_fd < 0)
{
perror(SMC_FILENAME);
return 1;
}
while (1)
{
unsigned char msg[16];
static struct option long_options[] =
{
{"query-poweron-type", no_argument, 0, 'p'},
{"query-rtc", no_argument, 0, 'r'},
{"query-sensors", no_argument, 0, 's'},
{"query-tray", no_argument, 0, 't'},
{"query-avpack", no_argument, 0, 'a'},
{"query-version", no_argument, 0, 'v'},
{"query-ir-address", no_argument, 0, 'i'},
{"query-tilt-sensor", no_argument, 0, 'n'},
{"set-standby", required_argument, 0, 'S'},
{"set-time", required_argument, 0, 'R'},
{"set-fan-algorithm", required_argument, 0, 'f'},
{"set-cpu-fan-speed", required_argument, 0, 'C'},
{"set-gpu-fan-speed", required_argument, 0, 'G'},
{"set-dvd-tray", required_argument, 0, 'T'},
{"set-powerled", required_argument, 0, 'P'},
{"set-audio-mute", required_argument, 0, 'M'},
{"set-ir-address", required_argument, 0, 'I'},
{"set-dvd-tray-secure", no_argument, 0, 'O'},
{"set-leds", required_argument, 0, 'L'},
{"set-rtc-wakeup", required_argument, 0, 'W'},
{"poll", no_argument, 0, 'w'},
{}
};
char *help[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
"speed from 0 to 127", "speed from 0 to 127", "0: open, 1: close",
"0: default, 1: on, 2: off, 3: animated", 0, 0, 0, "GR with 1+2+4+8 for the red&green segments", 0, 0};
int option_index = 0, c;
c = getopt_long (argc, argv, "prstavinS:R:f:C:G:T:P:M:I:OL:W:w",
long_options, &option_index);
if ((c == -1) && !first)
break;
first = 0;
if ((c == '?') || (c == -1))
{
struct option *o = long_options;
char **h = help;
fprintf(stderr, "usage:\n");
printf("\t%s <cmd> [<cmd>...]\n", argv[0]);
while (o->name)
{
printf("\t\t--%s, -%c \t%s\n", o->name, o->val, o->has_arg ? "<xxx>" : "");
if (*h)
printf("\t\t\t%s\n", *h);
++h;
++o;
}
break;
}
/* prepare message */
memset(msg, 0, 16);
switch (c)
{
case 'p':
query_poweron_type(msg);
break;
case 'r':
query_rtc(msg);
break;
case 's':
query_sensor(msg);
break;
case 't':
query_tray(msg);
break;
case 'a':
query_avpack(msg);
break;
case 'v':
query_version(msg);
break;
case 'i':
query_ir_address(msg);
break;
case 'n':
query_tilt_sensor(msg);
break;
case 'S':
set_standby(msg);
break;
case 'R':
set_time(msg, atoi(optarg));
break;
case 'f':
set_fan_algorithm(msg, atoi(optarg));
break;
case 'C':
set_fan_speed(msg, 0, atoi(optarg));
break;
case 'G':
set_fan_speed(msg, 1, atoi(optarg));
break;
case 'T':
set_dvd_tray(msg, atoi(optarg));
break;
case 'P':
switch (atoi(optarg))
{
case 0: // default
set_power_led(msg, 0, 0, 0);
break;
case 1: // always on
set_power_led(msg, 1, 1, 0);
break;
case 2: // always off
set_power_led(msg, 1, 0, 0);
break;
case 3: // animation
set_power_led(msg, 1, 0, 1);
break;
default:
break;
}
break;
case 'M':
set_audio_mute(msg, atoi(optarg));
break;
case 'I':
set_ir_address(msg, atoi(optarg));
break;
case 'O':
set_dvd_tray_secure(msg);
break;
case 'L':
{
int state = strtoul(optarg, 0, 0x10);
set_leds(msg, !!state, state & 0xF, (state >> 4) & 0xF);
break;
}
case 'W':
set_rtc_wake(msg, atoi(optarg));
break;
case 'w':
break;
default:
{
abort();
}
}
if (c != 'w')
{
printf("sending ");
int i;
for (i=0; i<0x10; ++i)
printf("%02x ", msg[i]);
printf("\n");
if (write(smc_fd, msg, 16) != 16)
{
perror("write");
break;
}
}
if ((c == 'w') || (msg[0] < 0x80))
{
int wait_for = msg[0];
while (1)
{
if (read(smc_fd, msg, 16) != 16)
perror("read");
show_response(msg);
if (msg[0] == wait_for)
break;
}
}
}
}
compile it gcc smc.c
and then do
./a.out --set-leds <xxx>