1/*cc -o /tmp/i2cexample i2cexample.c -framework IOKit -framework ApplicationServices -Wall -g
2*/
3
4
5#include <IOKit/IOKitLib.h>
6#include <ApplicationServices/ApplicationServices.h>
7#include <IOKit/i2c/IOI2CInterface.h>
8
9#include <assert.h>
10#include <stdio.h>
11#include <unistd.h>
12
13/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
14
15SInt32 EDIDSum( const UInt8 * bytes, IOByteCount len )
16{
17    int i,j;
18    UInt8 sum;
19
20    for (j=0; j < len; j += 128)
21    {
22        sum = 0;
23        for (i=0; i < 128; i++)
24            sum += bytes[j+i];
25        if(sum)
26            return (j/128);
27    }
28    return (-1);
29}
30
31void EDIDDump( const UInt8 * bytes, IOByteCount len )
32{
33    int i;
34
35    fprintf(stderr, "/*    0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F */");
36    for (i = 0; i < len; i++)
37    {
38        if( 0 == (i & 15))
39            fprintf(stderr, "\n    ");
40        fprintf(stderr, "0x%02x,", bytes[i]);
41    }
42    fprintf(stderr, "\n");
43}
44
45void EDIDRead( IOI2CConnectRef connect, Boolean save )
46{
47    kern_return_t       kr;
48    IOI2CRequest        request;
49    UInt8               data[128];
50    int                 i;
51
52    bzero( &request, sizeof(request) );
53
54    request.commFlags                   = 0;
55
56    request.sendAddress                 = 0xA0;
57    request.sendTransactionType         = kIOI2CSimpleTransactionType;
58    request.sendBuffer                  = (vm_address_t) &data[0];
59    request.sendBytes                   = 0x01;
60    data[0]                             = 0x00;
61
62    request.replyAddress                = 0xA1;
63    request.replyTransactionType        = kIOI2CSimpleTransactionType;
64    request.replyBuffer                 = (vm_address_t) &data[0];
65    request.replyBytes                  = sizeof(data);
66    bzero( &data[0], request.replyBytes );
67
68    kr = IOI2CSendRequest( connect, kNilOptions, &request );
69    assert( kIOReturnSuccess == kr );
70    fprintf(stderr, "/* Read result 0x%x, 0x%lx bytes */\n", request.result, request.replyBytes);
71    if( kIOReturnSuccess != request.result)
72        return;
73
74    EDIDDump( data, request.replyBytes );
75
76    i = EDIDSum( &data[0], request.replyBytes );
77
78    if( i >= 0)
79        fprintf(stderr, "/* Block %d checksum bad */\n", i);
80    else
81        fprintf(stderr, "/* Checksums ok */\n");
82
83    if( save)
84        write( STDOUT_FILENO, data, request.replyBytes );
85}
86
87/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
88
89int main( int argc, char * argv[] )
90{
91    kern_return_t kr;
92    io_service_t  framebuffer, interface;
93    io_string_t   path;
94    IOOptionBits  bus;
95    IOItemCount   busCount;
96    Boolean       save;
97
98    framebuffer = CGDisplayIOServicePort(CGMainDisplayID());
99
100    {
101        kr = IORegistryEntryGetPath(framebuffer, kIOServicePlane, path);
102        assert( KERN_SUCCESS == kr );
103        fprintf(stderr, "\n/* Using device: %s */\n", path);
104
105        kr = IOFBGetI2CInterfaceCount( framebuffer, &busCount );
106        assert( kIOReturnSuccess == kr );
107
108        for( bus = 0; bus < busCount; bus++ )
109        {
110            IOI2CConnectRef  connect;
111
112            fprintf(stderr, "/* Bus %ld: */\n", bus);
113
114            kr = IOFBCopyI2CInterfaceForBus(framebuffer, bus, &interface);
115            if( kIOReturnSuccess != kr)
116                continue;
117
118            kr = IOI2CInterfaceOpen( interface, kNilOptions, &connect );
119
120            IOObjectRelease(interface);
121            assert( kIOReturnSuccess == kr );
122            if( kIOReturnSuccess != kr)
123                continue;
124
125            save = (argc > 1) && (argv[1][0] == 's');
126
127            EDIDRead( connect, save );
128
129            IOI2CInterfaceClose( connect, kNilOptions );
130        }
131    }
132
133    exit(0);
134    return(0);
135}
136
137