Archives

Re-programming the 2Wire NAND flash IC

Californian hacker RyanC suggested another method for unlocking the 2Wires:  re-purposing a SmartMedia or xD-Picture card reader to program the NAND flash memory. [1]

The SmartMedia format uses the standard ONFI command set for reading and programming the NAND flash. The xD-Picture specs are slightly more involved, being a superset of ONFI.

Simple, so far?

2Wire, however, has its own flash translation layer (FTL) to hold the logical-to-physical block mapping.  This mapping data is stored in the out-of-band (OOB) area of the NAND page.  Unfortunately, the average flash card reader cannot program arbitrary data to the OOB area, so can’t be used to reprogram a 2Wire flash.  All is not lost though..

Aside the professional NAND programmers costing $2000 or more, there is one consumer-grade NAND controller IC which offers raw read and write access to all areas of the flash device. The IC, codenamed the Alauda, is something of a mystery. No one is even sure who developed it, but it was probably on behalf of Fuji and/or Olympus.

The Alauda IC has a USB peripheral controller to interface very simply with the PC. This allows easy transfer of control messages and page data to the raw NAND device.  And it doesn’t matter if the NAND chip is embedded in a camera card, or in a TSOP48 surface mount package, as in the case of the 2Wire.

It was perhaps BrendanU who first publicly documented the capabilities of Alauda-based card readers. [2] An open source kernel driver was then developed for the Alauda by legendary Linux hacker Daniel Drake.[3]   Cory1492, a well-known XBox and PSP hacker, ported Daniel’s code, and built it against the userspace USB library, libusb. [4]   Cory’s efforts have made the tool available for most Unix platforms and even for Microsoft Windows.

Alauda NAND flash controller harnessed to TSOP48 cradle
256Mbit NAND from 2Wire board loose beneath
(click to enlarge)

The Alauda NAND controller IC
(click to enlarge)

The plan to exploit this hack and hardware was described earlier.  Briefly:

  • Gently lift the NAND flash IC off the PCB with a hot-air gun;
  • Dump contents with a NAND reader. For reasons above, the Alauda IC is ideal;
  • Rewrite “initd” XML table to re-enable secure shell daemon. See: http://pastebin.com/ss8sqMdu
  • Rewrite “user” XML table with new root password. See: http://pastebin.com/gucCEM3H
  • Update ECC in OOB areas of all modified pages. See: http://hack..error-correcting-code-ecc/
  • Re-program the modified NAND pages;
  • Re-install NAND IC on the 2Wire PCB;
  • Fingers crossed and boot!

Userspace tool for Alauda NAND reader by Cory1492

UPDATE:

This method was just trialled several times. While the NAND reading and writing works fine, the 2Wire board still won’t boot with our modified firmware image. The device just hangs with a solid red LED.

The search for that elusive 2Wire hack continues!

As for the NAND hack in general, it could be very useful in a range of other applications. Whether for unlocking routers, digital TV set-top boxes, or for reflashing PC BIOS chips, etc.

EDIT:

There are some more notes in the comments below. In the dueness of time, it can be properly documented and referenced.  The beauty of this NAND reader is that it costs scarcely $10 to make.

[1] https://plus.google.com/102161594653790479451/posts
[2] http://www.uchobby.com/index.php/2007/05/05/read-embedded-flash-chips/
[3] http://www.reactivated.net/weblog/
[4] http://www.xboxhacker.org/index.php?action=profile;u=15891 DEAD LINK
Mirrored at http://docs.google.com/folder/d/0B6wW18mYskvBOWE2OGQ5NzAtZjc4ZS00MjNkLWE5ODAtMjZkMjYwZTZkMmVj/edit

Suitable Mini Edge Card Socket?

Earlier, we had great difficulty finding a connector to fit the JTAG/I2C port on the 2Wire PCBs. In the end, something usable was fashioned out of a Sullins PCIe edge card socket. However, the connector below could be a better, low-cost solution.

Connector specialist, Samtec, stocks the MEC-1 series socket and it looks very promising for hacking the 2Wire. [1] [2]    Infact, it may be the very connector that 2Wire / Pace uses to re-flash and unbrick these devices.

Samtec MEC1-108-02-F-D-A

The 1.0mm pitch dual row card edge connector

[1] http://www.samtec.com/documents/webfiles/pdf/MEC1.PDF
[2] http://hackingbtbusinesshub.files.wordpress.com/2012/10/320918.pdf

PCB photo of 2Wire 2701HGV-E

Below is a nice clear photograph of the PCB in a 2Wire 2701HGV-E.

The photo is attributed to ‘seya‘, a contributor to a discussion thread on right.com.cn, a Chinese language web forum. [1]:

We can see that the 2701HGV-E is driven by a 2Wire Ares, a TriMedia five-issue slot VLIW CPU.   On the DSL side, the 2701HGV-E has a SiLabs SI3112-ZM1  ADSL2+ AFE and Line Driver.    It also has a USB peripheral port which isn’t present on the BT-issue 2701HGV-C.

Pace plc (new owner of 2Wire Inc)  has published an incomplete list of 2Wire models in the Home Gateway family. [2]

PCB of the 2Wire 2701HGV-E (click to enlarge)

[1] http://www.right.com.cn/forum/thread-40668-1-1.html
[2] http://www.pace.com/universal/gateways/2wire/gateway-platforms/models-and-specs/

Optimising the JTAG scan

Aficionados of 2Wire kit will already know of the Tripod site, an excellent unofficial resource for these popular and powerful devices. The website can be found at [1].

Bill, the webmaster of the Tripod site, has done a sterling job for some years now. He tracks new firmware for the 2Wire, monitors firmware incompatibilities and follows new firmware rollout programmes. Bill also documents the ways to block or circumvent any undesirable firmware ‘features’.

Recently, Bill recounted his own experience of the painfully slow process of re-flashing an embedded device via JTAG.  [2]   We are developing an open source JTAG tool for the TriMedia and Bill’s account served as a prescient reminder to optimise the JTAG scan chain whenever possible!

The designers of the TriMedia core, Philips Semiconductors, clearly recognised the issue of long scan times.  Several useful mechanisms are built into the TM3260 JTAG controller to mitigate the problem.

Described below are two key techniques for JTAG optimisation which are found in the TriMedia.

JTAG state machine

