Discussion:
XVC server for FT2232H running on ARM SBC (e.g., OrangePi Zero)
(too old to reply)
Wojciech M. Zabołotny
2018-02-25 12:53:01 UTC
Permalink
Below are the sources of the XVC server allowing remote JTAG access
from Vivado to the Xilinx FPGA board.
The project is based on two sources:
1. https://github.com/Xilinx/XilinxVirtualCable
2. https://github.com/barawn/xvcd-anita

Unfortunately the original xvcd-anita didn't work with Vivado.
I got the "TMS movement inside data shift, don't know how to handle" errors.
Therefore I have decided to give up the analysis of the JTAG stream
and implement a context-free encapsulation of the XVC commands
into the FTDI MPSSE commands.

The maintained version of that code is available at
https://github.com/wzab/xcvd-ff2232h

Please note, that this is a free code, published without warranty
of any kind. It works for me, but I can not warrant that it will
work on any hardware. Maybe in certain conditions it may damage
your hardware. You use it on your own risk!

Regards,
Wojtek

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.15.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the '#!/bin/sh' line above, then type 'sh FILE'.
#
lock_dir=_sh21828
# Made on 2018-02-25 13:43 CET by <***@wzab>.
# Source directory was '/tmp/xvc'.
#
# Existing files will *not* be overwritten, unless '-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 170 -rw-r--r-- build.sh
# 7752 -rw-r--r-- ftdi_xvc_core.c
# 400 -rw-r--r-- ftdi_xvc_core.h
# 6555 -rw-r--r-- LICENSE
# 211 -rw-r--r-- Makefile
# 5209 -rw-r--r-- xvcServer.c
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false

for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done

if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done

if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901

if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'

elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'

elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'

else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU '\''touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= build.sh ==============
if test -n "${keep_file}" && test -f 'build.sh'
then
${echo} "x - SKIPPING build.sh (file already exists)"

else
${echo} "x - extracting build.sh (text)"
sed 's/^X//' << 'SHAR_EOF' > 'build.sh' &&
BRPATH=/home/xl/OrangePi_JTAGSRV/buildroot-2018.02-rc2
(
export PATH=$BRPATH/output/host/usr/bin:$PATH
make ARCH=arm CROSS_COMPILE=\
arm-linux-gnueabihf- xvcd-ft2232h
)
X
SHAR_EOF
(set 20 18 02 25 13 40 34 'build.sh'
eval "${shar_touch}") && \
chmod 0644 'build.sh'
if test $? -ne 0
then ${echo} "restore of build.sh failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'build.sh': 'MD5 check failed'
) << \SHAR_EOF
d6fca7012f9066c2a4fed279a9ed5f0b build.sh
SHAR_EOF

else
test `LC_ALL=C wc -c < 'build.sh'` -ne 170 && \
${echo} "restoration warning: size of 'build.sh' is not 170"
fi
fi
# ============= ftdi_xvc_core.c ==============
if test -n "${keep_file}" && test -f 'ftdi_xvc_core.c'
then
${echo} "x - SKIPPING ftdi_xvc_core.c (file already exists)"

