read-edid-3.0.1/0000755000175000017550000000000012274463427012363 5ustar mkernmkernread-edid-3.0.1/get-edid/0000755000175000017550000000000012274463226014042 5ustar mkernmkernread-edid-3.0.1/get-edid/get-edid.c0000644000175000017550000000674312274333547015704 0ustar mkernmkern#include #include #include int quiet=0; int i2conly=0; //0=both, 1=i2conly, 2=classiconly int i2cbus=-1; int classmon=0; #define display(...) if (quiet == 0) { fprintf(stderr, __VA_ARGS__); } #define version "3.0.1" int stuped(char *str) { int i; char temp[128]; for (i=0;i= '0' && str[i] <= '9') { temp[i] = str[i]; display("%c\n", temp[i]); } else { if (i==0) { display("-b and -m require numerical arguments.\n"); exit(3); } temp[i] = '\0'; break; } } return atoi(temp); } #if defined I2CBUILD && defined CLASSICBUILD #define BOTHBUILD #endif #ifdef CLASSICBUILD int classicmain( unsigned contr, int qit ); #endif #ifdef I2CBUILD int i2cmain( int bus, int qit ); #endif void help() { display("get-edid, from read-edid %s. Licensed under the GPL.\n", version); display("Current version by Matthew Kern \n"); display("Previous work by John Fremlin \n"); display("and others (See AUTHORS).\n\n"); display("Usage:\n"); #ifdef I2CBUILD display(" -b BUS, --bus BUS Only scan the i2c bus BUS.\n"); #endif #ifdef BOTHBUILD display(" -c, --classiconly Do not check the i2c bus for an EDID\n"); #endif display(" -h, --help Display this help\n"); #ifdef BOTHBUILD display(" -i, --i2conly Do not check for an EDID over VBE\n"); #endif #ifdef CLASSICBUILD display(" -m NUM, --monitor NUM For VBE only - some lame attempt at selecting monitors.\n"); #endif display(" -q, --quiet Do not output anything over stderr (messages, essentially)\n\n"); display("For help, go to or\n"); display("email .\n"); exit(0); } int main(int argc, char *argv[]) { int i; // display("%s\n", argv[2]); for (i=1;i.\n"); return 1; } read-edid-3.0.1/get-edid/i2c.c0000644000175000017550000000650011642716052014660 0ustar mkernmkern/* (c) 2010,2011 Matthew Kern */ #ifdef I2CBUILD #include #include "i2c-dev.h"//use ours 'cuz it's betterer. #include #include #include #include #include #include //Ideas (but not too much actual code) taken from i2c-tools. Thanks guys. int quiet; #define display(...) if (quiet == 0) { fprintf(stderr, __VA_ARGS__); } int open_i2c_dev(int i2cbus) { int i2cfile; char filename[16]; unsigned long funcs; sprintf(filename, "/dev/i2c-%d", i2cbus); i2cfile = open(filename, O_RDWR); if (i2cfile < 0 && errno == ENOENT) { filename[8] = '/'; i2cfile = open(filename, O_RDWR); } if (errno == EACCES) { display("Permission denied opening i2c. Run as root!\n"); i2cfile = -2; } if (i2cfile >=0) { if (ioctl(i2cfile, I2C_FUNCS, &funcs) < 0) { if (quiet==0) { perror("ioctl I2C_FUNCS"); } i2cfile=-3; } if (!(funcs & (I2C_FUNC_SMBUS_READ_BYTE_DATA))) { display("No byte reading on this bus...\n"); i2cfile=-4; } if (ioctl(i2cfile, I2C_SLAVE, 0x50) < 0) { if (quiet==0) {perror("Problem requesting slave address");} i2cfile=-5; } } return i2cfile; } int i2cmain( int bus, int qit ) { int i, j, ret, len, numbusses=0, tryonly=-1, i2cfile, i2cbus=0; int goodbus[128]; unsigned char block[256]; quiet = qit; for (i2cfile = open_i2c_dev(i2cbus);i2cfile >= 0 || i2cfile < -3;) { //read a byte. This is the official way to scan if (i2cfile < -3) //problem with a bus, not general enough. Skip and close. goto endloop; ret = i2c_smbus_read_byte_data(i2cfile, 0); if (ret < 0) { display("No EDID on bus %i\n", i2cbus); } else { goodbus[numbusses] = i2cbus; numbusses++; } endloop: close(i2cfile); i2cbus++; i2cfile = open_i2c_dev(i2cbus); } if (i2cfile == -2) { return 1; } if (numbusses == 0) { display("Looks like no busses have an EDID. Sorry!\n"); return 2; } display("%i potential busses found:", numbusses); for (i=0;i 1) { if (bus != -1) { tryonly = bus; display("Only trying %i as per your request.\n", tryonly); } else display("Will scan through until the first EDID is found.\nPass a bus number as an option to this program to go only for that one.\n"); } ret=1; for (i=0;i= 0) { i2cbus = tryonly; i = numbusses; //to break the loop once done. } i2cfile = open_i2c_dev(i2cbus); if (i2cfile >=0) {//no matter how many times, >=0 still looks really angry. for (j=0;j<256;j++) block[j] = i2c_smbus_read_byte_data(i2cfile, j); } close(i2cfile); if (block[0]==0x00&&block[7]==0x00&&block[1]==0xff&&block[2]==0xff&&block[3]==0xff&&block[4]==0xff&&block[5]==0xff&&block[6]==0xff) { ret = 0; break; } else display("Bus %i doesn't really have an EDID...\n", i2cbus); } if (ret==0) { if (block[128] == 0xff) len = 128; else len = 256; display("%i-byte EDID successfully retrieved from i2c bus %i\n", len, i2cbus); if (i2cbus < (numbusses-1)) display("If this isn't what you were looking for, consider the other potential busses.\n"); for (i=0;i This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* $Id: i2c-dev.h 5361 2008-10-19 09:47:02Z khali $ */ #ifndef LIB_I2CDEV_H #define LIB_I2CDEV_H #include #include /* -- i2c.h -- */ /* * I2C Message - used for pure i2c transaction, also from /dev interface */ struct i2c_msg { __u16 addr; /* slave address */ unsigned short flags; #define I2C_M_TEN 0x10 /* we have a ten bit chip address */ #define I2C_M_RD 0x01 #define I2C_M_NOSTART 0x4000 #define I2C_M_REV_DIR_ADDR 0x2000 #define I2C_M_IGNORE_NAK 0x1000 #define I2C_M_NO_RD_ACK 0x0800 short len; /* msg length */ char *buf; /* pointer to msg data */ }; /* To determine what functionality is present */ #define I2C_FUNC_I2C 0x00000001 #define I2C_FUNC_10BIT_ADDR 0x00000002 #define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */ #define I2C_FUNC_SMBUS_PEC 0x00000008 #define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_QUICK 0x00010000 #define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 #define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 #define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000 #define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000 #define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000 #define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000 #define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 #define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 #define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ #define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ I2C_FUNC_SMBUS_WRITE_BYTE) #define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \ I2C_FUNC_SMBUS_WRITE_BYTE_DATA) #define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \ I2C_FUNC_SMBUS_WRITE_WORD_DATA) #define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) #define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) /* Old name, for compatibility */ #define I2C_FUNC_SMBUS_HWPEC_CALC I2C_FUNC_SMBUS_PEC /* * Data for SMBus Messages */ #define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ #define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */ union i2c_smbus_data { __u8 byte; __u16 word; __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ /* and one more for PEC */ }; /* smbus_access read or write markers */ #define I2C_SMBUS_READ 1 #define I2C_SMBUS_WRITE 0 /* SMBus transaction types (size parameter in the above functions) Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ #define I2C_SMBUS_QUICK 0 #define I2C_SMBUS_BYTE 1 #define I2C_SMBUS_BYTE_DATA 2 #define I2C_SMBUS_WORD_DATA 3 #define I2C_SMBUS_PROC_CALL 4 #define I2C_SMBUS_BLOCK_DATA 5 #define I2C_SMBUS_I2C_BLOCK_BROKEN 6 #define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ #define I2C_SMBUS_I2C_BLOCK_DATA 8 /* ----- commands for the ioctl like i2c_command call: * note that additional calls are defined in the algorithm and hw * dependent layers - these can be listed here, or see the * corresponding header files. */ /* -> bit-adapter specific ioctls */ #define I2C_RETRIES 0x0701 /* number of times a device address */ /* should be polled when not */ /* acknowledging */ #define I2C_TIMEOUT 0x0702 /* set timeout - call with int */ /* this is for i2c-dev.c */ #define I2C_SLAVE 0x0703 /* Change slave address */ /* Attn.: Slave address is 7 or 10 bits */ #define I2C_SLAVE_FORCE 0x0706 /* Change slave address */ /* Attn.: Slave address is 7 or 10 bits */ /* This changes the address, even if it */ /* is already taken! */ #define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */ #define I2C_FUNCS 0x0705 /* Get the adapter functionality */ #define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/ #define I2C_PEC 0x0708 /* != 0 for SMBus PEC */ #define I2C_SMBUS 0x0720 /* SMBus-level access */ /* -- i2c.h -- */ /* Note: 10-bit addresses are NOT supported! */ /* This is the structure as used in the I2C_SMBUS ioctl call */ struct i2c_smbus_ioctl_data { char read_write; __u8 command; int size; union i2c_smbus_data *data; }; /* This is the structure as used in the I2C_RDWR ioctl call */ struct i2c_rdwr_ioctl_data { struct i2c_msg *msgs; /* pointers to i2c_msgs */ int nmsgs; /* number of i2c_msgs */ }; static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, int size, union i2c_smbus_data *data) { struct i2c_smbus_ioctl_data args; args.read_write = read_write; args.command = command; args.size = size; args.data = data; return ioctl(file,I2C_SMBUS,&args); } static inline __s32 i2c_smbus_write_quick(int file, __u8 value) { return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL); } static inline __s32 i2c_smbus_read_byte(int file) { union i2c_smbus_data data; if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data)) return -1; else return 0x0FF & data.byte; } static inline __s32 i2c_smbus_write_byte(int file, __u8 value) { return i2c_smbus_access(file,I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL); } static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) { union i2c_smbus_data data; if (i2c_smbus_access(file,I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data)) return -1; else return 0x0FF & data.byte; } static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value) { union i2c_smbus_data data; data.byte = value; return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, I2C_SMBUS_BYTE_DATA, &data); } static inline __s32 i2c_smbus_read_word_data(int file, __u8 command) { union i2c_smbus_data data; if (i2c_smbus_access(file,I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA,&data)) return -1; else return 0x0FFFF & data.word; } static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value) { union i2c_smbus_data data; data.word = value; return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, I2C_SMBUS_WORD_DATA, &data); } static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) { union i2c_smbus_data data; data.word = value; if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, I2C_SMBUS_PROC_CALL,&data)) return -1; else return 0x0FFFF & data.word; } /* Returns the number of read bytes */ static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values) { union i2c_smbus_data data; int i; if (i2c_smbus_access(file,I2C_SMBUS_READ,command, I2C_SMBUS_BLOCK_DATA,&data)) return -1; else { for (i = 1; i <= data.block[0]; i++) values[i-1] = data.block[i]; return data.block[0]; } } static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, __u8 *values) { union i2c_smbus_data data; int i; if (length > 32) length = 32; for (i = 1; i <= length; i++) data.block[i] = values[i-1]; data.block[0] = length; return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, I2C_SMBUS_BLOCK_DATA, &data); } /* Returns the number of read bytes */ /* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you ask for less than 32 bytes, your code will only work with kernels 2.6.23 and later. */ static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length, __u8 *values) { union i2c_smbus_data data; int i; if (length > 32) length = 32; data.block[0] = length; if (i2c_smbus_access(file,I2C_SMBUS_READ,command, length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN : I2C_SMBUS_I2C_BLOCK_DATA,&data)) return -1; else { for (i = 1; i <= data.block[0]; i++) values[i-1] = data.block[i]; return data.block[0]; } } static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length, __u8 *values) { union i2c_smbus_data data; int i; if (length > 32) length = 32; for (i = 1; i <= length; i++) data.block[i] = values[i-1]; data.block[0] = length; return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, I2C_SMBUS_I2C_BLOCK_BROKEN, &data); } /* Returns the number of read bytes */ static inline __s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length, __u8 *values) { union i2c_smbus_data data; int i; if (length > 32) length = 32; for (i = 1; i <= length; i++) data.block[i] = values[i-1]; data.block[0] = length; if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, I2C_SMBUS_BLOCK_PROC_CALL,&data)) return -1; else { for (i = 1; i <= data.block[0]; i++) values[i-1] = data.block[i]; return data.block[0]; } } #endif /* LIB_I2CDEV_H */ read-edid-3.0.1/get-edid/classic.c0000644000175000017550000002173012274463226015632 0ustar mkernmkern/* (c) 2000,2001,2002 John Fremlin */ /* (c) 2010,2011 Matthew Kern */ #ifdef CLASSICBUILD #include #include #include #include #include #include #include #include typedef u_int8_t byte; typedef u_int32_t uint32; typedef struct LRMI_regs reg_frame; typedef byte* real_ptr; #define access_register(reg_frame,reg) (reg_frame . reg) #define access_ptr_register(reg_frame,reg) (reg_frame -> reg) #define access_seg_register(reg_frame,es) reg_frame.es #define real_mode_int(interrupt,reg_frame_ptr) !LRMI_int(interrupt,reg_frame_ptr) #define alloc_real(size) LRMI_alloc_real(size) #define free_real(block) LRMI_free_real(block) #define dosmemput(buffer,length,offset) memcpy(offset,buffer,length) #define display(...) if (quiet == 0) { fprintf(stderr, __VA_ARGS__); } int quiet; real_ptr far_ptr_to_real_ptr( uint32 farptr ) { unsigned segment = (farptr & 0xffff0000)>>16; unsigned offset = (farptr & 0xffff); return (real_ptr)(segment*16+offset); } #define MAGIC 0x13 #define EDID_BLOCK_SIZE 128 #define EDID_V1_BLOCKS_TO_GO_OFFSET 126 #define SERVICE_REPORT_DDC 0 #define SERVICE_READ_EDID 1 #define SERVICE_LAST 1 // Read VDIF has been removed from the spec. const char* ddc1_support_message[] = { "Monitor and video card combination does not support DDC1 transfers", "Monitor and video card combination supports DDC1 transfers" } ; const char* ddc2_support_message[] = { "Monitor and video card combination does not support DDC2 transfers", "Monitor and video card combination supports DDC2 transfers" } ; const char* screen_blanked_message[] = { "Screen is not blanked during DDC transfer", "Screen is blanked during DDC transfer" } ; const char* supported_message[] = { "Function unsupported", "Function supported" } ; const char* call_successful_message[] = { "Call failed", "Call successful" } ; const char* vbe_service_message[] = { "Report DDC capabilities", "Read EDID" } ; void contact_author() { display("\n\n*********** Something special has happened!\n" ); display("This happens a lot with TV's, and other devices\n"); display("with extension blocks. If you have a TV, don't bother.\n"); display("Otherwise, please contact the author, Matthew Kern\n" ); display("E-mail: pyrophobicman@gmail.com\n" ); display("Please include full output from this program (especially that to stderr)\n\n\n\n" ); } int read_edid( unsigned controller, FILE* output ); int do_vbe_ddc_service(unsigned BX,reg_frame* regs); int report_ddc_capabilities( unsigned controller ); int report_vcontroller(); int classicmain( unsigned contr, int qit ) { unsigned controller = 0; int error; FILE* output; //fprintf(stderr, "%s: get-edid version %s\n", argv[0], VERSION); quiet=qit; if( !LRMI_init() ) { display( "error initialising realmode interface\n"); display( "do you have full superuser (root) permissions?\n"); return 10; } ioperm(0, 0x400 , 1); iopl(3); /*if ( argc == 1 ) output = stdout; else { if ( argc > 3 ) { display( "%s: syntax %s [output-filename] [controller]\n", argv[0],argv[0] ); return 3; } output = fopen( argv[1], "wb" ); if ( !output ) { display( "%s: error opening file \"%s\" for binary output\n", argv[0],argv[1] ); return 4; } if ( argc == 3 ) controller = strtol( argv[2],0,0 ); } */ output = stdout; controller = contr; report_vcontroller(); error = report_ddc_capabilities(controller); if (read_edid(controller,output)) error = 1; fclose(output); return error; } int do_vbe_service(unsigned AX,unsigned BX,reg_frame* regs) { const unsigned interrupt = 0x10; unsigned function_sup; unsigned success; int error = 0; access_ptr_register(regs,eax) = AX; access_ptr_register(regs,ebx) = BX; display( "\n\tPerforming real mode VBE call\n" ); display( "\tInterrupt 0x%x ax=0x%x bx=0x%x cx=0x%x\n", interrupt, AX, BX, (unsigned)access_ptr_register(regs,ecx) ); if( real_mode_int(interrupt, regs) ) { display( "Error: something went wrong performing real mode interrupt\n" ); error = 1; } AX = access_ptr_register(regs,eax); function_sup = ((AX & 0xff) == 0x4f); success = ((AX & 0xff00) == 0); display( "\t%s\n", supported_message[ function_sup ] ); display( "\t%s\n\n", call_successful_message[ success ] ); if (!success) error=1; if (!function_sup) error=2; return error; } int do_vbe_ddc_service(unsigned BX,reg_frame* regs) { unsigned service = BX&0xff; unsigned AX = 0x4f15; display( "\nVBE/DDC service about to be called\n" ); if ( service > SERVICE_LAST ) { display( "\tUnknown VBE/DDC service\n" ); } else { display( "\t%s\n", vbe_service_message[ service ] ); } return do_vbe_service(AX,BX,regs); } int report_ddc_capabilities( unsigned controller ) { reg_frame regs; int error; unsigned seconds_per_edid_block; unsigned ddc1_support; unsigned ddc2_support; unsigned screen_blanked_during_transfer; memset(®s, 0, sizeof(regs)); access_register(regs,ecx) = controller; error = do_vbe_ddc_service( SERVICE_REPORT_DDC,®s ); if ( !error ) { seconds_per_edid_block = (access_register(regs,ebx) & 0xff00)>>16; ddc1_support = (access_register(regs,ebx) & 0x1)?1:0; ddc2_support = (access_register(regs,ebx) & 0x2)?1:0; screen_blanked_during_transfer = (access_register(regs,ebx) & 0x4)?1:0; display( "\t%s\n", ddc1_support_message[ddc1_support] ); display( "\t%s\n", ddc2_support_message[ddc2_support] ); display( "\t%u seconds per 128 byte EDID block transfer\n", seconds_per_edid_block ); display( "\t%s\n\n", screen_blanked_message[screen_blanked_during_transfer] ); } return error; } int read_edid( unsigned controller, FILE* output ) { reg_frame regs; real_ptr block; byte* buffer; byte* pointer; unsigned blocks_left = 1; unsigned last_reported = 0x1000; /* just a large number */ unsigned author_msg_shown = 0; int err = 0; block = alloc_real( EDID_BLOCK_SIZE ); if ( !block ) { display( "Error: can't allocate 0x%x bytes of DOS memory for output block\n", EDID_BLOCK_SIZE ); return 2; } buffer = block; do { unsigned counter; display( "Reading next EDID block\n" ); memset( block, MAGIC, EDID_BLOCK_SIZE ); memset(®s, 0, sizeof(regs)); access_seg_register(regs,es) = ((unsigned)block)/16; access_register(regs,edi) = 0; access_register(regs,ecx) = controller; access_register(regs,edx)= blocks_left; if ( do_vbe_ddc_service( SERVICE_READ_EDID, ®s ) ) { display( "The EDID data should not be trusted as the VBE call failed\n" ); } for( pointer=block, counter=EDID_BLOCK_SIZE; counter; counter--,pointer++ ) { if ( *pointer != MAGIC ) goto block_ok; } display( "Error: output block unchanged\n" ); err = 1; break; block_ok: if ( EDID_BLOCK_SIZE != fwrite( buffer, sizeof( byte ), EDID_BLOCK_SIZE, output ) ) { display( "\nError: problem writing output\n" ); err = 1; break; } blocks_left--; if ( buffer[ EDID_V1_BLOCKS_TO_GO_OFFSET ] > blocks_left ) { int reported = buffer[ EDID_V1_BLOCKS_TO_GO_OFFSET ]; display( "EDID claims %u more blocks left\n", reported); if ( last_reported <= reported || reported == 0xff /* 0xff frequently comes up in corrupt edids */ || reported == MAGIC ) { display( "EDID blocks left is wrong.\n" "Your EDID is probably invalid.\n"); } else { if(!author_msg_shown) { contact_author(); author_msg_shown = 1; } last_reported = reported; blocks_left = reported; } } } while( blocks_left ); free_real( block ); return err; } int report_vcontroller() { const unsigned info_block_length = 0x200; real_ptr block; real_ptr oem_string; reg_frame regs; byte* buffer; uint32 oem_string_ptr; byte next; unsigned vbe_version=0; memset(®s, 0, sizeof(regs)); block = alloc_real( info_block_length ); if ( !block ) { display( "Error: can't allocate %x bytes of DOS memory for videocard info block\n", info_block_length ); return 2; } buffer = block; dosmemput("VBE2",4,block); access_seg_register(regs,es) = ((unsigned)block)/16; access_register(regs,edi) = 0; do_vbe_service(0x4f00,0,®s); memcpy( &vbe_version, buffer+4, 2 ); memcpy( &oem_string_ptr, buffer+6, 4 ); oem_string = far_ptr_to_real_ptr( oem_string_ptr ); display( "\tVBE version %x\n", vbe_version ); display( "\tVBE string at 0x%x \"", (unsigned)oem_string ); for(;;) { next = *oem_string; if ( !next ) break; fputc( next,stderr ); oem_string++; } display("\"\n" ); return 1; } #endif read-edid-3.0.1/ChangeLog0000644000175000017550000000225012274334412014123 0ustar mkernmkern2014-02-04 Matthew Kern * INSTALL: Rewrite for CMake instructions 2011-10-10 Matthew Kern * get-edid.c: new modular design, added i2c support * parse-edid.c: complete rewrite with e-edid support * CMakeLists.txt: Move from autotools to CMake 2008-09-21 Matthew Kern * get-edid.c: moved from lrmi to libx86 - same functions, more portable. 2008-08-25 Matthew Kern * lrmi.c: fixed for linux-2.6.26 and up. * makefile.am, configure.in: Made get-edid not build on !x86. 2001-06-10 John Fremlin * get-edid.c (read_edid): Fooled around with multiple block handling error logic some more. 2001-06-03 John Fremlin * get-edid.c (read_edid): Change action for EDIDs that keep claiming more blocks to return error. 2001-03-11 John Fremlin * parse-edid.c (parse_edid): Workaround lack of snprintf on djgpp 2001-03-04 John Fremlin * parse-edid.c (parse_timing_description): Fix commented out hfreq value - problem spotted by "GEORGE KUKA" read-edid-3.0.1/README0000644000175000017550000000045312274334506013240 0ustar mkernmkernThis package will try to read the monitor details directly from the monitor. The program get-edid asks a VBE BIOS for the EDID data. The program parse-edid parses the data and prints out a human readable summary. Please see http://www.polypux.org/projects/read-edid/ for more detailed information read-edid-3.0.1/cmake/0000755000175000017550000000000012207732225013432 5ustar mkernmkernread-edid-3.0.1/cmake/Modules/0000755000175000017550000000000012207733745015052 5ustar mkernmkernread-edid-3.0.1/cmake/Modules/Findx86.cmake0000644000175000017550000000032212207733060017265 0ustar mkernmkerninclude(LibFindMacros) find_path(x86_INCLUDE_DIR NAMES libx86.h PATHS) find_library(x86_LIBRARY NAMES libx86) set(x86_PROCESS_INCLUDES x86_INCLUDE_DIR) set(x86_PROCESS_LIBS x86_LIBRARY) libfind_process(x86) read-edid-3.0.1/parse-edid/0000755000175000017550000000000012274334045014371 5ustar mkernmkernread-edid-3.0.1/parse-edid/parse-edid.c0000644000175000017550000003000712274334045016552 0ustar mkernmkern/* Complete parse-edid rewrite. Using some unix-specific stuff - I don't care about dos :P * * Hope it works :P */ #include //for the *printf's et al. #include //read, and because it's nice to have #include //exit, and because it's nice to have #include "modes.h" typedef unsigned char byte; byte edid[128]; //edid itself byte extb[128]; //extension block. Hope there's only 1, for now. char modearray[128][128]; int native; int currentmode; static void die(char *msg) { fprintf(stderr, "%s", msg); exit(1); } static void warn(char *msg) { fprintf(stderr, "WARNING: "); fprintf(stderr, "%s", msg); fprintf(stderr, "Trying to continue...\n"); } static void diewemail(char *msg) { fprintf(stderr, "%s", msg); fprintf(stderr, "Something strange happened. Please contact the author,\nMatthew Kern at \n"); exit(1); } int parseedid() { int i; int j; byte sum = 0; char modelname[13]; //int ptm; int compsync = 0; int hres; int vres; //check the checksum for (i = 0; i<128; i++) { sum += edid[i]; } if (sum) warn("Checksum failed\n"); else fprintf(stderr, "Checksum Correct\n\n"); //check header for (i = 0; i < 8; i++) { if (!(((i == 0 || i == 7) && edid[i] == 0x00) || (edid[i] == 0xff))) //0x00 0xff 0xff 0xff 0xff 0xff 0x00 diewemail("Header incorrect. Probably not an edid\n"); } //Make a monitor section... printf("Section \"Monitor\"\n"); //Product Identification /* Model Name: Only thing I do out of order of edid, to comply with X standards... */ for (i = 0x36; i < 0x7E; i += 0x12) { //read through descriptor blocks... if (edid[i] == 0x00) { //not a timing descriptor if (edid[i+3] == 0xfc) { //Model Name tag for (j = 0; j < 13; j++) { if (edid[i+5+j] == 0x0a) modelname[j] = 0x00; else modelname[j] = edid[i+5+j]; } } } } printf("\tIdentifier \"%s\"\n\tModelName \"%s\"\n", modelname, modelname); /* Vendor Name: 3 characters, standardized by microsoft, somewhere. * bytes 8 and 9: f e d c b a 9 8 7 6 5 4 3 2 1 0 * Character 1 is e d c b a * Character 2 is 9 8 7 6 5 * Character 3 is 4 3 2 1 0 * Those values start at 0 (0x00 is 'A', 0x01 is 'B', 0x19 is 'Z', etc.) */ printf("\tVendorName \"%c%c%c\"\n", (edid[8] >> 2 & 0x1f) + 'A' - 1, (((edid[8] & 0x3) << 3) | ((edid[9] & 0xe0) >> 5)) + 'A' - 1, (edid[9] & 0x1f) + 'A' - 1 ); /* Skip Product ID and Serial Number. */ /* Week and Year: not required, but do it for fun. */ if (edid[0x10] <= 54) printf("\t# Monitor Manufactured week %i of %i\n", (int)(edid[0x10]), ((int)(edid[0x11])) + 1990); else if (edid[0x10] != 0xff) printf("\t# Monitor Manufactured in %i\n", ((int)(edid[0x11])) + 1990); else if (edid[0x10] == 0xff) printf("\t# Monitor Model Year: %i\n", ((int)(edid[0x11])) + 1990); //Edid Version printf("\t# EDID version %i.%i\n", (int)(edid[0x12]), (int)(edid[0x13])); //Basic Display Parameter /* Digital or not? */ if (edid[0x14] & 0x80) printf("\t# Digital Display\n"); else { printf("\t# Analog Display\n"); if (edid[0x14] & 0x02) //sync on green. printf("\tOption \"SyncOnGreen\" \"true\"\n"); if (edid[0x14] & 0x04) compsync = 1; //Composite sync. Save for modelines. } /* Ignore video input definitions, because X doesn't care. */ /* Size parameters: H and V, in centimeters. Projectors put 0 here. * DiplaySize is in millimeters, so multiply by 10 * If 0x16 is 0, but not 0x15, you really should do aspect ratio... */ if (edid[0x15] && edid[0x16]) printf("\tDisplaySize %i %i\n", ((int)(edid[0x15])) * 10, ((int)(edid[0x16])) * 10); else printf("\t# Display Physical Size not given. Normal for projectors.\n"); /* Gamma. Divide by 100, add 1. Defaults to 1, so if 0, it'll be 1 anyway. */ if (edid[0x17] != 0xff) printf("\tGamma %.2f\n", (float)((((float)edid[0x17]) / 100) + 1)); /* DPMS. Simple yes or no. */ printf("\tOption \"DPMS\" \"%s\"\n", (edid[0x18] & 0xE0) ? "true" : "false"); /* Preferred timing mode. This has no meaning, really. The first mode given is preferred. */ //ptm = ((edid[0x18] & 0x02) ? 1 : 0); //printf("\t# preferred timing mode %sfound\n", ptm ? "" : "not "); /* GTF. Not sure what it means to X, so ignore it (for now) */ /* ignore chroma stuff as well. */ //Monitor Limits... okay, another one out of order with the EDID... for (i = 0x36; i < 0x7E; i += 0x12) { //read through descriptor blocks... if (edid[i] == 0x00) { //not a timing descriptor if (edid[i+3] == 0xfd) { //monitor limits tag printf("\tHorizsync %i-%i\n", (int)edid[i+7] + (((edid[i+4] & 0x0c) & 0x04) ? 255 : 0), (int)edid[i+8] + ((edid[i+4] & 0x08) ? 255 : 0)); printf("\tVertRefresh %i-%i\n", (int)edid[i+5] + (((edid[i+4] & 0x03) & 0x01) ? 255 : 0), (int)edid[i+6] + ((edid[i+4] & 0x02) ? 255 : 0)); printf("\t# Maximum pixel clock is %iMHz\n", (int)edid[i+9] * 10); } } } //I can ignore predefined modes - X knows these already. int hactive, vactive, pixclk, hsyncoff, hsyncwidth, hblank, vsyncoff, vsyncwidth, vblank; //Parse for Detailed Timing Descriptors... for (i = 0x36; i < 0x7E; i += 0x12) { //read through descriptor blocks... if ((edid[i] != 0x00) && (edid[i+1] != 0x00)) { //a dtd hactive = edid[i+2] + ((edid[i+4] & 0xf0) << 4); hblank = edid[i+3] + ((edid[i+4] & 0x0f) << 8); vactive = edid[i+5] + ((edid[i+7] & 0xf0) << 4); vblank = edid[i+6] + ((edid[i+7] & 0x0f) << 8); //printf("\tModeline \t\"%dx%d\" ", hactive, vactive); pixclk = (edid[i+1] << 8) | (edid[i]); sprintf(modearray[currentmode], "%.2f ", (double)pixclk / 100.0); //I'm using Fremlin's nomenclature... //sync offset = front porch //sync width = sync pulse width hsyncoff = edid[i+8] | ((edid[i+11] & 0xC0) << 2); hsyncwidth = edid[i+9] | ((edid[i+11] & 0x30) << 4); vsyncoff = ((edid[i+10] & 0xf0) >> 4) | ((edid[i+11] & 0x0C) << 2); vsyncwidth = (edid[i+10] & 0x0f) | ((edid[i+11] & 0x03) << 4); sprintf(modearray[currentmode], "%s%u %u %u %u ", modearray[currentmode], hactive, hactive+hsyncoff, hactive+hsyncoff+hsyncwidth, hactive+hblank); sprintf(modearray[currentmode], "%s%u %u %u %u ", modearray[currentmode], vactive, vactive+vsyncoff, vactive+vsyncoff+vsyncwidth, vactive+vblank); if ( (edid[i+17]&0x80) || ((edid[i+17]&0x18) == 0x18) ) { sprintf(modearray[currentmode], "%s%shsync %svsync %s", modearray[currentmode], ((edid[i+17]&0x10) && edid[i+17]&0x02) ? "+": "-", ((edid[i+17]&0x10) && edid[i+17]&0x04) ? "+": "-", (edid[i+17]&0x80) ? "interlace": ""); //hehe... there's been at least 2 bugs in the old parse-edid the whole time - somebody caught the htimings one, and I just caught two problems right here - lack of checking for analog sync and getting hsync and vsync backwards... yes, vsync and hsync have been flipped this whole time. Glad I'm rewriting //printf("%s\n", modearray[currentmode]); currentmode++; } //printf("\tEndmode\n"); } } //Standard Timings - put these after dtd's, because this way preferred is up top. /* I started doing this, but I think it's unnecessary. Think not? you do it. I'll comment what you're missing.*/ int refresh; for (i = 0x26; i < 0x36; i += 0x2) { //read through list of resolutions... if (!(edid[i] == 1 && edid[i+1] == 1)) { //skip if it's "blank" hres = (((int)edid[i]) + 31) * 8; switch ((edid[i+1] & 0xC0) >> 6) { case 0: vres = (hres * 10) / 16; //16:10 aspect ratio break; case 1: vres = (hres * 3) / 4; //4:3 break; case 2: vres = (hres * 4) / 5; //5:4 break; case 3: vres = (hres * 9) / 16; //16:9 break; default: diewemail("The impossible has happened.\n"); } refresh = (edid[i+1] & 0x3F) + 60; printf("\t#Not giving standard mode: "); printf("%ix%i, %iHz\n", hres, vres, refresh); /* printf("\tMode\t\"%ix%i\"\n", hres, vres); printf("\t\tDotClock\t%.6f\n", (float)((hres * vres) * (((edid[i+1] & 0x3f) + 60)) / 1000000)); //(pixels/screen) * (screen/sec) / a million = megapixels/sec, aka dot clock in mHz printf("\t\tHTimings\t\n");*/ } } } int parseextb() { int i, curloc, j; //char nativename[64]; byte sum =0; printf("\n\t#Extension block found. Parsing...\n"); /* for (i = 0; i < 128; i++) printf("byte %xh is 0x%x\n", i, extb[i]); */ //printf("Tag: %x\n", extb[0]); for (i=0;i<128;i++) { sum +=extb[i]; } if (sum != 0x00) { die("Extension block checksum failed\n"); } if (extb[0] != 0x02) diewemail("I only know about extension blocks of type 02h. PLEASE email me!\n"); curloc = extb[2]; if (curloc == 0) { printf("#No data in the extension block\n"); return 0; } //printf("There are %i bytes of data block\n", curloc - 4); if (curloc > 4) { if (extb[4] & 0xE0 != 0x40) { //if the first one is not a video one diewemail("Hmm, you have data blocks, but not video ones... weird\n"); } for (i=0;i<(extb[4]&0x1F);i++) { sprintf(modearray[currentmode], "%s", ceamodes[extb[5+i]&0x7F]); if (extb[5+i]&0x80 == 0x80 && native == -1) { native = currentmode; } currentmode++; } } //starting 18-byte DTD's. //Copypaste the DTD stuff from above. int hactive, vactive, pixclk, hsyncoff, hsyncwidth, hblank, vsyncoff, vsyncwidth, vblank; //Parse for Detailed Timing Descriptors... for (i = curloc; i < curloc+(18*4); i += 0x12) { //read through descriptor blocks... if ((extb[i] != 0x00) && (extb[i+1] != 0x00)) { //a dtd hactive = extb[i+2] + ((extb[i+4] & 0xf0) << 4); hblank = extb[i+3] + ((extb[i+4] & 0x0f) << 8); vactive = extb[i+5] + ((extb[i+7] & 0xf0) << 4); vblank = extb[i+6] + ((extb[i+7] & 0x0f) << 8); //printf("\tModeline \t\"%dx%d\" ", hactive, vactive); if (i == curloc && extb[3]&0x0F > 0) { native = currentmode; //sprintf(nativename, "%dx%d", hactive, vactive); } pixclk = (extb[i+1] << 8) | (extb[i]); sprintf(modearray[currentmode], "%.2f ", (double)pixclk / 100.0); //I'm using Fremlin's nomenclature... //sync offset = front porch //sync width = sync pulse width hsyncoff = extb[i+8] | ((extb[i+11] & 0xC0) << 2); hsyncwidth = extb[i+9] | ((extb[i+11] & 0x30) << 4); vsyncoff = ((extb[i+10] & 0xf0) >> 4) | ((extb[i+11] & 0x0C) << 2); vsyncwidth = (extb[i+10] & 0x0f) | ((extb[i+11] & 0x03) << 4); sprintf(modearray[currentmode], "%s%u %u %u %u ", modearray[currentmode], hactive, hactive+hsyncoff, hactive+hsyncoff+hsyncwidth, hactive+hblank); sprintf(modearray[currentmode], "%s%u %u %u %u ", modearray[currentmode], vactive, vactive+vsyncoff, vactive+vsyncoff+vsyncwidth, vactive+vblank); if ( (extb[i+17]&0x80) || ((extb[i+17]&0x18) == 0x18) ) { sprintf(modearray[currentmode], "%s%shsync %svsync %s", modearray[currentmode], ((extb[i+17]&0x10) && extb[i+17]&0x02) ? "+": "-", ((extb[i+17]&0x10) && extb[i+17]&0x04) ? "+": "-", (extb[i+17]&0x80) ? "interlace": ""); //hehe... there's been at least 2 bugs in the old parse-edid the whole time - somebody caught the htimings one, and I just caught two problems right here - lack of checking for analog sync and getting hsync and vsync backwards... yes, vsync and hsync have been flipped this whole time. Glad I'm rewriting } //printf("\n"); currentmode++; } } } int dofooter() { int i; if (native != -1) printf("\tModeline \t\"Mode %i\" %s\n", native, modearray[native]); for (i=0;i 0x01) diewemail("You seem to have too many extension blocks. Will not continue to parse\n"); parseedid(); if (extblock) parseextb(); dofooter(); return 0; } read-edid-3.0.1/parse-edid/CMakeLists.txt0000644000175000017550000000012612207730127017125 0ustar mkernmkernadd_executable (parse-edid parse-edid.c) install (TARGETS parse-edid DESTINATION bin) read-edid-3.0.1/parse-edid/modes.h0000644000175000017550000000741611644153225015660 0ustar mkernmkernchar ceamodes[61][128] = { //Guess who had to do these by hand... you're welcome. "", "25.200 640 656 752 800 480 490 492 525 -hsync -vsync", "27.027 720 736 798 858 480 489 495 525 -hsync -vsync", "27.027 720 736 798 858 480 489 495 525 -hsync -vsync", "74.250 1280 1390 1420 1650 720 725 730 750 +hsync +vsync", "74.250 1920 2008 2052 2200 1080 1082 1087 1125 +hsync +vsync interlace", "27.027 1440 1478 1602 1716 480 484 487 525 -hsync -vsync interlace", "27.027 1440 1478 1602 1716 480 484 487 525 -hsync -vsync interlace", "27.027 1440 1478 1602 1716 240 244 247 262 -hsync -vsync", "27.027 1440 1478 1602 1716 240 244 247 262 -hsync -vsync", "54.054 2880 2956 3204 3432 480 484 487 525 -hsync -vsync interlace", "54.054 2880 2956 3204 3432 480 484 487 525 -hsync -vsync interlace", "54.054 2880 2956 3204 3432 240 244 247 262 -hsync -vsync", "54.054 2880 2956 3204 3432 240 244 247 262 -hsync -vsync", "54.054 1440 1472 1596 1716 480 489 495 525 -hsync -vsync", "54.054 1440 1472 1596 1716 480 489 495 525 -hsync -vsync", "148.500 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync",//16 "27.000 720 732 796 864 576 581 586 625 -hsync -vsync", "27.000 720 732 796 864 576 581 586 625 -hsync -vsync", "74.250 1280 1720 1760 1980 720 725 730 750 +hsync +vsync", "74.250 1920 2448 2492 2640 1080 1082 1089 1125 +hsync +vsync interlace", "27.000 1440 1464 1590 1728 576 578 581 625 -hsync -vsync interlace", "27.000 1440 1464 1590 1728 576 578 581 625 -hsync -vsync interlace", "27.000 1440 1464 1590 1728 288 290 293 312 -hsync -vsync", "27.000 1440 1464 1590 1728 288 290 293 312 -hsync -vsync", "54.000 2880 2928 3180 3456 576 578 581 625 -hsync -vsync interlace", "54.000 2880 2928 3180 3456 576 578 581 625 -hsync -vsync interlace", "54.000 2880 2928 3180 3456 288 290 393 312 -hsync -vsync", "54.000 2880 2928 3180 3456 288 290 393 312 -hsync -vsync", "54.000 1440 1464 1592 1728 576 581 586 625 -hsync -vsync", "54.000 1440 1464 1592 1728 576 581 586 625 -hsync -vsync", "148.500 1920 2448 2492 2640 1080 1084 1089 1125 +hsync +vsync", "74.250 1920 2558 2602 2750 1080 1084 1089 1125 +hsync +vsync",//32 "74.250 1920 2448 2492 2640 1080 1084 1089 1125 +hsync +vsync", "74.250 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync", "108.000 2880 2944 3192 3432 480 489 495 525 -hsync -vsync", "108.000 2880 2944 3192 3432 480 489 495 525 -hsync -vsync", "108.000 2880 2928 3184 3456 576 581 586 625 -hsync -vsync", "108.000 2880 2928 3184 3456 576 581 586 625 -hsync -vsync", "72.000 1920 1952 2120 2304 1080 1103 1108 1250 +hsync +vsync interlace", "148.500 1920 2448 2492 2640 1080 1082 1087 1125 +hsync +vsync interlace", "148.500 1280 1720 1760 1980 720 725 730 750 +hsync +vsync", "54.000 720 732 796 864 576 581 586 625 -hsync -vsync", "54.000 720 732 796 864 576 581 586 625 -hsync -vsync", "54.000 1440 1464 1590 1728 576 578 581 625 -hsync -vsync interlace", "54.000 1440 1464 1590 1728 576 578 581 625 -hsync -vsync interlace", "148.500 1920 2008 2052 2200 1080 1082 1087 1125 +hsync +vsync interlace", "148.500 1280 1390 1430 1650 720 725 730 750 +hsync +vsync", "54.000 720 736 798 858 480 489 495 525 -hsync -vsync", //48 "54.000 720 736 798 858 480 489 495 525 -hsync -vsync", "54.000 1440 1478 1602 1716 480 484 487 525 -hsync -vsync interlace", "54.000 1440 1478 1602 1716 480 484 487 525 -hsync -vsync interlace", "108.00 720 732 796 864 576 581 586 625 -hsync -vsync", "108.00 720 732 796 864 576 581 586 625 -hsync -vsync", "108.00 1440 1464 1590 1728 576 578 581 625 -hsync -vsync interlace", "108.00 1440 1464 1590 1728 576 578 581 625 -hsync -vsync interlace", "108.108 720 736 798 858 480 489 495 525 -hsync -vsync", "108.108 720 736 798 858 480 489 495 525 -hsync -vsync", "108.108 1440 1478 1602 1716 480 484 587 525 -hsync -vsync interlace", "108.108 1440 1478 1602 1716 480 484 587 525 -hsync -vsync interlace", }; read-edid-3.0.1/AUTHORS0000644000175000017550000000135311644417255013433 0ustar mkernmkernThe lrmi files were written by Josh Vanderhoof. Matthew Kern (poly-p man) is the current maintainer, fixed some minor bugs, and rewrote a significant chunk of code for 3.0.0. John Fremlin wrote get-edid and the original parse-edid. He was the maintainer until 1.4.1. Dan Hugo afforded immoral support, resulting in the 1.3 series. Martin Kavalec enhanced parse-edid to display frequencies and DPMS features. He also added better monitor name detection and h/vsync type printing. Branden Robinson wrote the manpage. If you want to distribute or modify read-edid, please e-mail the maintainer, Matthew Kern, a courtesy message. read-edid-3.0.1/get-edid.10000644000175000017550000000431112274334534014122 0ustar mkernmkern.TH get\-edid 1 "2013-08-29" .SH NAME get\-edid, parse\-edid \- read\-edid tools to retrieve and interpret monitor specifications using the VESA VBE DDC protocol .SH SYNOPSIS .B get\-edid [\fIOPTIONS\fR] | .B parse\-edid .br .B get\-edid [\fIOPTIONS\fR] > .I filename .br .B parse\-edid < .I filename .SH DESCRIPTION The .I read\-edid utility comprises two tools: .B get\-edid and .BR parse\-edid . .PP .B get\-edid uses real mode calls to perform Data Display Channel (DDC) transfers, or Linux i2c calls to perform Enhanced DDC transfers to retrieve information from monitors, including identification strings, supported sync ranges, available video modes, and video mode parameters. Such information can be useful for configuring X Window System servers in certain cases. .PP .B get\-edid returns the raw Extended Display Identification Data (EDID) block directly from the monitor, so the .B parse\-edid command is available to interpret it and generate a human-readable block of text information that can also be included in a X11 xorg.conf file. .PP Generally the output of .B get\-edid is piped directly to .BR parse\-edid . .PP New in version 3.0.0, .B get\-edid takes a few options. .TP \fB\-b \fIBUS\fR, \fB\-\-bus \fIBUS only scan the i2c bus \fIBUS\fR (if built with i2c support) .TP \fB\-c\fR, \fB\-\-classiconly only use the older VBE interface (if built with i2c and VBE support) .TP \fB\-h\fR, \fB\-\-help display a basic help message .TP \fB\-i\fR, \fB\-\-i2conly only use the newer i2c interface (if built with i2c and VBE support) .TP \fB\-m \fINUM\fR, \fB\-\-monitor \fINUM try to return information about monitor number \fINUM\fR (VBE only) .TP \fB\-q\fR, \fB\-\-quiet do not output messages over stderr .PP .B parse\-edid still does not take any options. \fB\-\-help\fR will show you which options your build of \fIread\-edid\fR supports. .SH AUTHOR .I read\-edid is originally the work of John Fremlin and others. Since 1.4.2, the new maintainer and programmer has been Matthew Kern. Nearly all of the code for this project, as well as this manual page, has been rewritten for 3.0.0 by Matthew Kern. See AUTHORS for more details. .SH "SEE ALSO" Matthew Kern's \fIread\-edid\fR website at read-edid-3.0.1/CMakeLists.txt0000644000175000017550000000075212274463156015126 0ustar mkernmkerncmake_minimum_required (VERSION 2.6) project (read-edid) option(I2CBUILD "Build I2C get-edid implementation" ON) option(CLASSICBUILD "Build VBE get-edid implementation" ON) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules") if (I2CBUILD OR CLASSICBUILD) add_subdirectory (get-edid) endif () add_subdirectory (parse-edid) INSTALL(FILES get-edid.1 DESTINATION share/man/man1) INSTALL(FILES AUTHORS ChangeLog COPYING README DESTINATION share/doc/read-edid) read-edid-3.0.1/COPYING0000644000175000017550000004357211644417517013430 0ustar mkernmkernread-edid 3.0.0 $Date: 2001/06/03 21:57:51 $ The lrmi.* files were written by Josh Vanderhoof. They are included here merely for convenience and are not strictly part of the read-edid package. See the LRMI file and their source code for license. This package is distributed under the license bellow: GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. read-edid-3.0.1/INSTALL0000644000175000017550000000115612274334164013412 0ustar mkernmkernread-edid is packaged using CMake. To install, simply run: cmake . from the current directory. Use the options '-DCLASSICBUILD=OFF' or '-DI2CBUILD=OFF' to disable building of either the VBE interface or the I2C interface to get-edid, respectively. Use both to disable building get-edid entirely. After CMake has completed, use 'make' and 'make install' to build and install the package. The latter command will most likely require root access to run. A note: read-edid requires CMake 2.6 or greater, as well as the libx86 library (and related development packages on binary ditributions) if VBE usage is to be built.