One optimisation method sees two JTAG registers combined into one.  The ifull handshaking bit of the CTRL2 JTAG register and the 32-bit DATA IN JTAG register are joined in serial to form a single virtual register of 33 bits. This virtual register is named IFULLIN.   This combination of control and data register can see a dramatic reduction in JTAG scan-in time. This is illustrated best by reference to the JTAG state machine diagram, above.

If there was no virtual register, transferring 32-bits of data to the TriMedia using JTAG would involve the following: The instruction to select the DATAIN register would be shifted it.   The 32-bits would then be scanned in to the JTAG data register (DR).  Then the instruction to select the CTRL2 register would be shifted in. Finally, to tell the TriMedia target that data is ready, the 8 control bits, including the ifull handshaking bit needs to be scanned in to the DR register.

However, with a virtual register combining both the DATAIN and the ifull bit from the CTRL2 register,  the scan time is shortened as follows:  the JTAG controller needs only shift in one instruction (to select the virtual register) before scanning in the data register. That scanned in data is 33-bits in size,  containing values for both the CTRL2.ifull bit as well as the 32 data bits.

By eliminating the second of those two-part operations – the instruction shift in to select the CTRL2 register and then the 8-bit scan in of the data register – the time needed to download object code to a TriMedia for a JTAG boot is reduced by 45% according to our tests.

Similar savings in scan time are obtained by combining the CTRL1 and the DATA OUT registers into another virtual register of 33 bits. This virtual register is labelled OFULLOUT.

The virtual JTAG registers allow us to greatly optimise the download function. We need only once shift in the instruction to select the IFULLIN virtual register. In the main loop to the function, we repeatedly scan in the data register containing all 33 bits of IFULLIN.  Those bits are the 32-bits of data and then the handshaking control bit, CTRL2.ifull.    This is the most optimal method for downloading.

A second, less obvious saving in scan time is achieved by capturing the state of the CTRL bits during a shift in of a TM32 JTAG instruction.  This mechanism removes the need to explicitly select and scan out a CTRL register, just to obtain the control flag status.

The shortcut allows the status of the JTAG control bits to be incidentally obtained from the output captured from scanning in any JTAG instruction.

Here, however, the operation of the TM3260 JTAG controller and the official Philips documentation for the controller were found not to tally. [3]

One of the major issues we discovered with the TriMedia‘s JTAG controller is that the CTRL2.ifull bit cannot be reliably read from the TAP interface. This issue runs contrary to the claims in the official documentation.  The CTRL2.ifull bit and the ofull bit are vital for handshaking between the TM32 target and the JTAG host that connects to the TriMedia via the TAP interface.

Several methods for reading the ifull bit via the TAP interface were tried without success:

  • select the CTRL2 register, scan out the contents, including the ifull bit.
  • select and scan out the 33 bit IFULLIN virtual register, including the ifull bit.
  • obtain control bits (ifull, ofull and sleepless) in captured output from a shifted-in instruction.

None of these methods can reliably capture the state of the CTRL2.ifull handshaking bit from the TAP interface.

It was also found, regarding the third method listed above, that the control bits are not in the bit positions described in the official TriMedia literature. The source code for our tool, and the output below, clarifies our findings of the true positions of those control bits:


asbokid@home:~/asboapps$ sudo ./2wiglet -c usbblaster -B testfile.bin
2Wiglet v0.5 - (c) 2011 asbokid
JTAG tool for 2Wire Routers with a TriMedia TM32 core

Searching for cable driver: usbblaster
usbblaster USB cable driver found
Connected to libftdi driver.
Connected to UsbBlaster cable
Waiting for JTAG chain to stabilise
Received IDCODE 3269b4c1 (2Wire Ares)
Current ctrl flags: 0x00  [     |     |         ]
L1BOOT_READY  = 12340002
Current ctrl flags: 0x15  [ofull|ifull|sleepless]
MMIO_BASE     = 1be00000  want: 1be00000
Current ctrl flags: 0x05  [     |ifull|sleepless]
Current ctrl flags: 0x15  [ofull|ifull|sleepless]
DRAM_LO       = 40000000  want: 40000000
Current ctrl flags: 0x05  [     |ifull|sleepless]
Current ctrl flags: 0x15  [ofull|ifull|sleepless]
DRAM_HI       = 44000000  want: 44000000
Current ctrl flags: 0x05  [     |ifull|sleepless]
Current ctrl flags: 0x15  [ofull|ifull|sleepless]
DRAM_CLIMIT   = 44000000  want: 44000000
Current ctrl flags: 0x05  [     |ifull|sleepless]
LOAD ADDRESS  = 40100000
Current ctrl flags: 0x05  [     |ifull|sleepless]
Current ctrl flags: 0x11  [ofull|     |sleepless]

In summary:  it was found that the CTRL2.ifull bit behaves like an interrupt control line. It can be asserted externally, but the bit itself can only be reliably read (and cleared) internally, by the JTAG controller on the TriMedia core.  Consequently, the ifull bit must be considered as a one-way handshaking flag.

Those limitations aside, it is certainly still possible to use the TM3260 JTAG controller for the efficient and reliable transfer of data both to and from the TriMedia.

In tests, a net rate of ~13.5kBytes per second was achieved in transfers from host to TM32 using a clone Altera USB-Blaster JTAG programmer. The USB-Blaster was connected to an x86 PC via a USB 2.0 bus.

Below are logs of the download of 1Mbyte of randomly-generated data.  The transfer took 76.31 seconds and attained 13.42kBytes/sec.

At that speed it would take roughly 40 minutes to transfer the whole 32MBytes of data stored in the NAND flash array on the 2Wire 2701 PCB.


asbokid@home:~/asboapps$ dd if=/dev/urandom of=testfile1M.bin bs=1K count=1K
1024+0 records in
1024+0 records out
1048576 bytes (1.0 MB) copied.

asbokid@home:~/asboapps$ sudo ./2wiglet -c usbblaster -B testfile1M.bin,0x40100000
2Wiglet v1.0 - (c) 2012 asbokid
JTAG tool for 2Wire Routers with a TriMedia TM32 core

Found USB cable driver for usbblaster
Connected to libftdi driver.
Connected to UsbBlaster cable
Waiting for JTAG chain to stabilise
Received IDCODE 3269b4c1 (2Wire Ares)
Download 1048576 bytes from 'testfile1M.bin' to 40100000