else
${echo} "x - extracting ftdi_xvc_core.c (text)"
sed 's/^X//' << 'SHAR_EOF' > 'ftdi_xvc_core.c' &&
// Basic XVC core for an FTDI device in MPSSE mode, using
// the libftdi library under Linux. I've tested this under Linux:
// I guess it could work under Windows as well, but since XVC
// is network based, I never saw the point.
X
// Thanks to tmbinc for the original xvcd implementation:
// this code however is (I'm pretty sure) a total rewrite of the
// physical layer code.
X
// Author: P.S. Allison (***@osu.edu)
// This code is in the public domain (CC0):
// see https://wiki.creativecommons.org/CC0
X
// Significantly rewritten by Wojciech M. Zabolotny (***@ise.pw.edu.pl)
// removed all assumptions how Xilinx tools use XVC, because Vivado
// didn't work with the original version
X
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <ftdi.h>
#include <usb.h>
X
unsigned int ftdi_verbosity;
#define DEBUGCOND(lvl) (lvl<=ftdi_verbosity)
#define DEBUG(lvl,...) if (lvl<=ftdi_verbosity) printf(__VA_ARGS__)
#define DEBUGPRINTF(...) printf(__VA_ARGS__)
X
struct ftdi_context ftdi;
X
/** \brief Read bytes from the FTDI device, possibly in multiple chunks. */
void ftdi_xvc_read_bytes(unsigned int len, unsigned char *buf) {
X int read, to_read, last_read;
X to_read = len;
X read = 0;
X last_read = ftdi_read_data(&ftdi, buf, to_read);
X if (last_read > 0) read += last_read;
X while (read < to_read) {
X last_read = ftdi_read_data(&ftdi, buf+read, to_read-read);
X if (last_read > 0) read += last_read;
X }
}
X
X
/** \brief Close the FTDI device. */
void ftdi_xvc_close_device() {
X ftdi_usb_reset(&ftdi);
X ftdi_usb_close(&ftdi);
X ftdi_deinit(&ftdi);
}
X
/** \brief Initialize the FTDI library. */
void ftdi_xvc_init(unsigned int verbosity)
{
X ftdi_init(&ftdi);
X ftdi_verbosity = verbosity;
}
X
/** \brief Open the FTDI device. */
int ftdi_xvc_open_device(int vendor, int product)
{
X if (ftdi_usb_open_desc(&ftdi, vendor, product, NULL, NULL) < 0)
X {
X fprintf(stderr, "xvcd: %s : can't open device.\n", __FUNCTION__);
X return -1;
X }
X ftdi_usb_reset(&ftdi);
X ftdi_set_interface(&ftdi, INTERFACE_A);
X ftdi_set_latency_timer(&ftdi, 1);
X return 0;
}
X
/** \brief Fetch the FTDI context, in case someone else wants to muck with the device before we do. */
struct ftdi_context *ftdi_xvc_get_context()
{
X return &ftdi;
}
X
/** \brief Initialize the MPSSE engine on the FTDI device. */
int ftdi_xvc_init_mpsse() {
X int res;
X unsigned char byte;
X
X unsigned char buf[7] = {
X SET_BITS_LOW, 0x08, 0x0B, // Set TMS high, TCK/TDI/TMS as outputs.
X TCK_DIVISOR, 0x01, 0x00, // Set TCK clock rate = 6 MHz.
X SEND_IMMEDIATE
X };
X ftdi_set_bitmode(&ftdi, 0x0B, BITMODE_BITBANG);
X ftdi_set_bitmode(&ftdi, 0x0B, BITMODE_MPSSE);
X while (res = ftdi_read_data(&ftdi, &byte, 1));
X if (ftdi_write_data(&ftdi, buf, 7) != 7)
X {
X fprintf(stderr, "xvcd: %s : FTDI initialization failed.\n", __FUNCTION__);
X return -1;
X }
X return 0;
}
typedef struct
{
X char oper; //0-byte shift, 1-bit shift, 2-TMS bit shift
X int len; //length of the operation
} data_desc;
X
#define MAX_DATA 4096
/* WZab - simplified command for shifting */
/** \brief Handle a 'shift:' command sent via XVC. */
int ftdi_xvc_shift_command(unsigned int len,
X unsigned char *buffer,
X unsigned char *result)
{
X int i;
X int nr_bytes;
X int cur_byte_pos=0;
X int bit_pos = 0;
X int left;
X nr_bytes = (len+7)/8;
X left = len;
X unsigned char ftdi_cmd[MAX_DATA];
X unsigned char ftdi_res[MAX_DATA];
X data_desc ftdi_desc[MAX_DATA];
X //Prepare the result buffer
X memset(result,0,nr_bytes);
X while(left) { //loop until there are data to handle
X int rd_len = 0;
X int nr_opers = 0;
X int wr_ptr = 0;
X int desc_pos = 0;
X int in_cmd_building = 0;
X int last_len = 0;
X int cur_len = 0;
X while( ( desc_pos < (MAX_DATA-8)) && // We may generate up to 9 descriptors in a single iteration
X ( wr_ptr < (MAX_DATA-25)) && // We may generate up to 24 command bytes in a single iteration
X (left > 0)
X ) { //loop until we may add a command to the current set
X if((left>7) && (buffer[cur_byte_pos] == 0)) { //No TMS and at least 1 byte to transmit
X if(in_cmd_building == 0) {
X in_cmd_building = 1;
X ftdi_cmd[wr_ptr++]=MPSSE_DO_WRITE|MPSSE_DO_READ|MPSSE_LSB|MPSSE_WRITE_NEG;
X last_len=wr_ptr; //Save pointer position, to write the length
X wr_ptr += 2; //reserve space for length
X cur_len = -1; //will be increased when the byte is added
X }
X ftdi_cmd[wr_ptr++] = buffer[cur_byte_pos+nr_bytes];
X rd_len += 1; //It generates one byte for reading
X cur_len += 1;
X cur_byte_pos++;
X left -= 8;
X } else {
X //It is no standard shift, so if we created a standard shift command before,
X //we must complete it
X if(in_cmd_building) { //Complete the last command
X ftdi_cmd[last_len] = cur_len & 0xff;
X ftdi_cmd[last_len+1]= (cur_len >> 8) & 0xff;
X in_cmd_building = 0;
X //Add the descriptor to the read descriptors
X ftdi_desc[desc_pos].oper = 0;
X ftdi_desc[desc_pos++].len = cur_len;
X }
X if ((buffer[cur_byte_pos] == 0) && (left<=7)) { //No TMS, bit shift of last bits
X ftdi_cmd[wr_ptr++] = MPSSE_DO_WRITE|MPSSE_DO_READ|MPSSE_LSB|MPSSE_BITMODE|MPSSE_WRITE_NEG;
X ftdi_cmd[wr_ptr++] = left-1;
X ftdi_cmd[wr_ptr++] = buffer[cur_byte_pos+nr_bytes];
X rd_len += 1;
X cur_byte_pos++;
X //Add the descriptor to the read descriptors
X ftdi_desc[desc_pos].oper = 1;
X ftdi_desc[desc_pos++].len = left-1;
X left = 0;
X } else if (buffer[cur_byte_pos] != 0) { //TMS shift, convert it into a set of TMS shifts
X int i;
X for(i=0;i<8;i++) {
X if(left==0) break; //This could be the last byte!
X ftdi_cmd[wr_ptr++] = MPSSE_WRITE_TMS|MPSSE_DO_READ|MPSSE_LSB|MPSSE_BITMODE|MPSSE_WRITE_NEG;
X ftdi_cmd[wr_ptr++] = 0; //One bit - 0!
X ftdi_cmd[wr_ptr++] =
X ((buffer[cur_byte_pos] & (1<<i)) ? 0x01 : 0x00) |
X ((buffer[cur_byte_pos+nr_bytes] & (1<<i)) ? 0x80 : 0x00);
X left--;
X rd_len += 1;
X //Add the descriptor to the read descriptors
X ftdi_desc[desc_pos].oper = 2;
X ftdi_desc[desc_pos++].len = 0;
X }
X cur_byte_pos++;
X }
X } // else
X } //while
X // We must complete the last command if it has not been completed yet
X //The code below should be the same, as in the loop!
X if(in_cmd_building) { //Complete the last command
X ftdi_cmd[last_len] = cur_len & 0xff;
X ftdi_cmd[last_len+1]= (cur_len >> 8) & 0xff;
X in_cmd_building = 0;
X //Add the descriptor to the read descriptors
X ftdi_desc[desc_pos].oper = 0;
X ftdi_desc[desc_pos++].len = cur_len;
X }
X //Send the created command list
X if (ftdi_write_data(&ftdi, ftdi_cmd, wr_ptr) != wr_ptr) {
X return 1;
X }
X //Read the response
X ftdi_xvc_read_bytes(rd_len, ftdi_res);
X //Unpack the response basing on the read descriptors
X //Please note, that the responses do not always come as full bits!
X int rd_byte_pos = 0;
X for(i=0;i<desc_pos;i++) {
X int j;
X //Reading depends on the type of command
X switch(ftdi_desc[i].oper) {
X case 0: //Standard shift
X for(j=0;j<=ftdi_desc[i].len;j++) {
X int bnr;
X for(bnr=0;bnr<8;bnr++) {
X result[bit_pos/8] |= (ftdi_res[rd_byte_pos] & (1<<bnr)) ? (1<<(bit_pos & 7)) : 0;
X bit_pos++;
X }
X rd_byte_pos++;
X }
X break;
X case 1://Bit shift
X {
X int bnr; //Please note, that the received bits are shifted from the MSB!
X for(bnr=7-ftdi_desc[i].len;bnr<8;bnr++) {
X result[bit_pos/8] |= (ftdi_res[rd_byte_pos] & (1<<bnr)) ? (1<<(bit_pos & 7)) : 0;
X bit_pos++;
X }
X rd_byte_pos++;
X }
X break;
X case 2://TMS shift
X result[bit_pos/8] |= (ftdi_res[rd_byte_pos] & 0x80) ? (1<<(bit_pos & 7)) : 0;
X bit_pos++;
X rd_byte_pos++;
X break;
X }
X }
X }
X return 0;
}
SHAR_EOF
(set 20 18 02 25 13 29 04 'ftdi_xvc_core.c'
eval "${shar_touch}") && \
chmod 0644 'ftdi_xvc_core.c'
if test $? -ne 0
then ${echo} "restore of ftdi_xvc_core.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'ftdi_xvc_core.c': 'MD5 check failed'
) << \SHAR_EOF
871c563d7d2ad09c58fed96459fed77f ftdi_xvc_core.c
SHAR_EOF

