From e828e317e44edf131d756c258ac1a4e2ce5f393d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnim=20L=C3=A4uger?= Date: Tue, 20 Nov 2007 20:35:49 +0000 Subject: [PATCH] ftd2xx parport driver added git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@782 b68d4a1b-bc3d-0410-92ed-d4ac073336b7 --- jtag/configure.ac | 23 +- jtag/src/cmd/cable.c | 9 +- jtag/src/tap/Makefile.am | 4 + jtag/src/tap/cable/ft2232.c | 30 ++- jtag/src/tap/parport.c | 11 +- jtag/src/tap/parport/ftd2xx.c | 468 ++++++++++++++++++++++++++++++++++ jtag/src/tap/parport/ftdi.c | 2 +- 7 files changed, 538 insertions(+), 9 deletions(-) create mode 100644 jtag/src/tap/parport/ftd2xx.c diff --git a/jtag/configure.ac b/jtag/configure.ac index 18f88c35..c1f9d96d 100644 --- a/jtag/configure.ac +++ b/jtag/configure.ac @@ -109,7 +109,7 @@ dnl LIBFTDI_CFLAGS=`$HAVELIBFTDI --cflags` AC_DEFINE(HAVE_LIBFTDI, 1, [Define if you have libftdi]) else AM_CONDITIONAL(HAVE_LIBFTDI, false) - AC_MSG_WARN([*** libftdi-config not found. No support for FTDI-based USB JTAG cables.]) + AC_MSG_WARN([*** libftdi-config not found. No support for FTDI-based USB JTAG cables via libftdi.]) fi dnl check for libusb-config @@ -126,6 +126,16 @@ else AC_MSG_WARN([*** libusb-config not found. Omitting support for some USB JTAG cables.]) fi +dnl check for availability of libftd2xx +AC_CHECK_LIB([ftd2xx], [FT_Open], [ + AM_CONDITIONAL(HAVE_LIBFTD2XX, true) + AC_DEFINE(HAVE_LIBFTD2XX, 1, [define if you have libftd2xx]) + LIBS="-lftd2xx $LIBS" +],[ + AM_CONDITIONAL(HAVE_LIBFTD2XX, false) + AC_MSG_WARN([*** libftd2xx not found. No support for FTDI-based USB JTAG cables via libftd2xx.]) +]) + CFLAGS="$CFLAGS -Wall" CPPFLAGS="$CPPFLAGS -I\$(top_srcdir) -I\$(top_srcdir)/include" @@ -145,9 +155,16 @@ if test ${HAVELIBUSB:-no} != no ; then else FLAG_HAVELIBUSB=no fi +if echo $LIBS | grep -q 'ftd2xx' ; then + FLAG_HAVELIBFTD2XX=yes +else + FLAG_HAVELIBFTD2XX=no +fi AC_MSG_RESULT([ jtag is now configured for - USB cable support: $FLAG_HAVELIBUSB - FTDI cable support: $FLAG_HAVELIBFTDI + USB cable support : $FLAG_HAVELIBUSB + FTDI cable support + via libftdi : $FLAG_HAVELIBFTDI + via libftd2xx : $FLAG_HAVELIBFTD2XX ]) diff --git a/jtag/src/cmd/cable.c b/jtag/src/cmd/cable.c index 968b76f8..6b435f73 100644 --- a/jtag/src/cmd/cable.c +++ b/jtag/src/cmd/cable.c @@ -89,6 +89,10 @@ cmd_cable_help( void ) "Usage: %s VID:PID:S/N CABLE\n" "Usage: %s VID:PID:S/N CABLE\n" #endif +#ifdef HAVE_LIBFTD2XX + "Usage: %s VID:PID:S/N CABLE\n" + "Usage: %s VID:PID:S/N CABLE\n" +#endif #ifdef HAVE_LIBUSB "Usage: %s VID:PID:S/N CABLE\n" #endif @@ -96,7 +100,7 @@ cmd_cable_help( void ) "\n" "PORTADDR parallel port address (e.g. 0x378)\n" "CABLE cable type\n" -#if defined HAVE_LIBUSB || defined HAVE_LIBFTDI +#if defined HAVE_LIBUSB || defined HAVE_LIBFTDI || defined HAVE_LIBFTD2XX "DEV ppdev device (e.g. /dev/parport0)\n" "VID empty or USB vendor ID, hex (e.g. 09FB)\n" "PID empty or USB product ID, hex (e.g. 6001)\n" @@ -109,6 +113,9 @@ cmd_cable_help( void ) #ifdef HAVE_LIBFTDI "cable ftdi", "cable ftdi-mpsse", #endif +#ifdef HAVE_LIBFTD2XX + "cable ftd2xx", "cable ftd2xx-mpsse", +#endif #ifdef HAVE_LIBUSB "cable xpcu", #endif diff --git a/jtag/src/tap/Makefile.am b/jtag/src/tap/Makefile.am index 704e8c76..0d3282e5 100644 --- a/jtag/src/tap/Makefile.am +++ b/jtag/src/tap/Makefile.am @@ -62,3 +62,7 @@ libtap_a_SOURCES += \ cable/ft2232.c endif +if HAVE_LIBFTD2XX +libtap_a_SOURCES += \ + parport/ftd2xx.c +endif diff --git a/jtag/src/tap/cable/ft2232.c b/jtag/src/tap/cable/ft2232.c index 52e8601f..1498a6bb 100644 --- a/jtag/src/tap/cable/ft2232.c +++ b/jtag/src/tap/cable/ft2232.c @@ -23,8 +23,6 @@ * */ -#include - #include "sysdep.h" #include "cable.h" @@ -52,6 +50,34 @@ #define FT2232_MAX_TCK_FREQ 6000000 +/* repeat the definitions for MPSSE command processor here + since we cannot rely on the existence of ftdih. even though + they're defined there */ + +/* Shifting commands IN MPSSE Mode*/ +#define MPSSE_WRITE_NEG 0x01 /* Write TDI/DO on negative TCK/SK edge*/ +#define MPSSE_BITMODE 0x02 /* Write bits, not bytes */ +#define MPSSE_READ_NEG 0x04 /* Sample TDO/DI on negative TCK/SK edge */ +#define MPSSE_LSB 0x08 /* LSB first */ +#define MPSSE_DO_WRITE 0x10 /* Write TDI/DO */ +#define MPSSE_DO_READ 0x20 /* Read TDO/DI */ +#define MPSSE_WRITE_TMS 0x40 /* Write TMS/CS */ + +/* FTDI MPSSE commands */ +#define SET_BITS_LOW 0x80 +/*BYTE DATA*/ +/*BYTE Direction*/ +#define SET_BITS_HIGH 0x82 +/*BYTE DATA*/ +/*BYTE Direction*/ +#define GET_BITS_LOW 0x81 +#define GET_BITS_HIGH 0x83 +#define LOOPBACK_START 0x84 +#define LOOPBACK_END 0x85 +#define TCK_DIVISOR 0x86 + + +/* bit and bitmask definitions for GPIO commands */ #define BIT_TCK 0 #define BIT_TDI 1 #define BIT_TDO 2 diff --git a/jtag/src/tap/parport.c b/jtag/src/tap/parport.c index d8f3bb1e..869c2d7c 100644 --- a/jtag/src/tap/parport.c +++ b/jtag/src/tap/parport.c @@ -32,6 +32,10 @@ extern parport_driver_t direct_parport_driver; #ifdef HAVE_LINUX_PPDEV_H extern parport_driver_t ppdev_parport_driver; #endif /* HAVE_LINUX_PPDEV_H */ +#ifdef HAVE_LIBFTD2XX +extern parport_driver_t ftd2xx_parport_driver; +extern parport_driver_t ftd2xx_mpsse_parport_driver; +#endif /* HAVE_LIBFTD2xx */ #ifdef HAVE_LIBFTDI extern parport_driver_t ftdi_parport_driver; extern parport_driver_t ftdi_mpsse_parport_driver; @@ -47,12 +51,16 @@ parport_driver_t *parport_drivers[] = { #ifdef HAVE_LINUX_PPDEV_H &ppdev_parport_driver, #endif /* HAVE_LINUX_PPDEV_H */ +#ifdef HAVE_LIBFTD2XX + &ftd2xx_parport_driver, + &ftd2xx_mpsse_parport_driver, +#endif /* HAVE_LIBFTD2XX */ #ifdef HAVE_LIBFTDI &ftdi_parport_driver, &ftdi_mpsse_parport_driver, #endif /* HAVE_LIBFTDI */ #ifdef HAVE_LIBUSB - &xpcu_pp_driver, + &xpcu_pp_driver, #endif /* HAVE_LIBUSB */ NULL /* last must be NULL */ }; @@ -92,4 +100,3 @@ parport_set_control( parport_t *port, uint8_t data ) { return port->driver->set_control( port, data ); } - diff --git a/jtag/src/tap/parport/ftd2xx.c b/jtag/src/tap/parport/ftd2xx.c new file mode 100644 index 00000000..59b4bba5 --- /dev/null +++ b/jtag/src/tap/parport/ftd2xx.c @@ -0,0 +1,468 @@ +/* + * $Id$ + * + * libftd2xx Driver + * + * Based on libftdi driver + * Copyright (C) 2006 K. Waschk + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Kolja Waschk, 2006. + * Structure taken from ppdev.c, written by Marcel Telka, 2003. + * Ported to libftd2xx by A. Laeuger, 2007. + * + */ + +#include "sysdep.h" + +#include +#include +#include +#include + +#include +#include + +#include + +#include "parport.h" +#include "cable.h" + +parport_driver_t ftd2xx_parport_driver; +parport_driver_t ftd2xx_mpsse_parport_driver; + +typedef struct port_node_t port_node_t; + +struct port_node_t { + parport_t *port; + port_node_t *next; +}; + +static port_node_t *ports = NULL; /* devices */ + +#define OUTBUF_LEN_STD 64 +#define OUTBUF_LEN_MPSSE 4096 + +typedef struct { + char *serial; + unsigned int vendor_id; + unsigned int product_id; + char autoflush; + FT_HANDLE fc; + int outcount; + unsigned char *outbuf; + int outbuf_len; +} ftd2xx_params_t; + +static int ftd2xx_flush_output ( ftd2xx_params_t *p ); + +static parport_t * +ftd2xx_parport_alloc( const char *vidpid, parport_driver_t * parport_driver, size_t outbuf_len ) +{ + ftd2xx_params_t *params = malloc( sizeof *params ); + parport_t *parport = malloc( sizeof *parport ); + port_node_t *node = malloc( sizeof *node ); + unsigned char *outbuf = malloc( outbuf_len ); + + if (!node || !parport || !params || !outbuf) { + free( node ); + free( parport ); + free( params ); + return NULL; + } + + params->outbuf = outbuf; + params->outbuf_len = outbuf_len; + params->outcount = 0; + params->autoflush = 0; + params->product_id = 0; + params->vendor_id = 0; + params->serial = NULL; + + { + char *f = strchr(vidpid, ':'); + char *l = strrchr(vidpid, ':'); + if(f) + { + params->vendor_id = strtoul(vidpid, NULL, 16); + params->product_id = strtoul(f+1, NULL, 16); + if(l!=f) params->serial = strdup(l+1); + }; + }; + + parport->params = params; + parport->driver = parport_driver; + parport->cable = NULL; + + node->port = parport; + node->next = ports; + + ports = node; + + return parport; +} + +static void +ftd2xx_parport_free( parport_t *port ) +{ + port_node_t **prev; + + for (prev = &ports; *prev; prev = &((*prev)->next)) + if ((*prev)->port == port) + break; + + if (*prev) { + port_node_t *pn = *prev; + *prev = pn->next; + free( pn ); + } + + free( ((ftd2xx_params_t *) port->params)->serial ); + free( ((ftd2xx_params_t *) port->params)->outbuf ); + free( port->params ); + free( port ); +} + + +static cable_driver_t * +ftd2xx_pre_connect( const char **par, int parnum ) +{ + int i; + port_node_t *pn; + + if (parnum != 2) { + printf( _("Syntax error!\n") ); + return NULL; + } + + for (pn = ports; pn; pn = pn->next) + if (strcmp( pn->port->params, par[0] ) == 0) { + printf( _("Disconnecting %s from FTDI device %s\n"), _(pn->port->cable->driver->description), par[0] ); + pn->port->cable->driver->disconnect( pn->port->cable ); + break; + } + + if (strcmp( par[1], "none" ) == 0) { + printf( _("Changed cable to 'none'\n") ); + return NULL; + } + + for (i = 0; cable_drivers[i]; i++) + if (strcmp( par[1], cable_drivers[i]->name ) == 0) + break; + + if (!cable_drivers[i]) { + printf( _("Unknown cable: %s\n"), par[1] ); + return NULL; + } + + printf( _("Initializing %s on FTDI device %s\n"), _(cable_drivers[i]->description), par[0] ); + + return cable_drivers[i]; +} + + +static cable_t * +ftd2xx_std_connect( const char **par, int parnum ) +{ + parport_t *parport; + cable_driver_t *cable_driver; + cable_t *cable; + + cable_driver = ftd2xx_pre_connect(par, parnum); + if (!cable_driver) + return NULL; + + parport = ftd2xx_parport_alloc( par[0], &ftd2xx_parport_driver, OUTBUF_LEN_STD ); + if (!parport) { + printf( _("%s(%d) Out of memory.\n"), __FILE__, __LINE__ ); + return NULL; + } + + cable = cable_driver->connect( cable_driver, parport ); + if (!cable) + ftd2xx_parport_free( parport ); + + return cable; +} + + +static cable_t * +ftd2xx_mpsse_connect( const char **par, int parnum ) +{ + parport_t *parport; + cable_driver_t *cable_driver; + cable_t *cable; + + cable_driver = ftd2xx_pre_connect(par, parnum); + if (!cable_driver) + return NULL; + + parport = ftd2xx_parport_alloc( par[0], &ftd2xx_mpsse_parport_driver, OUTBUF_LEN_MPSSE ); + if (!parport) { + printf( _("%s(%d) Out of memory.\n"), __FILE__, __LINE__ ); + return NULL; + } + + cable = cable_driver->connect( cable_driver, parport ); + if (!cable) + ftd2xx_parport_free( parport ); + + return cable; +} + + +static int +ftd2xx_generic_open( parport_t *parport ) +{ + ftd2xx_params_t *p = parport->params; + FT_STATUS status; + + /* Add non-standard Vid/Pid to the linux driver */ + if ((status = FT_SetVIDPID(p->vendor_id, p->product_id)) != FT_OK) + fprintf( stderr, "Warning: couldn't add %4.4x:%4.4x", p->vendor_id, p->product_id ); + + if ((status = FT_Open(0, &(p->fc))) != FT_OK) { + fprintf( stderr, "Error: unable to open FTDI device: %li\n", status); + return -1; + } + + return 0; +} + + +static int +ftd2xx_std_open( parport_t *parport ) +{ + int r; + ftd2xx_params_t *p = parport->params; + FT_HANDLE fc; + FT_STATUS status; + + r = ftd2xx_generic_open(parport); + if (r < 0) + return r; + + fc = p->fc; + + if ((status = FT_SetBitMode( fc, 0x00, 0x00 )) != FT_OK) { + fprintf(stderr, "Can't disable bitmode: %li\n", status); + FT_Close(fc); + return -1; + } + if ((status = FT_SetLatencyTimer(fc, 2)) != FT_OK) { + fprintf(stderr, "Can't set latency timer: %li\n", status); + FT_Close(fc); + return -1; + } + if ((status = FT_SetBaudRate(fc, 48000000)) != FT_OK) { + fprintf(stderr, "Can't set baudrate: %li\n", status); + FT_Close(fc); + return -1; + } + + return 0; +} + + +static int +ftd2xx_mpsse_open( parport_t *parport ) +{ + int r; + ftd2xx_params_t *p = parport->params; + FT_HANDLE fc; + FT_STATUS status; + + r = ftd2xx_generic_open(parport); + if (r < 0) + return r; + + fc = p->fc; + + /* This sequence might seem weird and containing superfluous stuff. + However, it's built after the description of JTAG_InitDevice + Ref. FTCJTAGPG10.pdf + Intermittent problems will occur when certain steps are skipped. */ + if ((status = FT_ResetDevice(fc)) != FT_OK) { + fprintf(stderr, "Can't reset 1 device: %li\n", status); + FT_Close(fc); + return -1; + } + if ((status = FT_Purge(fc, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK) { + fprintf(stderr, "Can't purge buffers: %li\n", status); + FT_Close(fc); + return -1; + } + if ((status = FT_SetBitMode( fc, 0x00, 0x00 )) != FT_OK) { + fprintf(stderr, "Can't disable bitmode: %li\n", status); + FT_Close(fc); + return -1; + } + if ((status = FT_SetBitMode( fc, 0x0b, 0x02 /*BITMODE_MPSSE*/ )) != FT_OK) { + fprintf(stderr, "Can't set bitmode: %li\n", status); + FT_Close(fc); + return -1; + } + if ((status = FT_ResetDevice(fc)) != FT_OK) { + fprintf(stderr, "Can't reset 2 device: %li\n", status); + FT_Close(fc); + return -1; + } + if ((status = FT_Purge(fc, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK) { + fprintf(stderr, "Can't purge buffers: %li\n", status); + FT_Close(fc); + return -1; + } + if ((status = FT_SetLatencyTimer(fc, 2)) != FT_OK) { + fprintf(stderr, "Can't set latency timer: %li\n", status); + FT_Close(fc); + return -1; + } + + return 0; +} + + +static int +ftd2xx_flush_output ( ftd2xx_params_t *p ) +{ + DWORD xferred; + FT_STATUS status; + + if ((status = FT_Write( p->fc, p->outbuf, (DWORD)(p->outcount), &xferred )) != FT_OK) + fprintf( stderr, "Error: FT_Write() failed in %i\n", __LINE__ ); + + if(xferred > 0 && xferred < p->outcount) + { + int offset = xferred; + int remaining = p->outcount - xferred; + + while(remaining) + { + printf("W\n"); + if(xferred < 0) return xferred; + if ((status = FT_Write( p->fc, p->outbuf + offset, (DWORD)remaining, &xferred)) != FT_OK) + fprintf( stderr, "Error: FT_Write() failed in %i\n", __LINE__ ); + if(xferred < 0) + { + memmove(p->outbuf, p->outbuf + offset, remaining); + p->outcount = remaining; + return 0; + } + offset += xferred; + remaining -= xferred; + } + }; + p->outcount = 0; + + return 0; +} + +static int +ftd2xx_close( parport_t *parport ) +{ + ftd2xx_params_t *p = parport->params; + + if(p->outcount > 0) ftd2xx_flush_output( p ); + p->outcount = 0; + + FT_SetBitMode( p->fc, 0x00, 0x00 ); + FT_Close(p->fc); + + return 0; +} + +static int +ftd2xx_set_data( parport_t *parport, uint8_t data ) +{ + ftd2xx_params_t *p = parport->params; + DWORD xferred; + FT_STATUS status; + + if(p->autoflush) + { + if ((status = FT_Write( p->fc, &data, 1 , &xferred)) != FT_OK) + fprintf( stderr, "Error: FT_Write() failed in %i\n", __LINE__ ); + if (xferred != 1) + printf("w\n"); + } + else + { + p->outbuf[p->outcount++] = data; + + if(p->outcount >= p->outbuf_len) + return ftd2xx_flush_output( p ); + }; + + return 0; +} + +static int +ftd2xx_get_data( parport_t *parport ) +{ + DWORD xferred = 0; + FT_STATUS status; + unsigned char d; + ftd2xx_params_t *p = parport->params; + + while (xferred == 0) { + if ((status = FT_Read( p->fc, &d, 1, &xferred )) != FT_OK) + printf( "Error: FT_Read() failed in %i\n", __LINE__ ); + } + return d; +} + +static int +ftd2xx_get_status( parport_t *parport ) +{ + return 0; +} + +static int +ftd2xx_set_control( parport_t *parport, uint8_t data ) +{ + ftd2xx_params_t *p = parport->params; + + p->autoflush = data; + if(p->autoflush) ftd2xx_flush_output( p ); + + return 0; +} + +parport_driver_t ftd2xx_parport_driver = { + "ftd2xx", + ftd2xx_std_connect, + ftd2xx_parport_free, + ftd2xx_std_open, + ftd2xx_close, + ftd2xx_set_data, + ftd2xx_get_data, + ftd2xx_get_status, + ftd2xx_set_control +}; + +parport_driver_t ftd2xx_mpsse_parport_driver = { + "ftd2xx-mpsse", + ftd2xx_mpsse_connect, + ftd2xx_parport_free, + ftd2xx_mpsse_open, + ftd2xx_close, + ftd2xx_set_data, + ftd2xx_get_data, + ftd2xx_get_status, + ftd2xx_set_control +}; diff --git a/jtag/src/tap/parport/ftdi.c b/jtag/src/tap/parport/ftdi.c index a4b1d89a..58228bfb 100644 --- a/jtag/src/tap/parport/ftdi.c +++ b/jtag/src/tap/parport/ftdi.c @@ -1,5 +1,5 @@ /* - * $Id: ftdi.c,v 1.7 2003/08/19 09:05:25 telka Exp $ + * $Id$ * * libftdi Driver * Copyright (C) 2006 K. Waschk