Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
470 lines (407 sloc) 12.4 KB
/*
* UniMotion - Unified Motion detection for Apple portables.
*
* Copyright (c) 2006 Lincoln Ramsay. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation Inc. 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
*/
/*
* HISTORY of Motion
* Written by Christian Klein
* Modified for iBook compatibility by Pall Thayer
* Modified for Hi Res Powerbook compatibility by Pall Thayer
* Modified for MacBook Pro compatibility by Randy Green
* Disparate forks unified into UniMotion by Lincoln Ramsay
*/
// This license applies to the portions created by Cristian Klein.
/* motion.c
*
* a little program to display the coords returned by
* the powerbook motion sensor
*
* A fine piece of c0de, brought to you by
*
* ---===---
* *** teenage mutant ninja hero coders ***
* ---===---
*
* All of the software included is copyrighted by Christian Klein <chris@5711.org>.
*
* Copyright 2005 Christian Klein. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author must not be used to endorse or promote
* products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include "unimotion.h"
#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CoreFoundation.h>
#include <string.h>
#include <stdint.h>
enum data_type {
PB_IB,
MBP
};
struct pb_ib_data {
int8_t x;
int8_t y;
int8_t z;
int8_t pad[57];
};
struct mbp_data {
int16_t x;
int16_t y;
int16_t z;
int8_t pad[34];
};
union motion_data {
struct pb_ib_data pb_ib;
struct mbp_data mbp;
};
struct default_real_values {
double xreal;
double yreal;
double zreal;
};
static struct default_real_values drv[] = {
{0.0,0.0,0.0}, // unknown
{2.0e-2,2.0e-2,2.0e-2}, // powerbook
{2.0e-2,2.0e-2,2.0e-2}, // ibook
{-2.0e-2,-2.0e-2,-2.0e-2}, // highrespb
{4.0e-3,4.0e-3,4.0e-3}, // macbookpro
};
struct default_scale_values {
int xscale;
int yscale;
int zscale;
};
static struct default_scale_values dsv[] = {
{0,0,0}, // unknown
{5,5,5}, // powerbook
{5,5,5}, // ibook
{-5,-5,-5}, // highrespb
{1,1,1}, // macbookpro
};
static int set_values(int type, int *kernFunc, char **servMatch, int *dataType)
{
switch ( type ) {
case powerbook:
*kernFunc = 21;
*servMatch = "IOI2CMotionSensor";
*dataType = PB_IB;
break;
case ibook:
*kernFunc = 21;
*servMatch = "IOI2CMotionSensor";
*dataType = PB_IB;
break;
case highrespb:
*kernFunc = 21;
*servMatch = "PMUMotionSensor";
*dataType = PB_IB;
break;
case macbookpro:
*kernFunc = 5;
*servMatch = "SMCMotionSensor";
*dataType = MBP;
break;
default:
return 0;
}
return 1;
}
static int probe_sms(int kernFunc, char *servMatch, int dataType, void *data)
{
kern_return_t result;
mach_port_t masterPort;
io_iterator_t iterator;
io_object_t aDevice;
io_connect_t dataPort;
IOItemCount structureInputSize;
size_t structureOutputSize;
union motion_data inputStructure;
union motion_data *outputStructure;
outputStructure = (union motion_data *)data;
result = IOMasterPort(MACH_PORT_NULL, &masterPort);
CFMutableDictionaryRef matchingDictionary = IOServiceMatching(servMatch);
result = IOServiceGetMatchingServices(masterPort, matchingDictionary, &iterator);
if (result != KERN_SUCCESS) {
//fputs("IOServiceGetMatchingServices returned error.\n", stderr);
return 0;
}
aDevice = IOIteratorNext(iterator);
IOObjectRelease(iterator);
if (aDevice == 0) {
//fputs("No motion sensor available\n", stderr);
return 0;
}
result = IOServiceOpen(aDevice, mach_task_self(), 0, &dataPort);
IOObjectRelease(aDevice);
if (result != KERN_SUCCESS) {
//fputs("Could not open motion sensor device\n", stderr);
return 0;
}
switch ( dataType ) {
case PB_IB:
structureInputSize = sizeof(struct pb_ib_data);
structureOutputSize = sizeof(struct pb_ib_data);
break;
case MBP:
structureInputSize = sizeof(struct mbp_data);
structureOutputSize = sizeof(struct mbp_data);
break;
default:
return 0;
}
memset(&inputStructure, 0, sizeof(union motion_data));
memset(outputStructure, 0, sizeof(union motion_data));
#if !defined(__LP64__)
// Check if Mac OS X 10.5 API is available...
if (IOConnectCallMethod != NULL) {
// ...and use it if it is.
#endif
result = IOConnectCallStructMethod(dataPort, kernFunc, &inputStructure, structureInputSize,
outputStructure, &structureOutputSize);
#if !defined(__LP64__)
}
else {
// Otherwise fall back to older API.
result = IOConnectMethodStructureIStructureO(dataPort, kernFunc, structureInputSize,
&structureOutputSize, &inputStructure, outputStructure);
}
#endif
IOServiceClose(dataPort);
if (result != KERN_SUCCESS) {
//puts("no coords");
return 0;
}
return 1;
}
int detect_sms()
{
int kernFunc;
char *servMatch;
int dataType;
union motion_data data;
int i;
for ( i = 1; ; i++ ) {
if ( !set_values(i, &kernFunc, &servMatch, &dataType) )
break;
if ( probe_sms(kernFunc, servMatch, dataType, &data) )
return i;
}
return unknown;
}
int read_sms_raw(int type, int *x, int *y, int *z)
{
int kernFunc;
char *servMatch;
int dataType;
union motion_data data;
int t;
t = type;
if ( t == 0 ) {
int i;
for ( i = 1; ; i++ ) {
if ( !set_values(i, &kernFunc, &servMatch, &dataType) )
break;
if ( probe_sms(kernFunc, servMatch, dataType, &data) ) {
t = i;
break;
}
}
} else {
if ( !set_values(type, &kernFunc, &servMatch, &dataType) )
return 0;
if ( !probe_sms(kernFunc, servMatch, dataType, &data) )
return 0;
}
if ( t ) {
switch ( dataType ) {
case PB_IB:
if ( x ) *x = data.pb_ib.x;
if ( y ) *y = data.pb_ib.y;
if ( z ) *z = data.pb_ib.z;
break;
case MBP:
if ( x ) *x = data.mbp.x;
if ( y ) *y = data.mbp.y;
if ( z ) *z = data.mbp.z;
break;
default:
return 0;
}
return 1;
}
return 0;
}
int read_sms(int type, int *x, int *y, int *z)
{
int _x, _y, _z;
long xoff, yoff, zoff;
Boolean ok;
int ret;
ret = read_sms_raw(type, &_x, &_y, &_z);
if ( !ret )
return 0;
static CFStringRef app = CFSTR("com.ramsayl.UniMotion");
static CFStringRef xoffstr = CFSTR("x_offset");
static CFStringRef yoffstr = CFSTR("y_offset");
static CFStringRef zoffstr = CFSTR("z_offset");
xoff = CFPreferencesGetAppIntegerValue(xoffstr, app, &ok);
if ( ok ) _x += xoff;
yoff = CFPreferencesGetAppIntegerValue(yoffstr, app, &ok);
if ( ok ) _y += yoff;
zoff = CFPreferencesGetAppIntegerValue(zoffstr, app, &ok);
if ( ok ) _z += zoff;
*x = _x;
*y = _y;
*z = _z;
return ret;
}
static Boolean getPrefDouble(CFStringRef key, CFStringRef app, double *val)
{
CFPropertyListRef prefRef;
Boolean ok;
double ret;
ok = false;
prefRef = CFPreferencesCopyAppValue(key, app);
if ( prefRef ) {
if ( CFGetTypeID(prefRef) == CFNumberGetTypeID() && CFNumberIsFloatType(prefRef) ) {
ok = CFNumberGetValue(prefRef, kCFNumberDoubleType, &ret);
if ( ok && val )
*val = ret;
}
CFRelease(prefRef);
}
return ok;
}
int read_sms_real(int type, double *x, double *y, double *z)
{
int _x, _y, _z;
long xscale, yscale, zscale;
double xreal, yreal, zreal;
int ret;
Boolean ok;
// start with the "calibrated" (offset applied) value
ret = read_sms(type, &_x, &_y, &_z);
if ( !ret )
return 0;
static CFStringRef app = CFSTR("com.ramsayl.UniMotion");
static CFStringRef xrealstr = CFSTR("x_real");
static CFStringRef yrealstr = CFSTR("y_real");
static CFStringRef zrealstr = CFSTR("z_real");
static CFStringRef xscalestr = CFSTR("x_scale");
static CFStringRef yscalestr = CFSTR("y_scale");
static CFStringRef zscalestr = CFSTR("z_scale");
#define codeblock(x,_x,xreal,xscale) \
ok = getPrefDouble(xreal##str, app, &xreal); \
if ( ok ) { \
*x = _x * xreal; /* use x_real if it's there */ \
} else { \
xscale = CFPreferencesGetAppIntegerValue(xscale##str, app, &ok); \
if ( ok ) { \
*x = _x / (double)xscale; /* try x_scale next */ \
} else { \
*x = _x * drv[type].xreal; /* fall back to "standard" values */ \
} \
}
codeblock(x,_x,xreal,xscale);
codeblock(y,_y,yreal,yscale);
codeblock(z,_z,zreal,zscale);
#undef codeblock
return 1;
}
uint8_t *read_sms_raw_bytes(int type, int *size)
{
int kernFunc;
char *servMatch;
int dataType;
uint8_t *data;
int t;
data = malloc(sizeof(union motion_data));
if ( data == 0 )
return 0;
t = type;
if ( t == 0 ) {
int i;
for ( i = 1; ; i++ ) {
if ( !set_values(i, &kernFunc, &servMatch, &dataType) )
break;
if ( probe_sms(kernFunc, servMatch, dataType, data) ) {
t = i;
break;
}
}
} else {
if ( !set_values(type, &kernFunc, &servMatch, &dataType) )
return 0;
if ( !probe_sms(kernFunc, servMatch, dataType, data) )
return 0;
}
if ( t ) {
switch ( dataType ) {
case PB_IB:
if ( size )
*size = sizeof(struct pb_ib_data);
break;
case MBP:
if ( size )
*size = sizeof(struct mbp_data);
break;
default:
t = 0;
break;
}
if ( t )
return data;
}
free(data);
if ( size )
*size = 0;
return 0;
}
int read_sms_scaled(int type, int *x, int *y, int *z)
{
int _x, _y, _z;
int ret;
ret = read_sms(type, &_x, &_y, &_z);
if ( !ret )
return 0;
*x = _x + dsv[type].xscale;
*y = _y + dsv[type].yscale;
*z = _z + dsv[type].zscale;
return ret;
}