else
test `LC_ALL=C wc -c < 'ftdi_xvc_core.c'` -ne 7752 && \
${echo} "restoration warning: size of 'ftdi_xvc_core.c' is not 7752"
fi
fi
# ============= ftdi_xvc_core.h ==============
if test -n "${keep_file}" && test -f 'ftdi_xvc_core.h'
then
${echo} "x - SKIPPING ftdi_xvc_core.h (file already exists)"

else
${echo} "x - extracting ftdi_xvc_core.h (text)"
sed 's/^X//' << 'SHAR_EOF' > 'ftdi_xvc_core.h' &&
#ifndef FTDI_XVC_CORE_H
#define FTDI_XVC_CORE_H
X
#include <ftdi.h>
X
void ftdi_xvc_init(unsigned int verbosity);
X
void ftdi_xvc_close_device();
X
struct ftdi_context *ftdi_xvc_get_context();
X
int ftdi_xvc_init_mpsse();
X
int ftdi_xvc_shift_command(unsigned int len,
X unsigned char *buffer,
X unsigned char *result);
X
int ftdi_xvc_open_device(int vendor, int product);
X
#endif // FTDI_XVC_CORE_H
SHAR_EOF
(set 20 18 02 24 11 51 00 'ftdi_xvc_core.h'
eval "${shar_touch}") && \
chmod 0644 'ftdi_xvc_core.h'
if test $? -ne 0
then ${echo} "restore of ftdi_xvc_core.h failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'ftdi_xvc_core.h': 'MD5 check failed'
) << \SHAR_EOF
7b4abd9992e2daf73ed5b1487d0f6431 ftdi_xvc_core.h
SHAR_EOF

