T221やCDU2150Aをより快適に使うにあたりに問題となるEDID。
某オークションにEDIDのoverrideする延長ケーブル、ROMが出品されているのだがいかんせん安くない。
T221購入時にoverrideケーブル、ROMx3個は購入したのだが。
実際のところ、どれが自分の環境に一番適しているか取っ替え引っ替えしたいのでコスパが悪い。
少し調べてみるとEDIDに使用されているEEPROMはI2Cで通信、データの保存をしているそうだ。
パソコンでの書き込みはパラレルポートを使用してトランジスタ2個と抵抗いくつかで自作できるようだ。
パラレルポートがあるPCが既に無いのでガレージに積んであった古いノートPCを復活させようと思ったが、
コンデンサがイカレているのか、OSインストール中に突然電源が落る。これは使えないと判断。
さらに調べる。
I2CといえばウチにはarduinoもRaspberryPiもあるぞ、もしかして書き換えできるのでは?
と、思ってしまった。
arduino I2C EEPROM で検索すると日本語ページで確かにある。こうなると試してみないと気が済まない。
arduinoで読み出し成功。書き込みはなぜかうまくいかない。
raspberrypi I2C EEPROM で英語のページを発見。
こちらでも読み出しは成功。
なぜ書き込みができないのか?使用しているEEPROMにプロテクトでもかかっているのだろう、と勝手に判断。
まぁ、読めるのなら書き込みもなんとかすればうまくゆくのだろうと、部材を発注。
某サイトにて Microchipの24LC01B/P。1個28円!。20個購入。8pinのICソケットも10個。
これ、さらっと書いているけどEEPROMの選定についてもいろいろ調べた。恐らくこれで大丈夫だろう…の見切り発車。
で、本日到着。うまく行ったので手順をまとめる。
取り敢えずテストなのでEEPROMに書き込むためのデータはExtron Electronicsが無償で配布している(登録が必要)
EDID ManagerをWindows8.1機にインストールしてこれを使用してファイルに保存。いろいろなソフトを試したが、
(編集こそできないが)これが一番使いやすい。
ちなみに現在T221には3840x2400x34HzのEDID乗っ取りoverrideケーブルで繋いでいるので、このROMデータを直接
読んでも同じデータとなる。うまくいったのかどうかはとりあえずこれのコピーを作れば確認ができる。
raspiとEEPROMの接続はこう。