Waiting for L1BOOT_READY from TM32 target

L1BOOT_READY  <- 12340002
MMIO_BASE     <- 1be00000  (expected: 1be00000)
DRAM_LO       <- 40000000  (expected: 40000000)
DRAM_HI       <- 44000000  (expected: 44000000)
DRAM_CLIMIT   <- 44000000  (expected: 44000000)

LOAD ADDRESS  -> 40100000
CODE SIZE     -> 00100000 (1048576)

Started L2 download..
L2 load done.

Comparing checksums:
PC MONITOR=07f922c7, TM32 TARGET=07f922c7
Checksums good.

Download complete
Elapsed time 76.31 secs (avg 13.42kB/sec)
Freed buses and JTAG chain
asbokid@home:~/asboapps$

That’s hardly an earth-shattering transfer speed but it appears to be the maximum for that particular programmer using the standard JTAG monitor code running on the TriMedia, and after applying the optimisations described above.

[1] http://bt2700hgv.tripod.com/
[2] http://logikir100.tripod.com/JTAG.htm
[3] http://www.tridentmicro.com/wp-content/uploads/2010/01/UM101041.pdf

That elusive card edge connector arrives! (update)

Hooking a JTAG cable to most models of 2Wire requires a card edge connector: [1]

2Wire dual row card edge connection

The pitch and finger count of this connector is unusual, and very hard to find. None of the major suppliers keep the component in stock.

Future Electronics of Quebec City is an exception, and Future also accepts small orders. [2]

Behold! A small miracle has arrived, courtesy of FedEx, and just in time for Xmas!

It is the GCE08DHRN..

2700HG-B

2700HG-B

2071A

2071A

The fit isn’t perfect. To squeeze the connector into the tight gaps on some boards, a groove needs to be filed along the sides of the connector.  It will certainly do for now though.  Many thanks to Patti at Future for sourcing it.[2]

UPDATE:

The connector has now been made into a working JTAG cable. See [3]

[1] hackingbtbusinesshub.wordpress.com/2011/09/12/the-edge-card-connector-on-the-2wire-27xx-modem-routers/
[2] http://www.futureelectronics.com/
[3] http://hackingbtbusinesshub.wordpress.com/2012/01/16/discovering-2wire-card-edge-pinout-for-jtag-i2c/

Open Source TriMedia JTAG tools (Updated)

Earlier, we looked at the proprietary Windows-only JTAG tools for the TriMedia. [1]

There is a clear need for some open source JTAG tools for this core. These will be rudimentary tools. As such, no substitute for the professional development packages like tmdbg from the official SDK which is sold today by Trident.

However, for our humble hacking needs, liburJTAG, the JTAG programming library, is more than adequate. [2]

The codebase to this library is mature and fully open source. liburJTAG supports a wide range of JTAG programmers, right down to the most austere parallel port ‘wiggler’ cable, like the one below:

An economy class JTAG 'wiggler' cable

Currently,  the liburJTAG library has no support for the TriMedia, but that can be redressed.

The first JTAG tool for the TriMedia has just been built.  Its functionality matches the proprietary usbjtag.exe tool for testing the JTAG TAP interface on the TriMedia.

Below it performs various tests on the Trimedia JTAG interface.

Our Open Source tool has been nicknamed 2Wiglet, a 2Wire tool for JTAG Wiggler cables.

asbokid@home:~/asboapps$ ./2wiglet -h
2Wiglet v1.1 - (c) 2012 asbokid
JTAG tool for 2Wire Routers with a TriMedia TM32 core

This program comes with asbolutely no warranty; This is free software,
and you are welcome to redistribute it under certain conditions:
GNU GPL v3 License: http://www.gnu.org/licenses/gpl.html

USAGE:
 -h, --help                    Displays this text
 -v, --version                 Version information
 -d, --debug                   Debug output
 -i, --input                   DATA IN register read/write test
 -o, --output                  DATA OUT register read test
 -O, --outchange               DATA OUT register change test
 -b, --bootready               Verify target is ready for JTAG boot
 -B, --Boot ,  Download file to load address and run
 -l, --listcables              List supported JTAG cables
 -c, --cable     Select cable type and parameters

EXAMPLE:
 $ 2wiglet -c usbblaster -B l2bootfile.mi,0x40100000

asbokid@home:~/asboapps$ ./2wiglet -l
2Wiglet v1.1 - (c) 2011 asbokid
JTAG tool for 2Wire Routers with a TriMedia TM32 core

Supported cables:
           ARCOM      ByteBlaster             DLC5
           EA253            EI012           FT2232
     ARM-USB-OCD    ARM-USB-OCD-H       Flyswatter
           gnICE           gnICE+          JTAGkey
       milkymist       OOCDLink-s       Signalyzer
     Turtelizer2   USB-JTAG-RS232       usbScarab2
  USB-to-JTAG-IF             gpio         ICE-100B
           IGLOO            jlink        KeithKoep
         Lattice          Minimal           MPCBDM
          TRITON       UsbBlaster          vsllink
         WIGGLER         WIGGLER2          xpc_ext
         xpc_int

asbokid@home:~/asboapps$ ./2wiglet -c usbblaster -i
2Wiglet v0.4 - (c) 2011 asbokid
JTAG tool for 2Wire Routers with a TriMedia TM32 core

Searching for cable driver: usbblaster
usbblaster USB cable driver found
Connected to libftdi driver.
Connected to UsbBlaster cable
Waiting for JTAG chain to stabilise
Received IDCODE 3269b4c1 (2Wire Ares)
Hit enter to stop
s/b 00204a16 is 00000000
s/b 1bf06409 is 00000000
s/b 3a5c020a is 00000000
s/b 7fda4e9d is 00000000
s/b ba7ca1c2 is 00000000
s/b 722ea4bc is 00000000
s/b 8d370ec3 is 00000000
Freed buses and JTAG chain

asbokid@home:~/asboapps$ ./2wiglet -c usbblaster -o
2Wiglet v0.4 - (c) 2011 asbokid
JTAG tool for 2Wire Routers with a TriMedia TM32 core