else
test `LC_ALL=C wc -c < 'ftdi_xvc_core.h'` -ne 400 && \
${echo} "restoration warning: size of 'ftdi_xvc_core.h' is not 400"
fi
fi
# ============= LICENSE ==============
if test -n "${keep_file}" && test -f 'LICENSE'
then
${echo} "x - SKIPPING LICENSE (file already exists)"

else
${echo} "x - extracting LICENSE (text)"
sed 's/^X//' << 'SHAR_EOF' > 'LICENSE' &&
CC0 1.0 Universal
X
Statement of Purpose
X
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
X
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
X
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
X
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
X
X i. the right to reproduce, adapt, distribute, perform, display, communicate,
X and translate a Work;
X
X ii. moral rights retained by the original author(s) and/or performer(s);
X
X iii. publicity and privacy rights pertaining to a person's image or likeness
X depicted in a Work;
X
X iv. rights protecting against unfair competition in regards to a Work,
X subject to the limitations in paragraph 4(a), below;
X
X v. rights protecting the extraction, dissemination, use and reuse of data in
X a Work;
X
X vi. database rights (such as those arising under Directive 96/9/EC of the
X European Parliament and of the Council of 11 March 1996 on the legal
X protection of databases, and under any national implementation thereof,
X including any amended or successor version of such directive); and
X
X vii. other similar, equivalent or corresponding rights throughout the world
X based on applicable law or treaty, and any national implementations thereof.
X
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
X
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
X
4. Limitations and Disclaimers.
X
X a. No trademark or patent rights held by Affirmer are waived, abandoned,
X surrendered, licensed or otherwise affected by this document.
X
X b. Affirmer offers the Work as-is and makes no representations or warranties
X of any kind concerning the Work, express, implied, statutory or otherwise,
X including without limitation warranties of title, merchantability, fitness
X for a particular purpose, non infringement, or the absence of latent or
X other defects, accuracy, or the present or absence of errors, whether or not
X discoverable, all to the greatest extent permissible under applicable law.
X
X c. Affirmer disclaims responsibility for clearing rights of other persons
X that may apply to the Work or any use thereof, including without limitation
X any person's Copyright and Related Rights in the Work. Further, Affirmer
X disclaims responsibility for obtaining any necessary consents, permissions
X or other rights required for any use of the Work.
X
X d. Affirmer understands and acknowledges that Creative Commons is not a
X party to this document and has no duty or obligation with respect to this
X CC0 or use of the Work.
X
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>
SHAR_EOF
(set 20 18 02 24 16 38 51 'LICENSE'
eval "${shar_touch}") && \
chmod 0644 'LICENSE'
if test $? -ne 0
then ${echo} "restore of LICENSE failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'LICENSE': 'MD5 check failed'
) << \SHAR_EOF
7bae63a234e80ee7c6427dce9fdba6cc LICENSE
SHAR_EOF

