287 lines
6.3 KiB
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;
|
||
|
}
|