Searching for cable driver: usbblaster
usbblaster USB cable driver found
Connected to libftdi driver.
Connected to UsbBlaster cable
Waiting for JTAG chain to stabilise
Received IDCODE 3269b4c1 (2Wire Ares)
Hit enter to stop
 00000000
 a5b00001
 a5b00002
 00000001
 00000002
 00000003
Freed buses and JTAG chain

asbokid@home:~/asboapps$ ./2wiglet -c usbblaster -O
2Wiglet v0.4 - (c) 2011 asbokid
JTAG tool for 2Wire Routers with a TriMedia TM32 core

Searching for cable driver: usbblaster
usbblaster USB cable driver found
Connected to libftdi driver.
Connected to UsbBlaster cable
Waiting for JTAG chain to stabilise
Received IDCODE 3269b4c1 (2Wire Ares)
Hit enter to stop
       1: 00000000 changed to a5b00001  delta t = 331 msec
       2: a5b00001 changed to a5b00002  delta t = 12 msec
       3: a5b00002 changed to 00000000  delta t = 36 msec
       4: 00000000 changed to 00000001  delta t = 71 msec
       5: 00000001 changed to 00000002  delta t = 71 msec
       6: 00000002 changed to 00000003  delta t = 71 msec
       7: 00000003 changed to 00000004  delta t = 71 msec
       8: 00000004 changed to 00000005  delta t = 71 msec
There were 8 changes in 1628 loops
Freed buses and JTAG chain

asbokid@home:~/asboapps$ ./2wiglet -c usbblaster -b
2Wiglet v0.4 - (c) 2011 asbokid
JTAG tool for 2Wire Routers with a TriMedia TM32 core

Searching for cable driver: usbblaster
usbblaster USB cable driver found
Connected to libftdi driver.
Connected to UsbBlaster cable
Waiting for JTAG chain to stabilise
Received IDCODE 3269b4c1 (2Wire Ares)
 L1 boot ready = 12340002
 MMIO_BASE     = 1be00000 s/b 1be00000
 DRAM_LO       = 40000000 s/b 40000000
 DRAM_HI       = 44000000 s/b 44000000
 DRAM_CLIMIT   = 44000000 s/b 44000000
Freed buses and JTAG chain

asbokid@home:~/asboapps$

UPDATE #1:

Illustrated below, the 2Wire is now booting from JTAG and running arbitrary code:

asbokid@home:~/asboapps$ ./2wiglet -c usbblaster -B threeblind_ares.mi,0x40100000
2Wiglet v1.1 - (c) 2012 asbokid
JTAG tool for 2Wire Routers with a TriMedia TM32 core

Found USB cable driver for usbblaster
Connected to libftdi driver.
Connected to UsbBlaster cable
Waiting for JTAG chain to stabilise
Received IDCODE 3269b4c1 (2Wire Ares)
Download 772 bytes from 'threeblind_ares.mi' to 40100000

Waiting for L1BOOT_READY from TM32 target
 L1 boot ready = 12340002
 MMIO_BASE    <- 1be00000 (expected: 1be00000) 
 DRAM_LO      <- 40000000 (expected: 40000000)
 DRAM_HI      <- 44000000 (expected: 44000000)
 DRAM_CLIMIT  <- 44000000 (expected: 44000000)
 LOAD ADDRESS <- 40100000
 CODE SIZE    -> 00000304 (772) 

Started L2 download..
L2 load done.

Comparing checksums:
PC MONITOR=0000e41b, TM32 TARGET=0000e41b
Checksums good.

Download complete
Elapsed time 0.06 secs (avg 13.42kB/sec)

Starting TM32 execution at 40100000

JTAG Console started:
---------------------------------------------

Three blind mice. Three blind mice.
See how they run. See how they run.
They all ran after the banker's wife
And cut up her cheques with a kitchen knife
Did you ever laugh so much in your life
At a poor banker's wife?!

Three blind mice. Three blind mice.
See how they run. See how they run.
They all ran after the banker's wife
And cut up her cheques with a kitchen knife
Did you ever laugh so much in your life
At a poor banker's wife?!

Three blind mice. Three blind mice.
See how they run. See how they run.
They all ran after the banker's wife
And cut up her cheques with a kitchen knife
Did you ever laugh so much in your life
At a poor banke

Key press detected. Aborting
Freed buses and JTAG chain
asbokid@home:~/asboapps$

This is the embedded code we downloaded with our JTAG tool to the 2Wire 2701HGV-C:

asbokid@home:~/asboapps$ cat threeblind.c

// TM32 JTAG MMIO register offsets

#define JTAG_DATAIN     0x061000
#define JTAG_DATAOUT    0x061004
#define JTAG_CTRL1      0x061008
#define JTAG_CTRL2      0x06100c
#define OFULL           0x1
#define IFULL           0x1
#define SLEEPLESS       0x2

#define MMIO(offset) (_MMIO_base_init[(offset) >> 2])

extern volatile unsigned int _MMIO_base_init[];

void waitifull(void) {
    unsigned int val = 0;

    while (!val)
        val = MMIO(JTAG_CTRL2) & IFULL;
    return;
}

unsigned char *micestr =
    "Three blind mice. Three blind mice.\n" \
    "See how they run. See how they run.\n" \
    "They all ran after the banker's wife\n \
    "And cut up her cheques with a kitchen knife\n" \
    "Did you ever laugh so much in your life\n" \
    "At a poor banker's wife?!\n\n\0\0\0\0\0\0\0";

void jtagputs(unsigned char *str) {
    unsigned char *ptr = str;
    unsigned int outword;

    do {
        outword  = *ptr++;
        outword |= *ptr++ << 8;
        outword |= *ptr++ << 16;
        outword |= *ptr++ << 24;
        MMIO(JTAG_DATAOUT) = outword;
        MMIO(JTAG_CTRL1)   = OFULL | SLEEPLESS;
        MMIO(JTAG_CTRL2)   = 0;
        waitifull();
    } while(outword);
    return;
}

int main(void) {
    while(1)
        jtagputs(micestr);
}

Once the tool is tested with a variety of USB and parallel port JTAG cables, the source code will be released under the GNU GPL.

UPDATE #2:

The source code for the JTAG tool, 2wiglet, is now available on sourceforge.  [3]

The tool should work with most USB-based JTAG cables but the code for parallel port cables still needs writing.

The JTAG monitor software that is downloaded to the TriMedia core is available on request separately.