else
test `LC_ALL=C wc -c < 'LICENSE'` -ne 6555 && \
${echo} "restoration warning: size of 'LICENSE' is not 6555"
fi
fi
# ============= Makefile ==============
if test -n "${keep_file}" && test -f 'Makefile'
then
${echo} "x - SKIPPING Makefile (file already exists)"

else
${echo} "x - extracting Makefile (text)"
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
LDLIBS=-lusb -lftdi
CC=$(CROSS_COMPILE)gcc
OBJS := xvcServer.o ftdi_xvc_core.o
all: xvcd-ft2232h
xvcd-ft2232h: $(OBJS)
X $(CC) -o xvcd-ft2232h $(OBJS) $(LDLIBS)
$(OBJS) : %.o : %.c
X $(CC) -c $(CFLAGS) $< -o $@
X
SHAR_EOF
(set 20 18 02 24 20 04 04 'Makefile'
eval "${shar_touch}") && \
chmod 0644 'Makefile'
if test $? -ne 0
then ${echo} "restore of Makefile failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'Makefile': 'MD5 check failed'
) << \SHAR_EOF
2b1da88d1b55ac68430e86af1653dedb Makefile
SHAR_EOF

else
test `LC_ALL=C wc -c < 'Makefile'` -ne 211 && \
${echo} "restoration warning: size of 'Makefile' is not 211"
fi
fi
# ============= xvcServer.c ==============
if test -n "${keep_file}" && test -f 'xvcServer.c'
then
${echo} "x - SKIPPING xvcServer.c (file already exists)"

