#include <string.h>
#include <stdio.h>
#include "IOI2C.h"
#define DEBUG 1
#ifdef DEBUG
#define DLOG printf
#else
#define DLOG(fmt, args...)
#endif
#pragma mark ***
#pragma mark *** IOI2CFamily API
#pragma mark ***
CFArrayRef findI2CDevices(void)
{
kern_return_t status;
io_iterator_t iter;
io_registry_entry_t next, nub, bus;
CFMutableArrayRef array;
CFMutableDictionaryRef dict;
char path[8*1024];
CFStringRef pathKey;
CFStringRef compatibleKey;
CFStringRef cfStr;
CFTypeRef cfRef;
DLOG("findI2CDevices\n");
status = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOI2CDevice"), &iter);
if ((status != kIOReturnSuccess) || (iter == 0))
{
DLOG("findI2CDevices found none\n");
return 0;
}
pathKey = CFStringCreateWithCString(NULL, "path", kCFStringEncodingMacRoman);
compatibleKey = CFStringCreateWithCString(NULL, "compatible", kCFStringEncodingMacRoman);
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (pathKey && compatibleKey && array)
{
DLOG("findI2CDevices searching...\n");
while (next = IOIteratorNext(iter))
{
DLOG("findI2CDevices next\n");
if (0 == (dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)))
{
DLOG("findI2CDevices CFDict, ain't!\n");
break;
}
if (kIOReturnSuccess == (status = IORegistryEntryGetPath(next, kIOServicePlane, path)))
{
DLOG("findI2CDevices got path:\n\"%s\"\n",path);
if (cfStr = CFStringCreateWithCString(NULL, path, kCFStringEncodingMacRoman))
{
DLOG("findI2CDevices adding path\n");
CFDictionaryAddValue(dict, pathKey, cfStr),
CFRelease(cfStr);
}
DLOG("findI2CDevices adding class key\n");
CFDictionaryAddValue(dict, CFSTR("IOClass"), CFSTR("IOI2CDevice"));
if (kIOReturnSuccess == (status = IORegistryEntryGetParentEntry(next, kIOServicePlane, &nub)))
{
if (cfRef = IORegistryEntryCreateCFProperty(nub, compatibleKey, NULL, 0))
{
DLOG("findI2CDevices got compatible\n");
CFDictionaryAddValue(dict, compatibleKey, cfRef);
CFRelease(cfRef);
}
if (cfRef = IORegistryEntryCreateCFProperty(nub, CFSTR("reg"), NULL, 0))
{
DLOG("findI2CDevices got address\n");
CFDictionaryAddValue(dict, CFSTR("address"), cfRef);
CFRelease(cfRef);
}
if (kIOReturnSuccess == (status = IORegistryEntryGetParentEntry(nub, kIODeviceTreePlane, &bus)))
{
if (cfRef = IORegistryEntryCreateCFProperty(bus, CFSTR("AAPL,i2c-bus"), NULL, 0))
{
DLOG("findI2CDevices got bus by \"AAPL,i2c-bus\"\n");
CFDictionaryAddValue(dict, CFSTR("bus"), cfRef);
CFRelease(cfRef);
}
else
if (cfRef = IORegistryEntryCreateCFProperty(bus, CFSTR("reg"), NULL, 0))
{
DLOG("findI2CDevices got bus by \"reg\"\n");
CFDictionaryAddValue(dict, CFSTR("bus"), cfRef);
CFRelease(cfRef);
}
IOObjectRelease(bus);
}
IOObjectRelease(nub);
}
DLOG("findI2CDevices got past compatible\n");
CFArrayAppendValue(array, dict);
DLOG("findI2CDevices got past array dict\n");
}
}
DLOG("findI2CDevices iter done\n");
}
DLOG("findI2CDevices release iter\n");
IOObjectRelease(iter);
if (pathKey)
CFRelease(pathKey);
if (compatibleKey)
CFRelease(compatibleKey);
if (array)
{
if (CFArrayGetCount(array) > 0)
{
DLOG("findI2CDevices found devices\n");
return array;
}
CFRelease(array);
}
return 0;
}
CFArrayRef findI2CControllers(void)
{
kern_return_t status;
io_iterator_t iter;
io_registry_entry_t next, nub;
CFMutableArrayRef array;
CFMutableDictionaryRef dict;
char path[8*1024];
CFStringRef pathKey;
CFStringRef compatibleKey;
CFStringRef cfStr;
CFTypeRef cfRef;
DLOG("findI2CControllers\n");
status = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOI2CController"), &iter);
if ((status != kIOReturnSuccess) || (iter == 0))
{
DLOG("findI2CControllers found none\n");
return 0;
}
pathKey = CFStringCreateWithCString(NULL, "path", kCFStringEncodingMacRoman);
compatibleKey = CFStringCreateWithCString(NULL, "compatible", kCFStringEncodingMacRoman);
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (pathKey && compatibleKey && array)
{
DLOG("findI2CControllers searching...\n");
while (next = IOIteratorNext(iter))
{
DLOG("findI2CControllers next\n");
if (0 == (dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)))
{
DLOG("findI2CControllers CFDict, ain't none!\n");
break;
}
if (kIOReturnSuccess == (status = IORegistryEntryGetPath(next, kIOServicePlane, path)))
{
DLOG("findI2CControllers got path:\n\"%s\"\n",path);
if (cfStr = CFStringCreateWithCString(NULL, path, kCFStringEncodingMacRoman))
{
DLOG("findI2CControllers adding path\n");
CFDictionaryAddValue(dict, pathKey, cfStr),
CFRelease(cfStr);
}
DLOG("findI2CControllers adding class key\n");
CFDictionaryAddValue(dict, CFSTR("IOClass"), CFSTR("IOI2CController"));
if (kIOReturnSuccess == (status = IORegistryEntryGetParentEntry(next, kIOServicePlane, &nub)))
{
if (cfRef = IORegistryEntryCreateCFProperty(nub, compatibleKey, NULL, 0))
{
DLOG("findI2CControllers got compatible\n");
CFDictionaryAddValue(dict, compatibleKey, cfRef);
CFRelease(cfRef);
}
if (cfRef = IORegistryEntryCreateCFProperty(nub, CFSTR("AAPL,bus-id"), NULL, 0))
{
DLOG("findI2CControllers got bus\n");
CFDictionaryAddValue(dict, CFSTR("bus"), cfRef);
CFRelease(cfRef);
}
else
if (cfRef = IORegistryEntryCreateCFProperty(nub, CFSTR("reg"), NULL, 0))
{
DLOG("findI2CControllers got bus\n");
CFDictionaryAddValue(dict, CFSTR("bus"), cfRef);
CFRelease(cfRef);
}
IOObjectRelease(nub);
}
DLOG("findI2CControllers got past compatible\n");
CFArrayAppendValue(array, dict);
DLOG("findI2CControllers got past array dict\n");
}
}
DLOG("findI2CControllers iter done\n");
}
DLOG("findI2CControllers release iter\n");
IOObjectRelease(iter);
if (pathKey)
CFRelease(pathKey);
if (compatibleKey)
CFRelease(compatibleKey);
if (array)
{
if (CFArrayGetCount(array) > 0)
{
DLOG("findI2CControllers found devices\n");
return array;
}
CFRelease(array);
}
return 0;
}
CFArrayRef findPPCI2CInterfaces(void)
{
CFMutableArrayRef array;
CFArrayRef pathsarray;
CFMutableDictionaryRef dict;
DLOG("findPPCI2CInterfaces\n");
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (pathsarray = findI2CInterfaces())
{
int i, count = CFArrayGetCount(pathsarray);
for (i = 0; i < count; i++)
{
if (dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))
{
CFDictionaryAddValue(dict, CFSTR("path"), CFArrayGetValueAtIndex(pathsarray, i)),
CFDictionaryAddValue(dict, CFSTR("IOClass"), CFSTR("PPCI2CInterface"));
CFArrayAppendValue(array, dict);
}
}
}
if (array)
{
if (CFArrayGetCount(array) > 0)
{
DLOG("findPPCI2CInterfaces found devices\n");
return array;
}
CFRelease(array);
}
return 0;
}
IOReturn openI2CDevice(
I2CDeviceRef *device,
CFStringRef path)
{
kern_return_t status;
io_string_t pathBuf;
io_service_t svc;
io_connect_t cnct;
const char *strPtr;
if (path == NULL || device == NULL)
return kIOReturnBadArgument;
device->_i2c_key = kIOI2C_CLIENT_KEY_DEFAULT;
strPtr = CFStringGetCStringPtr(path, kCFStringEncodingMacRoman);
if (strPtr == NULL)
return kIOReturnBadArgument;
strcpy(pathBuf, strPtr);
svc = IORegistryEntryFromPath(kIOMasterPortDefault, pathBuf);
if (svc == MACH_PORT_NULL)
{
DLOG("IOI2C failed to get service handle from path\n");
return kIOReturnNotFound;
}
status = IOServiceOpen(svc, mach_task_self(), kIOI2CUserClientType, &cnct);
IOObjectRelease(svc);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to instantiate user client\n");
return status;
}
device->_i2c_connect = cnct;
return kIOReturnSuccess;
}
IOReturn closeI2CDevice(
I2CDeviceRef *device)
{
kern_return_t status = kIOReturnSuccess;
if (device == NULL)
return kIOReturnBadArgument;
if (device->_i2c_key)
{
unlockI2CDevice(device);
device->_i2c_key = kIOI2C_CLIENT_KEY_DEFAULT;
}
if (device->_i2c_connect)
{
IOServiceClose(device->_i2c_connect);
device->_i2c_connect = 0;
}
return status;
}
IOReturn lockI2CDevice(
I2CDeviceRef *device)
{
if (device == NULL)
return kIOReturnBadArgument;
return IOConnectMethodScalarIScalarO(device->_i2c_connect, kI2CUCLock, 1, 1, 0, &device->_i2c_key);
}
IOReturn unlockI2CDevice(
I2CDeviceRef *device)
{
if (device == NULL)
return kIOReturnBadArgument;
return IOConnectMethodScalarIScalarO(device->_i2c_connect, kI2CUCUnlock, 1, 0, device->_i2c_key);
}
IOReturn readI2CDevice(
I2CDeviceRef *device,
UInt32 subAddress,
UInt8 *readBuf,
UInt32 count)
{
I2CUserReadInput inputs;
I2CUserReadOutput outputs;
IOByteCount inSize, outSize;
kern_return_t status;
int i;
if (count > kI2CUCBufSize)
{
DLOG("IOI2C readI2CBus count is too large\n");
return kIOReturnBadArgument;
}
inputs.count = count;
inputs.mode = kI2CMode_Combined;
inputs.subAddr = subAddress;
inputs.key = device->_i2c_key;
inSize = sizeof(I2CUserReadInput);
outSize = sizeof(I2CUserReadOutput);
status = IOConnectMethodStructureIStructureO(device->_i2c_connect,
kI2CUCRead, inSize, &outSize, &inputs, &outputs);
if (status == 0)
{
if (outputs.realCount != count)
return kIOReturnError;
for (i = 0; i < count; i++)
readBuf[i] = outputs.buf[i];
}
return status;
}
IOReturn writeI2CDevice(I2CDeviceRef *device, UInt32 subAddress, UInt8 *writeBuf, UInt32 count)
{
I2CUserWriteInput inputs;
I2CUserWriteOutput outputs;
IOByteCount inSize, outSize;
kern_return_t status;
int i;
if (count > kI2CUCBufSize)
{
DLOG("IOI2C writeI2CBus count is too large\n");
return kIOReturnBadArgument;
}
inputs.count = count;
inputs.mode = kI2CMode_StandardSub;
inputs.subAddr = subAddress;
inputs.key = device->_i2c_key;
outputs.realCount = 0;
inSize = sizeof(I2CUserWriteInput);
outSize = sizeof(I2CUserWriteOutput);
for (i = 0; i < count; i++)
inputs.buf[i] = writeBuf[i];
status = IOConnectMethodStructureIStructureO(device->_i2c_connect,
kI2CUCWrite, inSize, &outSize, &inputs, &outputs);
if (status == 0)
{
if (outputs.realCount != count)
return kIOReturnError;
}
return status;
}
IOReturn lockI2CExtended(
I2CDeviceRef *device,
UInt32 bus)
{
if (device == NULL)
return kIOReturnBadArgument;
return IOConnectMethodScalarIScalarO(device->_i2c_connect, kI2CUCLock, 1, 1, bus, &device->_i2c_key);
}
IOReturn readI2CExtended(
I2CDeviceRef *device,
UInt32 bus,
UInt32 address,
UInt32 subAddress,
UInt8 *readBuf,
UInt32 count,
UInt32 mode,
UInt32 options)
{
I2CUserReadInput inputs;
I2CUserReadOutput outputs;
IOByteCount inSize, outSize;
kern_return_t status;
int i;
if (count > kI2CUCBufSize)
{
DLOG("IOI2C readI2CExtended count is too large\n");
return kIOReturnBadArgument;
}
inputs.options = options;
inputs.mode = mode;
inputs.busNo = bus;
inputs.addr = address;
inputs.subAddr = subAddress;
inputs.count = count;
inputs.key = device->_i2c_key;
inSize = sizeof(I2CUserReadInput);
outSize = sizeof(I2CUserReadOutput);
status = IOConnectMethodStructureIStructureO(device->_i2c_connect,
kI2CUCRead, inSize, &outSize, &inputs, &outputs);
if (status == 0)
{
if (outputs.realCount != count)
return kIOReturnError;
for (i = 0; i < count; i++)
readBuf[i] = outputs.buf[i];
}
return status;
}
IOReturn writeI2CExtended(
I2CDeviceRef *device,
UInt32 bus,
UInt32 address,
UInt32 subAddress,
UInt8 *writeBuf,
UInt32 count,
UInt32 mode,
UInt32 options)
{
I2CUserWriteInput inputs;
I2CUserWriteOutput outputs;
IOByteCount inSize, outSize;
kern_return_t status;
int i;
if (count > kI2CUCBufSize)
{
DLOG("IOI2C writeI2CExtended count is too large\n");
return kIOReturnBadArgument;
}
inputs.options = options;
inputs.mode = mode;
inputs.busNo = bus;
inputs.addr = address;
inputs.subAddr = subAddress;
inputs.count = count;
inputs.key = device->_i2c_key;
outputs.realCount = 0;
inSize = sizeof(I2CUserWriteInput);
outSize = sizeof(I2CUserWriteOutput);
for (i = 0; i < count; i++)
inputs.buf[i] = writeBuf[i];
status = IOConnectMethodStructureIStructureO(device->_i2c_connect,
kI2CUCWrite, inSize, &outSize, &inputs, &outputs);
if (status == 0)
{
if (outputs.realCount != count)
return kIOReturnError;
}
return status;
}
#pragma mark ***
#pragma mark *** PPCI2CInterface API
#pragma mark ***
IOReturn readI2CInterface(
I2CInterfaceRef iface,
UInt32 bus,
UInt32 address,
UInt32 subAddress,
UInt8 *buffer,
UInt32 count,
UInt32 mode)
{
I2CReadInput inputs;
I2CReadOutput outputs;
IOByteCount inSize, outSize;
kern_return_t status;
int i;
if (count > kI2CUCBufSize)
{
DLOG("IOI2C readI2CBus count is too large\n");
return kIOReturnBadArgument;
}
inputs.busNo = bus;
inputs.addr = address;
inputs.subAddr = subAddress;
inputs.count = count;
inputs.mode = mode;
inSize = sizeof(I2CReadInput);
outSize = sizeof(I2CReadOutput);
status = IOConnectMethodStructureIStructureO(iface,
kI2CUCRead, inSize, &outSize, &inputs, &outputs);
if (status == 0)
{
if (outputs.realCount != count)
return kIOReturnError;
for (i = 0; i < count; i++)
buffer[i] = outputs.buf[i];
}
return status;
}
IOReturn writeI2CInterface(
I2CInterfaceRef iface,
UInt32 bus,
UInt32 address,
UInt32 subAddress,
UInt8 *buffer,
UInt32 count,
UInt32 mode)
{
I2CWriteInput inputs;
I2CWriteOutput outputs;
IOByteCount inSize, outSize;
kern_return_t status;
int i;
if (count > kI2CUCBufSize)
{
DLOG("IOI2C writeI2CExtended count is too large\n");
return kIOReturnBadArgument;
}
inputs.mode = mode;
inputs.busNo = bus;
inputs.addr = address;
inputs.subAddr = subAddress;
inputs.count = count;
outputs.realCount = 0;
inSize = sizeof(I2CWriteInput);
outSize = sizeof(I2CWriteOutput);
for (i = 0; i < count; i++)
inputs.buf[i] = buffer[i];
status = IOConnectMethodStructureIStructureO(iface,
kI2CUCWrite, inSize, &outSize, &inputs, &outputs);
if (status == 0)
{
if (outputs.realCount != count)
return kIOReturnError;
}
return status;
}
#if 1
#define IFACE_CLASSNAME "PPCI2CInterface"
Boolean isResouce(const char *key)
{
Boolean exists;
io_registry_entry_t resources;
CFStringRef propKey;
CFTypeRef cfRef;
propKey = CFStringCreateWithCString(NULL, key,
kCFStringEncodingMacRoman);
resources = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceNameMatching("IOResources"));
if (resources == 0)
{
DLOG("IOI2C failed to get IOResources\n");
return false;
}
cfRef = IORegistryEntryCreateCFProperty(resources,
propKey, NULL, 0);
IOObjectRelease(resources);
CFRelease(propKey);
if (cfRef == NULL)
{
exists = false;
}
else
{
exists = true;
CFRelease(cfRef);
}
return exists;
}
CFArrayRef findI2CInterfaces(void)
{
CFStringRef anIface;
CFMutableArrayRef ifaces;
ifaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (anIface = getMacIOI2CInterface())
{
CFArrayAppendValue(ifaces, anIface);
CFRelease(anIface);
}
if (anIface = getUniNI2CInterface())
{
CFArrayAppendValue(ifaces, anIface);
CFRelease(anIface);
}
if (anIface = getPMUI2CInterface())
{
CFArrayAppendValue(ifaces, anIface);
CFRelease(anIface);
}
if (anIface = getSMUI2CInterface())
{
CFArrayAppendValue(ifaces, anIface);
CFRelease(anIface);
}
if (CFArrayGetCount(ifaces) > 0)
{
return ifaces;
}
else
{
CFRelease(ifaces);
return NULL;
}
}
CFStringRef getMacIOI2CInterface(void)
{
io_service_t i2c_nub, i2c_driver;
io_string_t path;
io_name_t className;
kern_return_t status;
CFStringRef pathStr;
if (!isResouce("PPCI2CInterface.i2c-mac-io"))
{
DLOG("IOI2C no PPCI2CInterface bound to mac-io i2c\n");
return NULL;
}
i2c_nub = (io_service_t)IORegistryEntryFromPath(kIOMasterPortDefault,
"IODeviceTree:ki2c");
if (i2c_nub == MACH_PORT_NULL)
{
DLOG("IOI2C failed to resolve ki2c device alias\n");
i2c_nub = (io_service_t)IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:mac-io/i2c");
if (i2c_nub == MACH_PORT_NULL)
{
DLOG("IOI2C failed to find mac-io/i2c device nub\n");
return NULL;
}
}
if (i2c_nub == MACH_PORT_NULL)
{
DLOG("IOI2C failed to resolve ki2c device alias\n");
return NULL;
}
status = IORegistryEntryGetChildEntry(i2c_nub, kIOServicePlane, &i2c_driver);
IOObjectRelease(i2c_nub);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to fetch child of mac-io i2c nub\n");
return NULL;
}
status = IOObjectGetClass(i2c_driver, className);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to get class of mac-io i2c driver\n");
return NULL;
}
if (strcmp(className, IFACE_CLASSNAME) != 0)
{
DLOG("IOI2C mac-io i2c driver is wrong class: %s\n", className);
return NULL;
}
status = IORegistryEntryGetPath(i2c_driver, kIOServicePlane, path);
IOObjectRelease(i2c_driver);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to get path to mac-io i2c driver\n");
return NULL;
}
pathStr = CFStringCreateWithCString(NULL, path, kCFStringEncodingMacRoman);
if (pathStr == NULL)
{
DLOG("IOI2C failed to create CFString for mac-io i2c driver path\n");
return NULL;
}
return pathStr;
}
CFStringRef getUniNI2CInterface(void)
{
io_service_t i2c_nub, i2c_driver;
io_string_t path;
io_name_t className;
kern_return_t status;
CFStringRef pathStr;
if (!isResouce("PPCI2CInterface.i2c-uni-n"))
{
DLOG("IOI2C no PPCI2CInterface bound to UniN i2c\n");
return NULL;
}
i2c_nub = (io_service_t)IORegistryEntryFromPath(kIOMasterPortDefault,
"IODeviceTree:ui2c");
if (i2c_nub == MACH_PORT_NULL)
{
DLOG("IOI2C failed to resolve ui2c device alias\n");
i2c_nub = (io_service_t)IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:u3/i2c");
if (i2c_nub == MACH_PORT_NULL)
{
DLOG("IOI2C failed to find u3/i2c device nub\n");
return NULL;
}
}
status = IORegistryEntryGetChildEntry(i2c_nub, kIOServicePlane, &i2c_driver);
IOObjectRelease(i2c_nub);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to fetch child of unin i2c nub\n");
return NULL;
}
status = IOObjectGetClass(i2c_driver, className);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to get class of unin i2c driver\n");
return NULL;
}
if (strcmp(className, IFACE_CLASSNAME) != 0)
{
DLOG("IOI2C unin i2c driver is wrong class: %s\n", className);
return NULL;
}
status = IORegistryEntryGetPath(i2c_driver, kIOServicePlane, path);
IOObjectRelease(i2c_driver);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to get path to unin i2c driver\n");
return NULL;
}
pathStr = CFStringCreateWithCString(NULL, path, kCFStringEncodingMacRoman);
if (pathStr == NULL)
{
DLOG("IOI2C failed to create CFString for unin i2c driver path\n");
return NULL;
}
return pathStr;
}
CFStringRef getPMUI2CInterface(void)
{
io_service_t i2c_nub, i2c_driver;
io_string_t path;
io_name_t className;
kern_return_t status;
CFStringRef pathStr;
if (!isResouce("PPCI2CInterface.pmu-i2c"))
{
DLOG("IOI2C no PPCI2CInterface bound to PMU i2c\n");
return NULL;
}
i2c_nub = (io_service_t)IORegistryEntryFromPath(kIOMasterPortDefault,
"IODeviceTree:pi2c");
if (i2c_nub == MACH_PORT_NULL)
{
DLOG("IOI2C failed to resolve pi2c device alias\n");
i2c_nub = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceNameMatching("pmu-i2c"));
if (i2c_nub == MACH_PORT_NULL)
{
DLOG("IOI2C failed to find pmu-i2c device nub\n");
return NULL;
}
}
status = IORegistryEntryGetChildEntry(i2c_nub, kIOServicePlane, &i2c_driver);
IOObjectRelease(i2c_nub);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to fetch child of pmu i2c nub\n");
return NULL;
}
status = IOObjectGetClass(i2c_driver, className);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to get class of pmu i2c driver\n");
return NULL;
}
if (strcmp(className, IFACE_CLASSNAME) != 0)
{
DLOG("IOI2C pmu i2c driver is wrong class: %s\n", className);
return NULL;
}
status = IORegistryEntryGetPath(i2c_driver, kIOServicePlane, path);
IOObjectRelease(i2c_driver);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to get path to pmu i2c driver\n");
return NULL;
}
pathStr = CFStringCreateWithCString(NULL, path, kCFStringEncodingMacRoman);
if (pathStr == NULL)
{
DLOG("IOI2C failed to create CFString for pmu i2c driver path\n");
return NULL;
}
return pathStr;
}
CFStringRef getSMUI2CInterface(void)
{
io_service_t i2c_nub, i2c_driver;
io_string_t path;
io_name_t className;
kern_return_t status;
CFStringRef pathStr;
if (!isResouce("PPCI2CInterface.smu-i2c"))
{
DLOG("IOI2C no PPCI2CInterface bound to SMU i2c\n");
return NULL;
}
i2c_nub = (io_service_t)IORegistryEntryFromPath(kIOMasterPortDefault,
"IODeviceTree:smu/i2c");
if (i2c_nub == MACH_PORT_NULL)
{
DLOG("IOI2C failed to resolve smu/i2c device alias\n");
i2c_nub = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceNameMatching("smu-i2c"));
if (i2c_nub == MACH_PORT_NULL)
{
DLOG("IOI2C failed to find smu-i2c device nub\n");
return NULL;
}
}
status = IORegistryEntryGetChildEntry(i2c_nub, kIOServicePlane, &i2c_driver);
IOObjectRelease(i2c_nub);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to fetch child of smu i2c nub\n");
return NULL;
}
status = IOObjectGetClass(i2c_driver, className);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to get class of SMU i2c driver\n");
return NULL;
}
if (strcmp(className, IFACE_CLASSNAME) != 0)
{
DLOG("IOI2C SMU i2c driver is wrong class: %s\n", className);
return NULL;
}
status = IORegistryEntryGetPath(i2c_driver, kIOServicePlane, path);
IOObjectRelease(i2c_driver);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to get path to smu i2c driver\n");
return NULL;
}
pathStr = CFStringCreateWithCString(NULL, path, kCFStringEncodingMacRoman);
if (pathStr == NULL)
{
DLOG("IOI2C failed to create CFString for smu i2c driver path\n");
return NULL;
}
return pathStr;
}
IOReturn openI2CInterface(CFStringRef interface, I2CInterfaceRef *iface)
{
kern_return_t status;
io_string_t path;
io_service_t svc;
io_connect_t cnct;
const char *strPtr;
if (interface == NULL || iface == NULL) return kIOReturnBadArgument;
strPtr = CFStringGetCStringPtr(interface, kCFStringEncodingMacRoman);
if (strPtr == NULL) return kIOReturnBadArgument;
strcpy(path, strPtr);
svc = IORegistryEntryFromPath(kIOMasterPortDefault, path);
if (svc == MACH_PORT_NULL)
{
DLOG("IOI2C failed to get service handle from path\n");
return kIOReturnNotFound;
}
status = IOServiceOpen(svc, mach_task_self(), 0, &cnct);
IOObjectRelease(svc);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to instantiate user client\n");
return status;
}
status = IOConnectMethodScalarIScalarO(cnct, kI2CUCLock, 0, 0);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to open the user client\n");
IOServiceClose(cnct);
return status;
}
*iface = cnct;
return kIOReturnSuccess;
}
IOReturn closeI2CInterface(I2CInterfaceRef iface)
{
kern_return_t status;
if (iface == 0) return kIOReturnBadArgument;
status = IOConnectMethodScalarIScalarO(iface, kI2CUCUnlock, 0, 0);
if (status != kIOReturnSuccess)
{
DLOG("IOI2C failed to close the user client\n");
}
IOServiceClose(iface);
return status;
}
IOReturn readI2CBus(I2CInterfaceRef iface, I2CReadInput *inputs,
I2CReadOutput *outputs)
{
IOByteCount inSize, outSize;
kern_return_t status;
if (iface == 0 || inputs == NULL || outputs == NULL)
{
DLOG("IOI2C readI2CBus received NULL pointer arg\n");
return kIOReturnBadArgument;
}
if (inputs->count > kI2CUCBufSize)
{
DLOG("IOI2C readI2CBus count is too large\n");
return kIOReturnBadArgument;
}
inSize = sizeof(I2CReadInput);
outSize = sizeof(I2CReadOutput);
status = IOConnectMethodStructureIStructureO(iface,
kI2CUCRead, inSize, &outSize, inputs, outputs);
return status;
}
IOReturn writeI2CBus(I2CInterfaceRef iface, I2CWriteInput *inputs,
I2CWriteOutput *outputs)
{
IOByteCount inSize, outSize;
kern_return_t status;
if (iface == 0 || inputs == NULL || outputs == NULL)
{
DLOG("IOI2C writeI2CBus received NULL pointer arg\n");
return kIOReturnBadArgument;
}
if (inputs->count > kI2CUCBufSize)
{
DLOG("IOI2C writeI2CBus count is too large\n");
return kIOReturnBadArgument;
}
inSize = sizeof(I2CWriteInput);
outSize = sizeof(I2CWriteOutput);
status = IOConnectMethodStructureIStructureO(iface,
kI2CUCWrite, inSize, &outSize, inputs, outputs);
return status;
}
IOReturn rmwI2CBus(I2CInterfaceRef iface, I2CRMWInput *inputs)
{
IOByteCount inSize, outSize;
kern_return_t status;
if (iface == 0 || inputs == NULL)
{
DLOG("IOI2C rmwI2CBus received NULL pointer arg\n");
return kIOReturnBadArgument;
}
inSize = sizeof(I2CRMWInput);
outSize = 0;
status = IOConnectMethodStructureIStructureO(iface,
kI2CUCRMW, inSize, &outSize, inputs, NULL);
return status;
}
#endif