This is an automated email from Gerrit.

Tomasz CEDRO ([email protected]) just uploaded a new patch set to Gerrit, which 
you can find at http://openocd.zylin.com/1020

-- gerrit

commit a3c2677422ef3c54ddfd2c29e5e46bd2eeb6cb65
Author: Tomek CEDRO <[email protected]>
Date:   Tue Oct 30 16:59:20 2012 +0100

    Added ft2232_transfer() and ft2232_bitbang() implementation. New interface 
routines (interface signal handling) are now part of the build process 
(required by ft2232 transfer and bitbang functions). Extended ft2232 based jtag 
driver with existing ft2232_bitbang function.
    
    Change-Id: I934933a8724f0b4c4c57b841f0ae07e9f52b9dff
    Signed-off-by: Tomek CEDRO <[email protected]>

diff --git a/configure.ac b/configure.ac
index dadeef9..a259021 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1323,6 +1323,7 @@ AC_CONFIG_FILES([
   src/jtag/drivers/Makefile
   src/jtag/stlink/Makefile
   src/transport/Makefile
+  src/interface/Makefile
   src/xsvf/Makefile
   src/svf/Makefile
   src/target/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index c78e81c..f449677 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -5,6 +5,7 @@ SUBDIRS = \
        helper \
        target \
        transport \
+       interface \
        flash \
        svf \
        xsvf \
@@ -92,6 +93,7 @@ libopenocd_la_LIBADD = \
        $(top_builddir)/src/pld/libpld.la \
        $(top_builddir)/src/jtag/libjtag.la \
        $(top_builddir)/src/transport/libtransport.la \
+       $(top_builddir)/src/interface/liboocdinterface.la \
        $(top_builddir)/src/flash/libflash.la \
        $(top_builddir)/src/target/libtarget.la \
        $(top_builddir)/src/server/libserver.la \
diff --git a/src/interface/Makefile.am b/src/interface/Makefile.am
index 5762b38..b61fe0f 100644
--- a/src/interface/Makefile.am
+++ b/src/interface/Makefile.am
@@ -15,10 +15,11 @@ BUILT_SOURCES +=
 CLEANFILES += 
 
 liboocdinterface_la_SOURCES = \
-       interface.c
+       interface_signal.c
 
 noinst_HEADERS = \
-       interface.h
+       interface.h \
+       interface_signal.h
 
 EXTRA_DIST =
 
diff --git a/src/interface/interface_signal.c b/src/interface/interface_signal.c
index 8ff8ea8..f2a966a 100644
--- a/src/interface/interface_signal.c
+++ b/src/interface/interface_signal.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Tomasz Boleslaw CEDRO
+ * Copyright (C) 2011-2012 Tomasz Boleslaw CEDRO
  * [email protected], http://www.tomek.cedro.info
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/src/jtag/drivers/ft2232.c b/src/jtag/drivers/ft2232.c
index e474f41..14d37db 100644
--- a/src/jtag/drivers/ft2232.c
+++ b/src/jtag/drivers/ft2232.c
@@ -86,6 +86,7 @@
 #include <jtag/interface.h>
 #include <transport/transport.h>
 #include <helper/time_support.h>
+#include <interface/interface.h>
 
 #if IS_CYGWIN == 1
 #include <windows.h>
@@ -623,6 +624,186 @@ static bool ft2232_device_is_highspeed(void)
 #endif
 }
 
+
+/** Generic IO BITBANG Port Manipulation Routine.
+ * It can read and write port state using signal names. Each interface have its
+ * own specific signal names and fields. This function works on those fields
+ * and based on their values talks to the FT*232 chip on the interface device.
+ * ft2232 drivers use {low,high}_{output,direction} global variables to 
remember
+ * port direction and value, so we need to work on them as well not to change
+ * any other pin with our bit-baning performed only on selected pins.
+ * The function name 'bitbang' reflects ability to change selected pin states.
+ *
+ * @Note: FT2232 has special mechanism called MPSSE for serial communications
+ * that is far more efficient than pure 'bitbang' mode on this device family.
+ * Although our function is named 'bitbang' it does not use bitbang mode.
+ * MPSSE command send value and port bytes on port write, but does not on read.
+ * This happens every time we want to change pin value, so we need to use 
cache.
+ * On write we want to OR direction mask already set by init() procedure
+ * to mark bit-mask output. On read we want to clear bits given by mask
+ * to mark them input. To read we need to write/update port state first.
+ * Long story short: to read data we first need to set pins to input.
+ *
+ * @Warning: reading and writing will set pin direction input or output,
+ * so it is possible to disable basic data output pins with bad masking,
+ * but also gives chance to create and manage full TCL signal description,
+ * that can be used to take advantage of some additional interface hardware
+ * features installed on some devices (i.e. ADC, power supply, etc).
+ * This gives new way of signal handling that is still backward-compatible.
+ *
+ * \param *device void pointer to pass additional driver information to the 
routine.
+ * \param signal is the string representation of the signal mask stored in 
layout structure.
+ * \param GETnSET if zero then perform read operation, write otherwise.
+ * \param *value is the pointer that holds the value.
+ * \return ERROR_OK on success, or ERROR_FAIL on failure.
+ */
+int ft2232_bitbang(void *device, char *signal_name, int GETnSET, int *value){
+        uint8_t  buf[3];
+        int retval, vall=0, valh=0;
+        unsigned int sigmask;
+        uint32_t bytes_written, bytes_read;
+        oocd_interface_signal_t *sig;
+
+        //First get the signal mask, or return error if signal not defined.
+        if (!(sig=oocd_interface_signal_find(signal_name))){
+                LOG_ERROR("Requested signal not found on this interface!");
+                return ERROR_FAIL;
+        }
+        // Pin mask is also related with port direction and complicates it!!!
+        sigmask=sig->mask;
+
+        // First check against restricted port pins defined by the interface 
layout
+        if (sigmask & layout->bitbang_deny){
+                LOG_ERROR("This interface does not allow to bit-bang selected 
pins (0x%08X)!", layout->bitbang_deny);
+                return ERROR_FAIL;
+        }
+
+        if (!GETnSET){
+                // We will SET port pins selected by sigmask.
+                // Modify our pins value, but remember about other pins and 
their previous value
+                low_output  = (low_output & ~sigmask) | ((*value & sigmask) & 
0x0ff);
+                high_output = (high_output & ~(sigmask>>8)) | (((*value & 
sigmask)>>8) & 0x0ff);
+                // Modify our pins direction, but remember about other pins 
and their previous direction
+                low_direction  |= sigmask & 0x0ff;
+                high_direction |= (sigmask>>8) & 0x0ff;
+                // Now send those settings to the interface chip
+                buf[0] = 0x80;  //Set Data Bits LowByte
+                buf[1] = low_output;
+                buf[2] = low_direction;
+                if ((retval=ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) 
return retval;
+                buf[0] = 0x82;   //Set Data Bits HighByte
+                buf[1] = high_output;
+                buf[2] = high_direction;
+                if ((retval=ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) 
return retval;
+                sig->value = ((high_output<<8) | low_output) & sig->mask;
+        } else {
+                // Modify our pins value, but remember about other pins and 
their previous value
+                // DO WE REALLY NEED TO PULL-UP PINS TO READ THEIR STATE OR 
SIMPLY LEAVE AS IS?
+                //low_output  = (low_output & ~sigmask) | (sigmask & 0x0ff);
+                //high_output = (high_output & ~sigmask) | (sigmask>>8) & 
0x0ff);
+                // Modify our pins direction to input, but remember about 
other pins and their previous direction
+                low_direction  &= ~(sigmask);
+                high_direction &= ~(sigmask>>8);
+                // Now send those settings to the interface chip
+                // First change desired pins to input
+                buf[0] = 0x80;  //Set Data Bits LowByte
+                buf[1] = low_output;
+                buf[2] = low_direction;
+                if ((retval=ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) 
return retval;
+                buf[0] = 0x82;   //Set Data Bits HighByte
+                buf[1] = high_output;
+                buf[2] = high_direction;
+                if ((retval=ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) 
return retval;
+                // Then read pins designated by a signal mask
+                buf[0]=0x81;    //Read Data Bits LowByte.
+                if ((retval=ft2232_write(buf, 1, &bytes_written)) != ERROR_OK) 
return retval;
+                if ((retval=ft2232_read((uint8_t *)&vall, 1, &bytes_read)) != 
ERROR_OK) return retval;
+                buf[0]=0x83;    //Read Data Bits HighByte.
+                if ((retval=ft2232_write(buf, 1, &bytes_written)) != ERROR_OK) 
return retval;
+                if ((retval=ft2232_read((uint8_t *)&valh, 1, &bytes_read)) != 
ERROR_OK) return retval;
+                sig->value = *value = ((valh<<8)|vall) & sig->mask; //Join 
result bytes and apply signal bitmask
+        }
+        return ERROR_OK;
+}
+
+
+/** Transfer bits in/out stored in char array starting from LSB first or MSB 
first,
+ * alternatively if you want to make MSB-first shift on LSB-first mode put data
+ * in reverse order into input/output array.
+ * \param *device void pointer to pass driver details to the function.
+ * \param bits is the number of bits (char array elements) to transfer.
+ * \param *mosidata pointer to char array with data to be send.
+ * \param *misodata pointer to char array with data to be received.
+ * \param nLSBfirst if zero shift data LSB-first, otherwise MSB-first.
+ * \return number of bits sent on success, or ERROR_FAIL on failure.
+ */
+int ft2232_transfer(void *device, int bits, char *mosidata, char *misodata, 
int nLSBfirst){
+        static uint8_t buf[65539], databuf;
+        int i, retval, bit=0, byte=0, bytes=0;
+        uint32_t bytes_written, bytes_read;
+
+        LOG_DEBUG("ft2232_transfer(device=@%p, bits=%d, mosidata=@%p, 
misodata=@%p, nLSDfirst=%d) ",\
+                (void*)device, bits, (void*)mosidata, (void*)misodata, 
nLSBfirst);
+
+        if (bits>65535){
+                LOG_ERROR("Cannot transfer more than 65536 bits at once!");
+                return ERROR_FAIL;
+        }
+
+        if (bits>=8){
+                //Try to pack as many bits into bytes for better performance.
+                bytes = bits/8;
+                bytes--;                      // MPSSE starts counting bytes 
from 0.
+                buf[0]=(nLSBfirst)?0x31:0x39; // Clock Bytes In and Out LSb or 
MSb first.
+                buf[1]=(char)bytes&0x0ff;
+                buf[2]=(char)((bytes>>8)&0x0ff);
+                bytes++;
+                for (byte=0;byte*8<bits;byte++){
+                        databuf=0;
+                        for (i=0;i<8;i++) 
{databuf|=mosidata[byte*8+i]?(1<<i):0;}
+                        buf[byte+3]=databuf;
+                }
+                retval=ft2232_write(buf, bytes+3, &bytes_written);
+                if (retval<0){
+                        LOG_ERROR("ft2232_write() returns %d", retval);
+                        return ERROR_FAIL;
+                }
+                retval=ft2232_read((uint8_t *)buf, bytes, &bytes_read);
+                if (retval<0){
+                        LOG_ERROR("ft2232_read() returns %d", retval);
+                        return ERROR_FAIL;
+                }
+                // Explode read bytes into bit array.
+                for(byte=0;byte*8<bits;byte++) for(bit=0;bit<8;bit++) 
misodata[byte*8+bit]=buf[byte]&(1<<bit)?1:0;
+        }
+
+        // Now send remaining bits that cannot be packed as bytes.
+        // Because "Clock Data Bits In and Out LSB/MSB" of FTDI is a mess, 
pack single
+        //  bit read/writes into buffer and then flush it using single USB 
transfer.
+        for (bit=bytes*8;bit<bits;bit++){
+                buf[3*bit+0]=(nLSBfirst)?0x33:0x3b;     // Clock Bits In and 
Out LSb or MSb first.
+                buf[3*bit+1]=0;                                 // One bit per 
element.
+                buf[3*bit+2]=mosidata[bit]?0xff:0;      // Take data from 
supplied array.
+        }
+        retval=ft2232_write(buf, 3*(bits-(bytes*8)), &bytes_written);
+        if (retval<0){
+                LOG_ERROR("ft2232_write() returns %d", retval);
+                return ERROR_FAIL;
+        }
+        retval=ft2232_read((uint8_t *)misodata, bits-(bytes*8), &bytes_read);
+        if (retval<0){
+                LOG_ERROR("ft2232_read() returns %d", retval);
+                return ERROR_FAIL;
+        }
+        // FTDI MPSSE returns shift register value, our bit is MSb
+        for (bit=bytes*8;bit<bits;bit++) 
misodata[bit]=(misodata[bit]&(nLSBfirst?0x01:0x80))?1:0;
+        //USE THIS FOR WIRE-LEVEL DEBUG
+        //LOG_DEBUG("read 0x%02X written 0x%02X", misodata[bit], 
mosidata[bit]);
+
+        return bit;
+}
+
+
 /*
  * Commands that only apply to the highspeed FTx232H devices (FT2232H, 
FT4232H, FT232H).
  * See chapter 6 in http://www.ftdichip.com/Documents/AppNotes/
@@ -4284,4 +4465,5 @@ struct jtag_interface ft2232_interface = {
        .speed_div = ft2232_speed_div,
        .khz = ft2232_khz,
        .execute_queue = ft2232_execute_queue,
+       .bitbang = ft2232_bitbang,
 };

-- 

------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to