else
${echo} "x - extracting xvcServer.c (text)"
sed 's/^X//' << 'SHAR_EOF' > 'xvcServer.c' &&
/* This work, "xvcServer.c", is a derivative of "xvcd.c" (https://github.com/tmbinc/xvcd)
X * by tmbinc, used under CC0 1.0 Universal (http://creativecommons.org/publicdomain/zero/1.0/).
X * "xvcServer.c" is licensed under CC0 1.0 Universal (http://creativecommons.org/publicdomain/zero/1.0/)
X * by Avnet and is used by Xilinx for XAPP1251.
X *
X * Description : XAPP1251 Xilinx Virtual Cable Server for Linux
X *
X * Support for FT2232H has been added by Wojciech M. Zabolotny (***@ise.pw.edu.pl) basing on the
X * https://github.com/barawn/xvcd-anita project.
X */
X
X
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <stdint.h>
X
#include <sys/mman.h>
#include <fcntl.h>
X
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <pthread.h>
X
#include "ftdi_xvc_core.h"
X
#define VENDOR 0x0403
#define PRODUCT 0x6010
#define MAP_SIZE 0x10000
X
static int verbose = 0;
X
static int sread(int fd, void *target, int len) {
X unsigned char *t = target;
X while (len) {
X int r = read(fd, t, len);
X if (r <= 0)
X return r;
X t += r;
X len -= r;
X }
X return 1;
}
X
int handle_data(int fd) {
X
X const char xvcInfo[] = "xvcServer_v1.0:32768\n";
X
X do {
X int len, nr_bytes;
X char cmd[16];
X unsigned char blen[4];
X unsigned char buffer[32768], result[16384];
X memset(cmd, 0, 16);
X
X if (sread(fd, cmd, 2) != 1)
X return 1;
X
X if (memcmp(cmd, "ge", 2) == 0) {
X if (sread(fd, cmd, 6) != 1)
X return 1;
X memcpy(result, xvcInfo, strlen(xvcInfo));
X if (write(fd, result, strlen(xvcInfo)) != strlen(xvcInfo)) {
X perror("write");
X return 1;
X }
X if (verbose) {
X printf("%u : Received command: 'getinfo'\n", (int)time(NULL));
X printf("\t Replied with %s\n", xvcInfo);
X }
X break;
X } else if (memcmp(cmd, "se", 2) == 0) {
X if (sread(fd, cmd, 9) != 1)
X return 1;
X memcpy(result, cmd + 5, 4);
X if (write(fd, result, 4) != 4) {
X perror("write");
X return 1;
X }
X if (verbose) {
X printf("%u : Received command: 'settck'\n", (int)time(NULL));
X printf("\t Replied with '%.*s'\n\n", 4, cmd + 5);
X }
X break;
X } else if (memcmp(cmd, "sh", 2) == 0) {
X if (sread(fd, cmd, 4) != 1)
X return 1;
X if (verbose) {
X printf("%u : Received command: 'shift'\n", (int)time(NULL));
X }
X } else {
X
X fprintf(stderr, "invalid cmd '%s'\n", cmd);
X return 1;
X }
X /* Here we go only during the shift command */
X if (sread(fd, blen, 4) != 1) return 1;
X len = blen[0]+256*(blen[1]+256*(blen[2]+256*blen[3]));
X //fprintf(stderr,"%d\n",len);
X nr_bytes = (len + 7)/8;
X if (sread(fd, buffer, nr_bytes * 2) != 1) return 1;
X if (ftdi_xvc_shift_command(len, buffer, result)) return 1;
X if (write(fd,result, nr_bytes) != nr_bytes) {
X perror("write");
X return 1;
X }
X } while (1);
X /* Note: Need to fix JTAG state updates, until then no exit is allowed */
X return 0;
}
X
int main(int argc, char **argv) {
X int i;
X int s;
X int c;
X int fd_uio;
X
X struct sockaddr_in address;
X
X
X
X opterr = 0;
X
X while ((c = getopt(argc, argv, "v")) != -1)
X switch (c) {
X case 'v':
X verbose = 1;
X break;
X case '?':
X fprintf(stderr, "usage: %s [-v]\n", *argv);
X return 1;
X }
X ftdi_xvc_init(verbose);
X
X if (ftdi_xvc_open_device(VENDOR, PRODUCT) < 0) {
X return 1;
X }
X
X if (ftdi_xvc_init_mpsse() < 0)
X return 1;
X
X s = socket(AF_INET, SOCK_STREAM, 0);
X
X if (s < 0) {
X perror("socket");
X return 1;
X }
X
X
X i = 1;
X setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof i);
X
X address.sin_addr.s_addr = INADDR_ANY;
X address.sin_port = htons(2542);
X address.sin_family = AF_INET;
X
X if (bind(s, (struct sockaddr*) &address, sizeof(address)) < 0) {
X perror("bind");
X return 1;
X }
X
X if (listen(s, 1) < 0) {
X perror("listen");
X return 1;
X }
X
X fd_set conn;
X int maxfd = 0;
X
X FD_ZERO(&conn);
X FD_SET(s, &conn);
X
X maxfd = s;
X
X while (1) {
X fd_set read = conn, except = conn;
X int fd;
X
X if (select(maxfd + 1, &read, 0, &except, 0) < 0) {
X perror("select");
X break;
X }
X
X for (fd = 0; fd <= maxfd; ++fd) {
X if (FD_ISSET(fd, &read)) {
X if (fd == s) {
X int newfd;
X socklen_t nsize = sizeof(address);
X
X newfd = accept(s, (struct sockaddr*) &address, &nsize);
X
X // if (verbose)
X printf("connection accepted - fd %d\n", newfd);
X if (newfd < 0) {
X perror("accept");
X } else {
X printf("setting TCP_NODELAY to 1\n");
X int flag = 1;
X int optResult = setsockopt(newfd,
X IPPROTO_TCP,
X TCP_NODELAY,
X (char *)&flag,
X sizeof(int));
X if (optResult < 0)
X perror("TCP_NODELAY error");
X if (newfd > maxfd) {
X maxfd = newfd;
X }
X FD_SET(newfd, &conn);
X }
X }
X else if (handle_data(fd)) {
X
X if (verbose)
X printf("connection closed - fd %d\n", fd);
X close(fd);
X FD_CLR(fd, &conn);
X }
X }
X else if (FD_ISSET(fd, &except)) {
X if (verbose)
X printf("connection aborted - fd %d\n", fd);
X close(fd);
X FD_CLR(fd, &conn);
X if (fd == s)
X break;
X }
X }
X }
X return 0;
}
SHAR_EOF
(set 20 18 02 25 13 37 12 'xvcServer.c'
eval "${shar_touch}") && \
chmod 0644 'xvcServer.c'
if test $? -ne 0
then ${echo} "restore of xvcServer.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'xvcServer.c': 'MD5 check failed'
) << \SHAR_EOF
7319dec2e7c392a52d88865fdaa7dc3a xvcServer.c
SHAR_EOF

else
test `LC_ALL=C wc -c < 'xvcServer.c'` -ne 5209 && \
${echo} "restoration warning: size of 'xvcServer.c' is not 5209"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0
w***@gmail.com
2018-02-25 17:14:24 UTC
Permalink
The maintained version of that code is available at
https://github.com/wzab/xvcd-ff2232h
( not at https://github.com/wzab/xcvd-ff2232h )

Loading...