C Library that can be incorporated into other apps
krackers opened this issue · comments
Thanks for the logic. I wanted to incorporate this as part of another app, so I removed all the CLI parsing parts from the monolithic main function to get something more library like. I think I also made sure to handle iokit free... Maybe this can be useful to someone.
#import <Foundation/Foundation.h>
#import <IOKit/IOKitLib.h>
typedef CFTypeRef IOAVServiceRef;
extern IOAVServiceRef IOAVServiceCreate(CFAllocatorRef allocator);
extern IOAVServiceRef IOAVServiceCreateWithService(CFAllocatorRef allocator, io_service_t service);
extern IOReturn IOAVServiceReadI2C(IOAVServiceRef service, uint32_t chipAddress, uint32_t offset, void* outputBuffer, uint32_t outputBufferSize);
extern IOReturn IOAVServiceWriteI2C(IOAVServiceRef service, uint32_t chipAddress, uint32_t dataAddress, void* inputBuffer, uint32_t inputBufferSize);
#define LUMINANCE 0x10
#define CONTRAST 0x12
#define VOLUME 0x62
#define MUTE 0x8D
#define INPUT 0x60
#define STANDBY 0xD6
#define RED 0x16 // VCP Code - Video Gain (Drive): Red
#define GREEN 0x18 // VCP Code - Video Gain (Drive): Green
#define BLUE 0x1A // VCP Code - Video Gain (Drive): Blue
#define MUTE_ON 1
#define MUTE_OFF 2
#define DDC_WAIT 10000 // depending on display this must be set to as high as 50000
#define DDC_ITERATIONS 2 // depending on display this must be set higher
void free_ioobject(io_object_t *value) { if (*value != NULL) {IOObjectRelease(*value);} }
void free_cftype(CFTypeRef *value) { if (*value != NULL) {CFRelease(*value);} }
NSArray* getDisplayList() {
NSMutableArray *ret = [NSMutableArray array];
__attribute__((cleanup(free_ioobject))) io_iterator_t iter;
__attribute__((cleanup(free_ioobject))) io_service_t service = 0;
__attribute__((cleanup(free_ioobject))) io_registry_entry_t root = IORegistryGetRootEntry(kIOMainPortDefault);
kern_return_t kerr = IORegistryEntryCreateIterator(root, "IOService", kIORegistryIterateRecursively, &iter);
if (kerr != KERN_SUCCESS) {
return NULL;
}
int i=1;
while ((service = IOIteratorNext(iter)) != MACH_PORT_NULL) {
io_name_t name;
IORegistryEntryGetName(service, name);
if ( !strcmp(name, "AppleCLCD2") ) {
NSString *edidUUID = (__bridge_transfer NSString*) IORegistryEntrySearchCFProperty(service, kIOServicePlane, CFSTR("EDID UUID"), kCFAllocatorDefault, kIORegistryIterateRecursively);
if ( !(edidUUID == NULL) ) {
CFDictionaryRef displayAttrs = (CFDictionaryRef) IORegistryEntrySearchCFProperty(service, kIOServicePlane, CFSTR("DisplayAttributes"), kCFAllocatorDefault, kIORegistryIterateRecursively);
if (displayAttrs ) {
NSDictionary* displayAttrsNS = (__bridge NSDictionary*) displayAttrs;
NSDictionary* productAttrs = [displayAttrsNS objectForKey:@"ProductAttributes"];
if (productAttrs) {
[ret addObject: [NSString stringWithFormat:@"%d %@ %@", i, [productAttrs objectForKey:@"ProductName"], edidUUID]];
}
CFRelease(displayAttrs);
}
i++;
}
}
}
return ret;
}
IOAVServiceRef getAvService(int display) {
if (display == 0) {
return IOAVServiceCreate(kCFAllocatorDefault);
}
IOAVServiceRef ret;
__attribute__((cleanup(free_ioobject))) io_iterator_t iter;
__attribute__((cleanup(free_ioobject))) io_service_t service = 0;
__attribute__((cleanup(free_ioobject))) io_registry_entry_t root = IORegistryGetRootEntry(kIOMainPortDefault);
kern_return_t kerr = IORegistryEntryCreateIterator(root, "IOService", kIORegistryIterateRecursively, &iter);
if (kerr != KERN_SUCCESS) {
return NULL;
}
int i=1;
bool noMatch = true;
while ((service = IOIteratorNext(iter)) != MACH_PORT_NULL) {
io_name_t name;
IORegistryEntryGetName(service, name);
if ( !strcmp(name, "AppleCLCD2") ) {
CFStringRef edidUUID = (CFStringRef) IORegistryEntrySearchCFProperty(service, kIOServicePlane, CFSTR("EDID UUID"), kCFAllocatorDefault, kIORegistryIterateRecursively);
if ( !(edidUUID == NULL) ) {
if ( display == i ) {
while ((service = IOIteratorNext(iter)) != MACH_PORT_NULL) {
io_name_t name;
IORegistryEntryGetName(service, name);
if ( !strcmp(name, "DCPAVServiceProxy") ) {
ret = IOAVServiceCreateWithService(kCFAllocatorDefault, service);
CFStringRef location = (CFStringRef) IORegistryEntrySearchCFProperty(service, kIOServicePlane, CFSTR("Location"), kCFAllocatorDefault, kIORegistryIterateRecursively);
if ( !( location == NULL || !ret || CFStringCompare(CFSTR("External"), location, 0) ) ) {
noMatch = false;
break;
}
CFRelease(location);
}
}
}
i++;
CFRelease(edidUUID);
}
}
}
if ( noMatch ) {
printf("The specified display does not exist. Use 'display list' to list displays and use it's number (1, 2...) to specify display!\n");
return NULL;
}
return ret;
}
IOReturn readDDC(IOAVServiceRef avService, UInt8 action, signed char *curValue, signed char *maxValue) {
// Get ready for DDC operations
UInt8 data[256];
memset(data, 0, sizeof(data));
data[2] = action;
*curValue=-1;
*maxValue=-1;
data[0] = 0x82;
data[1] = 0x01;
data[3] = 0x6e ^ data[0] ^ data[1] ^ data[2] ^ data[3];
IOReturn err;
for (int i = 0; i < DDC_ITERATIONS; ++i) {
usleep(DDC_WAIT);
err = IOAVServiceWriteI2C(avService, 0x37, 0x51, data, 4);
if (err) {
NSLog(@"%@", [NSString stringWithFormat:@"I2C communication failure: %s\n", mach_error_string(err)]);
return err;
}
}
char i2cBytes[12];
memset(i2cBytes, 0, sizeof(i2cBytes));
usleep(DDC_WAIT);
err = IOAVServiceReadI2C(avService, 0x37, 0x51, i2cBytes, 12);
if (err) {
NSLog(@"%@", [NSString stringWithFormat:@"I2C communication failure: %s\n", mach_error_string(err)]);
return err;
}
NSData *readData = [NSData dataWithBytes:(const void *)i2cBytes length:(NSUInteger)11];
NSRange maxValueRange = {7, 1};
NSRange currentValueRange = {9, 1};
[[readData subdataWithRange:maxValueRange] getBytes:maxValue length:sizeof(1)];
[[readData subdataWithRange:currentValueRange] getBytes:curValue length:sizeof(1)];
return 0;
}
IOReturn setDDC( IOAVServiceRef avService, UInt8 action, int setValue) {
UInt8 data[256];
data[0] = 0x84;
data[1] = 0x03;
data[2] = action;
data[3] = (setValue) >> 8;
data[4] = setValue & 255;
data[5] = 0x6E ^ 0x51 ^ data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4];
IOReturn err;
for (int i = 0; i <= DDC_ITERATIONS; i++) {
usleep(DDC_WAIT);
err = IOAVServiceWriteI2C(avService, 0x37, 0x51, data, 6);
if (err) {
NSLog(@"%@", [NSString stringWithFormat:@"I2C communication failure: %s\n", mach_error_string(err)]);
return err;
}
}
return 0;
}
int main(int argc, char** argv) {
NSLog(@"%@", getDisplayList());
IOAVServiceRef ref = getAvService(1);
signed char current = 0;
signed char max = 0;
// readDDC(ref, VOLUME, ¤t, &max);
// printf("Current %d %d\n", current, max);
// setDDC(ref, VOLUME, 10);
readDDC(ref, VOLUME, ¤t, &max);
printf("Current %d %d\n", current, max);
CFRelease(ref);
}
Great, thank you! :)