├── Makefile ├── README ├── i2c-dev.h └── ddcci-tool.c /Makefile: -------------------------------------------------------------------------------- 1 | # file Makefile 2 | # copyright Copyright (c) 2014 Toradex AG 3 | # [Software License Agreement] 4 | # author $Author$ 5 | # version $Rev$ 6 | # date $Date$ 7 | # brief a simple makefile to (cross) compile. 8 | # uses the openembedded provided sysroot and toolchain 9 | # target linux on Colibri T20 / Colibri T30 / Colibri VF50 / Colibri VF61 / Apalis T30 / Apalis IMX6Q/D 10 | # caveats - 11 | 12 | ############################################################################## 13 | # Setup your project settings 14 | ############################################################################## 15 | 16 | # Set the input source files, the binary name and used libraries to link 17 | SRCS = ddcci-tool.o 18 | PROG := ddcci-tool 19 | LIBS = -lm 20 | 21 | # Set arch flags 22 | ARCH_CFLAGS = -march=armv7-a -fno-tree-vectorize -mthumb-interwork -mfloat-abi=hard 23 | 24 | ifeq ($(MACHINE), colibri-t20) 25 | ARCH_FLAGS += -mfpu=vfpv3-d16 -mtune=cortex-a9 26 | TOOLCHAIN = armv7at2hf-vfp-angstrom-linux-gnueabi 27 | else ifeq ($(MACHINE), colibri-t30) 28 | ARCH_FLAGS += -mfpu=neon -mtune=cortex-a9 29 | TOOLCHAIN = armv7at2hf-vfp-neon-angstrom-linux-gnueabi 30 | else ifeq ($(MACHINE), colibri-vf) 31 | ARCH_FLAGS += -mfpu=neon -mtune=cortex-a5 32 | TOOLCHAIN = armv7at2hf-vfp-neon-angstrom-linux-gnueabi 33 | else ifeq ($(MACHINE), apalis-t30) 34 | ARCH_FLAGS += -mfpu=neon -mtune=cortex-a9 35 | TOOLCHAIN = armv7at2hf-vfp-neon-angstrom-linux-gnueabi 36 | else ifeq ($(MACHINE), apalis-imx6) 37 | ARCH_FLAGS += -mfpu=neon -mtune=cortex-a9 38 | TOOLCHAIN = armv7at2hf-vfp-neon-angstrom-linux-gnueabi 39 | else 40 | $(error MACHINE is not set to a valid target) 41 | endif 42 | 43 | # Set flags to the compiler and linker 44 | CFLAGS += -O2 -g -Wall -DNV_IS_LDK=1 $(ARCH_CFLAGS) --sysroot=$(OECORE_TARGET_SYSROOT) 45 | LDFLAGS += 46 | 47 | ############################################################################## 48 | # Setup your build environment 49 | ############################################################################## 50 | 51 | # Set the path to the oe built sysroot and 52 | # Set the prefix for the cross compiler 53 | OECORE_NATIVE_SYSROOT ?= $(HOME)/oe-core/build/out-eglibc/sysroots/x86_64-linux/ 54 | OECORE_TARGET_SYSROOT ?= $(HOME)/oe-core/build/out-eglibc/sysroots/$(MACHINE)/ 55 | CROSS_COMPILE ?= $(OECORE_NATIVE_SYSROOT)usr/bin/$(TOOLCHAIN)/arm-angstrom-linux-gnueabi- 56 | 57 | ############################################################################## 58 | # The rest of the Makefile usually needs no change 59 | ############################################################################## 60 | 61 | # Set differencies between native and cross compilation 62 | ifneq ($(strip $(CROSS_COMPILE)),) 63 | LDFLAGS += -L$(OECORE_TARGET_SYSROOT)usr/lib -Wl,-rpath-link,$(OECORE_TARGET_SYSROOT)usr/lib -L$(OECORE_TARGET_SYSROOT)lib -Wl,-rpath-link,$(OECORE_TARGET_SYSROOT)lib 64 | BIN_POSTFIX = 65 | PKG-CONFIG = export PKG_CONFIG_SYSROOT_DIR=$(OECORE_TARGET_SYSROOT); \ 66 | export PKG_CONFIG_PATH=$(OECORE_TARGET_SYSROOT)/usr/lib/pkgconfig/; \ 67 | $(OECORE_NATIVE_SYSROOT)usr/bin/pkg-config 68 | else 69 | # Native compile 70 | PKG-CONFIG = pkg-config 71 | ARCH_CFLAGS = 72 | # Append .x86 to the object files and binaries, so that native and cross builds can live side by side 73 | BIN_POSTFIX = .x86 74 | endif 75 | 76 | # Toolchain binaries 77 | CC = $(CROSS_COMPILE)gcc 78 | LD = $(CROSS_COMPILE)ld 79 | STRIP = $(CROSS_COMPILE)strip 80 | RM = rm -f 81 | 82 | # Sets the output filename and object files 83 | PROG := $(PROG)$(BIN_POSTFIX) 84 | OBJS = $(SRCS:.c=$(BIN_POSTFIX).o) 85 | DEPS = $(OBJS:.o=.o.d) 86 | 87 | # pull in dependency info for *existing* .o files 88 | -include $(DEPS) 89 | 90 | .DEFAULT_GOAL := all 91 | 92 | all: $(PROG) 93 | 94 | $(PROG): $(OBJS) Makefile 95 | $(CC) $(CFLAGS) $(OBJS) $(LIBS) $(LDFLAGS) -o $@ 96 | $(STRIP) $@ 97 | 98 | %$(BIN_POSTFIX).o: %.c 99 | $(CC) -c $(CFLAGS) -o $@ $< 100 | $(CC) -MM $(CFLAGS) $< > $@.d 101 | 102 | clean: 103 | $(RM) $(OBJS) $(PROG) $(DEPS) 104 | 105 | .PHONY: all clean 106 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This program is used for communicating with monitor using DDC/CI interface. 2 | This program is GPLed and written by Oleg I. Vdovikin (oleg@cs.msu.su) 3 | 4 | Use i2cdetect to scan your DDC I2C buses first. Supported displays should 5 | respond at addresses 0x37 (DDC/CI) and 0x50 (EDID). Some displays are respond 6 | on VGA or DVI busses only, so check both. 7 | 8 | This program is based on info sniffed on wire and published in 9 | 10 | USB Monitor Control Class 1.0 specification for control codes 11 | available at http://www.usb.org/developers/hidpage/usbmon10.pdf 12 | 13 | and 14 | 15 | ACCESS.bus (tm) Specifications Version 3.0 available at 16 | http://measure.feld.cvut.cz/groups/micro/soucastky/spec/serial_p/Access_bus_spec_3_0.pdf 17 | 18 | In fact, up to date information about DDC/CI standard (Display Data Channel 19 | Command Interface (DDC/CI) Standard (formerly DDC2Bi), Version 1) is available 20 | from VESA (http://www.vesa.org) and the summary is freely available at 21 | http://www.vesa.org/summary/sumddcci.htm 22 | 23 | Tested with Samsung SyncMaster 173T (personally by me) with radeonfb and 24 | Mitsubishi Diamond Pro 2060u (by Nicolas Boichat) with rivafb. Mitsubishi 25 | Diamond Pro 2060u does not support capabilities request. 26 | 27 | Usage: 28 | ddcci-tool [-a adr] [-e] [-d] [-c] [-f] [-v] [-s] [-S] [-r ctrl] [-w value] dev 29 | dev: device, e.g. /dev/i2c-0 30 | adr: base address of ddc/ci, eg 0x37 (def) 31 | -e : query EDID at 0x50 32 | queries monitor EDID, which should be accessible at I2C address 0x50 33 | -c : query capability 34 | queries DDC/CI capabilities string 35 | -d : query ctrls 0 - 255 36 | dumps controls 0-255, checking validity byte, use -f to override 37 | -r : query ctrl 38 | specifies control index to read or write (-w) 39 | -w : value to write to ctrl 40 | value for control to be writen for index specified with -r 41 | -f : force (avoid validity checks) 42 | avoid validity check 43 | -s : save settings 44 | Sends DDC/CI command to save adjustments made by -w 45 | -v : verbosity (specify more to increase) 46 | try -v and -vv (low level send/recv) for greater effect 47 | -S : send Samsung DDC/CI enable 48 | seems some of the Samsung monitors requires this for operating 49 | 50 | Sample output: 51 | ddcci-tool version 0.03 52 | 53 | Reading EDID : 0x50@/dev/i2c-2 54 | Plug and Play ID: SAM00BA 55 | Input type: Analog 56 | 57 | Using ddc/ci : 0x37@/dev/i2c-2 58 | 59 | Capabilities: 60 | (type(LCD)vcp(04 05 06 08 0E 10 12 16 18 1A 1E 20 30 3E 60(1 3) B0(1 2) B6 C6 C8 C9 D6(1 4) DC(1 2 3 4) DF E0(0 1 2))) 61 | 62 | Controls (valid/current/max): 63 | Control 0x04: +/0/1 [Reset Factory Defaults] 64 | Control 0x05: +/0/1 [SAM: Reset Brightness and Contrast] 65 | Control 0x06: +/0/1 [Reset Factory Geometry] 66 | Control 0x08: +/0/1 [Reset Factory Default Color] 67 | Control 0x0e: +/60/120 [SAM: Image Lock Coarse] 68 | Control 0x10: +/0/100 [Brightness] 69 | Control 0x12: +/50/100 [Contrast] 70 | Control 0x16: +/8/16 [Red Video Gain] 71 | Control 0x18: +/8/16 [Green Video Gain] 72 | Control 0x1a: +/8/16 [Blue Video Gain] 73 | Control 0x1e: +/0/2 [SAM: Auto Size Center] 74 | Control 0x20: +/50/100 [Horizontal Position] 75 | Control 0x30: +/25/54 [Vertical Position] 76 | Control 0x3e: +/39/50 [SAM: Image Lock Fine] 77 | Control 0x60: +/1/3 [Input Source Select] 78 | Control 0x62: +/0/100 [Audio Speaker Volume Adjust] 79 | Control 0x6c: +/140/255 [Red Video Black Level] 80 | Control 0x6e: +/127/255 [Green Video Black Level] 81 | Control 0x70: +/121/255 [Blue Video Black Level] 82 | Control 0xb0: +/0/2 [Settings] 83 | Control 0xb6: +/3/8 [???] 84 | Control 0xc6: +/1/1 [???] 85 | Control 0xc8: +/5/16 [???] 86 | Control 0xc9: +/1/0 [???] 87 | Control 0xca: +/2/2 [On Screen Display] 88 | Control 0xcc: +/2/11 [SAM: On Screen Display Language] 89 | Control 0xd6: +/1/4 [SAM: DPMS control (1 - on/4 - stby)] 90 | Control 0xdc: +/4/4 [SAM: MagicBright (1 - text/2 - internet/3 - entertain/4 - custom)] 91 | Control 0xdf: +/512/0 [VCP Version] 92 | Control 0xe0: +/0/2 [SAM: Color preset (0 - normal/1 - warm/2 - cool)] 93 | Control 0xe1: +/1/1 [SAM: Power control (0 - off/1 - on)] 94 | Control 0xe2: +/0/1 [???] 95 | Control 0xed: +/108/255 [SAM: Red Video Black Level] 96 | Control 0xee: +/101/255 [SAM: Green Video Black Level] 97 | Control 0xef: +/103/255 [SAM: Blue Video Black Level] 98 | -------------------------------------------------------------------------------- /i2c-dev.h: -------------------------------------------------------------------------------- 1 | /* 2 | i2c-dev.h - i2c-bus driver, char device interface 3 | 4 | Copyright (C) 1995-97 Simon G. Vogl 5 | Copyright (C) 1998-99 Frodo Looijaard 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 20 | MA 02110-1301 USA. 21 | */ 22 | 23 | /* $Id: i2c-dev.h 5894 2010-12-12 13:22:29Z khali $ */ 24 | 25 | #ifndef LIB_I2CDEV_H 26 | #define LIB_I2CDEV_H 27 | 28 | #include 29 | #include 30 | 31 | /* -- i2c.h -- */ 32 | 33 | 34 | /* 35 | * I2C Message - used for pure i2c transaction, also from /dev interface 36 | */ 37 | struct i2c_msg { 38 | __u16 addr; /* slave address */ 39 | unsigned short flags; 40 | #define I2C_M_TEN 0x10 /* we have a ten bit chip address */ 41 | #define I2C_M_RD 0x01 42 | #define I2C_M_NOSTART 0x4000 43 | #define I2C_M_REV_DIR_ADDR 0x2000 44 | #define I2C_M_IGNORE_NAK 0x1000 45 | #define I2C_M_NO_RD_ACK 0x0800 46 | short len; /* msg length */ 47 | char *buf; /* pointer to msg data */ 48 | }; 49 | 50 | /* To determine what functionality is present */ 51 | 52 | #define I2C_FUNC_I2C 0x00000001 53 | #define I2C_FUNC_10BIT_ADDR 0x00000002 54 | #define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */ 55 | #define I2C_FUNC_SMBUS_PEC 0x00000008 56 | #define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ 57 | #define I2C_FUNC_SMBUS_QUICK 0x00010000 58 | #define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 59 | #define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 60 | #define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000 61 | #define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000 62 | #define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000 63 | #define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000 64 | #define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 65 | #define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 66 | #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 67 | #define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ 68 | #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ 69 | 70 | #define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ 71 | I2C_FUNC_SMBUS_WRITE_BYTE) 72 | #define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \ 73 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA) 74 | #define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \ 75 | I2C_FUNC_SMBUS_WRITE_WORD_DATA) 76 | #define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ 77 | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) 78 | #define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ 79 | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) 80 | 81 | /* Old name, for compatibility */ 82 | #define I2C_FUNC_SMBUS_HWPEC_CALC I2C_FUNC_SMBUS_PEC 83 | 84 | /* 85 | * Data for SMBus Messages 86 | */ 87 | #define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ 88 | #define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */ 89 | union i2c_smbus_data { 90 | __u8 byte; 91 | __u16 word; 92 | __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ 93 | /* and one more for PEC */ 94 | }; 95 | 96 | /* smbus_access read or write markers */ 97 | #define I2C_SMBUS_READ 1 98 | #define I2C_SMBUS_WRITE 0 99 | 100 | /* SMBus transaction types (size parameter in the above functions) 101 | Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ 102 | #define I2C_SMBUS_QUICK 0 103 | #define I2C_SMBUS_BYTE 1 104 | #define I2C_SMBUS_BYTE_DATA 2 105 | #define I2C_SMBUS_WORD_DATA 3 106 | #define I2C_SMBUS_PROC_CALL 4 107 | #define I2C_SMBUS_BLOCK_DATA 5 108 | #define I2C_SMBUS_I2C_BLOCK_BROKEN 6 109 | #define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ 110 | #define I2C_SMBUS_I2C_BLOCK_DATA 8 111 | 112 | 113 | /* ----- commands for the ioctl like i2c_command call: 114 | * note that additional calls are defined in the algorithm and hw 115 | * dependent layers - these can be listed here, or see the 116 | * corresponding header files. 117 | */ 118 | /* -> bit-adapter specific ioctls */ 119 | #define I2C_RETRIES 0x0701 /* number of times a device address */ 120 | /* should be polled when not */ 121 | /* acknowledging */ 122 | #define I2C_TIMEOUT 0x0702 /* set timeout - call with int */ 123 | 124 | 125 | /* this is for i2c-dev.c */ 126 | #define I2C_SLAVE 0x0703 /* Change slave address */ 127 | /* Attn.: Slave address is 7 or 10 bits */ 128 | #define I2C_SLAVE_FORCE 0x0706 /* Change slave address */ 129 | /* Attn.: Slave address is 7 or 10 bits */ 130 | /* This changes the address, even if it */ 131 | /* is already taken! */ 132 | #define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */ 133 | 134 | #define I2C_FUNCS 0x0705 /* Get the adapter functionality */ 135 | #define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/ 136 | #define I2C_PEC 0x0708 /* != 0 for SMBus PEC */ 137 | 138 | #define I2C_SMBUS 0x0720 /* SMBus-level access */ 139 | 140 | /* -- i2c.h -- */ 141 | 142 | 143 | /* Note: 10-bit addresses are NOT supported! */ 144 | 145 | /* This is the structure as used in the I2C_SMBUS ioctl call */ 146 | struct i2c_smbus_ioctl_data { 147 | char read_write; 148 | __u8 command; 149 | int size; 150 | union i2c_smbus_data *data; 151 | }; 152 | 153 | /* This is the structure as used in the I2C_RDWR ioctl call */ 154 | struct i2c_rdwr_ioctl_data { 155 | struct i2c_msg *msgs; /* pointers to i2c_msgs */ 156 | int nmsgs; /* number of i2c_msgs */ 157 | }; 158 | 159 | 160 | static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, 161 | int size, union i2c_smbus_data *data) 162 | { 163 | struct i2c_smbus_ioctl_data args; 164 | 165 | args.read_write = read_write; 166 | args.command = command; 167 | args.size = size; 168 | args.data = data; 169 | return ioctl(file,I2C_SMBUS,&args); 170 | } 171 | 172 | 173 | static inline __s32 i2c_smbus_write_quick(int file, __u8 value) 174 | { 175 | return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL); 176 | } 177 | 178 | static inline __s32 i2c_smbus_read_byte(int file) 179 | { 180 | union i2c_smbus_data data; 181 | if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data)) 182 | return -1; 183 | else 184 | return 0x0FF & data.byte; 185 | } 186 | 187 | static inline __s32 i2c_smbus_write_byte(int file, __u8 value) 188 | { 189 | return i2c_smbus_access(file,I2C_SMBUS_WRITE,value, 190 | I2C_SMBUS_BYTE,NULL); 191 | } 192 | 193 | static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) 194 | { 195 | union i2c_smbus_data data; 196 | if (i2c_smbus_access(file,I2C_SMBUS_READ,command, 197 | I2C_SMBUS_BYTE_DATA,&data)) 198 | return -1; 199 | else 200 | return 0x0FF & data.byte; 201 | } 202 | 203 | static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, 204 | __u8 value) 205 | { 206 | union i2c_smbus_data data; 207 | data.byte = value; 208 | return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, 209 | I2C_SMBUS_BYTE_DATA, &data); 210 | } 211 | 212 | static inline __s32 i2c_smbus_read_word_data(int file, __u8 command) 213 | { 214 | union i2c_smbus_data data; 215 | if (i2c_smbus_access(file,I2C_SMBUS_READ,command, 216 | I2C_SMBUS_WORD_DATA,&data)) 217 | return -1; 218 | else 219 | return 0x0FFFF & data.word; 220 | } 221 | 222 | static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, 223 | __u16 value) 224 | { 225 | union i2c_smbus_data data; 226 | data.word = value; 227 | return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, 228 | I2C_SMBUS_WORD_DATA, &data); 229 | } 230 | 231 | static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) 232 | { 233 | union i2c_smbus_data data; 234 | data.word = value; 235 | if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, 236 | I2C_SMBUS_PROC_CALL,&data)) 237 | return -1; 238 | else 239 | return 0x0FFFF & data.word; 240 | } 241 | 242 | 243 | /* Returns the number of read bytes */ 244 | static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, 245 | __u8 *values) 246 | { 247 | union i2c_smbus_data data; 248 | int i; 249 | if (i2c_smbus_access(file,I2C_SMBUS_READ,command, 250 | I2C_SMBUS_BLOCK_DATA,&data)) 251 | return -1; 252 | else { 253 | for (i = 1; i <= data.block[0]; i++) 254 | values[i-1] = data.block[i]; 255 | return data.block[0]; 256 | } 257 | } 258 | 259 | static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, 260 | __u8 length, const __u8 *values) 261 | { 262 | union i2c_smbus_data data; 263 | int i; 264 | if (length > 32) 265 | length = 32; 266 | for (i = 1; i <= length; i++) 267 | data.block[i] = values[i-1]; 268 | data.block[0] = length; 269 | return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, 270 | I2C_SMBUS_BLOCK_DATA, &data); 271 | } 272 | 273 | /* Returns the number of read bytes */ 274 | /* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you 275 | ask for less than 32 bytes, your code will only work with kernels 276 | 2.6.23 and later. */ 277 | static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, 278 | __u8 length, __u8 *values) 279 | { 280 | union i2c_smbus_data data; 281 | int i; 282 | 283 | if (length > 32) 284 | length = 32; 285 | data.block[0] = length; 286 | if (i2c_smbus_access(file,I2C_SMBUS_READ,command, 287 | length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN : 288 | I2C_SMBUS_I2C_BLOCK_DATA,&data)) 289 | return -1; 290 | else { 291 | for (i = 1; i <= data.block[0]; i++) 292 | values[i-1] = data.block[i]; 293 | return data.block[0]; 294 | } 295 | } 296 | 297 | static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, 298 | __u8 length, 299 | const __u8 *values) 300 | { 301 | union i2c_smbus_data data; 302 | int i; 303 | if (length > 32) 304 | length = 32; 305 | for (i = 1; i <= length; i++) 306 | data.block[i] = values[i-1]; 307 | data.block[0] = length; 308 | return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, 309 | I2C_SMBUS_I2C_BLOCK_BROKEN, &data); 310 | } 311 | 312 | /* Returns the number of read bytes */ 313 | static inline __s32 i2c_smbus_block_process_call(int file, __u8 command, 314 | __u8 length, __u8 *values) 315 | { 316 | union i2c_smbus_data data; 317 | int i; 318 | if (length > 32) 319 | length = 32; 320 | for (i = 1; i <= length; i++) 321 | data.block[i] = values[i-1]; 322 | data.block[0] = length; 323 | if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, 324 | I2C_SMBUS_BLOCK_PROC_CALL,&data)) 325 | return -1; 326 | else { 327 | for (i = 1; i <= data.block[0]; i++) 328 | values[i-1] = data.block[i]; 329 | return data.block[0]; 330 | } 331 | } 332 | 333 | 334 | #endif /* LIB_I2CDEV_H */ 335 | -------------------------------------------------------------------------------- /ddcci-tool.c: -------------------------------------------------------------------------------- 1 | /* 2 | ddc/ci interface program 3 | Copyright(c) 2004 Oleg I. Vdovikin (oleg@cs.msu.su) 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | */ 19 | 20 | /* See USB Monitor Control Class 1.0 specification for control codes 21 | available at http://www.usb.org/developers/devclass_docs/usbmon10.pdf, 22 | ACCESS.bus (tm) Specifications Version 3.0 available at 23 | http://www.semtech.com/pdf/abusv30.pdf 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "i2c-dev.h" 35 | 36 | /* ddc/ci defines */ 37 | #define DDCCI_COMMAND_READ 0x01 /* read ctrl value */ 38 | #define DDCCI_REPLY_READ 0x02 /* read ctrl value reply */ 39 | #define DDCCI_COMMAND_WRITE 0x03 /* write ctrl value */ 40 | 41 | #define DDCCI_COMMAND_SAVE 0x0c /* save current settings */ 42 | 43 | #define DDCCI_REPLY_CAPS 0xe3 /* get monitor caps reply */ 44 | #define DDCCI_COMMAND_CAPS 0xf3 /* get monitor caps */ 45 | #define DDCCI_COMMAND_PRESENCE 0xf7 /* ACCESS.bus presence check */ 46 | 47 | /* control numbers */ 48 | #define DDCCI_CTRL_BRIGHTNESS 0x10 49 | 50 | /* samsung specific, magictune starts with writing 1 to this register */ 51 | #define DDCCI_CTRL 0xf5 52 | #define DDCCI_CTRL_ENABLE 0x0001 53 | #define DDCCI_CTRL_DISABLE 0x0000 54 | 55 | /* ddc/ci iface tunables */ 56 | #define DEFAULT_DDCCI_ADDR 0x37 /* samsung ddc/ci logic sits at 0x37 */ 57 | #define MAX_BYTES 127 /* max message length */ 58 | #define DELAY 30000 /* uS to wait after write */ 59 | #define RETRYS 3 /* number of retry */ 60 | 61 | /* magic numbers */ 62 | #define MAGIC_1 0x51 /* first byte to send, host address */ 63 | #define MAGIC_2 0x80 /* second byte to send, ored with length */ 64 | #define MAGIC_XOR 0x50 /* initial xor for received frame */ 65 | 66 | 67 | /* verbosity level (0 - normal, 1 - encoded data, 2 - ddc/ci frames) */ 68 | static int verbosity = 0; 69 | 70 | /* debugging */ 71 | void dumphex(FILE *f, unsigned char *buf, unsigned char len) 72 | { 73 | int i, j; 74 | 75 | for (j = 0; j < len; j +=16) { 76 | if (len > 16) { 77 | fprintf(f, "%04x: ", j); 78 | } 79 | 80 | for (i = 0; i < 16; i++) { 81 | if (i + j < len) fprintf(f, "%02x ", buf[i + j]); 82 | else fprintf(f, " "); 83 | } 84 | 85 | fprintf(f, "| "); 86 | 87 | for (i = 0; i < 16; i++) { 88 | if (i + j < len) fprintf(f, "%c", 89 | buf[i + j] >= ' ' && buf[i + j] < 127 ? buf[i + j] : '.'); 90 | else fprintf(f, " "); 91 | } 92 | 93 | fprintf(f, "\n"); 94 | } 95 | } 96 | 97 | 98 | /* write len bytes (stored in buf) to i2c address addr */ 99 | /* return 0 on success, -1 on failure */ 100 | int i2c_write(int fd, unsigned int addr, unsigned char *buf, unsigned char len) 101 | { 102 | int i; 103 | struct i2c_rdwr_ioctl_data msg_rdwr; 104 | struct i2c_msg i2cmsg; 105 | 106 | /* done, prepare message */ 107 | msg_rdwr.msgs = &i2cmsg; 108 | msg_rdwr.nmsgs = 1; 109 | 110 | i2cmsg.addr = addr; 111 | i2cmsg.flags = 0; 112 | i2cmsg.len = len; 113 | i2cmsg.buf = buf; 114 | 115 | if ((i = ioctl(fd, I2C_RDWR, &msg_rdwr)) < 0 ) 116 | { 117 | perror("ioctl()"); 118 | fprintf(stderr,"ioctl returned %d\n",i); 119 | return -1; 120 | } 121 | 122 | return i; 123 | 124 | } 125 | 126 | /* read at most len bytes from i2c address addr, to buf */ 127 | /* return -1 on failure */ 128 | int i2c_read(int fd, unsigned int addr, unsigned char *buf, unsigned char len) 129 | { 130 | struct i2c_rdwr_ioctl_data msg_rdwr; 131 | struct i2c_msg i2cmsg; 132 | int i; 133 | 134 | msg_rdwr.msgs = &i2cmsg; 135 | msg_rdwr.nmsgs = 1; 136 | 137 | i2cmsg.addr = addr; 138 | i2cmsg.flags = I2C_M_RD; 139 | i2cmsg.len = len; 140 | i2cmsg.buf = buf; 141 | 142 | if ((i = ioctl(fd, I2C_RDWR, &msg_rdwr)) < 0) 143 | { 144 | perror("ioctl()"); 145 | fprintf(stderr,"ioctl returned %d\n",i); 146 | return -1; 147 | } 148 | 149 | return i; 150 | } 151 | 152 | /* write len bytes (stored in buf) to ddc/ci at address addr */ 153 | /* return 0 on success, -1 on failure */ 154 | int ddcci_write(int fd, unsigned int addr, unsigned char *buf, unsigned char len) 155 | { 156 | int i = 0; 157 | unsigned char _buf[MAX_BYTES + 3]; 158 | unsigned xor = ((unsigned char)addr << 1); /* initial xor value */ 159 | 160 | if (verbosity > 1) { 161 | fprintf(stderr, "Send: "); 162 | dumphex(stderr, buf, len); 163 | } 164 | 165 | /* put first magic */ 166 | xor ^= (_buf[i++] = MAGIC_1); 167 | 168 | /* second magic includes message size */ 169 | xor ^= (_buf[i++] = MAGIC_2 | len); 170 | 171 | while (len--) /* bytes to send */ 172 | xor ^= (_buf[i++] = *buf++); 173 | 174 | /* finally put checksum */ 175 | _buf[i++] = xor; 176 | 177 | return i2c_write(fd, addr, _buf, i); 178 | } 179 | 180 | /* read ddc/ci formatted frame from ddc/ci at address addr, to buf */ 181 | int ddcci_read(int fd, unsigned int addr, unsigned char *buf, unsigned char len) 182 | { 183 | unsigned char _buf[MAX_BYTES]; 184 | unsigned char xor = MAGIC_XOR; 185 | int i, _len; 186 | 187 | if (i2c_read(fd, addr, _buf, len + 3) <= 0 || 188 | _buf[0] == 0x51 || _buf[0] == 0xff) // busy ??? 189 | { 190 | return -1; 191 | } 192 | 193 | /* validate answer */ 194 | if (_buf[0] != addr * 2) { 195 | dumphex(stderr, _buf, sizeof(_buf)); 196 | fprintf(stderr, "Invalid response, first byte is 0x%02x, should be 0x%02x\n", 197 | _buf[0], addr * 2); 198 | return -1; 199 | } 200 | 201 | if ((_buf[1] & MAGIC_2) == 0) { 202 | fprintf(stderr, "Invalid response, magic is 0x%02x\n", _buf[1]); 203 | return -1; 204 | } 205 | 206 | _len = _buf[1] & ~MAGIC_2; 207 | if (_len > len || _len > sizeof(_buf)) { 208 | fprintf(stderr, "Invalid response, length is %d, should be %d at most\n", 209 | _len, len); 210 | return -1; 211 | } 212 | 213 | /* get the xor value */ 214 | for (i = 0; i < _len + 3; i++) { 215 | xor ^= _buf[i]; 216 | } 217 | 218 | if (xor != 0) { 219 | fprintf(stderr, "Invalid response, corrupted data - xor is 0x%02x, length 0x%02x\n", xor, _len); 220 | for (i = 0; i < _len + 3; i++) { 221 | fprintf(stderr, "0x%02x ", _buf[i]); 222 | } 223 | fprintf(stderr, "\n"); 224 | 225 | return -1; 226 | } 227 | 228 | /* copy payload data */ 229 | memcpy(buf, _buf + 2, _len); 230 | 231 | if (verbosity > 1) { 232 | fprintf(stderr, "Recv: "); 233 | dumphex(stderr, buf, _len); 234 | } 235 | 236 | return _len; 237 | } 238 | 239 | /* write value to register ctrl of ddc/ci at address addr */ 240 | int ddcci_writectrl(int fd, unsigned int addr, unsigned char ctrl, unsigned short value) 241 | { 242 | unsigned char buf[4]; 243 | 244 | buf[0] = DDCCI_COMMAND_WRITE; 245 | buf[1] = ctrl; 246 | buf[2] = (value >> 8); 247 | buf[3] = (value & 255); 248 | 249 | return ddcci_write(fd, addr, buf, sizeof(buf)); 250 | } 251 | 252 | /* read register ctrl raw data of ddc/ci at address addr */ 253 | int ddcci_readctrl(int fd, unsigned int addr, 254 | unsigned char ctrl, unsigned char *buf, unsigned char len) 255 | { 256 | unsigned char _buf[2]; 257 | 258 | _buf[0] = DDCCI_COMMAND_READ; 259 | _buf[1] = ctrl; 260 | 261 | if (ddcci_write(fd, addr, _buf, sizeof(_buf)) < 0) 262 | { 263 | return -1; 264 | } 265 | 266 | usleep(DELAY); 267 | 268 | return ddcci_read(fd, addr, buf, len); 269 | } 270 | 271 | /* read capabilities raw data of ddc/ci at address addr starting at offset to buf */ 272 | int ddcci_caps(int fd, unsigned int addr, 273 | unsigned int offset, unsigned char *buf, unsigned char len) 274 | { 275 | unsigned char _buf[3]; 276 | 277 | _buf[0] = DDCCI_COMMAND_CAPS; 278 | _buf[1] = offset >> 8; 279 | _buf[2] = offset & 255; 280 | 281 | if (ddcci_write(fd, addr, _buf, sizeof(_buf)) < 0) 282 | { 283 | return -1; 284 | } 285 | 286 | usleep(DELAY); 287 | 288 | return ddcci_read(fd, addr, buf, len); 289 | } 290 | 291 | /* save current settings */ 292 | int ddcci_command(int fd, unsigned int addr, unsigned char cmd) 293 | { 294 | unsigned char _buf[1]; 295 | 296 | _buf[0] = cmd; 297 | 298 | return ddcci_write(fd, addr, _buf, sizeof(_buf)); 299 | } 300 | 301 | /* testing stuff */ 302 | 303 | /* get ctrlname based on id */ 304 | char *ctrlname(unsigned char ctrl) 305 | { 306 | switch (ctrl) { 307 | case 0x00: return "Degauss"; /* ACCESS.bus */ 308 | case 0x01: return "Degauss"; /* USB */ 309 | case 0x02: return "Secondary Degauss"; /* ACCESS.bus */ 310 | case 0x04: return "Reset Factory Defaults"; 311 | case 0x05: return "SAM: Reset Brightness and Contrast"; /* ??? */ 312 | case 0x06: return "Reset Factory Geometry"; 313 | case 0x08: return "Reset Factory Default Color"; /* ACCESS.bus */ 314 | case 0x0a: return "Reset Factory Default Position"; /* ACCESS.bus */ 315 | case 0x0c: return "Reset Factory Default Size"; /* ACCESS.bus */ 316 | case 0x0e: return "SAM: Image Lock Coarse"; /* ??? */ 317 | case 0x10: return "Brightness"; 318 | case 0x12: return "Contrast"; 319 | case 0x14: return "Select Color Preset"; /* ACCESS.bus */ 320 | case 0x16: return "Red Video Gain"; 321 | case 0x18: return "Green Video Gain"; 322 | case 0x1a: return "Blue Video Gain"; 323 | case 0x1c: return "Focus"; /* ACCESS.bus */ 324 | case 0x1e: return "SAM: Auto Size Center"; /* ??? */ 325 | case 0x20: return "Horizontal Position"; 326 | case 0x22: return "Horizontal Size"; 327 | case 0x24: return "Horizontal Pincushion"; 328 | case 0x26: return "Horizontal Pincushion Balance"; 329 | case 0x28: return "Horizontal Misconvergence"; 330 | case 0x2a: return "Horizontal Linearity"; 331 | case 0x2c: return "Horizontal Linearity Balance"; 332 | case 0x30: return "Vertical Position"; 333 | case 0x32: return "Vertical Size"; 334 | case 0x34: return "Vertical Pincushion"; 335 | case 0x36: return "Vertical Pincushion Balance"; 336 | case 0x38: return "Vertical Misconvergence"; 337 | case 0x3a: return "Vertical Linearity"; 338 | case 0x3c: return "Vertical Linearity Balance"; 339 | case 0x3e: return "SAM: Image Lock Fine"; /* ??? */ 340 | case 0x40: return "Parallelogram Distortion"; 341 | case 0x42: return "Trapezoidal Distortion"; 342 | case 0x44: return "Tilt (Rotation)"; 343 | case 0x46: return "Top Corner Distortion Control"; 344 | case 0x48: return "Top Corner Distortion Balance"; 345 | case 0x4a: return "Bottom Corner Distortion Control"; 346 | case 0x4c: return "Bottom Corner Distortion Balance"; 347 | case 0x50: return "Hue"; /* ACCESS.bus */ 348 | case 0x52: return "Saturation"; /* ACCESS.bus */ 349 | case 0x54: return "Color Curve Adjust"; /* ACCESS.bus */ 350 | case 0x56: return "Horizontal Moire"; 351 | case 0x58: return "Vertical Moire"; 352 | case 0x5a: return "Auto Size Center Enable/Disable"; /* ACCESS.bus */ 353 | case 0x5c: return "Landing Adjust"; /* ACCESS.bus */ 354 | case 0x5e: return "Input Level Select"; /* ACCESS.bus */ 355 | case 0x60: return "Input Source Select"; 356 | case 0x62: return "Audio Speaker Volume Adjust"; /* ACCESS.bus */ 357 | case 0x64: return "Audio Microphone Volume Adjust"; /* ACCESS.bus */ 358 | case 0x66: return "On Screen Display Enable/Disable"; /* ACCESS.bus */ 359 | case 0x68: return "Language Select"; /* ACCESS.bus */ 360 | case 0x6c: return "Red Video Black Level"; 361 | case 0x6e: return "Green Video Black Level"; 362 | case 0x70: return "Blue Video Black Level"; 363 | case 0xa2: return "Auto Size Center"; /* USB */ 364 | case 0xa4: return "Polarity Horizontal Synchronization"; /* USB */ 365 | case 0xa6: return "Polarity Vertical Synchronization"; /* USB */ 366 | case 0xa8: return "Synchronization Type"; /* USB */ 367 | case 0xaa: return "Screen Orientation"; /* USB */ 368 | case 0xac: return "Horizontal Frequency"; /* USB */ 369 | case 0xae: return "Vertical Frequency"; /* USB */ 370 | case 0xb0: return "Settings"; 371 | /* case 0xb6: return "b6 r/o"; 372 | case 0xc6: return "c6 r/o"; 373 | case 0xc8: return "c8 r/o"; 374 | case 0xc9: return "c9 r/o";*/ 375 | case 0xca: return "On Screen Display"; /* USB */ 376 | case 0xcc: return "SAM: On Screen Display Language"; /* ??? */ 377 | case 0xd4: return "Stereo Mode"; /* USB */ 378 | case 0xd6: return "SAM: DPMS control (1 - on/4 - stby)"; 379 | case 0xdc: return "SAM: MagicBright (1 - text/2 - internet/3 - entertain/4 - custom)"; 380 | case 0xdf: return "VCP Version"; /* ??? */ 381 | case 0xe0: return "SAM: Color preset (0 - normal/1 - warm/2 - cool)"; 382 | case 0xe1: return "SAM: Power control (0 - off/1 - on)"; 383 | /* case 0xe2: return "e2 r/w";*/ 384 | case 0xed: return "SAM: Red Video Black Level"; 385 | case 0xee: return "SAM: Green Video Black Level"; 386 | case 0xef: return "SAM: Blue Video Black Level"; 387 | case 0xf5: return "SAM: VCP Enable"; 388 | } 389 | 390 | return "???"; 391 | } 392 | 393 | int ddcci_dumpctrl(int fd, unsigned int addr, 394 | unsigned char ctrl, int force) 395 | { 396 | unsigned char buf[8]; 397 | 398 | int len = ddcci_readctrl(fd, addr, ctrl, buf, sizeof(buf)); 399 | 400 | if (len == sizeof(buf) && buf[0] == DDCCI_REPLY_READ && 401 | buf[2] == ctrl && (force || !buf[1])) /* buf[1] is validity (0 - valid, 1 - invalid) */ 402 | { 403 | int current = buf[6] * 256 + buf[7]; 404 | int maximum = buf[4] * 256 + buf[5]; 405 | 406 | fprintf(stdout, "Control 0x%02x: %c/%d/%d\t[%s]\n", ctrl, 407 | buf[1] ? '-' : '+', current, maximum, ctrlname(ctrl)); 408 | if (verbosity) { 409 | fprintf(stderr, "Raw: "); 410 | dumphex(stderr, buf, sizeof(buf)); 411 | } 412 | } 413 | 414 | return len; 415 | } 416 | 417 | void usage(char *name) 418 | { 419 | fprintf(stderr,"%s [-a adr] [-e] [-d] [-c] [-f] [-v] [-s] [-S] [-r ctrl] [-w value] dev\n", name); 420 | fprintf(stderr,"\tdev: device, e.g. /dev/i2c-0\n"); 421 | fprintf(stderr,"\tadr: base address of ddc/ci, eg 0x37 (def)\n"); 422 | fprintf(stderr,"\t-e : query EDID at 0x50\n"); 423 | fprintf(stderr,"\t-c : query capability\n"); 424 | fprintf(stderr,"\t-d : query ctrls 0 - 255\n"); 425 | fprintf(stderr,"\t-r : query ctrl\n"); 426 | fprintf(stderr,"\t-w : value to write to ctrl\n"); 427 | fprintf(stderr,"\t-f : force (avoid validity checks)\n"); 428 | fprintf(stderr,"\t-s : save settings\n"); 429 | fprintf(stderr,"\t-v : verbosity (specify more to increase)\n"); 430 | fprintf(stderr,"\t-S : send Samsung DDC/CI enable\n"); 431 | } 432 | 433 | int main(int argc, char **argv) 434 | { 435 | int i, retry; 436 | 437 | /* filedescriptor and name of device */ 438 | int fd; 439 | char *fn; 440 | unsigned int addr = DEFAULT_DDCCI_ADDR; 441 | 442 | /* what to do */ 443 | int dump = 0; 444 | int ctrl = -1; 445 | int value = -1; 446 | int caps = 0; 447 | int edid = 0; 448 | int save = 0; 449 | int force = 0; 450 | int sam = 0; 451 | 452 | fprintf(stdout, "ddcci-tool version 0.03\n"); 453 | 454 | while ((i=getopt(argc,argv,"a:hdr:w:cesfvS")) >= 0) 455 | { 456 | switch(i) { 457 | case 'h': 458 | usage(argv[0]); 459 | exit(1); 460 | break; 461 | case 'a': 462 | if ((addr = strtol(optarg, NULL, 0)) < 0 || (addr > 127)){ 463 | fprintf(stderr,"'%s' does not seem to be a valid i2c address\n", optarg); 464 | exit(1); 465 | } 466 | break; 467 | case 'r': 468 | if ((ctrl = strtol(optarg, NULL, 0)) < 0 || (ctrl > 255)){ 469 | fprintf(stderr,"'%s' does not seem to be a valid register name\n", optarg); 470 | exit(1); 471 | } 472 | break; 473 | case 'w': 474 | if ((value = strtol(optarg, NULL, 0)) < 0 || (value > 65535)){ 475 | fprintf(stderr,"'%s' does not seem to be a valid value.\n", optarg); 476 | exit(1); 477 | } 478 | break; 479 | case 'c': 480 | caps++; 481 | break; 482 | case 'd': 483 | dump++; 484 | break; 485 | case 'e': 486 | edid = 0x50; 487 | break; 488 | case 's': 489 | save++; 490 | break; 491 | case 'f': 492 | force++; 493 | break; 494 | case 'v': 495 | verbosity++; 496 | break; 497 | case 'S': 498 | sam++; 499 | break; 500 | } 501 | } 502 | 503 | if (optind == argc) 504 | { 505 | usage(argv[0]); 506 | exit(1); 507 | } 508 | 509 | fn = argv[optind]; 510 | 511 | if ((fd = open(fn, O_RDWR)) < 0) 512 | { 513 | perror(fn); 514 | fprintf(stderr, "Be sure you've modprobed i2c-dev and correct i2c device.\n"); 515 | exit(1); 516 | } 517 | 518 | if (edid) 519 | { 520 | unsigned char buf[128]; 521 | buf[0] = 0; /* eeprom offset */ 522 | 523 | fprintf(stdout, "\nReading EDID : 0x%02x@%s\n", edid, fn); 524 | if (i2c_write(fd, edid, buf, 1) > 0 && 525 | i2c_read(fd, edid, buf, sizeof(buf)) > 0) 526 | { 527 | if (verbosity) { 528 | dumphex(stdout, buf, sizeof(buf)); 529 | } 530 | 531 | printf("\tPlug and Play ID: %c%c%c%02X%02X\n", 532 | ((buf[8] >> 2) & 31) + 'A' - 1, 533 | ((buf[8] & 3) << 3) + (buf[9] >> 5) + 'A' - 1, 534 | (buf[9] & 31) + 'A' - 1, 535 | buf[11], buf[10]); 536 | printf("\tInput type: %s\n", (buf[20] & 0x80) ? "Digital" : "Analog"); 537 | } else { 538 | fprintf(stderr, "Reading EDID 0x%02x@%s failed.\n", edid, fn); 539 | } 540 | } 541 | 542 | fprintf(stdout, "\nUsing ddc/ci : 0x%02x@%s\n", addr, fn); 543 | 544 | if ((sam ? ddcci_writectrl(fd, addr, DDCCI_CTRL, DDCCI_CTRL_ENABLE) : 545 | ddcci_command(fd, addr, DDCCI_COMMAND_PRESENCE)) < 0) 546 | { 547 | fprintf(stderr, "\nDDC/CI at 0x%02x is unusable.\n", addr); 548 | } else { 549 | /* enable/presence delay */ 550 | usleep(DELAY); 551 | 552 | if (caps) { 553 | unsigned char buf[35]; /* 19 bytes chunk */ 554 | int len, offset = 0; 555 | 556 | fprintf(stdout, "\nCapabilities:\n"); 557 | 558 | do { 559 | for (retry = RETRYS; retry && 560 | ((len = ddcci_caps(fd, addr, offset, buf, sizeof(buf))) < 0); retry--) usleep(DELAY); 561 | 562 | if (len < 3 || buf[0] != DDCCI_REPLY_CAPS || 563 | (buf[1] * 256 + buf[2]) != offset) 564 | { 565 | fprintf(stderr, "Invalid sequence in caps.\n"); 566 | break; 567 | } 568 | 569 | for (i = 3; i < len; i++) { 570 | fprintf(stdout, i > 2 && buf[i] >= 0x20 && buf[i] < 127 ? "%c" : "0x%02x ", buf[i]); 571 | } 572 | 573 | offset += len - 3; 574 | } while (len > 3); 575 | 576 | fprintf(stdout, "\n"); 577 | } 578 | if (ctrl >= 0) { 579 | if (value >= 0) { 580 | fprintf(stdout, "\nWriting 0x%02x(%s), 0x%02x(%d)\n", 581 | ctrl, ctrlname(ctrl), value, value); 582 | ddcci_writectrl(fd, addr, ctrl, value); 583 | usleep(DELAY); 584 | } else { 585 | fprintf(stdout, "\nReading 0x%02x(%s)\n", 586 | ctrl, ctrlname(ctrl)); 587 | } 588 | 589 | for (retry = RETRYS; retry && 590 | (ddcci_dumpctrl(fd, addr, ctrl, 1) < 0); retry--) usleep(DELAY); 591 | } 592 | if (dump) { 593 | fprintf(stdout, "\nControls (valid/current/max):\n"); 594 | 595 | for (i = 0; i < 256; i++) { 596 | for (retry = RETRYS; retry && 597 | (ddcci_dumpctrl(fd, addr, i, force) < 0); retry--) usleep(DELAY); 598 | } 599 | } 600 | if (save) { 601 | fprintf(stdout, "\nSaving settings...\n"); 602 | ddcci_command(fd, addr, DDCCI_COMMAND_SAVE); 603 | } 604 | 605 | usleep(DELAY); 606 | sam && ddcci_writectrl(fd, addr, DDCCI_CTRL, DDCCI_CTRL_DISABLE); 607 | } 608 | 609 | close(fd); 610 | 611 | exit(0); 612 | } 613 | --------------------------------------------------------------------------------