Skip to content

Instantly share code, notes, and snippets.

@alin23
Created July 27, 2021 20:50
Show Gist options
  • Select an option

  • Save alin23/6d89cfd15c22fb61cc1ad7b3c4ac69d1 to your computer and use it in GitHub Desktop.

Select an option

Save alin23/6d89cfd15c22fb61cc1ad7b3c4ac69d1 to your computer and use it in GitHub Desktop.

Revisions

  1. alin23 created this gist Jul 27, 2021.
    134 changes: 134 additions & 0 deletions i2cwrite-scan.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,134 @@
    @import Darwin;
    @import Foundation;
    @import IOKit;

    // clang -fmodules -o i2cwrite-scan i2cwrite-scan.m && ./i2cwrite-scan

    typedef CFTypeRef IOAVServiceRef;
    extern IOAVServiceRef IOAVServiceCreate(CFAllocatorRef allocator);
    extern IOAVServiceRef IOAVServiceCreateWithService(CFAllocatorRef allocator, io_service_t service);

    extern IOReturn IOAVServiceCopyEDID(IOAVServiceRef service, CFDataRef* x2);
    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 BRIGHTNESS 0x10
    #define CONTRAST 0x12
    #define AUDIO_SPEAKER_VOLUME 0x62
    #define AUDIO_MUTE 0x8D
    #define INPUT_SOURCE 0x60
    #define DPMS 0xD6

    struct DDCWriteCommand {
    UInt8 control_id;
    UInt8 new_value;
    };

    int main(int argc, char** argv)
    {
    io_iterator_t iter;
    io_service_t service = 0;
    io_registry_entry_t root = IORegistryGetRootEntry(kIOMasterPortDefault);
    kern_return_t kerr = IORegistryEntryCreateIterator(root, "IOService", kIORegistryIterateRecursively, &iter);
    if (kerr != KERN_SUCCESS) {
    IOObjectRelease(iter);
    NSLog(@"Error on IORegistryEntryCreateIterator: %d", kerr);
    return 1;
    }

    CFStringRef edidUUIDKey = CFStringCreateWithCString(kCFAllocatorDefault, "EDID UUID", kCFStringEncodingASCII);
    CFStringRef locationKey = CFStringCreateWithCString(kCFAllocatorDefault, "Location", kCFStringEncodingASCII);
    CFStringRef displayAttributesKey = CFStringCreateWithCString(kCFAllocatorDefault, "DisplayAttributes", kCFStringEncodingASCII);
    CFStringRef externalAVServiceLocation = CFStringCreateWithCString(kCFAllocatorDefault, "External", kCFStringEncodingASCII);

    while ((service = IOIteratorNext(iter)) != MACH_PORT_NULL) {
    io_name_t name;
    IORegistryEntryGetName(service, name);
    if (strcmp(name, "AppleCLCD2") == 0) {
    CFStringRef edidUUID = IORegistryEntrySearchCFProperty(service, kIOServicePlane, edidUUIDKey, kCFAllocatorDefault, kIORegistryIterateRecursively);
    CFDictionaryRef displayAttrs = IORegistryEntrySearchCFProperty(service, kIOServicePlane, displayAttributesKey, kCFAllocatorDefault, kIORegistryIterateRecursively);
    if (displayAttrs) {
    NSDictionary* displayAttrsNS = (NSDictionary*)displayAttrs;
    NSDictionary* productAttrs = [displayAttrsNS objectForKey:@"ProductAttributes"];
    if (productAttrs) {
    NSString* monitorName = [productAttrs objectForKey:@"ProductName"];
    NSLog(@"Testing monitor %@ [UUID: %@]", monitorName, edidUUID);
    NSLog(@"Attributes: %@", productAttrs);
    }
    }
    }
    if (strcmp(name, "DCPAVServiceProxy") == 0) {
    IOAVServiceRef avService = IOAVServiceCreateWithService(kCFAllocatorDefault, service);
    CFStringRef location = IORegistryEntrySearchCFProperty(service, kIOServicePlane, locationKey, kCFAllocatorDefault, kIORegistryIterateRecursively);
    if (location == NULL) {
    NSLog(@"No location for service %d: %s\n\n\n", service, name);
    continue;
    }

    if (!avService) {
    NSLog(@"No AVService for service %d: %s\n\n\n", service, name);
    continue;
    }

    if (CFStringCompare(externalAVServiceLocation, location, 0) == 0) {
    NSLog(@"Found External AVService for %d: %d", service, avService);
    } else {
    NSLog(@"Found Embedded AVService for %d: %d\n\n\n", service, avService);
    continue;
    }

    struct DDCWriteCommand command;
    command.control_id = BRIGHTNESS;

    UInt8 data[256];
    memset(data, 0, sizeof(data));
    data[0] = 0x84;
    data[1] = 0x03;
    data[2] = command.control_id;

    for (int chipAddress = 0; chipAddress < 0xff; ++chipAddress) {
    for (int dataAddress = 0; dataAddress < 0xff; ++dataAddress) {
    NSLog(@"Testing I2C Write on chipAddress=%d dataAddress=%d", chipAddress, dataAddress);

    command.new_value = 10;
    NSLog(@"Setting BRIGHTNESS to %d", command.new_value);

    data[3] = (command.new_value) >> 8;
    data[4] = command.new_value & 255;
    data[5] = 0x6E ^ 0x51 ^ data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4];

    for (int i = 0; i < 3; ++i) {
    IOReturn err = IOAVServiceWriteI2C(avService, 0x37, 0x51, data, 6);
    if (err) {
    NSLog(@"i2c error: %s", mach_error_string(err));
    }
    usleep(32000);
    }
    usleep(100000);

    command.new_value = 70;
    NSLog(@"Setting BRIGHTNESS to %d", command.new_value);

    data[3] = (command.new_value) >> 8;
    data[4] = command.new_value & 255;
    data[5] = 0x6E ^ 0x51 ^ data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4];

    for (int i = 0; i < 3; ++i) {
    IOReturn err = IOAVServiceWriteI2C(avService, 0x37, 0x51, data, 6);
    if (err) {
    NSLog(@"i2c error: %s", mach_error_string(err));
    }
    usleep(32000);
    }
    usleep(100000);
    }
    }
    usleep(100000);
    }
    }
    CFRelease(locationKey);
    CFRelease(edidUUIDKey);
    CFRelease(displayAttributesKey);
    CFRelease(externalAVServiceLocation);
    return 0;
    }