/* * Apple Macbook Pro SMC control * * Copyright (C) 2006 Nicolas Boichat * * 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 #include #include #include #include #include #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; }