SCLとSDAを繋ぎ1kΩでプルアップ。電源は3.3V。
raspiでのEEPROM読み書きソフトは以下より。
https://github.com/dgallot/i2c-tools/tree/master/eepromer/
eeprom.cをダウンロードして、EEPROMのサイズにあわせて適宜編集。
24LC01なら DEFAULT_NUM_PAGES を 8,BYTES_PER_PAGE を128,MAX_BYTES を8 に変更。
raspiでのi2cデバイスの有効化は検索すればでてくる。
http://www.gallot.be/?p=180 このページを参考にしたが、ワシの環境では /dev/i2c-1 である必要があった。
#i2cdetect -y -a 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 51 52 53 54 55 56 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
で50~にEEPROMが認識されていると言うことだと思う。
読み出し。-p 2は1ページ128bytex2で256byte分。 -f で 読み出し先ファイル名。
# ./eeprom -p 2 -f EDID.bin
base-address of eeproms : 0x50
number of pages to read : 2 (0x50 .. 0x51)
file opened for writing : EDID.bin
on filedescriptor : 3
i2c-devicenode is : /dev/i2c-1
on filedescriptor : 4
Read 8 bytes from eeprom at 0x50, offset 00000000
---割愛---
書き込み。
#./eeprom -w -p 2 -f EDID.bin
base-address of eeproms : 0x50
number of pages to read : 2 (0x50 .. 0x51)
file opened for reading : EDID_CDU2150A_256byte.bin
on filedescriptor : 3
i2c-devicenode is : /dev/i2c-1
on filedescriptor : 4
**WARNING**
- You have chosen to WRITE to this eeprom.
Make sure that this tiny chip is *NOT* vital to the
operation of your computer as you can easily corrupt
the configuration memory of your SDRAM-memory-module,
your IBM ThinkPad or whatnot...! Fixing these errors can be
a time-consuming and very costly process!
Things to consider:
- You can have more than one i2c-bus, check in /proc/bus/i2c
and specify the correct one with -d
right now you have chosen to use '/dev/i2c-1'
- A eeprom can occupy several i2c-addresses (one per page)
so please make sure that there is no vital eeprom in your computer
sitting at addresses between 0x50 and 0x51
Enter 'yes' to continue:yes
Wrote 8 bytes to eeprom at 0x50, offset 00000000
...... acked
Wrote 8 bytes to eeprom at 0x50, offset 00000008
...... acked
割愛
書き込まれたデータはきちんと読み出しできるか確認して実際にoverrideケーブルに付けてみる。
ドキドキしながらT221接続PCの電源をいれるとあっさり映る。成功。
EEPROMも手に入ったしデータの書き込みも確認できたのであとはDVIケーブルを
ハードオフで買って来てROMを乗っければEDID乗っ取りケーブルの出来上がり、と。
EDIDデータの作成もめんどうそうだが…..
githubで公開されているし、多分大丈夫だと思うので以下 eeprom.c の全ソース。
/*
This program is hereby placed into the public domain.
Of course the program is provided without warranty of any kind.
Downloaded from http://www.lm-sensors.org/browser/i2c-tools/trunk/eepromer/eeprom.c
*/
#include <sys/ioctl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <linux/i2c-dev.h>
/*
this program can read 24C16 (and probably smaller ones, too)
I wrote it as a quick and dirty hack because my satellite receiver
hung again... so I had to reprogram the eeprom where is stores it's
settings.
*/
#define DEFAULT_I2C_BUS "/dev/i2c-0"
#define DEFAULT_EEPROM_ADDR 0x50 /* the 24C16 sits on i2c address 0x50 */
#define DEFAULT_NUM_PAGES 8 /* we default to a 24C16 eeprom which has 8 pages */
#define BYTES_PER_PAGE 256 /* one eeprom page is 256 byte */
#define MAX_BYTES 16 /* max number of bytes to write in one chunk */
/* ... note: 24C02 and 24C01 only allow 8 bytes to be written in one chunk. *
* if you are going to write 24C04,8,16 you can change this to 16 */
/* write len bytes (stored in buf) to eeprom at address addr, page-offset offset */
/* if len=0 (buf may be NULL in this case) you can reposition the eeprom's read-pointer */
/* return 0 on success, -1 on failure */
int eeprom_write(int fd,
unsigned int addr,
unsigned int offset,
unsigned char *buf,
unsigned char len
){
struct i2c_rdwr_ioctl_data msg_rdwr;
struct i2c_msg i2cmsg;
int i;
char _buf[MAX_BYTES + 1];
if(len>MAX_BYTES){
fprintf(stderr,"I can only write MAX_BYTES bytes at a time!\n");
return -1;
}
if(len+offset >256){
fprintf(stderr,"Sorry, len(%d)+offset(%d) > 256 (page boundary)\n",
len,offset);
return -1;
}
_buf[0]=offset; /* _buf[0] is the offset into the eeprom page! */
for(i=0;i<len;i++) /* copy buf[0..n] -> _buf[1..n+1] */
_buf[1+i]=buf[i];
msg_rdwr.msgs = &i2cmsg;
msg_rdwr.nmsgs = 1;
i2cmsg.addr = addr;
i2cmsg.flags = 0;
i2cmsg.len = 1+len;
i2cmsg.buf = _buf;
if((i=ioctl(fd,I2C_RDWR,&msg_rdwr))<0){
if ( len > 0 ) {
perror("ioctl()");
fprintf(stderr,"ioctl returned %d\n",i);
}
return -1;
}
if(len>0)
fprintf(stderr,"Wrote %d bytes to eeprom at 0x%02x, offset %08x\n",
len,addr,offset);
return 0;
}
/* read len bytes stored in eeprom at address addr, offset offset in array buf */
/* return -1 on error, 0 on success */
int eeprom_read(int fd,
unsigned int addr,
unsigned int offset,
unsigned char *buf,
unsigned char len
){
struct i2c_rdwr_ioctl_data msg_rdwr;
struct i2c_msg i2cmsg;
int i;
if(len>MAX_BYTES){
fprintf(stderr,"I can only write MAX_BYTES bytes at a time!\n");
return -1;
}
if(eeprom_write(fd,addr,offset,NULL,0)<0)
return -1;
msg_rdwr.msgs = &i2cmsg;
msg_rdwr.nmsgs = 1;
i2cmsg.addr = addr;
i2cmsg.flags = I2C_M_RD;
i2cmsg.len = len;
i2cmsg.buf = buf;
if((i=ioctl(fd,I2C_RDWR,&msg_rdwr))<0){
perror("ioctl()");
fprintf(stderr,"ioctl returned %d\n",i);
return -1;
}
fprintf(stderr,"Read %d bytes from eeprom at 0x%02x, offset %08x\n",
len,addr,offset);
return 0;
}
int main(int argc, char **argv){
int i,j;
/* filedescriptor and name of device */
int d;
char *dn=DEFAULT_I2C_BUS;
/* filedescriptor and name of data file */
int f=-1;
char *fn=NULL;
unsigned int addr=DEFAULT_EEPROM_ADDR;
int rwmode=0;
int pages=DEFAULT_NUM_PAGES;
int force=0; /* suppress warning on write! */
int wait = 0;
int acked = 0;
while((i=getopt(argc,argv,"d:a:p:wyf:h"))>=0){
switch(i){
case 'h':
fprintf(stderr,"%s [-d dev] [-a adr] [-p pgs] [-w] [-y] [-f file]\n",argv[0]);
fprintf(stderr,"\tdev: device, e.g. /dev/i2c-0 (def)\n");
fprintf(stderr,"\tadr: base address of eeprom, eg 0xA0 (def)\n");
fprintf(stderr,"\tpgs: number of pages to read, eg 8 (def)\n");
fprintf(stderr,"\t-w : write to eeprom (default is reading!)\n");
fprintf(stderr,"\t-y : suppress warning when writing (default is to warn!)\n");
fprintf(stderr,"\t-f file: copy eeprom contents to/from file\n");
fprintf(stderr,"\t (default for read is test only; for write is all zeros)\n");
fprintf(stderr,"Note on pages/addresses:\n");
fprintf(stderr,"\teeproms with more than 256 byte appear as if they\n");
fprintf(stderr,"\twere several eeproms with consecutive addresses on the bus\n");
fprintf(stderr,"\tso we might as well address several separate eeproms with\n");
fprintf(stderr,"\tincreasing addresses....\n\n");
exit(1);
break;
case 'd':
dn=optarg;
break;
case 'a':
if(sscanf(optarg,"0x%x",&addr)!=1){
fprintf(stderr,"Cannot parse '%s' as addrs., example: 0xa0\n",
optarg);
exit(1);
}
break;
case 'p':
if(sscanf(optarg,"%d",&pages)!=1){
fprintf(stderr,"Cannot parse '%s' as number of pages, example: 8\n",
optarg);
exit(1);
}
break;
case 'w':
rwmode++;
break;
case 'f':
fn=optarg;
break;
case 'y':
force++;
break;
}
}
fprintf(stderr,"base-address of eeproms : 0x%02x\n",addr);
fprintf(stderr,"number of pages to read : %d (0x%02x .. 0x%02x)\n",
pages,addr,addr+pages-1);
if(fn){
if(!rwmode) /* if we are reading, *WRITE* to file */
f=open(fn,O_WRONLY|O_CREAT,0666);
else /* if we are writing to eeprom, *READ* from file */
f=open(fn,O_RDONLY);
if(f<0){
fprintf(stderr,"Could not open data-file %s for reading or writing\n",fn);
perror(fn);
exit(1);
}
fprintf(stderr,"file opened for %7s : %s\n",rwmode?"reading":"writing",fn);
fprintf(stderr," on filedescriptor : %d\n",f);
}
if((d=open(dn,O_RDWR))<0){
fprintf(stderr,"Could not open i2c at %s\n",dn);
perror(dn);
exit(1);
}
fprintf(stderr,"i2c-devicenode is : %s\n",dn);
fprintf(stderr," on filedescriptor : %d\n\n",d);
/***
*** I'm not the one to blame of you screw your computer!
***/
if(rwmode && ! force){
unsigned char warnbuf[4];
fprintf(stderr,"**WARNING**\n");
fprintf(stderr," - \tYou have chosen to WRITE to this eeprom.\n");
fprintf(stderr,"\tMake sure that this tiny chip is *NOT* vital to the\n");
fprintf(stderr,"\toperation of your computer as you can easily corrupt\n");
fprintf(stderr,"\tthe configuration memory of your SDRAM-memory-module,\n");
fprintf(stderr,"\tyour IBM ThinkPad or whatnot...! Fixing these errors can be\n");
fprintf(stderr,"\ta time-consuming and very costly process!\n\n");
fprintf(stderr,"Things to consider:\n");
fprintf(stderr," - \tYou can have more than one i2c-bus, check in /proc/bus/i2c\n");
fprintf(stderr,"\tand specify the correct one with -d\n");
fprintf(stderr,"\tright now you have chosen to use '%s'\n",dn);
fprintf(stderr," - \tA eeprom can occupy several i2c-addresses (one per page)\n");
fprintf(stderr,"\tso please make sure that there is no vital eeprom in your computer\n");
fprintf(stderr,"\tsitting at addresses between 0x%02x and 0x%02x\n",addr,addr+pages-1);
fprintf(stderr,"Enter 'yes' to continue:");
fflush(stderr);
if(!fgets(warnbuf,sizeof(warnbuf),stdin)){
fprintf(stderr,"\nCould not read confirmation from stdin!\n");
exit(1);
}
if(strncmp(warnbuf,"yes",3)){
fprintf(stderr,"\n** ABORTING WRITE! **, you did not answer 'yes'\n");
exit(1);
}
}
for(i=0;i<pages;i++){
unsigned char buf[BYTES_PER_PAGE];
if(rwmode){
if(f>=0){
j=read(f,buf,sizeof(buf));
if(j<0){
fprintf(stderr,"Cannot read from file '%s'\n",fn);
perror(fn);
exit(1);
}
if(j!=sizeof(buf)){
fprintf(stderr,"File '%s' is too small, padding eeprom with zeroes\n",fn);
while(j<sizeof(buf))
buf[j++]=0;
}
} else {
for(j=0;j<sizeof(buf);j++)
buf[j]=0;
}
for(j=0;j<(BYTES_PER_PAGE/MAX_BYTES);j++) {
if(eeprom_write(d,addr+i,j*MAX_BYTES,buf+(j*MAX_BYTES),MAX_BYTES)<0)
exit(1);
fprintf(stderr,".");
for ( wait = 0; wait < 10; wait ++ ) {
acked = eeprom_write(d,addr+i,j*MAX_BYTES,NULL,0);
if ( acked == 0 )
break;
fprintf(stderr,".");
usleep( 100 );
}
if ( acked != 0 ) {
fprintf(stderr,"Ack of write operation timedout");
exit ( 1 );
}
fprintf(stderr," acked \n");
}
} else {
for(j=0;j<(BYTES_PER_PAGE/MAX_BYTES);j++)
if(eeprom_read(d,addr+i,j*MAX_BYTES,buf+(j*MAX_BYTES),MAX_BYTES)<0)
exit(1);
}
if(!rwmode && f>=0){
j=write(f,buf,sizeof(buf));
if(j!=sizeof(buf)){
fprintf(stderr,"Cannot write to file '%s'\n",fn);
perror(fn);
exit(1);
}
}
}
if(f>=0)
close(f);
close(d);
exit(0);
}