macbook-tools/applesmc.c

287 lines
6.3 KiB
C

/*
* Apple Macbook Pro SMC control
*
* Copyright (C) 2006 Nicolas Boichat <nicolas@boichat.ch>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <stdio.h>
#include <sys/io.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#define LIGHT_SENSOR_LEFT_KEY "ALV0" //0x414c5630, r-o length 6
#define LIGHT_SENSOR_RIGHT_KEY "ALV1" //0x414c5631, r-o length 6
#define BACKLIGHT_KEY "LKSB" //0x4c4b5342, w-o
#define CLAMSHELL_KEY "MSLD" //0x4d534c44, r-o length 1 (unused)
#define MOTION_SENSOR_X_KEY "MO_X" //0x4d4f5f58, r-o length 2
#define MOTION_SENSOR_Y_KEY "MO_Y" //0x4d4f5f58, r-o length 2
#define MOTION_SENSOR_Z_KEY "MO_Z" //0x4d4f5f58, r-o length 2
#define MOTION_SENSOR_KEY "MOCN" //0x4d4f434e, r/w length 2
static int debug = 0;
static struct timeval lasttv;
static struct timeval newtv;
void inline ssleep(const int usec) {
gettimeofday(&lasttv, NULL);
while (1) {
gettimeofday(&newtv, NULL);
if (((newtv.tv_usec - lasttv.tv_usec) + ((newtv.tv_sec - lasttv.tv_sec)*1000000)) > usec) {
break;
}
}
}
unsigned char get_status() {
return inb(0x304);
}
int waitfree(char num) {
char c, pc = -1;
int retry = 100;
while (((c = get_status())&0x0F) != num && retry) {
ssleep(10);
retry--;
if (pc != c) {
//printf("%x-%d:", c, retry);
pc = c;
}
}
if (retry == 0) {
printf("Waitfree failed %x != %x.\n", c, num);
return 0;
}
/*else
printf("Waitfree ok %x.\n", c);*/
return 1;
}
int writekey(char* key, char len, unsigned char* buffer) {
int i;
outb(0x11, 0x304);
if (!waitfree(0x0c)) return 0;
for (i = 0; i < 4; i++) {
outb(key[i], 0x300);
if (!waitfree(0x04)) return 0;
}
if (debug) printf(">%s", key);
outb(len, 0x300);
if (debug) printf(">%x", len);
for (i = 0; i < len; i++) {
if (!waitfree(0x04)) return 0;
outb(buffer[i], 0x300);
if (debug) printf(">%x", buffer[i]);
}
if (debug) printf("\n");
return 1;
}
int readkey(char* key, char len, unsigned char* buffer) {
int i; unsigned char c;
outb(0x10, 0x304);
if (!waitfree(0x0c)) return 0;
for (i = 0; i < 4; i++) {
outb(key[i], 0x300);
if (!waitfree(0x04)) return 0;
}
if (debug) printf("<%s", key);
outb(len, 0x300);
if (debug) printf(">%x", len);
for (i = 0; i < len; i++) {
if (!waitfree(0x05)) return 0;
c = inb(0x300);
buffer[i] = c;
if (debug) printf("<%x", c);
}
if (debug) printf("\n");
return 1;
}
int read_light_sensor(int left) {
unsigned char buffer[6];
if (readkey(left ? LIGHT_SENSOR_LEFT_KEY : LIGHT_SENSOR_RIGHT_KEY, 6, buffer))
return buffer[2];
else
return -1;
}
int set_keyboard_backlight(char value) {
unsigned char buffer[2];
buffer[0] = value;
buffer[1] = 0x00;
return writekey(BACKLIGHT_KEY, 2, buffer);
}
int init_motion_sensor() {
unsigned char buffer[2];
int retry = 50;
int ret;
while (retry) {
ret = readkey(MOTION_SENSOR_KEY, 2, buffer);
if (ret) {
if (buffer[0] || buffer[1]) {
return 1;
}
}
else {
usleep(100000);
retry--;
continue;
}
buffer[0] = 0xe0;
buffer[1] = 0;
writekey(MOTION_SENSOR_KEY, 2, buffer);
retry--;
usleep(100000);
}
return 0;
}
int read_motion_sensor(int index) {
unsigned char buffer[2];
int ret;
switch (index) {
case 0:
ret = readkey(MOTION_SENSOR_X_KEY, 2, buffer);
break;
case 1:
ret = readkey(MOTION_SENSOR_Y_KEY, 2, buffer);
break;
case 2:
ret = readkey(MOTION_SENSOR_Z_KEY, 2, buffer);
break;
}
//printf("%d %x %x\n", index, buffer[0], buffer[1]);
if (ret) {
return (short)(buffer[0] << 8 | buffer[1]);
}
else {
return 0x0FFFFFFF;
}
}
/* Brute-force device probing... */
void probe() {
char key[5];
char chars[37];
unsigned char buffer[2];
int i, j, k, l;
for (i = 0; i < 26; i++) {
chars[i] = 'A'+i;
}
for (i = 0; i < 10; i++) {
chars[i+26] = '0'+i;
}
chars[36] = '_';
key[4] = 0;
for (i = 0; i < 37; i++) {
key[0] = chars[i];
for (j = 0; j < 37; j++) {
key[1] = chars[j];
for (k = 0; k < 37; k++) {
key[2] = chars[k];
for (l = 0; l < 37; l++) {
key[3] = chars[l];
printf("key=%s\n", key);
readkey(key, 2, buffer);
}
}
}
}
}
void usage(char* argv0) {
printf("Apple Macbook (pro) SMC control " VERSION);
printf("\n");
printf("Usage:\n");
printf("%s [-d]: read light/motion sensors values\n", argv0);
printf("%s [-d] value: write keyboard backlight value [0-255]\n", argv0);
}
int main(int argc, char** argv) {
int argi = 1;
if (argc > 3) {
usage(argv[0]);
return 1;
}
if (ioperm(0x300, 0x304, 1) < 0) {
perror("ioperm failed (you should be root).");
exit(1);
}
if ((argc > 1) && !strcmp(argv[1], "-d")) {
debug = 1;
argi = 2;
}
if (argc-argi == 1) {
char* endptr;
long value = strtol(argv[argi], &endptr, 10);
if ((value < 0) || (value > 255) || (endptr[0])) {
printf("Invalid value \"%s\" (should be an integer between 0 and 255).\n", argv[1]);
usage(argv[0]);
return 1;
}
else {
set_keyboard_backlight(value);
}
}
else {
init_motion_sensor();
printf("Light: Left: %d, Right: %d\n", read_light_sensor(1), read_light_sensor(0));
printf("Motion: X: %d, Y: %d, Z: %d\n", read_motion_sensor(0), read_motion_sensor(1), read_motion_sensor(2));
/*while (1) {
printf("Motion: X: %d, Y: %d, Z: %d\n", read_motion_sensor(0), read_motion_sensor(1), read_motion_sensor(2));
sleep(1);
}
int x, y, z, ox, oy, oz;
ox = read_motion_sensor(0);
oy = read_motion_sensor(1);
oz = read_motion_sensor(2);
while (1) {
x = read_motion_sensor(0);
y = read_motion_sensor(1);
z = read_motion_sensor(2);
if ((x-ox)*(x-ox)+(y-oy)*(y-oy)+(z-oz)*(z-oz) > 50)
printf("Accel: X: %d, Y: %d, Z: %d (%d %d)\n", x-ox, y-oy, z-oz, z, oz);
usleep(1000000);
ox = x; oy = y; oz = z;
}*/
}
return 0;
}