You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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);
}
The text was updated successfully, but these errors were encountered:
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.
The text was updated successfully, but these errors were encountered: