ft2232 and usbblaster cable drivers ported to usbconn layer

git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@1244 b68d4a1b-bc3d-0410-92ed-d4ac073336b7
master
Arnim Läuger 17 years ago
parent cf6e302089
commit 92c0c55e98

@ -1,3 +1,19 @@
2008-05-20 Arnim Laeuger <arniml@users.sourceforge.net>
* src/tap/cable/ft2232.c, src/tap/cable/usbblaster.c:
run on top of usbconn drivers
* src/tap/cable/cmd_xfer.c, src/tap/cable/cmd_xfer.h:
provide command queueing functions to ft2232.c and usbblaster.c
* src/tap/usbconn/libftd2xx.c, src/tap/usbconn/libftdi.c,
include/usbconn/libftdx.h, src/tap/parport/ftdi.c,
src/tap/parport/ftd2xx.c, src/tap/parport.c, src/tap/Makefile.am,
src/tap/usbconn.c, src/tap/cable/generic_usbconn.c,
src/tap/cable/generic_usbconn.h, doc/UrJTAG.txt:
ftdi & ftd2xx drivers ported from parport to usbconn
* src/tap/usbconn/libusb.c, include/usbconn.h: added read and write
* configure.ac: --enable-parport renamed to --enable-lowlevel
respective renaming for Makefile and C macros
2008-05-13 Kolja Waschk <kawk>
* src/tap/cable/generic_usbconn.c: Read VID/PID as hexadecimal, fixes

@ -487,45 +487,45 @@ CHECK_DRIVER([$cabledrivers], [enabled_cable_drivers], [wiggler], [ENABLE_CA
CHECK_DRIVER([$cabledrivers], [enabled_cable_drivers], [xpc], [ENABLE_CABLE_XPC])
# Enable parport drivers
AC_DEFUN([DEF_ENABLE_PARPORTDRIVERS], [\
# Enable lowlevel drivers
AC_DEFUN([DEF_ENABLE_LOWLEVELDRIVERS], [\
direct ftdi ftd2xx ppdev ppi])
AC_ARG_ENABLE(parport,
[AS_HELP_STRING([--enable-parport], [Enable default set or specific parport drivers:])]
[AS_HELP_STRING([], ['default' enables:])]
[AS_HELP_STRING([],DEF_ENABLE_PARPORTDRIVERS)]
AC_ARG_ENABLE(lowlevel,
[AS_HELP_STRING([--enable-lowlevel], [Enable default set or specific lowlevel drivers:])]
[AS_HELP_STRING([], ['default' enables:])]
[AS_HELP_STRING([],DEF_ENABLE_LOWLEVELDRIVERS)]
,
[AS_CASE([${enableval}],
[yes], [parportdrivers=default],
[no], [parportdrivers=none],
[none], [parportdrivers=none],
[parportdrivers=`echo ${enableval} | $SED -e 's/,/ /g'`])],
[parportdrivers=default])
# expand 'default' to default enabled parportdrivers
parportdrivers=`echo ${parportdrivers} | $SED -e "s/default/DEF_ENABLE_PARPORTDRIVERS/"`
# automatically disable parport drivers when a required feature is not available
[yes], [lowleveldrivers=default],
[no], [lowleveldrivers=none],
[none], [lowleveldrivers=none],
[lowleveldrivers=`echo ${enableval} | $SED -e 's/,/ /g'`])],
[lowleveldrivers=default])
# expand 'default' to default enabled lowlevel drivers
lowleveldrivers=`echo ${lowleveldrivers} | $SED -e "s/default/DEF_ENABLE_LOWLEVELDRIVERS/"`
# automatically disable lowlevel drivers when a required feature is not available
AS_IF([test "x$HAVELIBFTDI" != "xyes"], [
parportdrivers=`echo ${parportdrivers} | $SED -e "s/ftdi//"`
lowleveldrivers=`echo ${lowleveldrivers} | $SED -e "s/ftdi//"`
])
AS_IF([test "x$HAVELIBFTD2XX" != "xyes"], [
parportdrivers=`echo ${parportdrivers} | $SED -e "s/ftd2xx//"`
lowleveldrivers=`echo ${lowleveldrivers} | $SED -e "s/ftd2xx//"`
])
AS_IF([test "x$HAVE_LINUX_PPDEV_H" != "xyes"], [
parportdrivers=`echo ${parportdrivers} | $SED -e "s/ppdev//"`
lowleveldrivers=`echo ${lowleveldrivers} | $SED -e "s/ppdev//"`
])
AS_IF([test "x$HAVE_DEV_PPBUS_PPI_H" != "xyes"], [
parportdrivers=`echo ${parportdrivers} | $SED -e "s/ppi//"`
lowleveldrivers=`echo ${lowleveldrivers} | $SED -e "s/ppi//"`
])
AS_IF([test "x$HAVE_IOPERM" != "xyes" -a "x$HAVE_I386_SET_IOPERM" != "xyes"], [
parportdrivers=`echo ${parportdrivers} | $SED -e "s/direct//"`
lowleveldrivers=`echo ${lowleveldrivers} | $SED -e "s/direct//"`
])
#
enabled_parport_drivers=''
CHECK_DRIVER([$parportdrivers], [enabled_parport_drivers], [direct], [ENABLE_PARPORT_DIRECT])
CHECK_DRIVER([$parportdrivers], [enabled_parport_drivers], [ftd2xx], [ENABLE_PARPORT_FTD2XX])
CHECK_DRIVER([$parportdrivers], [enabled_parport_drivers], [ftdi], [ENABLE_PARPORT_FTDI])
CHECK_DRIVER([$parportdrivers], [enabled_parport_drivers], [ppdev], [ENABLE_PARPORT_PPDEV])
CHECK_DRIVER([$parportdrivers], [enabled_parport_drivers], [ppi], [ENABLE_PARPORT_PPI])
enabled_lowlevel_drivers=''
CHECK_DRIVER([$lowleveldrivers], [enabled_lowlevel_drivers], [direct], [ENABLE_LOWLEVEL_DIRECT])
CHECK_DRIVER([$lowleveldrivers], [enabled_lowlevel_drivers], [ftd2xx], [ENABLE_LOWLEVEL_FTD2XX])
CHECK_DRIVER([$lowleveldrivers], [enabled_lowlevel_drivers], [ftdi], [ENABLE_LOWLEVEL_FTDI])
CHECK_DRIVER([$lowleveldrivers], [enabled_lowlevel_drivers], [ppdev], [ENABLE_LOWLEVEL_PPDEV])
CHECK_DRIVER([$lowleveldrivers], [enabled_lowlevel_drivers], [ppi], [ENABLE_LOWLEVEL_PPI])
dnl Enable a relocatable jtag?
@ -580,5 +580,5 @@ jtag is now configured for
Build BSDL subsystem : $FLAG_BSDL
Bus drivers : $enabled_bus_drivers
Cable drivers : $enabled_cable_drivers
Parport drivers : $enabled_parport_drivers
Lowlevel drivers : $enabled_lowlevel_drivers
])

@ -397,13 +397,13 @@ host:
==== Driver tailoring ====
The configure script enables all default bus, cable and parport drivers. You
The configure script enables all default bus, cable and lowlevel drivers. You
can include and exclude specific drivers if required. For a list of parameters
run
./configure --help
to figure out the appropriate --enable-bus, --enable-cable and --enable-parport
to figure out the appropriate --enable-bus, --enable-cable and --enable-lowlevel
options.
@ -661,21 +661,26 @@ the jtag shell):
UrJTAG now also supports some USB cables. Unfortunately, there is no standard
for "JTAG over USB", so this support is limited to a few selected cables only.
For cables based on the FT2232 chip from FTDI, the cable command has to be
given cable name, driver name, and USB Vendor and Product ID of the cable:
given cable name and optionally the driver name, USB Vendor, and Product ID of
the cable:
jtag> cable ARM-USB-OCD ftdi-mpsse 15ba:3
jtag> cable ARM-USB-OCD vid=15ba pid=0003 driver=ftdi-mpsse
For some cables, UrJTAG knows the VID:PID and you can just say ":"
For all known cables, UrJTAG knows the VID and PID so you can just say
jtag> cable JTAGkey ftdi-mpsse :
jtag> cable ARM-USB-OCD
On Windows, if UrJTAG was compiled to use the drivers supplied by
FTDI, the command should instead look like this:
If your cable isn't detected automatically though it's listed as a known and
supported cable, feel free to report its VID and PID. It might be a different
revision and should be added to the known & tested list of cables.
jtag> cable ARM-USB-OCD ftd2xx-mpsse 15ba:3
The support for USB-based cables and their configuration is work
in progress; the above syntax may change (i.e. become simpler) soon.
As stated above, the driver name is not mandatory for the cable
command. UrJTAG will select the driver automatically based on UrJTAG's
configuration. In case your system provides just one of libftdi or FTD2XX
the respective driver is selected. If both libraries are available, then
FTD2XX is selected. That's simply because FTD2XX showed some performance
advantages over libftdi in the past. You can still force libftdi with the
respective parameter.
===== detect =====
@ -1192,15 +1197,19 @@ All parport drivers present a common API for setting and reading signals.
===== usbconn =====
The usbconn drivers provide a common API to search for and connect with USB
devices. At the moment, there's only a libusb driver, but others will follow
(e.g. to communicate with FTDI chip based cables through libftdi and/or FTD2XX,
to communicate with Cypress FX2 using EZUSB.SYS or CyUSB.sys, and more).
devices. At the moment, there are drivers for libusd, libftdi and FTD2XX
(e.g. to communicate with FTDI chip based cables through libftdi and/or
FTD2XX, to communicate with Cypress FX2 using EZUSB.SYS or CyUSB.sys, and
more).
/////////////////////////////////////////////////////////////////////////////
arniml, 18-may-2008: Obsolete?
In contrast to the parport API, the usbconn drivers provide only the functions
for connecting, disconnecting, and for releasing ressources. The actual
communication must be implemented using the underlying library's functions,
e.g. usb_write from libusb, or ftdi_write from libftdi. Therefore, each driver
using usbconn usually only works together with one particular usbconn driver.
/////////////////////////////////////////////////////////////////////////////
==== Bus drivers ====

@ -1,5 +1,5 @@
/*
* $Id: usbconn.h 809 2007-12-04 07:06:49Z kawk $
* $Id$
*
* USB Device Connection Driver Interface
* Copyright (C) 2008 K. Waschk
@ -27,6 +27,7 @@
#define USBCONN_H
#include <stdint.h>
#include <stddef.h>
typedef struct usbconn_t usbconn_t;
@ -47,6 +48,8 @@ typedef struct {
void (*free)( usbconn_t * );
int (*open)( usbconn_t * );
int (*close)( usbconn_t * );
int (*read)( usbconn_t *, uint8_t *, int );
int (*write)( usbconn_t *, uint8_t *, int, int );
} usbconn_driver_t;
struct usbconn_t {
@ -59,6 +62,8 @@ usbconn_t *usbconn_connect( const char **, int, usbconn_cable_t *);
int usbconn_free( usbconn_t *conn );
int usbconn_open( usbconn_t *conn );
int usbconn_close( usbconn_t *conn );
int usbconn_read( usbconn_t *conn, uint8_t *buf, int len );
int usbconn_write( usbconn_t *conn, uint8_t *buf, int len, int recv );
extern usbconn_driver_t *usbconn_drivers[];
#endif /* USBCONN_H */

@ -0,0 +1,36 @@
/*
* $Id$
*
* 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 A. Laeuger, 2008
*
*/
#ifndef _USBCONN_LIBFTDX_H
#define _USBCONN_LIBFTDX_H 1
#define FTDX_MAXSEND 4096
/* Maximum chunk to receive from ftdi/ftd2xx driver.
Larger values might speed up comm, but there's an upper limit
when too many bytes are sent and the underlying libftdi or libftd2xx
don't fetch the returned data in time -> deadlock */
#define FTDI_MAXRECV ( 4 * 64)
#define FTD2XX_MAXRECV (63 * 64)
#define FTDX_MAXRECV (FTD2XX_MAXRECV < FTDI_MAXRECV ? FTD2XX_MAXRECV : FTDI_MAXRECV)
#endif

@ -1,5 +1,5 @@
/*
* $Id: usbconn/libusb.h,v 1.7 2003/08/19 09:05:25 telka Exp $
* $Id$
*
* Link driver for accessing USB devices via libusb
*

@ -41,7 +41,9 @@ libtap_a_SOURCES = \
cable/generic_usbconn.h \
cable/generic_usbconn.c \
cable/generic_parport.h \
cable/generic_parport.c
cable/generic_parport.c \
cable/cmd_xfer.h \
cable/cmd_xfer.c
if ENABLE_CABLE_ARCOM
libtap_a_SOURCES += \
@ -126,27 +128,27 @@ libtap_a_SOURCES += \
cable/jim.c
endif
if ENABLE_PARPORT_FTDI
if ENABLE_LOWLEVEL_FTDI
libtap_a_SOURCES += \
parport/ftdi.c
usbconn/libftdi.c
endif
if ENABLE_PARPORT_FTD2XX
if ENABLE_LOWLEVEL_FTD2XX
libtap_a_SOURCES += \
parport/ftd2xx.c
usbconn/libftd2xx.c
endif
if ENABLE_PARPORT_DIRECT
if ENABLE_LOWLEVEL_DIRECT
libtap_a_SOURCES += \
parport/direct.c
endif
if ENABLE_PARPORT_PPDEV
if ENABLE_LOWLEVEL_PPDEV
libtap_a_SOURCES += \
parport/ppdev.c
endif
if ENABLE_PARPORT_PPI
if ENABLE_LOWLEVEL_PPI
libtap_a_SOURCES += \
parport/ppi.c
endif

@ -0,0 +1,323 @@
/*
* $Id$
*
* Generic command buffer handler.
*
* 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 Arnim Laeuger, 2008.
*
*/
#include <stdlib.h>
#include <string.h>
#include "sysdep.h"
#include "generic.h"
#include "generic_usbconn.h"
#include "cmd_xfer.h"
/*****************************************************************************
* extend_cmd_buffer( cmd )
*
* Extends the buffer of the given command if a new byte wouldn't fit into
* the current buffer size.
*
* cmd : pointer to cx_cmd_t
*
* Return value:
* 0 : Error occured, not enough memory
* 1 : All ok
*
****************************************************************************/
static int
extend_cmd_buffer( cx_cmd_t *cmd )
{
/* check size of cmd buffer and increase it if not sufficient */
if (cmd->buf_pos >= cmd->buf_len)
{
cmd->buf_len *= 2;
if (cmd->buf)
cmd->buf = (uint8_t *)realloc( cmd->buf, cmd->buf_len );
}
return cmd->buf ? 1 : 0;
}
/*****************************************************************************
* cx_cmd_push( cmd, d )
*
* Pushes the byte value d to the buffer of the current last command.
*
* cmd_root : pointer to cx_cmd_root_t struct
* d : new value to be pushed
*
* Return value:
* 0 : Error occured
* 1 : All ok
*
****************************************************************************/
int
cx_cmd_push( cx_cmd_root_t *cmd_root, uint8_t d )
{
cx_cmd_t *cmd = cmd_root->last;
if (!cmd)
return 0;
if (!extend_cmd_buffer( cmd ))
return 0;
cmd->buf[cmd->buf_pos++] = d;
return 1;
}
/*****************************************************************************
* cx_cmd_dequeue( cmd_root )
*
* Dequeues the first command.
*
* cmd_root : pointer to cx_cmd_root_t parameter struct
*
* Return value:
* NULL : Error occured
* <>NULL : All ok, pointer to dequeued cx_cmd_t
*
****************************************************************************/
cx_cmd_t *
cx_cmd_dequeue( cx_cmd_root_t *cmd_root )
{
cx_cmd_t *cmd = cmd_root->first;
if (cmd)
{
if ((cmd_root->first = cmd->next) == NULL)
cmd_root->last = NULL;
cmd->next = NULL;
}
return cmd;
}
/*****************************************************************************
* cx_cmd_free( cmd )
*
* Frees allocated memory of specified cmd structure.
*
* cmd : pointer to cx_cmd_t
*
* Return value:
* none
*
****************************************************************************/
void
cx_cmd_free( cx_cmd_t *cmd )
{
if (cmd)
{
if (cmd->buf)
free( cmd->buf );
free( cmd );
}
}
/*****************************************************************************
* cx_cmd_queue( cmd_root, to_recv )
*
* Allocates a new cx_cmd_t and queues it at the end of the command
* queue. The value of to_recv will be stored in the new cmd element,
* set to 0 if this command will not generate receive bytes.
*
* cmd_root : pointer to cx_cmd_root_t parameter struct
* to_recv : number of receive bytes that this command will generate
*
* Return value:
* NULL : Error occured
* <>NULL : All ok, pointer to allocated cx_cmd_t
*
****************************************************************************/
cx_cmd_t *
cx_cmd_queue( cx_cmd_root_t *cmd_root, uint32_t to_recv )
{
cx_cmd_t *cmd = (cx_cmd_t *)malloc( sizeof( cx_cmd_t ) );
if (cmd)
{
cmd->buf_len = 64;
if ((cmd->buf = (uint8_t *)malloc( cmd->buf_len )) == NULL)
{
free( cmd );
cmd = NULL;
}
else
{
cmd->buf_pos = 0;
cmd->to_recv = to_recv;
cmd->next = NULL;
if (!cmd_root->first)
cmd_root->first = cmd;
if (cmd_root->last)
cmd_root->last->next = cmd;
cmd_root->last = cmd;
}
}
return cmd;
}
/*****************************************************************************
* cx_cmd_init( cmd_root )
*
* Initializes the command root structure.
*
* cmd_root : pointer to cx_cmd_root_t
*
* Return value:
* none
*
****************************************************************************/
void
cx_cmd_init( cx_cmd_root_t *cmd_root )
{
cmd_root->first = NULL;
cmd_root->last = NULL;
}
/*****************************************************************************
* cx_cmd_deinit( cmd_root )
*
* Deinitialzes and frees all elements from the command root structure.
*
* cmd_root : pointer to cx_cmd_root_t
*
* Return value:
* none
*
****************************************************************************/
void
cx_cmd_deinit( cx_cmd_root_t *cmd_root )
{
cx_cmd_t *cmd;
while (cmd_root->first)
{
cmd = cx_cmd_dequeue( cmd_root );
cx_cmd_free( cmd );
}
}
/*****************************************************************************
* cx_xfer( cmd_root, out_cmd, cable, how_much )
*
* Unrolls the queued commands and posts their payload to the usbconn driver.
* NB: usbconn_write will buffer the accumulated payload until usbconn_read
* is called.
*
* Flushing of the posted payload bytes is triggered when how_much
* requests to do so or if receive bytes are expected.
*
* cmd_root : pointer to cx_cmd_root_t struct
* out_cmd : pointer to cx_cmd_t for an optional command that is appended
* to send buffer in case commands have been scheduled that
* yield return/receive data from the device
* cable : current cable_t
* how_much : cable_flush_amount_t value specifying the flush strategy
*
* Return value:
* none
*
****************************************************************************/
void
cx_xfer( cx_cmd_root_t *cmd_root, const cx_cmd_t *out_cmd,
cable_t *cable, cable_flush_amount_t how_much )
{
cx_cmd_t *cmd = cx_cmd_dequeue( cmd_root );
uint32_t bytes_to_recv;
bytes_to_recv = 0;
while (cmd)
{
/* Step 1: copy command bytes buffered for sending them later
through the usbconn driver */
bytes_to_recv += cmd->to_recv;
/* write command data (buffered) */
usbconn_write( cable->link.usb, cmd->buf, cmd->buf_pos, cmd->to_recv );
cx_cmd_free( cmd );
cmd = cx_cmd_dequeue( cmd_root );
}
/* it's possible for the caller to define an extra command that is
appended right before sending commands to the device in case output
data is expected */
if (bytes_to_recv && out_cmd)
{
usbconn_write( cable->link.usb, out_cmd->buf, out_cmd->buf_pos, out_cmd->to_recv );
bytes_to_recv += out_cmd->to_recv;
}
if (bytes_to_recv || (how_much != TO_OUTPUT))
{
/* Step 2: flush scheduled bytes */
usbconn_read( cable->link.usb, NULL, 0 );
bytes_to_recv = 0;
}
}
/*****************************************************************************
* cx_xfer_recv( cable )
*
* Extracts the byte at the current position from the receive buffer.
*
* cable : pointer to the current cable struct
*
* Return value:
* Byte value from receive buffer
*
****************************************************************************/
uint8_t
cx_xfer_recv( cable_t *cable )
{
uint8_t buf;
if (usbconn_read( cable->link.usb, &buf, 1 ) == 1)
{
return buf;
}
else
return 0;
}
/*
Local Variables:
mode:C
c-default-style:gnu
indent-tabs-mode:nil
End:
*/

@ -0,0 +1,61 @@
/*
* $Id$
*
* Generic command buffer handler.
*
* 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 Arnim Laeuger, 2008.
*
*/
#ifndef CMD_XFER_H
#define CMD_XFER_H
#include "sysdep.h"
#include <cable.h>
/* description of a command
the buffer can contain one or more commands if receive count
is zero for all of them */
typedef struct cx_cmd cx_cmd_t;
struct cx_cmd {
cx_cmd_t *next;
uint32_t buf_len;
uint32_t buf_pos;
uint8_t *buf;
uint32_t to_recv;
};
struct cx_cmd_root {
cx_cmd_t *first;
cx_cmd_t *last;
};
typedef struct cx_cmd_root cx_cmd_root_t;
int cx_cmd_push( cx_cmd_root_t *cmd_root, uint8_t d);
cx_cmd_t *cx_cmd_dequeue( cx_cmd_root_t *cmd_root );
void cx_cmd_free( cx_cmd_t *cmd );
cx_cmd_t *cx_cmd_queue( cx_cmd_root_t *cmd_root, uint32_t to_recv );
void cx_cmd_init( cx_cmd_root_t *cmd_root );
void cx_cmd_deinit( cx_cmd_root_t *cmd_root );
void cx_xfer( cx_cmd_root_t *cmd_root, const cx_cmd_t *out_cmd,
cable_t *cable, cable_flush_amount_t how_much );
uint8_t cx_xfer_recv( cable_t *cable );
#endif /* CMD_XFER_H */