[1] http://hackingbtbusinesshub.wordpress.com/2011/12/16/the-proprietary-trimedia-jtag-tools/
[2] https://sourceforge.net/projects/urjtag/
[3] https://sourceforge.net/projects/jtag2w/

Product Teardown: 3800HGV (Electronic Products, Feb 2007)

The following page is taken from Electronic Products, an industry magazine published by Hearst.

In the February 2007 issue, the magazine performed a full teardown of the 2Wire 3800HGV-B. The components on the PCB were categorised according to their type, function and cost.

The 3800HGV is consumer premises equipment (CPE) supplied by AT&T for the VDSL2 service it markets as U-Verse.

The 3800HGV is driven by a 2Wire Ares CPU with its powerful TriMedia TM3260 core used for digital signal processing.

Product Teardown of 2Wire 3800HGV (full article from Electronic Products at links below)

[1] https://docs.google.com/open?id=0B6wW18mYskvBMDQyODdmMTAtMzMzNC00M2EzLWI1NjUtYmU4NTg1OTk4MjVj
[2] http://www.nxtbook.com/nxtbooks/hearst/ep0207/index.php?startid=70

EEPROM programmer based on the Winchiphead CH341a

In an earlier blog entry, a low-cost USB-based EEPROM programmer was examined.  It is being used to burn boot ROMs for the 2Wire modems. [1]

USB-based EEPROM programmer for just US$8

The programmer works well but its software is closed-source, only for Microsoft™ Windows®, and Chinese language to boot.