File diff suppressed because it is too large Load Diff

@ -1,5 +1,5 @@
/*
* $Id: generic.c 1003 2008-02-10 10:00:30Z kawk $
* $Id$
*
* Copyright (C) 2003 ETC s.r.o.
*
@ -37,18 +37,94 @@
#undef VERBOSE
#ifdef HAVE_LIBUSB
#ifdef ENABLE_CABLE_XPC
extern usbconn_cable_t usbconn_cable_xpc_int;
extern usbconn_cable_t usbconn_cable_xpc_ext;
#endif
#ifdef ENABLE_CABLE_JLINK
extern usbconn_cable_t usbconn_cable_jlink;
#endif
#ifdef ENABLE_CABLE_FT2232
#ifdef ENABLE_LOWLEVEL_FTD2XX
extern usbconn_cable_t usbconn_cable_ft2232_ftd2xx;
extern usbconn_cable_t usbconn_cable_armusbocd_ftd2xx;
extern usbconn_cable_t usbconn_cable_bfin_ujtag_ftd2xx;
extern usbconn_cable_t usbconn_cable_jtagkey_ftd2xx;
extern usbconn_cable_t usbconn_cable_oocdlinks_ftd2xx;
extern usbconn_cable_t usbconn_cable_turtelizer2_ftd2xx;
extern usbconn_cable_t usbconn_cable_usbtojtagif_ftd2xx;
extern usbconn_cable_t usbconn_cable_signalyzer_ftd2xx;
#endif
#ifdef ENABLE_LOWLEVEL_FTDI
extern usbconn_cable_t usbconn_cable_ft2232_ftdi;
extern usbconn_cable_t usbconn_cable_armusbocd_ftdi;
extern usbconn_cable_t usbconn_cable_bfin_ujtag_ftdi;
extern usbconn_cable_t usbconn_cable_jtagkey_ftdi;
extern usbconn_cable_t usbconn_cable_oocdlinks_ftdi;
extern usbconn_cable_t usbconn_cable_turtelizer2_ftdi;
extern usbconn_cable_t usbconn_cable_usbtojtagif_ftdi;
extern usbconn_cable_t usbconn_cable_signalyzer_ftdi;
#endif
#endif
#ifdef ENABLE_CABLE_USBBLASTER
#ifdef ENABLE_LOWLEVEL_FTD2XX
extern usbconn_cable_t usbconn_cable_usbblaster_ftd2xx;
extern usbconn_cable_t usbconn_cable_cubic_cyclonium_ftd2xx;
extern usbconn_cable_t usbconn_cable_nios_eval_ftd2xx;
extern usbconn_cable_t usbconn_cable_usb_jtag_ftd2xx;
#endif
#ifdef ENABLE_LOWLEVEL_FTDI
extern usbconn_cable_t usbconn_cable_usbblaster_ftdi;
extern usbconn_cable_t usbconn_cable_cubic_cyclonium_ftdi;
extern usbconn_cable_t usbconn_cable_nios_eval_ftdi;
extern usbconn_cable_t usbconn_cable_usb_jtag_ftdi;
#endif
#endif
usbconn_cable_t *usbconn_cables[] =
{
#ifdef HAVE_LIBUSB
#ifdef ENABLE_CABLE_XPC
&usbconn_cable_xpc_int,
&usbconn_cable_xpc_ext,
#endif
#ifdef ENABLE_CABLE_JLINK
&usbconn_cable_jlink,
#endif
#ifdef ENABLE_CABLE_FT2232
#ifdef ENABLE_LOWLEVEL_FTD2XX
&usbconn_cable_ft2232_ftd2xx,
&usbconn_cable_armusbocd_ftd2xx,
&usbconn_cable_bfin_ujtag_ftd2xx,
&usbconn_cable_jtagkey_ftd2xx,
&usbconn_cable_oocdlinks_ftd2xx,
&usbconn_cable_turtelizer2_ftd2xx,
&usbconn_cable_usbtojtagif_ftd2xx,
&usbconn_cable_signalyzer_ftd2xx,
#endif
#ifdef ENABLE_LOWLEVEL_FTDI
&usbconn_cable_ft2232_ftdi,
&usbconn_cable_armusbocd_ftdi,
&usbconn_cable_bfin_ujtag_ftdi,
&usbconn_cable_jtagkey_ftdi,
&usbconn_cable_oocdlinks_ftdi,
&usbconn_cable_turtelizer2_ftdi,
&usbconn_cable_usbtojtagif_ftdi,
&usbconn_cable_signalyzer_ftdi,
#endif
#endif
#ifdef ENABLE_CABLE_USBBLASTER
#ifdef ENABLE_LOWLEVEL_FTD2XX
&usbconn_cable_usbblaster_ftd2xx,
&usbconn_cable_cubic_cyclonium_ftd2xx,
&usbconn_cable_nios_eval_ftd2xx,
&usbconn_cable_usb_jtag_ftd2xx,
#endif
#ifdef ENABLE_LOWLEVEL_FTDI
&usbconn_cable_usbblaster_ftdi,
&usbconn_cable_cubic_cyclonium_ftdi,
&usbconn_cable_nios_eval_ftdi,
&usbconn_cable_usb_jtag_ftdi,
#endif
#endif
NULL
};

@ -1,5 +1,5 @@
/*
* $Id: generic.h 1002 2008-02-10 09:50:59Z kawk $
* $Id$
*
* Copyright (C) 2003 ETC s.r.o.
*

@ -26,13 +26,20 @@
#include "sysdep.h"
#include <stdlib.h>
#include <string.h>
#include "cable.h"
#include "parport.h"
#include "chain.h"
#include "cmd.h"
#include "generic.h"
#include "generic_parport.h"
#include "generic_usbconn.h"
#include "usbconn.h"
#include "usbconn/libftdx.h"
#include "cmd_xfer.h"
#define TCK 0
#define TMS 1
@ -43,26 +50,71 @@
#define TDO 0
/* The default driver if not specified otherwise during connect */
#ifdef ENABLE_LOWLEVEL_FTD2XX
#define DEFAULT_DRIVER "ftd2xx"
#else
#define DEFAULT_DRIVER "ftdi"
#endif
typedef struct {
cx_cmd_root_t cmd_root;
} params_t;
static int
usbblaster_connect( char *params[], cable_t *cable )
{
params_t *cable_params;
int result;
/* perform generic_usbconn_connect */
result = generic_usbconn_connect( params, cable );
if (result == 0)
{
cx_cmd_init( &(cable_params->cmd_root) );
/* exchange generic cable parameters with our private parameter set */
free( cable->params );
cable->params = cable_params;
}
return result;
}
static int
usbblaster_init( cable_t *cable )
{
int i;
params_t *params = (params_t *)cable->params;
cx_cmd_root_t *cmd_root = &(params->cmd_root);
if (parport_open( cable->link.port ))
return -1;
if (usbconn_open( cable->link.usb )) return -1;
cx_cmd_queue( cmd_root, 0 );
for(i=0;i<64;i++)
parport_set_data( cable->link.port, 0 );
cx_cmd_push( cmd_root, 0 );
parport_set_control( cable->link.port, 1 ); // flush
parport_set_control( cable->link.port, 0 ); // noflush
cx_xfer( cmd_root, NULL, cable, COMPLETELY );
return 0;
}
static void
usbblaster_cable_free( cable_t *cable )
{
params_t *params = (params_t *)cable->params;
cx_cmd_deinit( &(params->cmd_root) );
generic_usbconn_free( cable );
}
static void
usbblaster_clock( cable_t *cable, int tms, int tdi, int n )
{
params_t *params = (params_t *)cable->params;
cx_cmd_root_t *cmd_root = &(params->cmd_root);
int i, m;
tms = tms ? (1<<TMS) : 0;
@ -75,49 +127,52 @@ usbblaster_clock( cable_t *cable, int tms, int tdi, int n )
{
unsigned char tdis = tdi ? 0xFF : 0;
parport_set_control( cable->link.port, 0 ); // noflush
cx_cmd_queue( cmd_root, 0 );
while (m >= 8)
{
int i;
int chunkbytes = (m >> 3);
if(chunkbytes > 63) chunkbytes = 63;
parport_set_data( cable->link.port,(1<<SHMODE)|(0<<READ)|chunkbytes);
cx_cmd_push( cmd_root, (1<<SHMODE)|(0<<READ)|chunkbytes );
for (i=0; i<chunkbytes; i++)
{
parport_set_data( cable->link.port, tdis);
cx_cmd_push( cmd_root, tdis );
}
m -= (chunkbytes << 3);
}
cx_xfer( cmd_root, NULL, cable, COMPLETELY );
}
for (i = 0; i < m; i++) {
parport_set_data( cable->link.port, OTHERS | (0 << TCK) | tms | tdi );
parport_set_data( cable->link.port, OTHERS | (1 << TCK) | tms | tdi );
parport_set_control( cable->link.port, 1 ); // flush
parport_set_control( cable->link.port, 0 ); // noflush
cx_cmd_queue( cmd_root, 0 );
cx_cmd_push( cmd_root, OTHERS | (0 << TCK) | tms | tdi );
cx_cmd_push( cmd_root, OTHERS | (1 << TCK) | tms | tdi );
cx_xfer( cmd_root, NULL, cable, COMPLETELY );
}
}
static int
usbblaster_get_tdo( cable_t *cable )
{
parport_set_control( cable->link.port, 0 ); // noflush
parport_set_data( cable->link.port, OTHERS ); /* TCK low */
parport_set_data( cable->link.port, OTHERS | (1 << READ) ); /* TCK low */
parport_set_control( cable->link.port, 1 ); // flush
parport_set_control( cable->link.port, 0 ); // noflush
params_t *params = (params_t *)cable->params;
cx_cmd_root_t *cmd_root = &(params->cmd_root);
cx_cmd_queue( cmd_root, 1 );
cx_cmd_push( cmd_root, OTHERS ); /* TCK low */
cx_cmd_push( cmd_root, OTHERS | (1 << READ) ); /* TCK low */
cx_xfer( cmd_root, NULL, cable, COMPLETELY );
#if 0
{
char x = ( parport_get_data( cable->link.port ) & (1 << TDO)) ? 1 : 0;
printf("GetTDO %d\n", x);
return x;
}
{
char x = ( cx_xfer_recv( cable ) & (1 << TDO)) ? 1 : 0;
printf("GetTDO %d\n", x);
return x;
}
#else
return ( parport_get_data( cable->link.port ) & (1 << TDO)) ? 1 : 0;
return ( cx_xfer_recv( cable ) & (1 << TDO)) ? 1 : 0;
#endif
}
@ -130,10 +185,13 @@ usbblaster_set_trst( cable_t *cable, int trst )
static int
usbblaster_transfer( cable_t *cable, int len, char *in, char *out )
{
params_t *params = (params_t *)cable->params;
cx_cmd_root_t *cmd_root = &(params->cmd_root);
int in_offset = 0;
int out_offset = 0;
parport_set_control( cable->link.port, 0 );
parport_set_data( cable->link.port, OTHERS ); /* TCK low */
cx_cmd_queue( cmd_root, 0 );
cx_cmd_push( cmd_root, OTHERS ); /* TCK low */
#if 0
{
@ -151,27 +209,31 @@ usbblaster_transfer( cable_t *cable, int len, char *in, char *out )
if(chunkbytes > 63) chunkbytes = 63;
if(out)
parport_set_data( cable->link.port,(1<<SHMODE)|(1<<READ)|chunkbytes);
else
parport_set_data( cable->link.port,(1<<SHMODE)|(0<<READ)|chunkbytes);
{
cx_cmd_queue( cmd_root, chunkbytes );
cx_cmd_push( cmd_root, (1<<SHMODE)|(1<<READ)|chunkbytes );
}
else {
cx_cmd_queue( cmd_root, 0 );
cx_cmd_push( cmd_root, (1<<SHMODE)|(0<<READ)|chunkbytes );
}
for(i=0; i<chunkbytes; i++)
{
int j;
unsigned char b = 0;
for(j=1; j<256; j<<=1) if(in[in_offset++]) b |= j;
parport_set_data( cable->link.port, b );
cx_cmd_push( cmd_root, b );
};
if(out)
{
parport_set_control( cable->link.port, 1 ); // flush
parport_set_control( cable->link.port, 0 );
cx_xfer( cmd_root, NULL, cable, COMPLETELY );
for(i=0; i<chunkbytes; i++)
{
int j;
unsigned char b = parport_get_data( cable->link.port );
unsigned char b = cx_xfer_recv( cable );
#if 0
printf("read byte: %02X\n", b);
#endif
@ -184,17 +246,18 @@ usbblaster_transfer( cable_t *cable, int len, char *in, char *out )
while(len > in_offset)
{
char tdi = in[in_offset++] ? 1 : 0;
parport_set_data( cable->link.port, OTHERS | ((out)?(1 << READ):0) | (tdi << TDI));/* TCK low */
parport_set_data( cable->link.port, OTHERS | (1 << TCK) | (tdi << TDI));
cx_cmd_queue( cmd_root, out ? 1 : 0 );
cx_cmd_push( cmd_root, OTHERS | ((out)?(1 << READ):0) | (tdi << TDI));/* TCK low */
cx_cmd_push( cmd_root, OTHERS | (1 << TCK) | (tdi << TDI));
}
if(out)
{
parport_set_control( cable->link.port, 1 ); // flush
parport_set_control( cable->link.port, 0 );
cx_xfer( cmd_root, NULL, cable, COMPLETELY );
while(len > out_offset)
out[out_offset++] = ( parport_get_data( cable->link.port ) & (1 << TDO)) ? 1 : 0;
out[out_offset++] = ( cx_xfer_recv( cable ) & (1 << TDO)) ? 1 : 0;
#if 0
{
@ -213,6 +276,9 @@ usbblaster_transfer( cable_t *cable, int len, char *in, char *out )
static void
usbblaster_flush( cable_t *cable, cable_flush_amount_t how_much )
{
params_t *params = (params_t *)cable->params;
cx_cmd_root_t *cmd_root = &(params->cmd_root);
if( how_much == OPTIONALLY ) return;
while (cable->todo.num_items > 0)
@ -233,16 +299,18 @@ usbblaster_flush( cable_t *cable, cable_flush_amount_t how_much )
// printf("clock: %d %d %d\n", tms, tdi, m);
for(; m>0; m--)
{
parport_set_data( cable->link.port, OTHERS | tms | tdi );
parport_set_data( cable->link.port, OTHERS | (1 << TCK) | tms | tdi );
cx_cmd_queue( cmd_root, 0 );
cx_cmd_push( cmd_root, OTHERS | tms | tdi );
cx_cmd_push( cmd_root, OTHERS | (1 << TCK) | tms | tdi );
to_send += 2;
}
break;
}
case CABLE_GET_TDO:
{
parport_set_data( cable->link.port, OTHERS ); /* TCK low */
parport_set_data( cable->link.port, OTHERS | (1 << READ) ); /* TCK low */
cx_cmd_queue( cmd_root, 1 );
cx_cmd_push( cmd_root, OTHERS ); /* TCK low */
cx_cmd_push( cmd_root, OTHERS | (1 << READ) ); /* TCK low */
// printf("get_tdo\n");
to_send += 2;
break;
@ -258,14 +326,13 @@ usbblaster_flush( cable_t *cable, cable_flush_amount_t how_much )
#if 0
if(cable->todo.num_items > 0 && cable->todo.data[i].action == CABLE_TRANSFER)
{
parport_set_data( cable->link.port, OTHERS ); /* TCK low */
cx_cmd_push( cmd_root, OTHERS ); /* TCK low */
};
#endif
if(to_send > 0)
{
parport_set_control( cable->link.port, 1 ); // flush
parport_set_control( cable->link.port, 0 );
cx_xfer( cmd_root, NULL, cable, COMPLETELY );
}
while(j!=i)
@ -274,7 +341,7 @@ usbblaster_flush( cable_t *cable, cable_flush_amount_t how_much )
{
case CABLE_GET_TDO:
{
int tdo = (parport_get_data( cable->link.port ) & (1<<TDO)) ? 1 : 0;
int tdo = (cx_xfer_recv( cable ) & (1<<TDO)) ? 1 : 0;
int m = cable_add_queue_item( cable, &(cable->done) );
cable->done.data[m].action = CABLE_GET_TDO;
cable->done.data[m].arg.value.tdo = tdo;
@ -334,22 +401,28 @@ void
usbblaster_help( const char *cablename )
{
printf( _(
"Usage: cable %s ftdi VID:PID\n"
"Usage: cable %s [vid=VID] [pid=PID] [desc=DESC] [driver=DRIVER]\n"
"\n"
"VID vendor ID (hex, e.g. 9FB, or empty)\n"
"PID product ID (hex, e.g. 6001, or empty)\n"
"VID vendor ID (hex, e.g. 0abc)\n"
"PID product ID (hex, e.g. 0abc)\n"
"DESC Some string to match in description or serial no.\n"
"DRIVER usbconn driver, either ftdi of ftd2xx\n"
" defaults to %s if not specified\n"
"\n"
), cablename );
),
cablename,
DEFAULT_DRIVER
);
}
cable_driver_t usbblaster_cable_driver = {
"UsbBlaster",
N_("Altera USB-Blaster Cable"),
generic_parport_connect,
usbblaster_connect,
generic_disconnect,
generic_parport_free,
usbblaster_cable_free,
usbblaster_init,
generic_parport_done,
generic_usbconn_done,
usbblaster_set_frequency,
usbblaster_clock,
usbblaster_get_tdo,
@ -361,3 +434,59 @@ cable_driver_t usbblaster_cable_driver = {
usbblaster_flush,
usbblaster_help,
};
usbconn_cable_t usbconn_cable_usbblaster_ftdi = {
"UsbBlaster", /* cable name */
NULL, /* string pattern, not used */
"ftdi", /* default usbconn driver */
0x09FB, /* VID */
0x6001 /* PID */
};
usbconn_cable_t usbconn_cable_cubic_cyclonium_ftdi = {
"UsbBlaster", /* cable name */
NULL, /* string pattern, not used */
"ftdi", /* default usbconn driver */
0x09FB, /* VID */
0x6002 /* PID */
};
usbconn_cable_t usbconn_cable_nios_eval_ftdi = {
"UsbBlaster", /* cable name */
NULL, /* string pattern, not used */
"ftdi", /* default usbconn driver */
0x09FB, /* VID */
0x6003 /* PID */
};
usbconn_cable_t usbconn_cable_usb_jtag_ftdi = {
"UsbBlaster", /* cable name */
NULL, /* string pattern, not used */
"ftdi", /* default usbconn driver */
0x16C0, /* VID */
0x06AD /* PID */
};
usbconn_cable_t usbconn_cable_usbblaster_ftd2xx = {
"UsbBlaster", /* cable name */
NULL, /* string pattern, not used */
"ftd2xx", /* default usbconn driver */
0x09FB, /* VID */
0x6001 /* PID */
};
usbconn_cable_t usbconn_cable_cubic_cyclonium_ftd2xx = {
"UsbBlaster", /* cable name */
NULL, /* string pattern, not used */
"ftd2xx", /* default usbconn driver */
0x09FB, /* VID */
0x6002 /* PID */
};
usbconn_cable_t usbconn_cable_nios_eval_ftd2xx = {
"UsbBlaster", /* cable name */
NULL, /* string pattern, not used */
"ftdi", /* default usbconn driver */
0x09FB, /* VID */
0x6003 /* PID */
};
usbconn_cable_t usbconn_cable_usb_jtag_ftd2xx = {
"UsbBlaster", /* cable name */
NULL, /* string pattern, not used */
"ftd2xx", /* default usbconn driver */
0x16C0, /* VID */
0x06AD /* PID */
};

@ -28,34 +28,20 @@
extern parport_driver_t direct_parport_driver;
extern parport_driver_t ppdev_parport_driver;
extern parport_driver_t ftd2xx_parport_driver;
extern parport_driver_t ftd2xx_mpsse_parport_driver;
extern parport_driver_t ftdi_parport_driver;
extern parport_driver_t ftdi_mpsse_parport_driver;
extern parport_driver_t ppi_parport_driver;
parport_driver_t *parport_drivers[] = {
#ifdef ENABLE_PARPORT_DIRECT
#ifdef ENABLE_LOWLEVEL_DIRECT
&direct_parport_driver,
#endif /* ENABLE_PARPORT_DIRECT */
#endif /* ENABLE_LOWLEVEL_DIRECT */
#ifdef ENABLE_PARPORT_PPDEV
#ifdef ENABLE_LOWLEVEL_PPDEV
&ppdev_parport_driver,
#endif /* ENABLE_PARPORT_PPDEV */
#endif /* ENABLE_LOWLEVEL_PPDEV */
#ifdef ENABLE_PARPORT_FTD2XX
&ftd2xx_parport_driver,
&ftd2xx_mpsse_parport_driver,
#endif /* ENABLE_PARPORT_FTD2XX */
#ifdef ENABLE_PARPORT_FTDI
&ftdi_parport_driver,
&ftdi_mpsse_parport_driver,
#endif /* ENABLE_PARPORT_FTDI */
#ifdef ENABLE_PARPORT_PPI
#ifdef ENABLE_LOWLEVEL_PPI
&ppi_parport_driver,
#endif /* ENABLE_PARPORT_PPI */
#endif /* ENABLE_LOWLEVEL_PPI */
NULL /* last must be NULL */
};

@ -1,490 +0,0 @@
/*
* $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 <fcntl.h>
#include <unistd.h>
#if __CYGWIN__ || __MINGW32__
#include <windows.h>
#endif
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <ftd2xx.h>
#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_set_data ( parport_t *parport, uint8_t data );
static int ftd2xx_set_control ( parport_t *parport, uint8_t data );
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 );
}
int
ftd2xx_pre_connect( const char **par, int parnum )
{
port_node_t *pn;
if (parnum != 1) {
printf( _("Syntax error!\n") );
return 0;
}
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 TODO
printf( _("Initializing %s on FTDI device %s\n"), _(cable_drivers[i]->description), par[0] );
#else
printf( _("Initializing on FTDI device %s\n"), par[0] );
#endif
return 1;
}
parport_t *
ftd2xx_std_connect( const char **par, int parnum )
{
parport_t *parport;
if (!ftd2xx_pre_connect(par, parnum))
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;
}
return parport;
}
parport_t *
ftd2xx_mpsse_connect( const char **par, int parnum )
{
parport_t *parport;
if (!ftd2xx_pre_connect(par, parnum))
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;
}
return parport;
}
static int
ftd2xx_generic_open( parport_t *parport )
{
ftd2xx_params_t *p = parport->params;
FT_STATUS status;
#if !__CYGWIN__ && !__MINGW32__
/* 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 );
#endif
if ((status = FT_Open(0, &(p->fc))) != FT_OK) {
fprintf( stderr, "Error: unable to open FTDI device: %li\n", status);
/* mark ftd2xx layer as not initialized */
p->fc = NULL;
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, 3E6)) != 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 device: %li\n", status);
FT_Close(fc);
return -1;
}
if ((status = FT_Purge(fc, FT_PURGE_RX)) != FT_OK) {
fprintf(stderr, "Can't purge buffers: %li\n", status);
FT_Close(fc);
return -1;
}
if ((status = FT_SetChars(fc, 0, 0, 0, 0)) != FT_OK) {
fprintf(stderr, "Can't set special characters: %li\n", status);
FT_Close(fc);
return -1;
}
/* set a reasonable latency timer value
if this value is too low then the chip will send intermediate result data
in short packets (suboptimal performance) */
if ((status = FT_SetLatencyTimer(fc, 16)) != FT_OK) {
fprintf(stderr, "Can't set target latency timer: %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 device: %li\n", status);
FT_Close(fc);
return -1;
}
if ((status = FT_Purge(fc, FT_PURGE_RX)) != FT_OK) {
fprintf(stderr, "Can't purge buffers: %li\n", status);
FT_Close(fc);
return -1;
}
/* set TCK Divisor */
ftd2xx_set_data(parport, 0x86);
ftd2xx_set_data(parport, 0x00);
ftd2xx_set_data(parport, 0x00);
ftd2xx_set_control(parport, 1);
ftd2xx_set_control(parport, 0);
/* switch off loopback */
ftd2xx_set_data(parport, 0x85);
ftd2xx_set_control(parport, 1);
ftd2xx_set_control(parport, 0);
if ((status = FT_ResetDevice(fc)) != FT_OK) {
fprintf(stderr, "Can't reset device: %li\n", status);
FT_Close(fc);
return -1;
}
if ((status = FT_Purge(fc, FT_PURGE_RX)) != FT_OK) {
fprintf(stderr, "Can't purge buffers: %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->fc) {
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->fc) {
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;
if (p->fc) {
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;
} else
return 0;
}
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;
if (p->fc) {
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
};

@ -1,602 +0,0 @@
/*
* $Id$
*
* 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.
*
*/
#include "sysdep.h"
#ifdef HAVE_LIBFTDI
#include <fcntl.h>
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ftdi.h>
#include "parport.h"
#include "cable.h"
parport_driver_t ftdi_parport_driver;
parport_driver_t ftdi_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;
struct ftdi_context *fc;
int outcount;
unsigned char *outbuf;
int outbuf_len;
} ftdi_params_t;
static int ftdi_set_data ( parport_t *parport, uint8_t data );
static int ftdi_set_control ( parport_t *parport, uint8_t data );
static int ftdi_flush_output ( ftdi_params_t *p );
static parport_t *
ftdi_parport_alloc( const char *vidpid, parport_driver_t * parport_driver, size_t outbuf_len )
{
ftdi_params_t *params = malloc( sizeof *params );
parport_t *parport = malloc( sizeof *parport );
port_node_t *node = malloc( sizeof *node );
struct ftdi_context *fc = malloc( sizeof(struct ftdi_context) );
unsigned char *outbuf = malloc( outbuf_len );
if (!node || !parport || !params || !fc || !outbuf) {
free( node );
free( parport );
free( params );
free( fc );
return NULL;
}
ftdi_init(fc);
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;
params->fc = fc;
{
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
ftdi_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( ((ftdi_params_t *) port->params)->serial );
free( ((ftdi_params_t *) port->params)->outbuf );
free( ((ftdi_params_t *) port->params)->fc );
free( port->params );
free( port );
}
int
ftdi_pre_connect( const char **par, int parnum )
{
port_node_t *pn;
if (parnum != 1) {
printf( _("Syntax error!\n") );
return 0;
}
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 TODO
printf( _("Initializing %s on FTDI device %s\n"), _(cable_drivers[i]->description), par[0] );
#else
printf( _("Initializing on FTDI device %s\n"), par[0] );
#endif
return 1;
}
parport_t *
ftdi_std_connect( const char **par, int parnum )
{
parport_t *parport;
if(!ftdi_pre_connect(par, parnum))
return NULL;
parport = ftdi_parport_alloc( par[0], &ftdi_parport_driver, OUTBUF_LEN_STD );
if (!parport) {
printf( _("%s(%d) Out of memory.\n"), __FILE__, __LINE__ );
return NULL;
}
return parport;
}
parport_t *
ftdi_mpsse_connect( const char **par, int parnum )
{
parport_t *parport;
if(!ftdi_pre_connect(par, parnum))
return NULL;
parport = ftdi_parport_alloc( par[0], &ftdi_mpsse_parport_driver, OUTBUF_LEN_MPSSE );
if (!parport) {
printf( _("%s(%d) Out of memory.\n"), __FILE__, __LINE__ );
return NULL;
}
return parport;
}
static int
ftdi_generic_open( parport_t *parport )
{
int r;
ftdi_params_t *p = parport->params;
struct ftdi_context *fc = p->fc;
/* Try to be intelligent about IDs */
if(p->vendor_id)
r = ftdi_usb_open_desc(fc, p->vendor_id, p->product_id, NULL, p->serial); /* USB-Blaster */
else
{
r = ftdi_usb_open_desc(fc, 0x09FB, 0x6001, NULL, p->serial); /* USB-Blaster */
if(r<0) r = ftdi_usb_open_desc(fc, 0x09FB, 0x6002, NULL, p->serial); /* Cubic Cyclonium */
if(r<0) r = ftdi_usb_open_desc(fc, 0x09FB, 0x6003, NULL, p->serial); /* NIOS II Evaluation board */
if(r<0) r = ftdi_usb_open_desc(fc, 0x16C0, 0x06AD, NULL, p->serial); /* http://www.ixo.de/info/usb_jtag/ */
if(r<0) r = ftdi_usb_open_desc(fc, 0x0403, 0xCFF8, NULL, p->serial); /* Amontec JTAGkey http://www.amontec.com/jtagkey.shtml */
if(r<0) r = ftdi_usb_open_desc(fc, 0x15BA, 0x0003, NULL, p->serial); /* Olimex ARM-USB-OCD */
if(r<0) r = ftdi_usb_open_desc(fc, 0x0403, 0xBDC8, NULL, p->serial); /* Turtelizer 2 */
if(r<0) r = ftdi_usb_open_desc(fc, 0x0456, 0xF000, NULL, p->serial); /* Analog Devices BFIN-UJTAG */
};
if(r<0)
{
fprintf (stderr, "Can't open ftdi device: %s\n",
ftdi_get_error_string (fc));
ftdi_deinit(fc);
/* mark ftdi layer as not initialized */
p->fc = NULL;
return -1;
};
return 0;
}
static int
ftdi_std_open( parport_t *parport )
{
int r;
ftdi_params_t *p = parport->params;
struct ftdi_context *fc = p->fc;
r = ftdi_generic_open(parport);
if (r < 0)
return r;
(void)ftdi_disable_bitbang(fc);
if(ftdi_set_latency_timer(fc, 2)<0)
{
fprintf (stderr, "Can't set minimum latency: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
};
#if 1
/* libftdi 0.6 doesn't allow high baudrates, so we send the control
message outselves */
if (usb_control_msg(fc->usb_dev, 0x40, 3, 1, 0, NULL, 0, fc->usb_write_timeout) != 0)
{
fprintf (stderr, "Can't set max baud rate.\n");
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
};
#else
if(ftdi_set_baudrate(fc, 48000000)<0)
{
fprintf (stderr, "Can't set max baud rate: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
};
#endif
return 0;
}
#undef LIBFTDI_UNIMPLEMENTED
static int
seq_purge( struct ftdi_context *fc, int purge_rx, int purge_tx )
{
int result = 0;
unsigned char buf;
#ifndef LIBFTDI_UNIMPLEMENTED
result = ftdi_usb_purge_buffers( fc );
if (result == 0)
result = ftdi_read_data( fc, &buf, 1 );
#else /* not yet available */
{
int rx_loop;
if (purge_rx)
for (rx_loop = 0; (rx_loop < 6) && (result == 0); rx_loop++)
result = ftdi_usb_purge_rx_buffer( fc );
if (purge_tx)
if (result == 0)
result = ftdi_usb_purge_tx_buffer( fc );
if (result == 0)
ftdi_read_data( fc, &buf, 1 );
}
#endif
return result;
}
static int
seq_reset( struct ftdi_context *fc )
{
int result = 0;
#ifdef LIBFTDI_UNIMPLEMENTED /* not yet available */
{
unsigned short status;
if ((result = ftdi_poll_status( fc, &status )) < 0)
return result;
}
#endif
if ((result = ftdi_usb_reset( fc)) < 0)
return result;
return seq_purge( fc, 1, 1 );
}
static int
ftdi_mpsse_open( parport_t *parport )
{
int r;
ftdi_params_t *p = parport->params;
struct ftdi_context *fc = p->fc;
r = ftdi_generic_open(parport);
if (r < 0)
return r;
/* 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 (seq_reset(fc) < 0)
{
fprintf (stderr, "Can't reset USB: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
if (seq_purge(fc, 1, 0) < 0)
{
fprintf (stderr, "Can't purge USB RX buffer: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
#ifdef LIBFTDI_UNIMPLEMENTED /* not yet available */
if (ftdi_set_chars(fc, 0, 0, 0, 0) < 0)
{
fprintf (stderr, "Can't set special characters: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
#endif
/* set a reasonable latency timer value
if this value is too low then the chip will send intermediate result data
in short packets (suboptimal performance) */
if(ftdi_set_latency_timer(fc, 16) < 0)
{
fprintf (stderr, "Can't set target latency: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
if (ftdi_disable_bitbang(fc) < 0)
{
fprintf (stderr, "Can't reset bitmode: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
if (ftdi_set_bitmode(fc, 0x0b, BITMODE_MPSSE) < 0)
{
fprintf (stderr, "Can't set mpsse mode: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
if (ftdi_usb_reset(fc) < 0)
{
fprintf (stderr, "Can't reset USB: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
if (seq_purge(fc, 1, 0) < 0)
{
fprintf (stderr, "Can't purge USB RX buffer: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
/* set TCK Divisor */
ftdi_set_data(parport, TCK_DIVISOR);
ftdi_set_data(parport, 0x00);
ftdi_set_data(parport, 0x00);
ftdi_set_control(parport, 1);
ftdi_set_control(parport, 0);
/* switch off loopback */
ftdi_set_data(parport, LOOPBACK_END);
ftdi_set_control(parport, 1);
ftdi_set_control(parport, 0);
if (ftdi_usb_reset(fc) < 0)
{
fprintf (stderr, "Can't reset USB: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
if (seq_purge(fc, 1, 0) < 0)
{
fprintf (stderr, "Can't purge USB RX buffer: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
return 0;
}
static int
ftdi_flush_output ( ftdi_params_t *p )
{
int xferred;
//int i;
//unsigned char * q;
// printf("ftdi_flush_output, length %d", p->outcount);
// for (i=0, q=p->outbuf; i<p->outcount; i++, q++)
// printf(" %01x", *q);
// printf("\n");
xferred = ftdi_write_data(p->fc, p->outbuf, p->outcount);
if (xferred < 0)
printf( _("Error from ftdi_write_data(): %d\n"), xferred);
if(xferred > 0 && xferred < p->outcount)
{
int offset = xferred;
int remaining = p->outcount - xferred;
while(remaining)
{
printf("W\n");
if(xferred < 0) return xferred;
xferred = ftdi_write_data(p->fc, p->outbuf + offset, remaining);
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
ftdi_close( parport_t *parport )
{
ftdi_params_t *p = parport->params;
if (p->fc) {
if(p->outcount > 0) ftdi_flush_output( p );
p->outcount = 0;
ftdi_disable_bitbang(p->fc);
ftdi_usb_close(p->fc);
ftdi_deinit(p->fc);
}
return 0;
}
static int
ftdi_set_data( parport_t *parport, uint8_t data )
{
ftdi_params_t *p = parport->params;
if (p->fc) {
if(p->autoflush)
{
if(ftdi_write_data(p->fc, &data, 1) != 1) printf("w\n");
}
else
{
p->outbuf[p->outcount++] = data;
if(p->outcount >= p->outbuf_len)
return ftdi_flush_output( p );
}
}
return 0;
}
static int
ftdi_get_data( parport_t *parport )
{
unsigned char d;
ftdi_params_t *p = parport->params;
int res = 0;
if (p->fc) {
while(ftdi_read_data( p->fc, &d, 1) == 0);
res = d;
} else
res = 0;
// printf("ftdi_get_data %01x\n", d);
return res;
}
static int
ftdi_get_status( parport_t *parport )
{
return 0;
}
static int
ftdi_set_control( parport_t *parport, uint8_t data )
{
ftdi_params_t *p = parport->params;
if (p->fc) {
p->autoflush = data;
if(p->autoflush) ftdi_flush_output( p );
}
return 0;
}
parport_driver_t ftdi_parport_driver = {
"ftdi",
ftdi_std_connect,
ftdi_parport_free,
ftdi_std_open,
ftdi_close,
ftdi_set_data,
ftdi_get_data,
ftdi_get_status,
ftdi_set_control
};
parport_driver_t ftdi_mpsse_parport_driver = {
"ftdi-mpsse",
ftdi_mpsse_connect,
ftdi_parport_free,
ftdi_mpsse_open,
ftdi_close,
ftdi_set_data,
ftdi_get_data,
ftdi_get_status,
ftdi_set_control
};
#endif /* HAVE_LIBFTDI */

@ -1,5 +1,5 @@
/*
* $Id: usbconn.c 851 2007-12-15 22:53:24Z kawk $
* $Id$
*
* Copyright (C) 2008 K. Waschk
*
@ -31,11 +31,27 @@
#ifdef HAVE_LIBUSB
extern usbconn_driver_t usbconn_libusb_driver;
#endif /* HAVE_LIBUSB */
#ifdef ENABLE_LOWLEVEL_FTD2XX
extern usbconn_driver_t usbconn_ftd2xx_driver;
extern usbconn_driver_t usbconn_ftd2xx_mpsse_driver;
#endif /* ENABLE_LOWLEVEL_FTD2XX */
#ifdef ENABLE_LOWLEVEL_FTDI
extern usbconn_driver_t usbconn_ftdi_driver;
extern usbconn_driver_t usbconn_ftdi_mpsse_driver;
#endif /* ENABLE_LOWLEVEL_FTDI */
usbconn_driver_t *usbconn_drivers[] = {
#ifdef HAVE_LIBUSB
&usbconn_libusb_driver,
#endif /* HAVE_LIBUSB */
#ifdef ENABLE_LOWLEVEL_FTD2XX
&usbconn_ftd2xx_driver,
&usbconn_ftd2xx_mpsse_driver,
#endif /* ENABLE_LOWLEVEL_FTD2XX */
#ifdef ENABLE_LOWLEVEL_FTDI
&usbconn_ftdi_driver,
&usbconn_ftdi_mpsse_driver,
#endif /* ENABLE_LOWLEVEL_FTDI */
NULL /* last must be NULL */
};
@ -50,3 +66,21 @@ usbconn_close( usbconn_t *conn )
{
return conn->driver->close( conn );
}
int
usbconn_read( usbconn_t *conn, uint8_t *buf, int len )
{
if (conn->driver->read)
return conn->driver->read( conn, buf, len );
else
return 0;
}
int
usbconn_write( usbconn_t *conn, uint8_t *buf, int len, int recv )
{
if (conn->driver->write)
return conn->driver->write( conn, buf, len, recv );
else
return 0;
}

@ -0,0 +1,482 @@
/*
* $Id$
*
* Link driver for accessing FTDI devices via libftd2xx
*
* 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 Arnim Laeuger, 2008
*
*/
#include "sysdep.h"
#include <fcntl.h>
#if __CYGWIN__ || __MINGW32__
#include <windows.h>
#endif
#include <stdio.h>
#include <string.h>
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <ftd2xx.h>
#include "cable.h"
#include "usbconn.h"
#include "usbconn/libftdx.h"
typedef struct {
/* USB device information */
unsigned int vid;
unsigned int pid;
FT_HANDLE fc;
char *serial;
/* send and receive buffer handling */
uint32_t send_buf_len;
uint32_t send_buffered;
uint8_t *send_buf;
uint32_t recv_buf_len;
uint32_t to_recv;
uint32_t recv_write_idx;
uint32_t recv_read_idx;
uint8_t *recv_buf;
} ftd2xx_param_t;
usbconn_driver_t usbconn_ftd2xx_driver;
usbconn_driver_t usbconn_ftd2xx_mpsse_driver;
/* ---------------------------------------------------------------------- */
static int
usbconn_ftd2xx_flush( ftd2xx_param_t *p )
{
FT_STATUS status;
DWORD xferred;
DWORD recvd = 0;
if (!p->fc)
return -1;
if (p->send_buffered == 0)
return 0;
if ((status = FT_Write( p->fc, p->send_buf, p->send_buffered, &xferred )) != FT_OK)
perror( _("usbconn_ftd2xx_flush(): FT_Write() failed.\n") );
if (xferred < p->send_buffered)
{
perror( _("usbconn_ftd2xx_flush(): Written fewer bytes than requested.\n") );
return -1;
}
p->send_buffered = 0;
/* now read all scheduled receive bytes */
if (p->to_recv)
{
if (p->recv_write_idx + p->to_recv > p->recv_buf_len)
{
/* extend receive buffer */
p->recv_buf_len = p->recv_write_idx + p->to_recv;
if (p->recv_buf)
p->recv_buf = (uint8_t *)realloc( p->recv_buf, p->recv_buf_len );
}
if (!p->recv_buf)
{
perror( _("usbconn_ftd2xx_flush(): Receive buffer does not exist.\n") );
return -1;
}
while (recvd == 0)
if ((status = FT_Read( p->fc, &(p->recv_buf[p->recv_write_idx]),
p->to_recv, &recvd )) != FT_OK)
printf( _("usbconn_ftd2xx_flush(): Error from FT_Read(): %d\n"), (int)status );
if (recvd < p->to_recv)
printf( _("usbconn_ftd2xx_flush(): Received less bytes than requested.\n") );
p->to_recv -= recvd;
p->recv_write_idx += recvd;
}
return status != FT_OK ? -1 : xferred;
}
/* ---------------------------------------------------------------------- */
static int
usbconn_ftd2xx_read( usbconn_t *conn, uint8_t *buf, int len )
{
ftd2xx_param_t *p = conn->params;
int cpy_len;
FT_STATUS status = FT_OK;
DWORD recvd = 0;
if (!p->fc)
return -1;
/* flush send buffer to get all scheduled receive bytes */
if (usbconn_ftd2xx_flush( p ) < 0)
return -1;
if (len == 0)
return 0;
/* check for number of remaining bytes in receive buffer */
cpy_len = p->recv_write_idx - p->recv_read_idx;
if (cpy_len > len)
cpy_len = len;
len -= cpy_len;
if (cpy_len > 0)
{
/* get data from the receive buffer */
memcpy( buf, &(p->recv_buf[p->recv_read_idx]), cpy_len );
p->recv_read_idx += cpy_len;
if (p->recv_read_idx == p->recv_write_idx)
p->recv_read_idx = p->recv_write_idx = 0;
}
if (len > 0)
{
/* need to get more data directly from the device */
while (recvd == 0)
if ((status = FT_Read( p->fc, &(buf[cpy_len]), len, &recvd )) != FT_OK)
printf( _("usbconn_ftd2xx_read(): Error from FT_Read(): %d\n"), (int)status );
}
return status != FT_OK ? -1 : cpy_len + len;
}
/* ---------------------------------------------------------------------- */
static int
usbconn_ftd2xx_write( usbconn_t *conn, uint8_t *buf, int len, int recv )
{
ftd2xx_param_t *p = conn->params;
int xferred = 0;
if (!p->fc)
return -1;
/* this write function will try to buffer write data
buffering will be ceased and a flush triggered in two cases. */
/* Case A: max number of scheduled receive bytes will be exceeded
with this write
Case B: max number of scheduled send bytes has been reached */
if ((p->to_recv + recv > FTD2XX_MAXRECV)
|| ((p->send_buffered > FTDX_MAXSEND) && (p->to_recv == 0)))
xferred = usbconn_ftd2xx_flush( p );
if (xferred < 0)
return -1;
/* now buffer this write */
if (p->send_buffered + len > p->send_buf_len)
{
p->send_buf_len = p->send_buffered + len;
if (p->send_buf)
p->send_buf = (uint8_t *)realloc( p->send_buf, p->send_buf_len);
}
if (p->send_buf)
{
memcpy( &(p->send_buf[p->send_buffered]), buf, len );
p->send_buffered += len;
p->to_recv += recv;
if (recv < 0)
{
/* immediate write requested, so flush the buffered data */
xferred = usbconn_ftd2xx_flush( p );
}
return xferred < 0 ? -1 : len;
}
else
{
perror( _("usbconn_ftd2xx_write(): Send buffer does not exist.\n") );
return -1;
}
}
/* ---------------------------------------------------------------------- */
usbconn_t *
usbconn_ftd2xx_connect( const char **param, int paramc, usbconn_cable_t *template )
{
usbconn_t *c = malloc( sizeof( usbconn_t ) );
ftd2xx_param_t *p = malloc( sizeof( ftd2xx_param_t ) );
if (p)
{
p->send_buf_len = FTDX_MAXSEND;
p->send_buffered = 0;
p->send_buf = (uint8_t *)malloc( p->send_buf_len );
p->recv_buf_len = FTD2XX_MAXRECV;
p->to_recv = 0;
p->recv_write_idx = 0;
p->recv_read_idx = 0;
p->recv_buf = (uint8_t *)malloc( p->recv_buf_len );
}
if (!p || !c || !p->send_buf || !p->recv_buf)
{
printf( _("Out of memory\n") );
if (p->send_buf)
free( p->send_buf );
if (p->recv_buf)
free( p->recv_buf );
if (p)
free( p );
if (c)
free( c );
return NULL;
}
p->fc = NULL;
p->pid = template->pid;
p->vid = template->vid;
p->serial = NULL;
c->params = p;
c->driver = &usbconn_ftd2xx_driver;
c->cable = NULL;
printf( _("Connected to libftd2xx driver.\n") );
return c;
}
usbconn_t *
usbconn_ftd2xx_mpsse_connect( const char **param, int paramc, usbconn_cable_t *template )
{
usbconn_t *conn = usbconn_ftd2xx_connect( param, paramc, template );
if (conn)
conn->driver = &usbconn_ftd2xx_mpsse_driver;
return conn;
}
/* ---------------------------------------------------------------------- */
static int
usbconn_ftd2xx_common_open( usbconn_t *conn )
{
ftd2xx_param_t *p = conn->params;
FT_STATUS status;
#if !__CYGWIN__ && !__MINGW32__
/* Add non-standard Vid/Pid to the linux driver */
if ((status = FT_SetVIDPID( p->vid, p->pid )) != FT_OK)
fprintf( stderr, "Warning: couldn't add %4.4x:%4.4x", p->vid, p->pid );
#endif
if ((status = FT_Open( 0, &(p->fc) )) != FT_OK)
{
perror( "Unable to open FTDO device.\n" );
/* mark ftd2xx layer as not initialized */
p->fc = NULL;
return -1;
}
return 0;
}
/* ---------------------------------------------------------------------- */
static int
usbconn_ftd2xx_open( usbconn_t *conn )
{
ftd2xx_param_t *p = conn->params;
FT_HANDLE fc;
FT_STATUS status;
if (usbconn_ftd2xx_common_open( conn ) < 0)
return -1;
fc = p->fc;
if ((status = FT_SetBitMode( fc, 0x00, 0x00 )) != FT_OK)
perror( _("Can't disable bitmode.\n") );
if (status == FT_OK) if ((status = FT_SetLatencyTimer(fc, 2)) != FT_OK)
perror( _("Can't set latency timer.\n") );
if (status == FT_OK) if ((status = FT_SetBaudRate(fc, 3E6)) != FT_OK)
perror( _("Can't set baudrate.\n") );
if (status != FT_OK)
{
FT_Close( fc );
/* mark ftdi layer as not initialized */
p->fc = NULL;
}
return status != FT_OK ? -1 : 0;
}
/* ---------------------------------------------------------------------- */
static int
usbconn_ftd2xx_mpsse_open( usbconn_t *conn )
{
ftd2xx_param_t *p = conn->params;
FT_HANDLE fc;
FT_STATUS status;
if (usbconn_ftd2xx_common_open( conn ) < 0)
return -1;
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)
perror( _("Can't reset device.\n") );
if (status == FT_OK) if ((status = FT_Purge( fc, FT_PURGE_RX )) != FT_OK)
perror( _("Can't purge RX buffer.\n") );
if (status == FT_OK) if ((status = FT_SetChars( fc, 0, 0, 0, 0 )) != FT_OK)
perror( _("Can't set special characters.\n") );
/* set a reasonable latency timer value
if this value is too low then the chip will send intermediate result data
in short packets (suboptimal performance) */
if (status == FT_OK) if ((status = FT_SetLatencyTimer( fc, 16 )) != FT_OK)
perror( _("Can't set target latency timer.\n") );
if (status == FT_OK) if ((status = FT_SetBitMode( fc, 0x00, 0x00 )) != FT_OK)
perror( _("Can't disable bitmode.\n") );
if (status == FT_OK) if ((status = FT_SetBitMode( fc, 0x0b, 0x02 /* BITMODE_MPSSE */ )) != FT_OK)
perror( _("Can't set MPSSE bitmode.\n") );
if (status == FT_OK) if ((status = FT_ResetDevice( fc )) != FT_OK)
perror( _("Can't reset device.\n") );
if (status == FT_OK) if ((status = FT_Purge( fc, FT_PURGE_RX )) != FT_OK)
perror( _("Can't purge RX buffer.\n") );
/* set TCK Divisor */
if (status == FT_OK)
{
uint8_t buf[3] = {0x86, 0x00, 0x00};
if (usbconn_ftd2xx_write( conn, buf, 3, 0 ) < 0)
status = FT_OTHER_ERROR;
}
/* switch off loopback */
if (status == FT_OK)
{
uint8_t buf[1] = {0x85};
if (usbconn_ftd2xx_write( conn, buf, 1, 0 ) < 0)
status = FT_OTHER_ERROR;
}
if (status == FT_OK)
if (usbconn_ftd2xx_read( conn, NULL, 0 ) < 0)
status = FT_OTHER_ERROR;
if (status == FT_OK) if ((status = FT_ResetDevice( fc )) != FT_OK)
perror( _("Can't reset device.\n") );
if (status == FT_OK) if ((status = FT_Purge( fc, FT_PURGE_RX )) != FT_OK)
perror( _("Can't purge RX buffer.\n") );
if (status != FT_OK)
{
FT_Close( fc );
/* mark ftdi layer as not initialized */
p->fc = NULL;
}
return status != FT_OK ? -1 : 0;
}
/* ---------------------------------------------------------------------- */
static int
usbconn_ftd2xx_close( usbconn_t *conn )
{
ftd2xx_param_t *p = conn->params;
if (p->fc)
{
FT_SetBitMode( p->fc, 0x00, 0x00 );
FT_Close( p->fc );
p->fc = NULL;
}
return 0;
}
/* ---------------------------------------------------------------------- */
static void
usbconn_ftd2xx_free( usbconn_t *conn )
{
ftd2xx_param_t *p = conn->params;
if (p->send_buf)
free( p->send_buf );
if (p->recv_buf)
free( p->recv_buf );
if (p->serial)
free( p->serial );
free( conn->params );
free( conn );
}
/* ---------------------------------------------------------------------- */
usbconn_driver_t usbconn_ftd2xx_driver = {
"ftd2xx",
usbconn_ftd2xx_connect,
usbconn_ftd2xx_free,
usbconn_ftd2xx_open,
usbconn_ftd2xx_close,
usbconn_ftd2xx_read,
usbconn_ftd2xx_write
};
usbconn_driver_t usbconn_ftd2xx_mpsse_driver = {
"ftd2xx-mpsse",
usbconn_ftd2xx_mpsse_connect,
usbconn_ftd2xx_free,
usbconn_ftd2xx_mpsse_open,
usbconn_ftd2xx_close,
usbconn_ftd2xx_read,
usbconn_ftd2xx_write
};
/*
Local Variables:
mode:C
c-default-style:gnu
indent-tabs-mode:nil
End:
*/

@ -0,0 +1,542 @@
/*
* $Id$
*
* Link driver for accessing FTDI devices via libftdi
*
* 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 Arnim Laeuger, 2008
*
*/
#include "sysdep.h"
#include <fcntl.h>
#if __CYGWIN__ || __MINGW32__
#include <windows.h>
#endif
#include <stdio.h>
#include <string.h>
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <ftdi.h>
#include "cable.h"
#include "usbconn.h"
#include "usbconn/libftdx.h"
typedef struct {
/* USB device information */
unsigned int vid;
unsigned int pid;
struct ftdi_context *fc;
char *serial;
/* send and receive buffer handling */
uint32_t send_buf_len;
uint32_t send_buffered;
uint8_t *send_buf;
uint32_t recv_buf_len;
uint32_t to_recv;
uint32_t recv_write_idx;
uint32_t recv_read_idx;
uint8_t *recv_buf;
} ftdi_param_t;
usbconn_driver_t usbconn_ftdi_driver;
usbconn_driver_t usbconn_ftdi_mpsse_driver;
/* ---------------------------------------------------------------------- */
static int
usbconn_ftdi_flush( ftdi_param_t *p )
{
int xferred;
int recvd = 0;
if (!p->fc)
return -1;
if (p->send_buffered == 0)
return 0;
if ((xferred = ftdi_write_data( p->fc, p->send_buf, p->send_buffered )) < 0)
perror( ftdi_get_error_string( p->fc ) );
if (xferred < p->send_buffered)
{
perror( _("usbconn_ftdi_flush(): Written fewer bytes than requested.\n") );
return -1;
}
p->send_buffered = 0;
/* now read all scheduled receive bytes */
if (p->to_recv)
{
if (p->recv_write_idx + p->to_recv > p->recv_buf_len)
{
/* extend receive buffer */
p->recv_buf_len = p->recv_write_idx + p->to_recv;
if (p->recv_buf)
p->recv_buf = (uint8_t *)realloc( p->recv_buf, p->recv_buf_len );
}
if (!p->recv_buf)
{
perror( _("usbconn_ftdi_flush(): Receive buffer does not exist.\n") );
return -1;
}
while (recvd == 0)
if ((recvd = ftdi_read_data( p->fc, &(p->recv_buf[p->recv_write_idx]),
p->to_recv )) < 0)
printf( _("usbconn_ftdi_flush(): Error from ftdi_read_data(): %s\n"),
ftdi_get_error_string( p->fc ) );
if (recvd < p->to_recv)
printf( _("usbconn_ftdi_flush(): Received less bytes than requested.\n") );
p->to_recv -= recvd;
p->recv_write_idx += recvd;
}
return xferred < 0 ? -1 : xferred;
}
/* ---------------------------------------------------------------------- */
static int
usbconn_ftdi_read( usbconn_t *conn, uint8_t *buf, int len )
{
ftdi_param_t *p = conn->params;
int cpy_len;
int recvd = 0;
if (!p->fc)
return -1;
/* flush send buffer to get all scheduled receive bytes */
if (usbconn_ftdi_flush( p ) < 0)
return -1;
if (len == 0)
return 0;
/* check for number of remaining bytes in receive buffer */
cpy_len = p->recv_write_idx - p->recv_read_idx;
if (cpy_len > len)
cpy_len = len;
len -= cpy_len;
if (cpy_len > 0)
{
/* get data from the receive buffer */
memcpy( buf, &(p->recv_buf[p->recv_read_idx]), cpy_len );
p->recv_read_idx += cpy_len;
if (p->recv_read_idx == p->recv_write_idx)
p->recv_read_idx = p->recv_write_idx = 0;
}
if (len > 0)
{
/* need to get more data directly from the device */
while (recvd == 0)
if ((recvd = ftdi_read_data( p->fc, &(buf[cpy_len]), len )) < 0)
printf( _("usbconn_ftdi_read(): Error from ftdi_read_data(): %s\n"),
ftdi_get_error_string( p->fc ) );
}
return recvd < 0 ? -1 : cpy_len + len;
}
/* ---------------------------------------------------------------------- */
static int
usbconn_ftdi_write( usbconn_t *conn, uint8_t *buf, int len, int recv )
{
ftdi_param_t *p = conn->params;
int xferred = 0;
if (!p->fc)
return -1;
/* this write function will try to buffer write data
buffering will be ceased and a flush triggered in two cases. */
/* Case A: max number of scheduled receive bytes will be exceeded
with this write
Case B: max number of scheduled send bytes has been reached */
if ((p->to_recv + recv > FTDI_MAXRECV)
|| ((p->send_buffered > FTDX_MAXSEND) && (p->to_recv == 0)))
xferred = usbconn_ftdi_flush( p );
if (xferred < 0)
return -1;
/* now buffer this write */
if (p->send_buffered + len > p->send_buf_len)
{
p->send_buf_len = p->send_buffered + len;
if (p->send_buf)
p->send_buf = (uint8_t *)realloc( p->send_buf, p->send_buf_len);
}
if (p->send_buf)
{
memcpy( &(p->send_buf[p->send_buffered]), buf, len );
p->send_buffered += len;
p->to_recv += recv;
if (recv < 0)
{
/* immediate write requested, so flush the buffered data */
xferred = usbconn_ftdi_flush( p );
}
return xferred < 0 ? -1 : len;
}
else
{
perror( _("usbconn_ftdi_write(): Send buffer does not exist.\n") );
return -1;
}
}
/* ---------------------------------------------------------------------- */
usbconn_t *
usbconn_ftdi_connect( const char **param, int paramc, usbconn_cable_t *template )
{
usbconn_t *c = malloc( sizeof( usbconn_t ) );
ftdi_param_t *p = malloc( sizeof( ftdi_param_t ) );
struct ftdi_context *fc = malloc( sizeof( struct ftdi_context ) );
if (p)
{
p->send_buf_len = FTDX_MAXSEND;
p->send_buffered = 0;
p->send_buf = (uint8_t *)malloc( p->send_buf_len );
p->recv_buf_len = FTDI_MAXRECV;
p->to_recv = 0;
p->recv_write_idx = 0;
p->recv_read_idx = 0;
p->recv_buf = (uint8_t *)malloc( p->recv_buf_len );
}
if (!p || !c || !fc || !p->send_buf || !p->recv_buf)
{
printf( _("Out of memory\n") );
if (p->send_buf)
free( p->send_buf );
if (p->recv_buf)
free( p->recv_buf );
if (p)
free( p );
if (c)
free( c );
if (fc)
free( fc );
return NULL;
}
ftdi_init( fc );
p->fc = fc;
p->pid = template->pid;
p->vid = template->vid;
p->serial = NULL;
c->params = p;
c->driver = &usbconn_ftdi_driver;
c->cable = NULL;
printf( _("Connected to libftdi driver.\n") );
return c;
}
usbconn_t *
usbconn_ftdi_mpsse_connect( const char **param, int paramc, usbconn_cable_t *template )
{
usbconn_t *conn = usbconn_ftdi_connect( param, paramc, template );
if (conn)
conn->driver = &usbconn_ftdi_mpsse_driver;
return conn;
}
/* ---------------------------------------------------------------------- */
static int
usbconn_ftdi_common_open( usbconn_t *conn )
{
ftdi_param_t *p = conn->params;
struct ftdi_context *fc = p->fc;
if (ftdi_usb_open_desc( fc, p->vid, p->pid, NULL, p->serial ) < 0)
{
perror( ftdi_get_error_string( fc ) );
ftdi_deinit( fc );
/* mark ftdi layer as not initialized */
p->fc = NULL;
/* TODO: disconnect? */
return -1;
}
return 0;
}
/* ---------------------------------------------------------------------- */
static int
usbconn_ftdi_open( usbconn_t *conn )
{
ftdi_param_t *p = conn->params;
struct ftdi_context *fc = p->fc;
int r;
if (usbconn_ftdi_common_open( conn ) < 0)
return -1;
if ((r = ftdi_disable_bitbang( fc )) < 0)
perror( ftdi_get_error_string( fc ) );
if (r >= 0) if ((r = ftdi_set_latency_timer( fc, 2 )) < 0)
perror( ftdi_get_error_string( fc ) );
#if 1
/* libftdi 0.6 doesn't allow high baudrates, so we send the control
message outselves */
if (r >= 0) if (usb_control_msg( fc->usb_dev, 0x40, 3, 1, 0, NULL, 0, fc->usb_write_timeout ) != 0)
{
perror( "Can't set max baud rate.\n" );
r = -1;
}
#else
if (r >= 0) if ((r = ftdi_set_baudrate( fc, 48000000 )) < 0)
perror( ftdi_get_error_string( fc ) );
#endif
if (r < 0)
{
ftdi_usb_close( fc );
ftdi_deinit( fc );
/* mark ftdi layer as not initialized */
p->fc = NULL;
}
return r < 0 ? -1 : 0;
}
/* ---------------------------------------------------------------------- */
#undef LIBFTDI_UNIMPLEMENTED
static int
seq_purge( struct ftdi_context *fc, int purge_rx, int purge_tx )
{
int r;
unsigned char buf;
#ifndef LIBFTDI_UNIMPLEMENTED
if ((r = ftdi_usb_purge_buffers( fc )) < 0)
perror( ftdi_get_error_string( fc ) );
if (r >= 0) if ((r = ftdi_read_data( fc, &buf, 1 )) < 0)
perror( ftdi_get_error_string( fc ) );
#else /* not yet available */
{
int rx_loop;
if (purge_rx)
for (rx_loop = 0; (rx_loop < 6) && (r >= 0); rx_loop++)
if ((r = ftdi_usb_purge_rx_buffer( fc )) < 0)
perror( ftdi_get_error_string( fc ) );
if (purge_tx)
if (r >= 0) if ((r = ftdi_usb_purge_tx_buffer( fc )) < 0)
perror( ftdi_get_error_string( fc ) );
if (r >= 0) if ((r = ftdi_read_data( fc, &buf, 1 )) < 0)
perror( ftdi_get_error_string( fc ) );
}
#endif
return r < 0 ? -1 : 0;
}
static int
seq_reset( struct ftdi_context *fc )
{
int r;
#ifdef LIBFTDI_UNIMPLEMENTED /* not yet available */
{
unsigned short status;
if ((r = ftdi_poll_status( fc, &status )) < 0)
perror( ftdi_get_error_string( fc ) );
}
#endif
if ((r = ftdi_usb_reset( fc )) < 0)
perror( ftdi_get_error_string( fc ) );
if (r >= 0) r = seq_purge( fc, 1, 1 );
return r < 0 ? -1 : 0;
}
static int
usbconn_ftdi_mpsse_open( usbconn_t *conn )
{
ftdi_param_t *p = conn->params;
struct ftdi_context *fc = p->fc;
int r;
if (usbconn_ftdi_common_open( conn ) < 0)
return -1;
/* 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. */
r = seq_reset( fc );
if (r >= 0) r = seq_purge( fc, 1, 0 );
#ifdef LIBFTDI_UNIMPLEMENTED
if (r >= 0) if ((r = ftdi_set_event_char( fc, 0, 0 )) < 0)
perror( ftdi_get_error_string( fc ) );
if (r >= 0) if ((r = ftdi_set_error_char( fc, 0, 0 )) < 0)
perror( ftdi_get_error_string( fc ) );
#endif
/* set a reasonable latency timer value
if this value is too low then the chip will send intermediate result data
in short packets (suboptimal performance) */
if (r >= 0) if ((r = ftdi_set_latency_timer( fc, 16 )) < 0)
perror( ftdi_get_error_string( fc ) );
if (r >= 0) if ((r = ftdi_disable_bitbang( fc )) < 0)
perror( ftdi_get_error_string( fc ) );
if (r >= 0) if ((r = ftdi_set_bitmode( fc, 0x0b, BITMODE_MPSSE )) < 0)
perror( ftdi_get_error_string( fc ) );
if (r >= 0) if ((r = ftdi_usb_reset( fc )) < 0)
perror( ftdi_get_error_string( fc ) );
if (r >= 0) r = seq_purge( fc, 1, 0 );
/* set TCK Divisor */
if (r >= 0)
{
uint8_t buf[3] = {TCK_DIVISOR, 0x00, 0x00};
r = usbconn_ftdi_write( conn, buf, 3, 0 );
}
/* switch off loopback */
if (r >= 0)
{
uint8_t buf[1] = {LOOPBACK_END};
r = usbconn_ftdi_write( conn, buf, 1, 0 );
}
if (r >= 0) r = usbconn_ftdi_read( conn, NULL, 0 );
if (r >= 0) if ((r = ftdi_usb_reset( fc )) < 0)
perror( ftdi_get_error_string( fc ) );
if (r >= 0) r = seq_purge( fc, 1, 0 );
if (r < 0)
{
ftdi_usb_close( fc );
ftdi_deinit( fc );
/* mark ftdi layer as not initialized */
p->fc = NULL;
}
return r < 0 ? -1 : 0;
}
/* ---------------------------------------------------------------------- */
static int
usbconn_ftdi_close( usbconn_t *conn )
{
ftdi_param_t *p = conn->params;
if (p->fc)
{
ftdi_disable_bitbang( p->fc );
ftdi_usb_close( p->fc );
ftdi_deinit( p->fc );
p->fc = NULL;
}
return 0;
}
/* ---------------------------------------------------------------------- */
static void
usbconn_ftdi_free( usbconn_t *conn )
{
ftdi_param_t *p = conn->params;
if (p->send_buf)
free( p->send_buf );
if (p->recv_buf)
free( p->recv_buf );
if (p->fc)
free( p->fc );
if (p->serial)
free( p->serial );
free( conn->params );
free( conn );
}
/* ---------------------------------------------------------------------- */
usbconn_driver_t usbconn_ftdi_driver = {
"ftdi",
usbconn_ftdi_connect,
usbconn_ftdi_free,
usbconn_ftdi_open,
usbconn_ftdi_close,
usbconn_ftdi_read,
usbconn_ftdi_write
};
usbconn_driver_t usbconn_ftdi_mpsse_driver = {
"ftdi-mpsse",
usbconn_ftdi_mpsse_connect,
usbconn_ftdi_free,
usbconn_ftdi_mpsse_open,
usbconn_ftdi_close,
usbconn_ftdi_read,
usbconn_ftdi_write
};
/*
Local Variables:
mode:C
c-default-style:gnu
indent-tabs-mode:nil
End:
*/

@ -1,5 +1,5 @@
/*
* $Id: ftdi.c,v 1.7 2003/08/19 09:05:25 telka Exp $
* $Id$
*
* Link driver for accessing USB devices via libusb
*
@ -148,8 +148,10 @@ usbconn_libusb_connect( const char **param, int paramc, usbconn_cable_t *templat
if(libusb_params == NULL || libusb_conn == NULL)
{
printf(_("Out of memory\n"));
free(libusb_params);
free(libusb_conn);
if (libusb_params)
free(libusb_params);
if (libusb_conn)
free(libusb_conn);
return NULL;
};
@ -235,7 +237,9 @@ usbconn_driver_t usbconn_libusb_driver = {
usbconn_libusb_connect,
usbconn_libusb_free,
usbconn_libusb_open,
usbconn_libusb_close
usbconn_libusb_close,
NULL,
NULL
};
#endif /* HAVE_LIBUSB */

Loading…
Cancel
Save