Of all those issues, it is, of course, the requirement for Microsoft® that is the greatest hindrance!  :-(

Well not any more.  A Linux tool for reading and writing EEPROMs using the i2c mode of the CH341a has been developed.  The tool is based on the popular and portable libUSB programming library.

The CH341a is not well documented. There is a solitary C header file relating to a (closed source) Windows™ DLL (with comments in Chinese), but there is no proper datasheet for the CH341a.

To understand the CH341a means sniffing the USB bus traffic to and from the device. This reveals that the CH341a is using asynchronous transfers in its USB transaction protocol. Something of an overkill for such a simple application.

That asynchronous requirement makes the programming more complicated, since periodic polling and callback functions are needed. It also means that the newer libUSB-1.0 API is required. The earlier and simpler libUSB-0.1 only supports synchronous transactions.

As it stands, the tool meets our current needs:  programming and reading the 24c32/24c64 boot ROMs used by the 2Wire modem-routers.  However it could be extended to support a wider range of EEPROMs with different addressing modes and page sizes. Please email if you would like to develop this tool.

The GPL’ed source code can be downloaded from SourceForge. [2]

asbokid@u50si1:~/ch341eepromtool_0.5$ cat README

About
=====

    Beta libUSB code for EEPROM programmers based on the WinChipHead CH341a IC

Author
======

    Written by asbokid and released under the terms of the GNU GPL, version 3, or later.
    Copyright Dec 2011, asbokid <ballymunboy@gmail.com>

Licence
=======

    This is free software: you can redistribute it and/or modify it under the terms of
    the latest GNU General Public License as published by the Free Software Foundation.

    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, see <http://www.gnu.org/licenses/>.

Requires
========

    gcc
    GNU make
    libusb-1.0 and the libusb library development files. See http://libusb.wiki.sourceforge.net/
    libusb-1.0-dev  (on debian-based distros)

Compiling
=========

    gcc -o ch341eeprom ch341eeprom.c ch341funcs.c -lusb-1.0

Running
=======

    asbokid@u50si1:$ ./ch341eeprom

    ch341eeprom - an i2c EEPROM programming tool for the WCH CH341a IC
    Version 0.5 copyright (c) 2011  asbokid <ballymunboy@gmail.com>

    This program comes with asbolutely no warranty; This is free software,
    and you are welcome to redistribute it under certain conditions:
    GNU GPL v3 License: http://www.gnu.org/licenses/gpl.html

    Usage:
     -h, --help             display this text
     -v, --verbose          verbose output
     -d, --debug            debug output
     -s, --size             size of EEPROM {24c32|24c64}
     -e, --erase            erase EEPROM (fill with 0xff)
     -w, --write <filename> write EEPROM with image from filename
     -r, --read  <filename> read EEPROM and save image to filename

    Example:  ch341eeprom -v -s 24c64 -w bootrom.bin

    asbokid@u50si1:$ sudo ./ch341eeprom -v -s 24c64 -e

    Searching USB buses for WCH CH341a i2c EEPROM programmer [1a86:5512]
    Found [1a86:5512] as device [7] on USB bus [2]
    Opened device [1a86:5512]
    Claimed device interface [0]
    Device reported its revision [3.03]
    Configured USB device
    Set i2c bus speed to [100kHz]
    Erased [8192] bytes of [24c64] EEPROM
    Closed USB device

    asbokid@u50si1:$ sudo ./ch341eeprom -v -s 24c64 -r output.bin

    Searching USB buses for WCH CH341a i2c EEPROM programmer [1a86:5512]
    Found [1a86:5512] as device [7] on USB bus [2]
    Opened device [1a86:5512]
    Claimed device interface [0]
    Device reported its revision [3.03]
    Configured USB device
    Set i2c bus speed to [100kHz]
    Read [8192] bytes from [24c64] EEPROM
    Wrote [8192] bytes to file [output.bin]
    Closed USB device

    asbokid@u50si1:$ xxd -l 128 output.bin

    0000000: ffff ffff ffff ffff ffff ffff ffff ffff  ................
    0000010: ffff ffff ffff ffff ffff ffff ffff ffff  ................
    0000020: ffff ffff ffff ffff ffff ffff ffff ffff  ................
    0000030: ffff ffff ffff ffff ffff ffff ffff ffff  ................
    0000040: ffff ffff ffff ffff ffff ffff ffff ffff  ................
    0000050: ffff ffff ffff ffff ffff ffff ffff ffff  ................
    0000060: ffff ffff ffff ffff ffff ffff ffff ffff  ................
    0000070: ffff ffff ffff ffff ffff ffff ffff ffff  ................

    asbokid@u50si1:$ ./mktestimg > testimg24c64.bin

    asbokid@u50si1:$ xxd -l 128 testimg24c64.bin

    0000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
    0000010: 1111 1111 1111 1111 1111 1111 1111 1111  ................
    0000020: 2222 2222 2222 2222 2222 2222 2222 2222  """"""""""""""""
    0000030: 3333 3333 3333 3333 3333 3333 3333 3333  3333333333333333
    0000040: 4444 4444 4444 4444 4444 4444 4444 4444  DDDDDDDDDDDDDDDD
    0000050: 5555 5555 5555 5555 5555 5555 5555 5555  UUUUUUUUUUUUUUUU
    0000060: 6666 6666 6666 6666 6666 6666 6666 6666  ffffffffffffffff
    0000070: 7777 7777 7777 7777 7777 7777 7777 7777  wwwwwwwwwwwwwwww

    asbokid@u50si1:$ sudo ./ch341eeprom -v -s 24c64 -w testimg24c64.bin

    Searching USB buses for WCH CH341a i2c EEPROM programmer [1a86:5512]
    Found [1a86:5512] as device [7] on USB bus [2]
    Opened device [1a86:5512]
    Claimed device interface [0]
    Device reported its revision [3.03]
    Configured USB device
    Set i2c bus speed to [100kHz]
    Read [8192] bytes from file [testimg24c64.bin]
    Wrote [8192] bytes to [24c64] EEPROM
    Closed USB device

    asbokid@u50si1:$ sudo ./ch341eeprom -v -s 24c64 -r output.bin

    Searching USB buses for WCH CH341a i2c EEPROM programmer [1a86:5512]
    Found [1a86:5512] as device [7] on USB bus [2]
    Opened device [1a86:5512]
    Claimed device interface [0]
    Device reported its revision [3.03]
    Configured USB device
    Set i2c bus speed to [100kHz]
    Read [8192] bytes from [24c64] EEPROM
    Wrote [8192] bytes to file [output.bin]
    Closed USB device

    asbokid@u50si1:$ xxd -l 128 output.bin

    0000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
    0000010: 1111 1111 1111 1111 1111 1111 1111 1111  ................
    0000020: 2222 2222 2222 2222 2222 2222 2222 2222  """"""""""""""""
    0000030: 3333 3333 3333 3333 3333 3333 3333 3333  3333333333333333
    0000040: 4444 4444 4444 4444 4444 4444 4444 4444  DDDDDDDDDDDDDDDD
    0000050: 5555 5555 5555 5555 5555 5555 5555 5555  UUUUUUUUUUUUUUUU
    0000060: 6666 6666 6666 6666 6666 6666 6666 6666  ffffffffffffffff
    0000070: 7777 7777 7777 7777 7777 7777 7777 7777  wwwwwwwwwwwwwwww

Concluding Notes
================

    The code handles the 3 byte addressing used by EEPROMS of 32kbit and greater (24c32-)
    It uses asynchronous USB transfers but should be portable to Microsoft Windows.

    All comments and contributions welcomed!

    asbokid <ballymunboy@gmail.com> - Dec 2011

[1] http://hackingbtbusinesshub.wordpress.com/2011/11/05/ultra-low-cost-boot-rom-programmer/

[2] http://sourceforge.net/projects/ch341eepromtool/

Twiddling the JTAG TAP (Test Access Port)

$ sudo jtag

UrJTAG 0.10 #2017
Copyright (C) 2002, 2003 ETC s.r.o.
Copyright (C) 2007, 2008, 2009 Kolja Waschk and the respective authors

UrJTAG is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
There is absolutely no warranty for UrJTAG.

warning: UrJTAG may damage your hardware!
Type "quit" to exit, "help" for help.

jtag> cable usbblaster
Connected to libftdi driver.

jtag> detect
IR length: 5
Chain length: 1
Device Id: 00110010011010011011010011000001 (0x3269B4C1)
  Unknown manufacturer! (01001100000) (/usr/local/share/urjtag/MANUFACTURERS)

jtag> discover
Detecting IR length ... 5
Detecting DR length for IR 11111 ... 1
Detecting DR length for IR 00000 ... 573
Detecting DR length for IR 00001 ... 573
Detecting DR length for IR 00010 ... 32
Detecting DR length for IR 00011 ... 32
Detecting DR length for IR 00100 ... warning: TDO seems to be stuck at 0   -1
Detecting DR length for IR 00101 ... 177
Detecting DR length for IR 00110 ... 19
Detecting DR length for IR 00111 ... 1
Detecting DR length for IR 01000 ... warning: TDO seems to be stuck at 0   -1
Detecting DR length for IR 01001 ... warning: TDO seems to be stuck at 0   -1
Detecting DR length for IR 01010 ... 1
Detecting DR length for IR 01011 ... 1
Detecting DR length for IR 01100 ... 1
Detecting DR length for IR 01101 ... 1
Detecting DR length for IR 01110 ... 1
Detecting DR length for IR 01111 ... 1
Detecting DR length for IR 10000 ... 1
Detecting DR length for IR 10001 ... 32
Detecting DR length for IR 10010 ... 32
Detecting DR length for IR 10011 ... 33
Detecting DR length for IR 10100 ... 33
Detecting DR length for IR 10101 ... 2
Detecting DR length for IR 10110 ... 1
Detecting DR length for IR 10111 ... 1
Detecting DR length for IR 11000 ... 1
Detecting DR length for IR 11001 ... 1
Detecting DR length for IR 11010 ... 1
Detecting DR length for IR 11011 ... 1
Detecting DR length for IR 11100 ... 1
Detecting DR length for IR 11101 ... 1
Detecting DR length for IR 11110 ... 1

jtag> help instruction
Usage: instruction INSTRUCTION
Usage: instruction length LENGTH
Usage: instruction INSTRUCTION CODE REGISTER
Change active INSTRUCTION for a part or declare new instruction.

INSTRUCTION   instruction name (e.g. BYPASS)
LENGTH        common instruction length
CODE          instruction code (e.g. 11111)
REGISTER      default data register for instruction (e.g. BR)

jtag> instruction length 5

jtag> help register
Usage: register NAME LENGTH
Define new data register with specified NAME and LENGTH.

NAME          Data register name
LENGTH        Data register length

jtag> # now we define the registers
jtag> # we dont know their names so we will number them instead, REG00, REG01, etc..
jtag>
jtag> register REG31 1
jtag> register REG00 573
jtag> register REG01 573
jtag> register REG02 32
jtag> register REG03 32
jtag> # instruction code 04 (00100) was -1 so we ignore
jtag> register REG05 177
jtag> register REG06 19
jtag> register REG07 1
jtag> # instruction code 08 (01000) was -1 so we ignore
jtag> # instruction code 09 (01001) was -1 so we ignore
jtag> register REG10 1
jtag> register REG11 1
jtag> register REG12 1
jtag> register REG13 1
jtag> register REG14 1
jtag> register REG15 1
jtag> register REG16 1
jtag> register REG17 32
jtag> register REG18 32
jtag> register REG19 33
jtag> register REG20 33
jtag> register REG21 1
jtag> register REG22 1
jtag> register REG23 1
jtag> register REG24 1
jtag> register REG25 1
jtag> register REG26 1
jtag> register REG27 1
jtag> register REG28 1
jtag> register REG29 1
jtag> register REG30 1
jtag>
jtag> # now we define a new instruction for selecting each register
jtag>
jtag> instruction SEL_REG31 11111 REG31
jtag> instruction SEL_REG00 00000 REG00
jtag> instruction SEL_REG01 00001 REG01
jtag> instruction SEL_REG02 00010 REG02
jtag> instruction SEL_REG03 00011 REG03
jtag> # there is no instruction code 04
jtag> instruction SEL_REG05 00101 REG05
jtag> instruction SEL_REG06 00110 REG06
jtag> instruction SEL_REG07 00000 REG07
jtag> # there is no instruction code 08
jtag> # there is no instruction code 09
jtag> instruction SEL_REG10 01010 REG10
jtag> instruction SEL_REG11 01011 REG11
jtag> instruction SEL_REG12 01100 REG12
jtag> instruction SEL_REG13 01101 REG13
jtag> instruction SEL_REG14 01110 REG14
jtag> instruction SEL_REG15 01111 REG15
jtag> instruction SEL_REG16 10000 REG16
jtag> instruction SEL_REG17 10001 REG17
jtag> instruction SEL_REG18 10010 REG18
jtag> instruction SEL_REG19 10011 REG19
jtag> instruction SEL_REG20 10100 REG20
jtag> instruction SEL_REG21 10101 REG21
jtag> instruction SEL_REG22 10110 REG22
jtag> instruction SEL_REG23 10111 REG23
jtag> instruction SEL_REG24 11000 REG24
jtag> instruction SEL_REG25 11001 REG25
jtag> instruction SEL_REG26 11010 REG26
jtag> instruction SEL_REG27 11011 REG27
jtag> instruction SEL_REG28 11100 REG28
jtag> instruction SEL_REG29 11101 REG29
jtag> instruction SEL_REG30 11110 REG30
jtag>
jtag> # now we can test our register and instruction declarations.
jtag>
jtag> # first we select instruction code 02 (00010) and shift it in
jtag> # (we know from datasheet that instruction (00010) selects the IDCODE register)
jtag>
jtag> instruction SEL_REG02
jtag> shift ir
jtag>
jtag> # now we shift out its 32-bit data register
jtag> 
jtag> shift dr
jtag> 
jtag> # and view the data register
jtag> 
jtag> dr
00110010011010011011010011000001 (0x3269B4C1)
jtag> 
jtag> # we know that 0x3269b4c1 is the IDCODE for a TriMedia TM3260 CPU
jtag>
jtag> # from this we confirm instruction code 02 (00010) selects the IDCODE register
jtag> 
jtag> # now we can look at the register(s) of 573 bits. We can guess from
jtag> # the very long length that this is the Boundary Scan Register (BSR)
jtag>
jtag> ins SEL_REG00
jtag> shift ir
jtag> shift dr
jtag> dr
11111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111 (0x00000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFF)
jtag>
jtag> # nothing meaningful scanned out there, so this must be the EXTEST instruction for
jtag> # the BSR, for writing to the register only
jtag>
jtag> # now we try the other instruction (code 00001) that manipulates that 573-bit register
jtag>  
jtag> ins sel_REG01
jtag> shift ir
jtag> shift dr
jtag> dr
00010101101110110110110101101101101001101101100001101101101110101110110110
11011011011011011011011011011011011011011011011011111111011111111111011111
01011101101101101101101101000101101101101101101101101111011011011000101000
11110101110101111101100001101000011110101101100000001000000000001100000001
00110000110110110110110110100100100100110000100100110100000000100000000001
01010000010000011011011011011000011000000000011000000000000011000011010011
01110100000000000000000000000000000000000010100000000010110110100010110101
0010010000010010010010010101010010010010000010010010010 (0x00000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000005A920924AA490492)
jtag> 
jtag> # JTAG instruction code 00001 must be the SAMPLE instruction for the BSR
jtag> # The bits shifted out are the boundary scan cell values (CPU I/O pin states)
jtag>
jtag> # If we shift out the data register again we will see some of the pin states change.
jtag> # these will be the CPU I/O pins to the main memory bus, PCI bus, etc:
jtag>
jtag> shift dr
jtag> dr
00010101101110110110110101101101101001101101100001101101101110101110110110
11011011011011011011011011011011011011011011011011111111011111111111011111
01011101101101101101101101000101101101101101101101101111011011011000101000
01000001110101111101100001101000011110101101100000001010100000001100000001
00110000110110110110110110100100100100110000100100100100000000100000000001
01010000010000011011011011011000011000000000011000000000000011000011010011
01110100000000000000000000000000000000000010100000000010110110100010110101
0010010000010010010010010101010010010010000010010010010 (0x00000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000005A920924AA490492)
jtag>
jtag> # study very closely! A few bit states have changed, e.g. spot the different
jtag> # bits at the beginning of the fourth line.
jtag>
jtag> # Those changed bits will be boundary scan cells storing state of the DRAM / PCI bus pins
jtag> # (ignore hexadecimal conversion: 0x5A920.. it is wrong)
jtag>
jtag> # One more example showing how to write to a JTAG register:
jtag>
jtag> # We know from Philips datasheet that instruction (10001) selects the DATAIN
jtag> # register of TriMedia JTAG controller
jtag>
jtag> ins SEL_REG17
jtag> shift ir
jtag> shift dr
jtag> dr
00000000000000000000000000000000 (0x00000000)
jtag>
jtag> # The DATAIN register has 0x00000000 in it, so we shift in a recognisable value:
jtag>
jtag> dr 0xcafebabe
11001010111111101011101010111110 (0xCAFEBABE)
jtag> shift dr
jtag> dr
00000000000000000000000000000000 (0x00000000)
jtag> shift dr
jtag> dr
11001010111111101011101010111110 (0xCAFEBABE)
jtag> 
jtag> # We can try that again with another memorable value
jtag>
jtag> dr 0xbabeb00b
10111010101111101011000000001011 (0xBABEB00B)
jtag> shift dr
jtag> dr
11001010111111101011101010111110 (0xCAFEBABE)
jtag> shift dr
jtag> dr
10111010101111101011000000001011 (0xBABEB00B)
jtag> 
jtag> # That example demonstrates how to write to a JTAG register
jtag>

Low-cost boot ROM programmer

Spotted on ebay:  a USB i2c EEPROM programmer for just $8.

Irresistible!

Eight dollar EEPROM programmer

The plan is to use the programmer to burn new boot ROMs for the 2Wire.

The boot ROM on the 2Wire board is a 32Kbit device from the 24Cxx family of i2c serial CMOS EEPROM.

These devices have three address pins A0, A1 and A2. The pins can be asserted (or not) to configure the physical address of the ROM. Up to eight ROMs can be connected in series on the same i2c bus and addressed individually. [1]

24Cxx pinout - A0, A1 and A2 are address pins

We can use this addressing feature to ‘piggyback’ our clone ROM onto the 2Wire board.

If pin A0 of the board boot ROM is pulled up, its address is changed from a default of 0xA0/A1 to 0xA2/A3.

If we pin strap our ROM to assign it the original address (0xA0/A1) of the board ROM, then the Trimedia CPU will boot from our ROM instead.

Device Addressing of the 24Cxx

The contents of our piggyback ROM can hold new code, such as a JTAG debug monitor. This would leverage access to the flash device on the 2Wire PCB.

Back to that five quid programmer, though..

EEPROM programmer based on CH341A

The programmer is only supplied with software for Microsoft Windows®, and it’s Chinese language software at that. An English translation of the programmer manual is here. [2]

Some naughty soul has also been busy with the sandpaper, trying to erase the identifying marks from the programmer’s controller chip.

All in vain because the Linux tool lsusb reveals all..

The USB device controller on the programmer has a vid:pid of 1a86:5512. That Vendor ID is assigned to Nanjing QinHeng Electronics Co.,Ltd. [3]

And the controller identifies as the company’s WinChipHead CH341A in i2c mode. [4]

$ sudo lsusb -d 1a86:5512
Bus 002 Device 017: ID 1a86:5512 QinHeng Electronics

It seems that the Linux kernel already contains driver code for the CH341A, and has done for some while.[5]

The CH341 is a USB peripheral controller and multi-protocol line driver.  The IC supports the IEEE-1284 parallel printer interface as well as several two, three, four and five wire serial communication protocols, including i2c.

The Linux kernel supports RS232 comms using the CH341A but doesn’t currently include an i2c driver for the IC, which is a shame.

With no driver for the CH341A, this is one of those thankfully rare occasions when Microsoft Windows® has to be used.

HINT: here is a great project for someone – writing the i2c Linux kernel driver code for the CH341A.

  • An incomplete userspace USB driver to program EEPROMs with the CH341A has been developed and it is here.[11]
  • The IC datasheet for the CH341A is here [4].
  • The GPL’ed source code for a project by Relavak Labs draws on the userspace libUSB library to talk with the IC.[6] 
  • Another project is by Roaring Penguin Software Inc. [7]   Both the Relavak and the Roaring Penguin projects concern an i2c-based thermometer known as a TEMPer. The device communicates over a USB bus via a CH341A.   In both projects, the CH341 is used in serial mode to twiddle the RTS, DTR and DTS lines to drive an i2c peripheral.
  • Python code shared by Panda Xiong, however, drives the CH341A in its native i2c mode  [8].
  • A tiny bit of ‘official’ source code for the CH341a and what passes for a programming manual is here [9].
  • And for those who don’t have it, a RAR containing the original Windows software for the programmer is here [10].

But we digress.

Back to our task..

A low-cost source of 24Cxx EEPROMs was found. These ROMs are conveniently soldered to a prototyping board with header pins already attached for programming and pin jumpers for configuring the device address. The ROMs are actually 24C64 (8KByte) whereas the 2Wire board only uses the 24C32 (4KByte). But that hopefully won’t matter. The extra capacity might even be useful.

24C64 EEPROM for prototyping and 'piggybacking'

The EEPROM Programmer software runs fine in Windows XP Pro which was running as a guest OS in VirtualBox.

A boot ROM image was lifted from the PCB of a 2701HGV-C using a BusPirate and this image was successfully burnt into one of the virgin 24C64 devices:

PC -> USB -> CH341A -> I2C -> 24Cxx

Burning a 2Wire boot ROM clone

UPDATE:

A basic Linux tool has been coded to read and write 32kBit and 64kBit EEPROMs with this programmer.  See [11]

[1] https://docs.google.com/open?id=0B6wW18mYskvBNjhiMGM0NDQtYWY5Zi00YzBmLWEzNTktNTc2N2Y0ZjgwNzJh
[2] http://hackingbtbusinesshub.files.wordpress.com/2012/01/usbprogrammer_24cxxseries_version22.pdf
[3] http://wch-ic.com/
[4] http://wch-ic.com/download/list.asp?id=114
[5] http://lwn.net/Articles/246334/
[6] http://relavak.wordpress.com/2009/10/17/temper-temperature-sensor-linux-driver/
[7] http://www.roaringpenguin.com/products/temper-tools
[8] http://code.google.com/p/common-codebase/source/browse/#svn%2Ftrunk%2Fothers%2Fpython_test%2Fi2c
[9] https://docs.google.com/open?id=0B6wW18mYskvBMDQ2MDBjMWMtMzhjNS00MTM1LTk4OGUtODYxZDdjNjg5MTFj
[10] https://docs.google.com/open?id=0B6wW18mYskvBMmIwMGJjOTQtZDMxNS00MzNiLThkYzgtMGE4N2ZiNTEwMGM3
[11] http://hackingbtbusinesshub.wordpress.com/2011/12/08/eeprom-programmer-based-on-the-winchiphead-ch341a/