add misc directory
authoradam <adam@megacz.com>
Wed, 30 Jan 2008 07:33:47 +0000 (08:33 +0100)
committeradam <adam@megacz.com>
Wed, 30 Jan 2008 07:33:47 +0000 (08:33 +0100)
15 files changed:
misc/Makefile [new file with mode: 0644]
misc/README [new file with mode: 0644]
misc/config.c [new file with mode: 0644]
misc/config.h [new file with mode: 0644]
misc/index.html [new file with mode: 0644]
misc/jtagkey.c [new file with mode: 0644]
misc/jtagkey.h [new file with mode: 0644]
misc/jtagmon.c [new file with mode: 0644]
misc/jtagmon.h [new file with mode: 0644]
misc/libusb-driverrc [new file with mode: 0644]
misc/parport.c [new file with mode: 0644]
misc/parport.h [new file with mode: 0644]
misc/program.sh [new file with mode: 0644]
misc/usb-driver.c [new file with mode: 0644]
misc/usb-driver.h [new file with mode: 0644]

diff --git a/misc/Makefile b/misc/Makefile
new file mode 100644 (file)
index 0000000..8a21424
--- /dev/null
@@ -0,0 +1,38 @@
+#Add -DFORCE_PC3_IDENT to CFLAGS to force the identification of
+#a Parallel Cable III
+CFLAGS=-Wall -fPIC -DUSB_DRIVER_VERSION="\"$(shell stat -c '%y' usb-driver.c |cut -d\. -f1)\"" #-DFORCE_PC3_IDENT
+
+LIBS=-ldl -lusb -lpthread
+
+SRC=usb-driver.c parport.c config.c jtagmon.c
+HEADER=usb-driver.h parport.h jtagkey.h config.h jtagmon.h
+
+ifeq ($(LIBVER),32)
+CFLAGS += -m32
+endif
+
+FTDI := $(shell libftdi-config --libs 2>/dev/null)
+ifneq ($(FTDI),)
+SRC += jtagkey.c
+CFLAGS += -DJTAGKEY
+LIBS += $(FTDI)
+endif
+
+SOBJECTS=libusb-driver.so libusb-driver-DEBUG.so
+
+all: $(SOBJECTS)
+       @file libusb-driver.so | grep x86-64 >/dev/null && echo Built library is 64 bit. Run \`make lib32\' to build a 32 bit version || true
+
+libusb-driver.so: $(SRC) $(HEADER) Makefile
+       $(CC) $(CFLAGS) $(SRC) -o $@ $(LIBS) -shared
+
+libusb-driver-DEBUG.so: $(SRC) $(HEADER) Makefile
+       $(CC) -DDEBUG $(CFLAGS) $(SRC) -o $@ $(LIBS) -shared
+
+lib32:
+       $(MAKE) LIBVER=32 clean all
+
+clean:
+       rm -f $(SOBJECTS)
+
+.PHONY: clean all lib32
diff --git a/misc/README b/misc/README
new file mode 100644 (file)
index 0000000..f69cadd
--- /dev/null
@@ -0,0 +1,151 @@
+This library emulates Jungo Windrvr USB and parallel port functions in
+userspace which are required by XILINX impact to access the Platform cable USB
+and Parallel Cable III.
+With this library it is possible to access the cables without loading a
+proprietary kernel module which breaks with every new kernel release. It uses
+the functionality provided by the libusb userspace library for USB access and
+the kernel interface at /dev/parport0 for parallel port access instead and
+should work on every kernel version which is supported by libusb and supports
+ppdev. It was written against impact from ISE Webpack 9.1SP1 and tested with
+the following software:
+
+ * ISE Webpack 9.2SP1, SP2, SP3
+ * ISE Webpack 9.1SP1, SP2, SP3
+ * ISE Webpack 8.2SP3
+ * ISE Webpack 8.1SP3
+ * ChipScope 9.2.01i, 9.2.02i
+ * ChipScope 9.1.02i, 9.1.03i
+ * ChipScope 8.2.04i
+ * EDK 9.2.01i
+ * EDK 9.1.01i, 9.1.02i
+ * EDK 8.2.02i
+ * EDK 8.1.02i
+ * Synplicity Identify
+
+In addition to the XILINX USB and parallel cables, devices based on the FTDI
+2232 serial converter chip are also experimentally supported. This includes
+devices like the Amontec JTAGkey(-Tiny).
+
+Build the library by calling `make'. If you are on a 64 bit system but want
+to build a 32 bit library, run `make lib32' instead.
+
+To use this library you have to preload the library before starting impact:
+
+$ LD_PRELOAD=/path/to/libusb-driver.so impact
+or
+$ export LD_PRELOAD=/path/to/libusb-driver.so  (for sh shells)
+$ setenv LD_PRELOAD /path/to/libusb-driver.so  (for csh shells)
+$ impact
+
+The source for this library can be found at:
+http://git.zerfleddert.de/cgi-bin/gitweb.cgi/usb-driver
+
+The main website is located at:
+http://www.rmdir.de/~michael/xilinx/
+
+The Git repository can be cloned with:
+git clone git://git.zerfleddert.de/usb-driver
+
+
+Notes for the USB cable
+=======================
+
+To use the device as an ordinary user, put the following line in a new
+file "libusb-driver.rules" in /etc/udev/rules.d/ and restart udev:
+ACTION=="add", BUS=="usb", SYSFS{idVendor}=="03fd", MODE="666"
+
+
+If your cable does not have the ID 03fd:0008 in the output of lsusb,
+the initial firmware has not been loaded (loading it changes the
+product-ID from another value to 8). To load the firmware follow
+these steps:
+
+1. If you have no /etc/udev/rules.d/xusbdfwu.rules file, copy it from
+   /path/to/ISE/bin/lin/xusbdfwu.rules to /etc/udev/rules.d/xusbdfwu.rules
+
+2. Install the package containing /sbin/fxload from your linux distribution.
+   It is usually called "fxload"
+
+3. copy the files /path/to/ISE/bin/lin/xusb*.hex to /usr/share/
+
+4. restart udev and re-plug the cable
+
+
+If you have multiple cables connected, you can specify the cable to use
+in the XILINX_USB_DEV environment-variable as "bus:device".
+These identifiers are available in the output of lsusb:
+Bus 001 Device 004: ID 03fd:0008 Xilinx, Inc.
+    ^^^        ^^^
+To use this cable, set the XILINX_USB_DEV variable to "001:004".
+
+
+Notes for the parallel cable
+============================
+
+To access the parallel port from userspace, the kernel needs to be built with
+the features "Parallel port support" (CONFIG_PARPORT), "PC-style hardware"
+(CONFIG_PARPORT_PC) and "Support for user-space parallel port device drivers"
+(CONFIG_PPDEV) builtin or as modules. If these features are built as modules,
+they need to be loaded before using this library.
+These modules are called:
+parport
+parport_pc
+ppdev
+
+
+To use the device as an ordinary user, put the user in the group 'lp'
+
+
+If you have an almost compatible cable which works with other software but not
+with Impact, try adding -DFORCE_PC3_IDENT to the CFLAGS line in the Makefile.
+This enables a hack by Stefan Ziegenbalg to force detection of a parallel cable.
+
+
+Parallel Cable IV is currently only supported in 'compatibility mode', as no
+attempt to configure the ECP registers is done by this library.
+
+
+If you get "Programming failed" or "DONE did not go high" when programming
+through the parallel cable with Impact 9.1, make sure to have the option "Use
+HIGHZ instead of BYPASS" enabled in Edit -> Preferences -> iMPACT Configuration
+Preferences.
+If you are using batch mode, add the following line to your cmd file:
+setPreference -pref UseHighz:TRUE
+(This problem also occurs on windows and when using the real windrvr in linux
+and is solved with the same workaround. Impact 8.2 is working fine with the same
+boards and designs)
+
+
+Notes for FTDI 2232 based cables
+================================
+
+To build the driver with FTDI 2232 support, you need to have libftdi and
+the libftdi development package installed. On debian, you can install both
+by installing 'libftdi-dev'.
+
+To set-up the device:
+1. Find out the vendor and product id of your cable using lsusb:
+   Bus 003 Device 005: ID 0403:cff8 Future Technology Devices ...
+                          ~~~~~~~~~
+
+2. Copy the sample libusb-driverrc to ~/.libusb-driverrc, edit it and replace
+   the vendor and product-id in the example file with the values provided in
+   the lsusb-output. You can also change the 'parallel port' which is mapped to
+   this cable. Impact sees the device at that port as a Parallel Cable III.
+
+3. To use the device as an ordinary user, put the following line in a new file
+   in /etc/udev/rules.d/ and restart udev:
+   ACTION=="add", BUS=="usb", SYSFS{idVendor}=="0403", SYSFS{idProduct}=="cff8", MODE="666"
+   (replace the vendor and product id with your values)
+
+The support for FTDI 2232 based devices is experimental and they are currently
+significantly slower than the other supported cables.
+
+
+Locked cables
+=============
+
+If you get the message 'The cable is being used by another application.' from
+impact, try running the following command:
+
+echo -e 'cleancablelock\nexit' | impact -batch
diff --git a/misc/config.c b/misc/config.c
new file mode 100644 (file)
index 0000000..a39902e
--- /dev/null
@@ -0,0 +1,245 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include "usb-driver.h"
+#include "parport.h"
+#ifdef JTAGKEY
+#include "jtagkey.h"
+#endif
+#include "config.h"
+
+#define LINELEN 1024
+
+#define PARSEERROR fprintf(stderr,"LIBUSB-DRIVER WARNING: Invalid config statement at line %d\n", line)
+
+static struct parport_config pp_config[4];
+
+static void read_config() {
+       int i;
+       static int config_read = 0;
+       FILE *cfg;
+       char buf[LINELEN];
+#ifdef JTAGKEY
+       char *pbuf;
+       unsigned short vid, pid;
+       int line, len, num;
+#endif
+
+       if (config_read)
+               return;
+       
+       config_read = 1;
+
+       for (i=0; i<sizeof(pp_config)/sizeof(struct parport_config); i++) {
+               pp_config[i].num = i;
+               pp_config[i].ppbase = i*0x10;
+               pp_config[i].real = 1;
+               pp_config[i].open = parport_open;
+               pp_config[i].close = parport_close;
+               pp_config[i].transfer = parport_transfer;
+       }
+
+       snprintf(buf, sizeof(buf), "%s/.libusb-driverrc", getenv("HOME"));
+
+       cfg = fopen(buf, "r");
+       if (cfg) {
+#ifdef JTAGKEY
+               line = 0;
+               do {
+                       pbuf = fgets(buf, sizeof(buf), cfg);
+                       if (!pbuf)
+                               break;
+
+                       line++;
+
+                       len = strlen(buf);
+
+                       if (len > 0 && buf[len-1] == '\n') {
+                               buf[len-1] = '\0';
+                               len--;
+                       }
+                       if (len > 0 && buf[len-1] == '\r') {
+                               buf[len-1] = '\0';
+                               len--;
+                       }
+                       
+                       for (i = 0; i < len; i++) {
+                               if (buf[i] != ' ' && buf[i] != '\t')
+                                       break;
+                       }
+
+                       if (buf[i] == '#' || buf[i] == ';' || buf[i] == '\0')
+                               continue;
+
+                       if (!strncasecmp(buf+i, "LPT", 3)) {
+                               unsigned char equal_seen = 0;
+
+                               i += 3;
+                               pbuf = buf+i;
+                               for (; i < len; i++) {
+                                       if (buf[i] == ' ' || buf[i] == '\t' || buf[i] == '=') {
+                                               if (buf[i] == '=')
+                                                       equal_seen = 1;
+
+                                               buf[i] = '\0';
+                                               i++;
+                                               break;
+                                       }
+                               }
+
+                               if (*pbuf == '\0') {
+                                       PARSEERROR;
+                                       continue;
+                               }
+
+                               num = 0;
+                               num = strtol(pbuf, NULL, 10);
+                               if (num < 1) {
+                                       PARSEERROR;
+                                       continue;
+                               }
+                               num--;
+
+                               for (; (i < len) && (!equal_seen) ; i++) {
+                                       if (buf[i] == '=') {
+                                               equal_seen = 1;
+                                               i++;
+                                               break;
+                                       } else if (buf[i] != ' ' && buf[i] != '\t') {
+                                               break;
+                                       }
+                               }
+
+                               if (!equal_seen) {
+                                       PARSEERROR;
+                                       continue;
+                               }
+
+                               for (; i < len; i++) {
+                                       if (buf[i] != ' ' && buf[i] != '\t')
+                                               break;
+                               }
+
+                               if (strncasecmp(buf+i, "FTDI:", 5)) {
+                                       PARSEERROR;
+                                       continue;
+                               }
+
+                               i += 5;
+                               pbuf = buf + i;
+
+                               for (; i < len; i++) {
+                                       if (buf[i] == ':')
+                                               break;
+                               }
+
+                               if (buf[i] != ':') {
+                                       PARSEERROR;
+                                       continue;
+                               }
+
+                               buf[i] = '\0';
+
+                               vid = 0;
+                               vid = strtol(pbuf, NULL, 16);
+                               if (!vid) {
+                                       PARSEERROR;
+                                       continue;
+                               }
+
+                               i++;
+                               pbuf = buf + i;
+
+                               for (; i < len; i++) {
+                                       if (buf[i] == ' ' || buf[i] == '\t')
+                                               break;
+                               }
+
+                               pid = 0;
+                               pid = strtol(pbuf, NULL, 16);
+                               if (!pid) {
+                                       PARSEERROR;
+                                       continue;
+                               }
+
+                               pp_config[num].real = 0;
+                               pp_config[num].usb_vid = vid;
+                               pp_config[num].usb_pid = pid;
+                               pp_config[num].open = jtagkey_open;
+                               pp_config[num].close = jtagkey_close;
+                               pp_config[num].transfer = jtagkey_transfer;
+                       } else {
+                               PARSEERROR;
+                       }
+               } while (pbuf);
+#else
+               fprintf(stderr,"libusb-driver not compiled with FTDI2232-support, config file ignored!\n");
+#endif
+               fclose(cfg);
+       }
+}
+
+struct parport_config *config_get(int num) {
+       struct parport_config *ret = NULL;
+       int i;
+
+       read_config();
+       
+       for (i=0; i<sizeof(pp_config)/sizeof(struct parport_config); i++) {
+               if (pp_config[i].num == num) {
+                       ret = &(pp_config[i]);
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+unsigned char config_is_real_pport(int num) {
+       int ret = 1;
+       int i;
+
+       read_config();
+       
+       for (i=0; i<sizeof(pp_config)/sizeof(struct parport_config); i++) {
+               if (pp_config[i].num == num) {
+                       ret = pp_config[i].real;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+unsigned short config_usb_vid(int num) {
+       unsigned short ret = 0x00;
+       int i;
+       
+       read_config();
+       
+       for (i=0; i<sizeof(pp_config)/sizeof(struct parport_config); i++) {
+               if (pp_config[i].num == num) {
+                       ret = pp_config[i].usb_vid;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+unsigned short config_usb_pid(int num) {
+       unsigned short ret = 0x00;
+       int i;
+       
+       read_config();
+       
+       for (i=0; i<sizeof(pp_config)/sizeof(struct parport_config); i++) {
+               if (pp_config[i].num == num) {
+                       ret = pp_config[i].usb_pid;
+                       break;
+               }
+       }
+
+       return ret;
+}
diff --git a/misc/config.h b/misc/config.h
new file mode 100644 (file)
index 0000000..e3e42ea
--- /dev/null
@@ -0,0 +1,15 @@
+struct parport_config {
+       int num;
+       unsigned long ppbase;
+       unsigned char real;
+       unsigned short usb_vid;
+       unsigned short usb_pid;
+       int (*open) (int num);
+       void (*close) (int handle);
+       int (*transfer) (WD_TRANSFER *tr, int fd, unsigned int request, int ppbase, int ecpbase, int num);
+};
+
+struct parport_config *config_get(int num);
+unsigned char config_is_real_pport(int num);
+unsigned short config_usb_vid(int num);
+unsigned short config_usb_pid(int num);
diff --git a/misc/index.html b/misc/index.html
new file mode 100644 (file)
index 0000000..9066731
--- /dev/null
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<HTML>
+       <HEAD>
+               <TITLE>XILINX USB/Parallel JTAG cables on Linux without windrvr</TITLE>
+       </HEAD>
+       <BODY BGCOLOR="#FFFFFF" TEXT="#000000">
+               <H1>XILINX JTAG tools on Linux without proprietary kernel modules</H1>
+               <H2>About</H2>
+               <P>
+               When using <a href="http://www.xilinx.com">XILINX</a> JTAG software like Impact, Chipscope and XMD
+               on Linux, the proprietary kernel module <i>windrvr</i> from <a href="http://www.jungo.com">Jungo</a>
+               is needed to access the parallel- or usb-cable.
+               As this module does not work with current linux kernel versions (&gt; 2.6.18) a library was developed,
+               which emulates the module in userspace and allows the tools to access the JTAG cable without the need
+               for a proprietary kernel module.
+               </P>
+               <P>
+               The library uses <a href="http://libusb.sourceforge.net/">libusb</a> to access USB devices and the
+               <a href="http://people.redhat.com/twaugh/parport/html/x623.html">ppdev</a> interface to communicate
+               with parallel cables. The parallel part currently only supports Parallel Cable III mode (and PCIV in
+               PCIII compatibility mode) as the faster PCIV modes use another kernel module which is not emulated by
+               this library. So you are limited to a 200kHz JTAG clock when using Parallel Cable IV with this software.
+               The USB cable is supported at full speed.
+               </P>
+               <P>
+               Experimental support for FTDI 2232 based devices has been added. They are seen by Impact as a Parallel
+               Cable III. These devices are currently significantly slower than every other supported cable.
+               </P>
+               <P>
+               The library is called <i>libusb-driver</i> as it was developed to support the USB cable, but later
+               extended to also support parallel cables.
+               </P>
+               <H2>Supported Cables</H2>
+               The following cables are reported to work with this driver:
+               <ul>
+                       <li><a href="http://direct.xilinx.com/bvdocs/publications/ds300.pdf">XILINX Platform Cable USB DLC9, DLC9LP and DLC9G</a></li>
+                       <li><a href="http://www.xilinx.com/s3estarter">Integrated Platform Cable USB on Spartan 3E starter kit</a></li>
+                       <li><a href="http://www.xilinx.com/s3astarter">Integrated Platform Cable USB on Spartan 3A starter kit</a></li>
+                       <li><a href="http://www.digilentinc.com/Products/Detail.cfm?Nav1=Products&Nav2=Programmable&Prod=XUPV2P">Integrated Platform Cable USB on XUP-V2Pro</a></li>
+                       <li><a href="http://direct.xilinx.com/bvdocs/publications/ds097.pdf">XILINX Parallel Cable IV</a> (in Parallel Cable III compatibility mode)</li>
+                       <li><a href="http://www.enterpoint.co.uk/">Enterpoint Prog2</a> Parallel Cable III clone</li>
+                       <li><a href="http://www.trenz-electronic.de/">Trenz TE0149-01</a> Parallel Cable III clone</li>
+                       <li><a href="http://www.digilentinc.com/Products/Catalog.cfm?Nav1=Products&amp;Nav2=Cables&amp;Cat=Cable">Digilent JTAG3</a> Parallel Cable III clone</li>
+                       <li><a href="http://www.amontec.com/">Amontec JTAGkey-Tiny</a> (experimental)</li>
+               </ul>
+               These cables should work but have not yet been tested:
+               <ul>
+                       <li>Integrated Platform Cable USB on other development boards</li>
+                       <li>other Parallel Cable III clones</li>
+                       <li>other FTDI2232 based devices which use the chips standard JTAG pinout (experimental)</li>
+               </ul>
+               <H2>Supported Software</H2>
+               The following software is reported to work with this driver:
+               <ul>
+                       <li><a href="http://www.xilinx.com/ise/logic_design_prod/webpack.htm">ISE Webpack 9.2 SP1, SP2 and SP3</a></li>
+                       <li><a href="http://www.xilinx.com/ise/logic_design_prod/webpack.htm">ISE Webpack 9.1 SP1, SP2 and SP3</a></li>
+                       <li><a href="http://www.xilinx.com/ise/logic_design_prod/webpack.htm">ISE Webpack 8.2 SP3</a></li>
+                       <li><a href="http://www.xilinx.com/ise/logic_design_prod/webpack.htm">ISE Webpack 8.1 SP3</a></li>
+                       <li><a href="http://www.xilinx.com/ise/optional_prod/cspro.htm">ChipScope Pro 9.2.01i</a></li>
+                       <li><a href="http://www.xilinx.com/ise/optional_prod/cspro.htm">ChipScope Pro 9.1.02i and 9.1.03i</a></li>
+                       <li><a href="http://www.xilinx.com/ise/optional_prod/cspro.htm">ChipScope Pro 8.2.04i</a></li>
+                       <li><a href="http://www.xilinx.com/ise/embedded_design_prod/platform_studio.htm">EDK 9.2.01i</a></li>
+                       <li><a href="http://www.xilinx.com/ise/embedded_design_prod/platform_studio.htm">EDK 9.1.01i and 9.1.02i</a></li>
+                       <li><a href="http://www.xilinx.com/ise/embedded_design_prod/platform_studio.htm">EDK 8.2.02i</a></li>
+                       <li><a href="http://www.xilinx.com/ise/embedded_design_prod/platform_studio.htm">EDK 8.1.02i</a></li>
+                       <li><a href="http://www.synplicity.com/products/identify/index.html">Synplicity Identify Debugger</a></li>
+               </ul>
+               <H2>Download</H2>
+               <ul>
+                       <li>Download <a href="http://git.zerfleddert.de/cgi-bin/gitweb.cgi/usb-driver?a=snapshot;h=HEAD;sf=tgz">usb-driver-HEAD.tar.gz</a> (to build it, you need to have the libusb development package installed. It is called libusb-dev on Debian.)</li>
+                       <li>Read the <a href="http://git.zerfleddert.de/cgi-bin/gitweb.cgi/usb-driver?a=blob_plain;f=README;hb=HEAD">README</a></li>
+                       <li>Browse the <a href="http://git.zerfleddert.de/cgi-bin/gitweb.cgi/usb-driver?a=tree">Git repository</a> (<a href="http://git.zerfleddert.de/cgi-bin/gitweb.cgi/usb-driver">Summary</a>)</li>
+                       <li>Precompiled <a href="libusb-driver.so">libusb-driver.so</a> for Debian Etch, but better build your own</li>
+                       <li>Clone the <a href="http://git.or.cz/">Git</a> repository with: <kbd>git clone git://git.zerfleddert.de/usb-driver</kbd></li>
+               </ul>
+               <H2>Links</H2>
+               <ul>
+                       <li><a href="http://groups.google.com/group/comp.arch.fpga/msg/94d8bb1f52e06b44">XILINX listened</a></li>
+                       <li><a href="http://svenand.blogdrive.com/archive/55.html">Installation instructions using a MacBook running Ubuntu in VMware by Sven Andersson</a></li>
+                       <li><a href="http://groups.google.com/group/comp.arch.fpga/browse_thread/thread/954a145428ec2c54/555f6bfb766a3a93#555f6bfb766a3a93">Using the libusb-driver on a 64bit system with a 32bit ISE by Ken Ryan</a></li>
+                       <li><a href="http://groups.google.com/group/comp.arch.fpga/msg/2dfa36541174a4f2">Ubuntu installation instructions by Luzerne</a></li>
+                       <li><a href="http://www.itee.uq.edu.au/~listarch/microblaze-uclinux/archive/2007/03/msg00101.html">Ubuntu installation instructions by Paul-Armand Verhaegen</a></li>
+                       <li><a href="http://groups.google.com/group/comp.arch.fpga/browse_frm/thread/f149e5b6028e2c70">Initial announcement on comp.arch.fpga</a></li>
+                       <li><a href="http://inisyn.org/src/xup/">XUP</a> by inisyn research, opensource JTAG programming for Spartan 3E starter kit USB cable</li>
+                       <li><a href="http://www.ixo.de/info/usb_jtag/">USB JTAG adapter</a> by Kolja Waschk, opensource integration of the XILINX platform cable USB into OpenOCD and openwince JTAG Tools</li>
+                       <li><a href="http://www.rogerstech.co.uk/xc3sprog/">Spartan3 JTAG download tools for GNU/Linux (xc3sprog)</a></li>
+               </ul>
+               <HR>
+               <FONT SIZE="-1"><I><A HREF="mailto:cabledriver@zerfleddert.de">Michael Gernoth</A></I></FONT>
+       </BODY>
+</HTML>
diff --git a/misc/jtagkey.c b/misc/jtagkey.c
new file mode 100644 (file)
index 0000000..fc9587c
--- /dev/null
@@ -0,0 +1,376 @@
+#include <stdio.h>
+#include <ftdi.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <inttypes.h>
+#include "usb-driver.h"
+#include "config.h"
+#include "jtagkey.h"
+#include "jtagmon.h"
+
+#define USBBUFSIZE 1048576
+#define JTAG_SPEED 100000
+#define BULK_LATENCY 2
+#define OTHER_LATENCY 1
+
+static struct ftdi_context ftdic;
+
+static int jtagkey_latency(int latency) {
+       static int current = 0;
+       int ret;
+
+       if (current != latency) {
+               DPRINTF("switching latency\n");
+               if ((ret = ftdi_set_latency_timer(&ftdic, latency))  != 0) {
+                       fprintf(stderr, "unable to set latency timer: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
+                       return ret;
+               }
+               
+               current = latency;
+       }
+
+       return ret;
+}
+
+static int jtagkey_init(unsigned short vid, unsigned short pid) {
+       int ret = 0;
+       unsigned char c;
+
+       if ((ret = ftdi_init(&ftdic)) != 0) {
+               fprintf(stderr, "unable to initialise libftdi: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
+               return ret;
+       }
+       
+       if ((ret = ftdi_usb_open(&ftdic, vid, pid)) != 0) {
+               fprintf(stderr, "unable to open ftdi device: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
+               return ret;
+       }
+
+       if ((ret = ftdi_usb_reset(&ftdic)) != 0) {
+               fprintf(stderr, "unable reset device: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
+               return ret;
+       }
+
+       if ((ret = ftdi_set_interface(&ftdic, INTERFACE_A)) != 0) {
+               fprintf(stderr, "unable to set interface: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
+               return ret;
+       }
+
+       if ((ret = ftdi_write_data_set_chunksize(&ftdic, USBBUFSIZE))  != 0) {
+               fprintf(stderr, "unable to set write chunksize: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
+               return ret;
+       }
+
+       if ((ret = ftdi_read_data_set_chunksize(&ftdic, USBBUFSIZE))  != 0) {
+               fprintf(stderr, "unable to set read chunksize: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
+               return ret;
+       }
+
+       if ((ret = jtagkey_latency(OTHER_LATENCY)) != 0)
+               return ret;
+
+       c = 0x00;
+       ftdi_write_data(&ftdic, &c, 1);
+
+       if ((ret = ftdi_set_bitmode(&ftdic, JTAGKEY_TCK|JTAGKEY_TDI|JTAGKEY_TMS|JTAGKEY_OEn, BITMODE_SYNCBB))  != 0) {
+               fprintf(stderr, "unable to enable bitbang mode: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
+               return ret;
+       }
+
+       if ((ret = ftdi_set_baudrate(&ftdic, JTAG_SPEED))  != 0) {
+               fprintf(stderr, "unable to set baudrate: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
+               return ret;
+       }
+
+       if ((ret = ftdi_usb_purge_buffers(&ftdic))  != 0) {
+               fprintf(stderr, "unable to purge buffers: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
+               return ret;
+       }
+
+       return ret;
+}
+
+int jtagkey_open(int num) {
+       int ret;
+
+       ret = jtagkey_init(config_usb_vid(num), config_usb_pid(num));
+
+       if (ret >= 0)
+               ret = 0xff;
+
+       return ret;
+}
+
+void jtagkey_close(int handle) {
+       if (handle == 0xff) {
+               ftdi_disable_bitbang(&ftdic);
+               ftdi_usb_close(&ftdic);
+               ftdi_deinit(&ftdic);
+       }
+}
+
+#ifdef DEBUG
+static void jtagkey_state(unsigned char data) {
+       fprintf(stderr,"Pins high: ");
+
+       if (data & JTAGKEY_TCK)
+               fprintf(stderr,"TCK ");
+
+       if (data & JTAGKEY_TDI)
+               fprintf(stderr,"TDI ");
+
+       if (data & JTAGKEY_TDO)
+               fprintf(stderr,"TDO ");
+
+       if (data & JTAGKEY_TMS)
+               fprintf(stderr,"TMS ");
+
+       if (data & JTAGKEY_VREF)
+               fprintf(stderr,"VREF ");
+       
+       fprintf(stderr,"\n");
+}
+#endif
+
+struct jtagkey_reader_arg {
+       int             num;
+       unsigned char   *buf;
+};
+
+static void *jtagkey_reader(void *thread_arg) {
+       struct jtagkey_reader_arg *arg = (struct jtagkey_reader_arg*)thread_arg;
+       int i;
+
+       i = 0;
+       DPRINTF("reader for %d bytes\n", arg->num);
+       while (i < arg->num) {
+               i += ftdi_read_data(&ftdic, arg->buf + i, arg->num - i);
+       }
+       
+       pthread_exit(NULL);
+}
+
+/* TODO: Interpret JTAG commands and transfer in MPSSE mode */
+int jtagkey_transfer(WD_TRANSFER *tr, int fd, unsigned int request, int ppbase, int ecpbase, int num) {
+       int ret = 0;
+       int i;
+       int nread = 0;
+       unsigned long port;
+       unsigned char val;
+       static unsigned char last_data = 0;
+       static unsigned char last_write = 0x00;
+       static unsigned char writebuf[USBBUFSIZE], *writepos = writebuf;
+       static unsigned char readbuf[USBBUFSIZE], *readpos;
+       unsigned char data, prev_data, last_cyc_write;
+       struct jtagkey_reader_arg targ;
+       pthread_t reader_thread;
+
+       /* Count reads */
+       for (i = 0; i < num; i++)
+               if (tr[i].cmdTrans == PP_READ)
+                       nread++;
+
+       /* Write combining */
+       if ((writepos-writebuf > sizeof(writebuf)-num) || (nread && writepos-writebuf)) {
+               unsigned char *pos = writebuf;
+               int len;
+
+               DPRINTF("writing %d bytes due to %d following reads in %d chunks or full buffer\n", writepos-writebuf, nread, num);
+               jtagkey_latency(BULK_LATENCY);
+
+               targ.num = writepos-pos;
+               targ.buf = readbuf;
+               pthread_create(&reader_thread, NULL, &jtagkey_reader, &targ);
+
+               while (pos < writepos) {
+                       len = writepos-pos;
+
+                       if (len > USBBUFSIZE)
+                               len = USBBUFSIZE;
+
+                       DPRINTF("combined write of %d/%d\n",len,writepos-pos);
+                       ftdi_write_data(&ftdic, pos, len);
+                       pos += len;
+               }
+               pthread_join(reader_thread, NULL);
+
+               writepos = writebuf;
+       }
+
+       last_cyc_write = last_write;
+
+       for (i = 0; i < num; i++) {
+               DPRINTF("dwPort: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n",
+                               (unsigned long)tr[i].dwPort, tr[i].cmdTrans, tr[i].dwBytes,
+                               tr[i].fAutoinc, tr[i].dwOptions);
+
+               port = (unsigned long)tr[i].dwPort;
+               val = tr[i].Data.Byte;
+
+#ifdef DEBUG
+               if (tr[i].cmdTrans == 13)
+                       DPRINTF("write byte: %d\n", val);
+
+               if (tr[i].cmdTrans == 13)
+                       jtagmon(val & PP_TCK, val & PP_TMS, val & PP_TDI);
+#endif
+
+               /* Pad writebuf for read-commands in stream */
+               *writepos = last_data;
+               prev_data = last_data;
+
+               if (port == ppbase + PP_DATA) {
+                       DPRINTF("data port\n");
+
+                       data = 0x00;
+                       switch(tr[i].cmdTrans) {
+                               case PP_READ:
+                                       ret = 0; /* We don't support reading of the data port */
+                                       break;
+
+                               case PP_WRITE:
+                                       if (val & PP_TDI) {
+                                               data |= JTAGKEY_TDI;
+                                               DPRINTF("TDI\n");
+                                       } else {
+                                               DPRINTF("!TDI\n");
+                                       }
+                                       if (val & PP_TCK) {
+                                               data |= JTAGKEY_TCK;
+                                               DPRINTF("TCK\n");
+                                       } else {
+                                               DPRINTF("!TCK\n");
+                                       }
+                                       if (val & PP_TMS) {
+                                               data |= JTAGKEY_TMS;
+                                               DPRINTF("TMS\n");
+                                       } else {
+                                               DPRINTF("!TMS\n");
+                                       }
+                                       if (val & PP_CTRL) {
+                                               data = JTAGKEY_OEn;
+                                               DPRINTF("CTRL\n");
+                                       } else {
+                                               DPRINTF("!CTRL\n");
+                                       }
+
+                                       if (val & PP_PROG) {
+                                               DPRINTF("PROG\n");
+                                       } else {
+                                               DPRINTF("!PROG\n");
+                                       }
+
+                                       *writepos = data;
+
+                                       last_data = data;
+                                       last_write = val;
+                                       break;
+
+                               default:
+                                       fprintf(stderr,"!!!Unsupported TRANSFER command: %lu!!!\n", tr[i].cmdTrans);
+                                       ret = -1;
+                                       break;
+                       }
+               }
+
+               if ((tr[i].cmdTrans == PP_READ) || (*writepos != prev_data) || (i == num-1))
+                       writepos++;
+       }
+
+       if (nread)
+       {
+               DPRINTF("writing %d bytes\n", writepos-writebuf);
+
+               *writepos = last_data;
+               writepos++;
+
+               jtagkey_latency(OTHER_LATENCY);
+
+               targ.num = writepos-writebuf;
+               targ.buf = readbuf;
+               pthread_create(&reader_thread, NULL, &jtagkey_reader, &targ);
+               ftdi_write_data(&ftdic, writebuf, writepos-writebuf);
+               pthread_join(reader_thread, NULL);
+
+#ifdef DEBUG
+               DPRINTF("write: ");
+               hexdump(writebuf, writepos-writebuf);
+               DPRINTF("read: ");
+               hexdump(readbuf, i);
+#endif
+
+               writepos = writebuf;
+       } else {
+               return ret;
+       }
+
+       readpos = readbuf;
+       last_write = last_cyc_write;
+
+       for (i = 0; i < num; i++) {
+               DPRINTF("dwPort: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n",
+                               (unsigned long)tr[i].dwPort, tr[i].cmdTrans, tr[i].dwBytes,
+                               tr[i].fAutoinc, tr[i].dwOptions);
+
+               port = (unsigned long)tr[i].dwPort;
+               val = tr[i].Data.Byte;
+
+               if ((tr[i].cmdTrans != PP_READ) && (val == last_write) && (i != num-1))
+                       continue;
+
+               readpos++;
+
+               if (port == ppbase + PP_DATA) {
+                       if (tr[i].cmdTrans == PP_WRITE) {
+                               last_write = val;
+                       }
+               } else if (port == ppbase + PP_STATUS) {
+                       DPRINTF("status port (last write: 0x%x)\n", last_write);
+                       switch(tr[i].cmdTrans) {
+                               case PP_READ:
+                                       data = *readpos;
+
+#ifdef DEBUG
+                                       DPRINTF("READ: 0x%x\n", data);
+                                       jtagkey_state(data);
+#endif
+
+                                       val = 0x00;
+                                       if ((data & JTAGKEY_TDO) && (last_write & PP_PROG))
+                                               val |= PP_TDO;
+
+                                       if (~last_write & PP_PROG)
+                                               val |= 0x08;
+
+                                       if (last_write & 0x40)
+                                               val |= 0x20;
+                                       else
+                                               val |= 0x80;
+                                       break;
+
+                               case PP_WRITE:
+                                       ret = 0; /* Status Port is readonly */
+                                       break;
+
+                               default:
+                                       fprintf(stderr,"!!!Unsupported TRANSFER command: %lu!!!\n", tr[i].cmdTrans);
+                                       ret = -1;
+                                       break;
+                       }
+               } else {
+                       ret = 0;
+               }
+
+               tr[i].Data.Byte = val;
+
+               DPRINTF("dwPortReturn: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n",
+                               (unsigned long)tr[i].dwPort, tr[i].cmdTrans, tr[i].dwBytes,
+                               tr[i].fAutoinc, tr[i].dwOptions);
+#ifdef DEBUG
+               if (tr[i].cmdTrans == 10)
+                       DPRINTF("read byte: %d\n", tr[i].Data.Byte);
+#endif
+       }
+
+       return ret;
+}
diff --git a/misc/jtagkey.h b/misc/jtagkey.h
new file mode 100644 (file)
index 0000000..2c13260
--- /dev/null
@@ -0,0 +1,10 @@
+#define JTAGKEY_TCK    0x01
+#define JTAGKEY_TDI    0x02
+#define JTAGKEY_TDO    0x04
+#define JTAGKEY_TMS    0x08
+#define JTAGKEY_VREF   0x20
+#define JTAGKEY_OEn    0x10
+
+int jtagkey_transfer(WD_TRANSFER *tr, int fd, unsigned int request, int ppbase, int ecpbase, int num);
+int jtagkey_open(int num);
+void jtagkey_close(int handle);
diff --git a/misc/jtagmon.c b/misc/jtagmon.c
new file mode 100644 (file)
index 0000000..1a71ce0
--- /dev/null
@@ -0,0 +1,214 @@
+#include <string.h>
+#include <stdio.h>
+#include "jtagmon.h"
+
+enum tap_states {
+       TEST_LOGIC_RESET,
+       RUN_TEST_IDLE,
+       SELECT_DR,
+       CAPTURE_DR,
+       SHIFT_DR,
+       EXIT1_DR,
+       PAUSE_DR,
+       EXIT2_DR,
+       UPDATE_DR,
+       SELECT_IR,
+       CAPTURE_IR,
+       SHIFT_IR,
+       EXIT1_IR,
+       PAUSE_IR,
+       EXIT2_IR,
+       UPDATE_IR
+};
+
+void jtagmon(unsigned char tck, unsigned char tms, unsigned char tdi) {
+       static unsigned char last_tck = 1;
+       static char tdi_written = 0;
+       static int state = TEST_LOGIC_RESET;
+       static char state_text[32] = "Test Logic Reset";
+       char last_state_text[32];
+       int last_state = state;
+
+       strcpy(last_state_text, state_text);
+
+       if (!last_tck && tck) {
+               switch(state) {
+                       case TEST_LOGIC_RESET:
+                               if (tms) {
+                                       state = TEST_LOGIC_RESET;
+                               } else {
+                                       state = RUN_TEST_IDLE;
+                               }
+                               break;
+                       case RUN_TEST_IDLE:
+                               if (tms) {
+                                       state = SELECT_DR;
+                               } else {
+                                       state = RUN_TEST_IDLE;
+                               }
+                               break;
+                       case SELECT_DR:
+                               if (tms) {
+                                       state = SELECT_IR;
+                               } else {
+                                       state = CAPTURE_DR;
+                               }
+                               break;
+                       case CAPTURE_DR:
+                               if (tms) {
+                                       state = EXIT1_DR;
+                               } else {
+                                       state = SHIFT_DR;
+                               }
+                               break;
+                       case SHIFT_DR:
+                               if (tms) {
+                                       state = EXIT1_DR;
+                               } else {
+                                       state = SHIFT_DR;
+                               }
+                               break;
+                       case EXIT1_DR:
+                               if (tms) {
+                                       state = UPDATE_DR;
+                               } else {
+                                       state = PAUSE_DR;
+                               }
+                               break;
+                       case PAUSE_DR:
+                               if (tms) {
+                                       state = EXIT2_DR;
+                               } else {
+                                       state = PAUSE_DR;
+                               }
+                               break;
+                       case EXIT2_DR:
+                               if (tms) {
+                                       state = UPDATE_DR;
+                               } else {
+                                       state = SHIFT_DR;
+                               }
+                               break;
+                       case UPDATE_DR:
+                               if (tms) {
+                                       state = SELECT_DR;
+                               } else {
+                                       state = RUN_TEST_IDLE;
+                               }
+                               break;
+                       case SELECT_IR:
+                               if (tms) {
+                                       state = TEST_LOGIC_RESET;
+                               } else {
+                                       state = CAPTURE_IR;
+                               }
+                               break;
+                       case CAPTURE_IR:
+                               if (tms) {
+                                       state = EXIT1_IR;
+                               } else {
+                                       state = SHIFT_IR;
+                               }
+                               break;
+                       case SHIFT_IR:
+                               if (tms) {
+                                       state = EXIT1_IR;
+                               } else {
+                                       state = SHIFT_IR;
+                               }
+                               break;
+                       case EXIT1_IR:
+                               if (tms) {
+                                       state = UPDATE_IR;
+                               } else {
+                                       state = PAUSE_IR;
+                               }
+                               break;
+                       case PAUSE_IR:
+                               if (tms) {
+                                       state = EXIT2_IR;
+                               } else {
+                                       state = PAUSE_IR;
+                               }
+                               break;
+                       case EXIT2_IR:
+                               if (tms) {
+                                       state = UPDATE_IR;
+                               } else {
+                                       state = SHIFT_IR;
+                               }
+                               break;
+                       case UPDATE_IR:
+                               if (tms) {
+                                       state = SELECT_DR;
+                               } else {
+                                       state = RUN_TEST_IDLE;
+                               }
+                               break;
+               }
+
+               switch(state) {
+                       case TEST_LOGIC_RESET:
+                               strcpy(state_text, "Test Logic Reset");
+                               break;
+                       case RUN_TEST_IDLE:
+                               strcpy(state_text, "Run-Test / Idle");
+                               break;
+                       case SELECT_DR:
+                               strcpy(state_text, "Select-DR");
+                               break;
+                       case CAPTURE_DR:
+                               strcpy(state_text, "Capture-DR");
+                               break;
+                       case SHIFT_DR:
+                               strcpy(state_text, "Shift-DR");
+                               break;
+                       case EXIT1_DR:
+                               strcpy(state_text, "Exit1-DR");
+                               break;
+                       case PAUSE_DR:
+                               strcpy(state_text, "Pause-DR");
+                               break;
+                       case EXIT2_DR:
+                               strcpy(state_text, "Exit2-DR");
+                               break;
+                       case UPDATE_DR:
+                               strcpy(state_text, "Update-DR");
+                               break;
+                       case SELECT_IR:
+                               strcpy(state_text, "Select-IR");
+                               break;
+                       case CAPTURE_IR:
+                               strcpy(state_text, "Capture-IR");
+                               break;
+                       case SHIFT_IR:
+                               strcpy(state_text, "Shift-IR");
+                               break;
+                       case EXIT1_IR:
+                               strcpy(state_text, "Exit1-IR");
+                               break;
+                       case PAUSE_IR:
+                               strcpy(state_text, "Pause-IR");
+                               break;
+                       case EXIT2_IR:
+                               strcpy(state_text, "Exit2-IR");
+                               break;
+                       case UPDATE_IR:
+                               strcpy(state_text, "Update-IR");
+                               break;
+               }
+
+               if (last_state != state) {
+                       if (tdi_written)
+                               fprintf(stderr,"\n");
+
+                       fprintf(stderr,"TAP state transition from %s to %s\n", last_state_text, state_text);
+                       tdi_written = 0;
+               } else {
+                       fprintf(stderr,"%d",(tdi ? 1 : 0));
+                       tdi_written = 1;
+               }
+       }
+
+       last_tck = tck;
+}
diff --git a/misc/jtagmon.h b/misc/jtagmon.h
new file mode 100644 (file)
index 0000000..030db23
--- /dev/null
@@ -0,0 +1 @@
+void jtagmon(unsigned char tck, unsigned char tms, unsigned char tdi);
diff --git a/misc/libusb-driverrc b/misc/libusb-driverrc
new file mode 100644 (file)
index 0000000..98d0e31
--- /dev/null
@@ -0,0 +1,6 @@
+# Copy this file to ~/.libusb-driverrc if you want to use FTDI2232 cables
+# All parallel ports not defined in this file are mapped to real ports on the
+# system
+
+# Amontec Jtagkey
+LPT2 = FTDI:0403:cff8
diff --git a/misc/parport.c b/misc/parport.c
new file mode 100644 (file)
index 0000000..57ab083
--- /dev/null
@@ -0,0 +1,168 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <linux/parport.h>
+#include <linux/ppdev.h>
+#include "usb-driver.h"
+#include "parport.h"
+
+static int parportfd = -1;
+
+int parport_transfer(WD_TRANSFER *tr, int fd, unsigned int request, int ppbase, int ecpbase, int num) {
+       int ret = 0;
+       int i;
+       unsigned long port;
+       unsigned char val;
+       static unsigned char last_pp_write = 0;
+
+       for (i = 0; i < num; i++) {
+               DPRINTF("dwPort: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n",
+                               (unsigned long)tr[i].dwPort, tr[i].cmdTrans, tr[i].dwBytes,
+                               tr[i].fAutoinc, tr[i].dwOptions);
+
+               port = (unsigned long)tr[i].dwPort;
+               val = tr[i].Data.Byte;
+
+#ifdef DEBUG
+               if (tr[i].cmdTrans == 13)
+                       DPRINTF("write byte: %d\n", val);
+#endif
+
+               if (parportfd < 0)
+                       return ret;
+
+               if (port == ppbase + PP_DATA) {
+                       DPRINTF("data port\n");
+                       switch(tr[i].cmdTrans) {
+                               case PP_READ:
+                                       ret = 0; /* We don't support reading of the data port */
+                                       break;
+
+                               case PP_WRITE:
+                                       ret = ioctl(parportfd, PPWDATA, &val);
+                                       last_pp_write = val;
+                                       break;
+
+                               default:
+                                       fprintf(stderr,"!!!Unsupported TRANSFER command: %lu!!!\n", tr[i].cmdTrans);
+                                       ret = -1;
+                                       break;
+                       }
+               } else if (port == ppbase + PP_STATUS) {
+                       DPRINTF("status port (last write: %d)\n", last_pp_write);
+                       switch(tr[i].cmdTrans) {
+                               case PP_READ:
+                                       ret = ioctl(parportfd, PPRSTATUS, &val);
+#ifdef FORCE_PC3_IDENT
+                                       val &= 0x5f;
+                                       if (last_pp_write & 0x40)
+                                               val |= 0x20;
+                                       else
+                                               val |= 0x80;
+#endif
+                                       break;
+
+                               case PP_WRITE:
+                                       ret = 0; /* Status Port is readonly */
+                                       break;
+
+                               default:
+                                       fprintf(stderr,"!!!Unsupported TRANSFER command: %lu!!!\n", tr[i].cmdTrans);
+                                       ret = -1;
+                                       break;
+                       }
+               } else if (port == ppbase + PP_CONTROL) {
+                       DPRINTF("control port\n");
+                       switch(tr[i].cmdTrans) {
+                               case PP_READ:
+                                       ret = ioctl(parportfd, PPRCONTROL, &val);
+                                       break;
+
+                               case PP_WRITE:
+                                       ret = ioctl(parportfd, PPWCONTROL, &val);
+                                       break;
+
+                               default:
+                                       fprintf(stderr,"!!!Unsupported TRANSFER command: %lu!!!\n", tr[i].cmdTrans);
+                                       ret = -1;
+                                       break;
+                       }
+               } else if ((port == ecpbase + PP_ECP_CFGA) && ecpbase) {
+                       DPRINTF("ECP_CFGA port\n");
+               } else if ((port == ecpbase + PP_ECP_CFGB) && ecpbase) {
+                       DPRINTF("ECP_CFGB port\n");
+               } else if ((port == ecpbase + PP_ECP_ECR) && ecpbase) {
+                       DPRINTF("ECP_ECR port\n");
+               } else {
+                       DPRINTF("access to unsupported address range!\n");
+                       ret = 0;
+               }
+
+               tr[i].Data.Byte = val;
+
+               DPRINTF("dwPortReturn: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n",
+                               (unsigned long)tr[i].dwPort, tr[i].cmdTrans, tr[i].dwBytes,
+                               tr[i].fAutoinc, tr[i].dwOptions);
+#ifdef DEBUG
+               if (tr[i].cmdTrans == 10)
+                       DPRINTF("read byte: %d\n", tr[i].Data.Byte);
+#endif
+       }
+
+       return ret;
+}
+
+int parport_open(int num) {
+       char ppdev[32];
+
+       if (parportfd < 0) {
+               snprintf(ppdev, sizeof(ppdev), "/dev/parport%u", num);
+               DPRINTF("opening %s\n", ppdev);
+               parportfd = open(ppdev, O_RDWR|O_EXCL);
+
+               if (parportfd < 0)
+                       fprintf(stderr,"Can't open %s: %s\n", ppdev, strerror(errno));
+       }
+
+       if (parportfd >= 0) {
+               int pmode;
+
+               if (ioctl(parportfd, PPCLAIM) == -1)
+                       return -1;
+
+               pmode = IEEE1284_MODE_COMPAT;
+               if (ioctl(parportfd, PPNEGOT, &pmode) == -1)
+                       return -1;
+
+#if 0
+               if (cr->Card.dwItems > 1 && cr->Card.Item[1].I.IO.dwAddr) {
+                       DPRINTF("ECP mode requested\n");
+                       ecpbase = (unsigned long)cr->Card.Item[1].I.IO.dwAddr;
+                       /* TODO: Implement ECP mode */
+                       pmode = IEEE1284_MODE_ECP;
+
+                       if (ioctl(parportfd, PPNEGOT, &pmode) == -1) {
+                               ecpbase = 0;
+                               pmode = IEEE1284_MODE_COMPAT;
+                               if (ioctl(parportfd, PPNEGOT, &pmode) == -1)
+                                       return ret;
+                       }
+               }
+#endif
+       }
+
+       return parportfd;
+}
+
+void parport_close(int handle) {
+       if (parportfd == handle && parportfd >= 0) {
+               ioctl(parportfd, PPRELEASE);
+               close(parportfd);
+               parportfd = -1;
+       }
+}
diff --git a/misc/parport.h b/misc/parport.h
new file mode 100644 (file)
index 0000000..ee46098
--- /dev/null
@@ -0,0 +1,3 @@
+int parport_transfer(WD_TRANSFER *tr, int fd, unsigned int request, int ppbase, int ecpbase, int num);
+int parport_open(int num);
+void parport_close(int handle);
diff --git a/misc/program.sh b/misc/program.sh
new file mode 100644 (file)
index 0000000..bb9357d
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+export XILINX=/usr/local/xilinx/ise/
+
+
+DEVICE=`lsusb | grep Xilinx | sed 's_Bus __' | sed 's_ Device _/_' | sed 's_:.*__'`
+
+sudo sh -c 'cat > /etc/udev/rules.d/xusbdfwu.rules' <<EOF
+# version 0002
+SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0008", MODE="666"
+BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0007", RUN+="/sbin/fxload -v -t fx2 -I $XILINX/bin/lin/xusbdfwu.hex -D $TEMPNODE"
+BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0009", RUN+="/sbin/fxload -v -t fx2 -I $XILINX/bin/lin/xusb_xup.hex -D $TEMPNODE"
+BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="000d", RUN+="/sbin/fxload -v -t fx2 -I $XILINX/bin/lin/xusb_emb.hex -D $TEMPNODE"
+BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="000f", RUN+="/sbin/fxload -v -t fx2 -I $XILINX/bin/lin/xusb_xlp.hex -D $TEMPNODE"
+BUS=="usb", ACTION=="add", SYSFS{idVendor}=="03fd", SYSFS{idProduct}=="0013", RUN+="/sbin/fxload -v -t fx2 -I $XILINX/bin/lin/xusb_xpr.hex -D $TEMPNODE"
+EOF
+
+(lsusb | grep '000f Xilinx') && \
+ (/sbin/fxload -v -t fx2 -I $XILINX/bin/lin/xusb_xlp.hex -D /proc/bus/usb/$DEVICE;\
+  sudo /etc/init.d/udev stop;\
+  sudo /etc/init.d/udev start)
+
+export BITFILE=$1
+
+sudo rmmod xpc4drvr
+sudo rmmod windrvr6
+#sudo insmod /lib/modules/2.6.22.9goliath/kernel/drivers/misc/xpc4drvr.ko
+#sudo insmod /lib/modules/2.6.22.9goliath/kernel/drivers/misc/windrvr6.ko
+#DEVNUM=`grep windrvr /proc/devices | sed 's_ .*__'`
+#sudo rm -f /dev/windrvr6
+#sudo mknod /dev/windrvr6 c $DEVNUM 0
+
+export LD_PRELOAD=`pwd`/misc/libusb-driver.so
+
+sudo ln -sf $XILINX/bin/lin/xusbdfwu.hex /usr/share/xusbdfwu.hex
+
+$XILINX/bin/lin/impact -batch <<EOF
+cleancablelock
+setMode -bs
+setCable -port usb21 -baud 12000000
+identify
+setMode -bs
+assignFile -p 2 -file $BITFILE
+program -p 2
+quit
+EOF
+
+sudo rm _impact*
+sudo rm /usr/share/xusbdfwu.hex
+#rm /etc/udev/rules.d/xusbdfwu.rules
diff --git a/misc/usb-driver.c b/misc/usb-driver.c
new file mode 100644 (file)
index 0000000..34fa02c
--- /dev/null
@@ -0,0 +1,939 @@
+/* libusb/ppdev connector for XILINX impact
+ *
+ * Copyright (c) 2007 Michael Gernoth <michael@gernoth.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define _GNU_SOURCE 1
+
+#include <dlfcn.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <usb.h>
+#include <signal.h>
+#include <pthread.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <sys/ioctl.h>
+#include "usb-driver.h"
+#include "config.h"
+
+static int (*ioctl_func) (int, int, void *) = NULL;
+static int windrvrfd = -1;
+static unsigned long ppbase = 0;
+static unsigned long ecpbase = 0;
+static struct parport_config *pport = NULL;
+static FILE *modulesfp = NULL;
+static FILE *baseaddrfp = NULL;
+static int baseaddrnum = 0;
+static int modules_read = 0;
+static struct usb_bus *busses = NULL;
+static struct usb_device *usbdevice;
+static usb_dev_handle *usb_devhandle = NULL;
+static int usbinterface = -1;
+static unsigned long card_type;
+static int ints_enabled = 0;
+static pthread_mutex_t int_wait = PTHREAD_MUTEX_INITIALIZER;
+
+#define NO_WINDRVR 1
+
+void hexdump(unsigned char *buf, int len) {
+       int i;
+
+       for(i=0; i<len; i++) {
+               fprintf(stderr,"%02x ", buf[i]);
+               if ((i % 16) == 15)
+                       fprintf(stderr,"\n");
+       }
+       fprintf(stderr,"\n");
+}
+
+static int usb_deviceinfo(unsigned char *buf) {
+       int i,j,k,l;
+       int len = 0;
+       WDU_CONFIGURATION **pConfigs, **pActiveConfig;
+       WDU_INTERFACE **pActiveInterface;
+
+       if (buf) {
+               struct usb_device_info *udi = (struct usb_device_info*)(buf+len);
+
+               udi->Descriptor.bLength = sizeof(WDU_DEVICE_DESCRIPTOR);
+               udi->Descriptor.bDescriptorType = usbdevice->descriptor.bDescriptorType;
+               udi->Descriptor.bcdUSB = usbdevice->descriptor.bcdUSB;
+               udi->Descriptor.bDeviceClass = usbdevice->descriptor.bDeviceClass;
+               udi->Descriptor.bDeviceSubClass = usbdevice->descriptor.bDeviceSubClass;
+               udi->Descriptor.bDeviceProtocol = usbdevice->descriptor.bDeviceProtocol;
+               udi->Descriptor.bMaxPacketSize0 = usbdevice->descriptor.bMaxPacketSize0;
+               udi->Descriptor.idVendor = usbdevice->descriptor.idVendor;
+               udi->Descriptor.idProduct = usbdevice->descriptor.idProduct;
+               udi->Descriptor.bcdDevice = usbdevice->descriptor.bcdDevice;
+               udi->Descriptor.iManufacturer = usbdevice->descriptor.iManufacturer;
+               udi->Descriptor.iProduct = usbdevice->descriptor.iProduct;
+               udi->Descriptor.iSerialNumber = usbdevice->descriptor.iSerialNumber;
+               udi->Descriptor.bNumConfigurations = usbdevice->descriptor.bNumConfigurations;
+
+               /* TODO: Fix Pipe0! */
+               udi->Pipe0.dwNumber = 0x00;
+               udi->Pipe0.dwMaximumPacketSize = usbdevice->descriptor.bMaxPacketSize0;
+               udi->Pipe0.type = 0;
+               udi->Pipe0.direction = WDU_DIR_IN_OUT;
+               udi->Pipe0.dwInterval = 0;
+
+               pConfigs = &(udi->pConfigs);
+               pActiveConfig = &(udi->pActiveConfig);
+               pActiveInterface = &(udi->pActiveInterface[0]);
+       }
+
+       len = sizeof(struct usb_device_info);
+
+       for (i=0; i<usbdevice->descriptor.bNumConfigurations; i++)
+       {
+               struct usb_config_descriptor *conf_desc = &usbdevice->config[i];
+               WDU_INTERFACE **pInterfaces;
+               WDU_ALTERNATE_SETTING **pAlternateSettings[conf_desc->bNumInterfaces];
+               WDU_ALTERNATE_SETTING **pActiveAltSetting[conf_desc->bNumInterfaces];
+
+               if (buf) {
+                       WDU_CONFIGURATION *cfg = (WDU_CONFIGURATION*)(buf+len);
+
+                       *pConfigs = cfg;
+                       *pActiveConfig = cfg;
+
+                       cfg->Descriptor.bLength = conf_desc->bLength;
+                       cfg->Descriptor.bDescriptorType = conf_desc->bDescriptorType;
+                       cfg->Descriptor.wTotalLength = conf_desc->wTotalLength;
+                       cfg->Descriptor.bNumInterfaces = conf_desc->bNumInterfaces;
+                       cfg->Descriptor.bConfigurationValue = conf_desc->bConfigurationValue;
+                       cfg->Descriptor.iConfiguration = conf_desc->iConfiguration;
+                       cfg->Descriptor.bmAttributes = conf_desc->bmAttributes;
+                       cfg->Descriptor.MaxPower = conf_desc->MaxPower;
+
+                       cfg->dwNumInterfaces = conf_desc->bNumInterfaces;
+
+                       pInterfaces = &(cfg->pInterfaces);
+               }
+               len += sizeof(WDU_CONFIGURATION);
+
+               if (buf) {
+                       *pInterfaces = (WDU_INTERFACE*)(buf+len);
+                       for (j=0; j<conf_desc->bNumInterfaces; j++) {
+                               WDU_INTERFACE *iface = (WDU_INTERFACE*)(buf+len);
+
+                               pActiveInterface[j] = iface;
+
+                               pAlternateSettings[j] = &(iface->pAlternateSettings);
+                               iface->dwNumAltSettings = usbdevice->config[i].interface[j].num_altsetting;
+                               pActiveAltSetting[j] = &(iface->pActiveAltSetting);
+
+                               len += sizeof(WDU_INTERFACE);
+                       }
+               } else {
+                       len += sizeof(WDU_INTERFACE) * conf_desc->bNumInterfaces;
+               }
+
+               for (j=0; j<conf_desc->bNumInterfaces; j++)
+               {
+                       struct usb_interface *interface = &usbdevice->config[i].interface[j];
+
+                       if (buf) {
+                               *pAlternateSettings[j] = (WDU_ALTERNATE_SETTING*)(buf+len);
+                               /* FIXME: */
+                               *pActiveAltSetting[j] = (WDU_ALTERNATE_SETTING*)(buf+len);
+                       }
+
+                       for(k=0; k<interface->num_altsetting; k++)
+                       {
+                               unsigned char bNumEndpoints = interface->altsetting[k].bNumEndpoints;
+                               WDU_ENDPOINT_DESCRIPTOR **pEndpointDescriptors;
+                               WDU_PIPE_INFO **pPipes;
+
+                               if (buf) {
+                                       WDU_ALTERNATE_SETTING *altset = (WDU_ALTERNATE_SETTING*)(buf+len);
+
+                                       altset->Descriptor.bLength = interface->altsetting[k].bLength;
+                                       altset->Descriptor.bDescriptorType = interface->altsetting[k].bDescriptorType;
+                                       altset->Descriptor.bInterfaceNumber = interface->altsetting[k].bInterfaceNumber;
+                                       altset->Descriptor.bAlternateSetting = interface->altsetting[k].bAlternateSetting;
+                                       altset->Descriptor.bNumEndpoints = interface->altsetting[k].bNumEndpoints;
+                                       altset->Descriptor.bInterfaceClass = interface->altsetting[k].bInterfaceClass;
+                                       altset->Descriptor.bInterfaceSubClass = interface->altsetting[k].bInterfaceSubClass;
+                                       altset->Descriptor.bInterfaceProtocol = interface->altsetting[k].bInterfaceProtocol;
+                                       altset->Descriptor.iInterface = interface->altsetting[k].iInterface;
+                                       pEndpointDescriptors = &(altset->pEndpointDescriptors);
+                                       pPipes = &(altset->pPipes);
+
+                               }
+                               len +=sizeof(WDU_ALTERNATE_SETTING);
+
+                               if (buf) {
+                                       *pEndpointDescriptors = (WDU_ENDPOINT_DESCRIPTOR*)(buf+len);
+                                       for (l = 0; l < bNumEndpoints; l++) {
+                                               WDU_ENDPOINT_DESCRIPTOR *ed = (WDU_ENDPOINT_DESCRIPTOR*)(buf+len);
+
+                                               ed->bLength = interface->altsetting[k].endpoint[l].bLength;
+                                               ed->bDescriptorType = interface->altsetting[k].endpoint[l].bDescriptorType;
+                                               ed->bEndpointAddress = interface->altsetting[k].endpoint[l].bEndpointAddress;
+                                               ed->bmAttributes = interface->altsetting[k].endpoint[l].bmAttributes;
+                                               ed->wMaxPacketSize = interface->altsetting[k].endpoint[l].wMaxPacketSize;
+                                               ed->bInterval = interface->altsetting[k].endpoint[l].bInterval;
+
+                                               len += sizeof(WDU_ENDPOINT_DESCRIPTOR);
+                                       }
+                                               
+                                       *pPipes = (WDU_PIPE_INFO*)(buf+len);
+                                       for (l = 0; l < bNumEndpoints; l++) {
+                                               WDU_PIPE_INFO *pi = (WDU_PIPE_INFO*)(buf+len);
+
+                                               pi->dwNumber = interface->altsetting[k].endpoint[l].bEndpointAddress;
+                                               pi->dwMaximumPacketSize = WDU_GET_MAX_PACKET_SIZE(interface->altsetting[k].endpoint[l].wMaxPacketSize);
+                                               pi->type = interface->altsetting[k].endpoint[l].bmAttributes & USB_ENDPOINT_TYPE_MASK;
+                                               if (pi->type == PIPE_TYPE_CONTROL)
+                                                       pi->direction = WDU_DIR_IN_OUT;
+                                               else
+                                               {
+                                                       pi->direction = interface->altsetting[k].endpoint[l].bEndpointAddress & USB_ENDPOINT_DIR_MASK ?  WDU_DIR_IN : WDU_DIR_OUT;
+                                               }
+
+                                               pi->dwInterval = interface->altsetting[k].endpoint[l].bInterval;
+
+                                               len += sizeof(WDU_PIPE_INFO);
+                                       }
+                               } else {
+                                       len +=(sizeof(WDU_ENDPOINT_DESCRIPTOR)+sizeof(WDU_PIPE_INFO))*bNumEndpoints;
+                               }
+                       }
+               }
+       }
+
+       return len;
+}
+
+static int do_wdioctl(int fd, unsigned int request, unsigned char *wdioctl) {
+       struct header_struct* wdheader = (struct header_struct*)wdioctl;
+       struct version_struct *version;
+       int ret = 0;
+
+       if (wdheader->magic != MAGIC) {
+               fprintf(stderr,"!!!ERROR: magic header does not match!!!\n");
+               return (*ioctl_func) (fd, request, wdioctl);
+       }
+
+       switch(request & ~(0xc0000000)) {
+               case VERSION:
+                       version = (struct version_struct*)(wdheader->data);
+                       strcpy(version->version, "libusb-driver.so version: " USB_DRIVER_VERSION);
+                       version->versionul = 802;
+                       DPRINTF("VERSION\n");
+                       break;
+
+               case LICENSE:
+                       DPRINTF("LICENSE\n");
+                       break;
+
+               case CARD_REGISTER_OLD:
+               case CARD_REGISTER:
+                       DPRINTF("CARD_REGISTER\n");
+                       {
+                               struct card_register* cr = (struct card_register*)(wdheader->data);
+
+                               DPRINTF("Items: %lu, Addr: 0x%lx, bytes: %lu, bar: %lu\n",
+                               cr->Card.dwItems,
+                               (unsigned long)cr->Card.Item[0].I.IO.dwAddr,
+                               cr->Card.Item[0].I.IO.dwBytes,
+                               cr->Card.Item[0].I.IO.dwBar);
+                               
+                               DPRINTF("Items: %lu, Addr: 0x%lx, bytes: %lu, bar: %lu\n",
+                               cr->Card.dwItems,
+                               (unsigned long)cr->Card.Item[1].I.IO.dwAddr,
+                               cr->Card.Item[1].I.IO.dwBytes,
+                               cr->Card.Item[1].I.IO.dwBar);
+#ifndef NO_WINDRVR
+                               ret = (*ioctl_func) (fd, request, wdioctl);
+#else
+
+                               pport = config_get((unsigned long)cr->Card.Item[0].I.IO.dwAddr / 0x10);
+                               if (!pport)
+                                       break;
+
+                               ret = pport->open((unsigned long)cr->Card.Item[0].I.IO.dwAddr / 0x10);
+
+                               ppbase = (unsigned long)cr->Card.Item[0].I.IO.dwAddr;
+
+                               if (cr->Card.dwItems > 1 && cr->Card.Item[1].I.IO.dwAddr)
+                                       ecpbase = (unsigned long)cr->Card.Item[1].I.IO.dwAddr;
+
+                               if (ret >= 0) {
+                                       cr->hCard = ret;
+                               } else {
+                                       cr->hCard = 0;
+                               }
+#endif
+                               DPRINTF("hCard: %lu\n", cr->hCard);
+                       }
+                       break;
+
+               case USB_TRANSFER:
+                       DPRINTF("in USB_TRANSFER");
+                       {
+                               struct usb_transfer *ut = (struct usb_transfer*)(wdheader->data);
+
+#ifdef DEBUG
+                               DPRINTF(" unique: %lu, pipe: %lu, read: %lu, options: %lx, size: %lu, timeout: %lx\n",
+                               ut->dwUniqueID, ut->dwPipeNum, ut->fRead,
+                               ut->dwOptions, ut->dwBufferSize, ut->dwTimeout);
+                               DPRINTF("setup packet: ");
+                               hexdump(ut->SetupPacket, 8);
+
+                               if (!ut->fRead && ut->dwBufferSize)
+                               {
+                                       hexdump(ut->pBuffer, ut->dwBufferSize);
+                               }
+#endif
+
+#ifndef NO_WINDRVR
+                               ret = (*ioctl_func) (fd, request, wdioctl);
+#else
+                               /* http://www.jungo.com/support/documentation/windriver/802/wdusb_man_mhtml/node55.html#SECTION001213000000000000000 */
+                               if (ut->dwPipeNum == 0) { /* control pipe */
+                                       int requesttype, request, value, index, size;
+                                       requesttype = ut->SetupPacket[0];
+                                       request = ut->SetupPacket[1];
+                                       value = ut->SetupPacket[2] | (ut->SetupPacket[3] << 8);
+                                       index = ut->SetupPacket[4] | (ut->SetupPacket[5] << 8);
+                                       size = ut->SetupPacket[6] | (ut->SetupPacket[7] << 8);
+                                       DPRINTF("requesttype: %x, request: %x, value: %u, index: %u, size: %u\n", requesttype, request, value, index, size);
+                                       ret = usb_control_msg(usb_devhandle, requesttype, request, value, index, ut->pBuffer, size, ut->dwTimeout);
+                               } else {
+                                       if (ut->fRead) {
+                                               ret = usb_bulk_read(usb_devhandle, ut->dwPipeNum, ut->pBuffer, ut->dwBufferSize, ut->dwTimeout);
+
+                                       } else {
+                                               ret = usb_bulk_write(usb_devhandle, ut->dwPipeNum, ut->pBuffer, ut->dwBufferSize, ut->dwTimeout);
+                                       }
+                               }
+
+                               if (ret < 0) {
+                                       fprintf(stderr, "usb_transfer: %d (%s)\n", ret, usb_strerror());
+                               } else {
+                                       ut->dwBytesTransferred = ret;
+                                       ret = 0;
+                               }
+#endif
+
+#ifdef DEBUG
+                               DPRINTF("Transferred: %lu (%s)\n",ut->dwBytesTransferred, (ut->fRead?"read":"write"));
+                               if (ut->fRead && ut->dwBytesTransferred)
+                               {
+                                       DPRINTF("Read: ");
+                                       hexdump(ut->pBuffer, ut->dwBytesTransferred);
+                               }
+#endif
+                       }
+                       break;
+
+               case INT_ENABLE_OLD:
+               case INT_ENABLE:
+                       DPRINTF("INT_ENABLE\n");
+                       {
+                               struct interrupt *it = (struct interrupt*)(wdheader->data);
+
+                               DPRINTF("Handle: %lu, Options: %lx, ncmds: %lu, enableok: %lu, count: %lu, lost: %lu, stopped: %lu\n",
+                               it->hInterrupt, it->dwOptions,
+                               it->dwCmds, it->fEnableOk, it->dwCounter,
+                               it->dwLost, it->fStopped);
+
+                               it->fEnableOk = 1;
+                               it->fStopped = 0;
+                               ints_enabled = 1;
+                               pthread_mutex_trylock(&int_wait);
+                       }
+
+                       break;
+                       
+               case INT_DISABLE:
+                       DPRINTF("INT_DISABLE\n");
+                       {
+                               struct interrupt *it = (struct interrupt*)(wdheader->data);
+
+                               DPRINTF("Handle: %lu, Options: %lx, ncmds: %lu, enableok: %lu, count: %lu, lost: %lu, stopped: %lu\n",
+                               it->hInterrupt, it->dwOptions,
+                               it->dwCmds, it->fEnableOk, it->dwCounter,
+                               it->dwLost, it->fStopped);
+#ifndef NO_WINDRVR
+                               ret = (*ioctl_func) (fd, request, wdioctl);
+#else
+                               it->dwCounter = 0;
+                               it->fStopped = 1;
+                               ints_enabled = 0;
+                               if (pthread_mutex_trylock(&int_wait) == EBUSY)
+                                       pthread_mutex_unlock(&int_wait);
+#endif
+                               DPRINTF("Handle: %lu, Options: %lx, ncmds: %lu, enableok: %lu, count: %lu, lost: %lu, stopped: %lu\n",
+                               it->hInterrupt, it->dwOptions,
+                               it->dwCmds, it->fEnableOk, it->dwCounter,
+                               it->dwLost, it->fStopped);
+                       }
+                       break;
+
+               case USB_SET_INTERFACE:
+                       DPRINTF("USB_SET_INTERFACE\n");
+                       {
+                               struct usb_set_interface *usi = (struct usb_set_interface*)(wdheader->data);
+
+                               DPRINTF("unique: %lu, interfacenum: %lu, alternatesetting: %lu, options: %lx\n",
+                               usi->dwUniqueID, usi->dwInterfaceNum,
+                               usi->dwAlternateSetting, usi->dwOptions);
+#ifndef NO_WINDRVR
+                               ret = (*ioctl_func) (fd, request, wdioctl);
+#else
+                               if (usbdevice) {
+                                  if (!usb_devhandle)
+                                    usb_devhandle = usb_open(usbdevice);
+
+                                       /* FIXME: Select right interface! */
+                                       ret = usb_claim_interface(usb_devhandle, usbdevice->config[0].interface[usi->dwInterfaceNum].altsetting[usi->dwAlternateSetting].bInterfaceNumber);
+                                       if (!ret) {
+                                               if(!ret) {
+                                                       usbinterface = usbdevice->config[0].interface[usi->dwInterfaceNum].altsetting[usi->dwAlternateSetting].bInterfaceNumber;
+                                                       ret = usb_set_altinterface(usb_devhandle, usi->dwAlternateSetting);
+                                                       if (ret)
+                                                               fprintf(stderr, "usb_set_altinterface: %d\n", ret);
+                                               } else {
+                                                       fprintf(stderr, "usb_set_configuration: %d (%s)\n", ret, usb_strerror());
+                                               }
+                                       } else {
+                                               fprintf(stderr, "usb_claim_interface: %d -> %d (%s)\n",
+                                               usbdevice->config[0].interface[usi->dwInterfaceNum].altsetting[usi->dwAlternateSetting].bInterfaceNumber,
+                                               ret, usb_strerror());
+                                       }
+                               }
+#endif
+                               DPRINTF("unique: %lu, interfacenum: %lu, alternatesetting: %lu, options: %lx\n",
+                               usi->dwUniqueID, usi->dwInterfaceNum,
+                               usi->dwAlternateSetting, usi->dwOptions);
+                       }
+                       break;
+
+               case USB_GET_DEVICE_DATA_OLD:
+               case USB_GET_DEVICE_DATA:
+                       DPRINTF("USB_GET_DEVICE_DATA\n");
+                       {
+                               struct usb_get_device_data *ugdd = (struct usb_get_device_data*)(wdheader->data);
+                               int pSize;
+
+                               DPRINTF("unique: %lu, bytes: %lu, options: %lx\n",
+                               ugdd->dwUniqueID, ugdd->dwBytes,
+                               ugdd->dwOptions);
+
+                               pSize = ugdd->dwBytes;
+                               if (!ugdd->dwBytes) {
+                                       if (usbdevice) {
+                                               ugdd->dwBytes = usb_deviceinfo(NULL);
+                                       }
+                               } else {
+                                       usb_deviceinfo((unsigned char*)ugdd->pBuf);
+                               }
+                       }
+                       break;
+
+               case EVENT_REGISTER_OLD:
+               case EVENT_REGISTER:
+                       DPRINTF("EVENT_REGISTER\n");
+                       {
+                               struct event *e = (struct event*)(wdheader->data);
+                               struct usb_bus *bus;
+                               char* devpos;
+                               int busnum = -1, devnum = -1;
+                               int i;
+
+                               DPRINTF("handle: %lu, action: %lu, status: %lu, eventid: %lu, cardtype: %lu, kplug: %lu, options: %lu, dev: %lx:%lx, unique: %lu, ver: %lu, nummatch: %lu\n",
+                               e->handle, e->dwAction,
+                               e->dwStatus, e->dwEventId, e->dwCardType,
+                               e->hKernelPlugIn, e->dwOptions,
+                               e->u.Usb.deviceId.dwVendorId,
+                               e->u.Usb.deviceId.dwProductId,
+                               e->u.Usb.dwUniqueID, e->dwEventVer,
+                               e->dwNumMatchTables);
+
+                               devpos = getenv("XILINX_USB_DEV");
+                               if (devpos != NULL) {
+                                       int j;
+                                       char *devstr = NULL, *remainder;
+
+                                       DPRINTF("XILINX_USB_DEV=%s\n", devpos);
+
+                                       for (j = 0; j < strlen(devpos) && devpos[j] != 0; j++) {
+                                               if (devpos[j] == ':') {
+                                                       devpos[j] = 0;
+                                                       devstr = &(devpos[j+1]);
+                                               }
+                                       }
+
+                                       if (devstr && strlen(devstr) > 0) {
+                                               busnum = strtol(devpos, &remainder, 10);
+                                               if (devpos == remainder) {
+                                                       busnum = -1;
+                                               } else {
+                                                       devnum = strtol(devstr, &remainder, 10);
+                                                       if (devstr == remainder) {
+                                                               busnum = -1;
+                                                               devnum = -1;
+                                                       } else {
+                                                               fprintf(stderr,"Using XILINX platform cable USB at %03d:%03d\n",
+                                                               busnum, devnum);
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               for (i = 0; i < e->dwNumMatchTables; i++) {
+
+                                       DPRINTF("match: dev: %04x:%04x, class: %x, subclass: %x, intclass: %x, intsubclass: %x, intproto: %x\n",
+                                       e->matchTables[i].VendorId,
+                                       e->matchTables[i].ProductId,
+                                       e->matchTables[i].bDeviceClass,
+                                       e->matchTables[i].bDeviceSubClass,
+                                       e->matchTables[i].bInterfaceClass,
+                                       e->matchTables[i].bInterfaceSubClass,
+                                       e->matchTables[i].bInterfaceProtocol);
+
+                                       for (bus = busses; bus; bus = bus->next) {
+                                               struct usb_device *dev;
+
+                                               if ((devnum != -1) && (strtol(bus->dirname, NULL, 10) != busnum))
+                                                       continue;
+
+                                               for (dev = bus->devices; dev; dev = dev->next) {
+                                                       struct usb_device_descriptor *desc = &(dev->descriptor);
+
+                                                       if((desc->idVendor == e->matchTables[i].VendorId) &&
+                                                          (desc->idProduct == e->matchTables[i].ProductId) &&
+                                                          (desc->bDeviceClass == e->matchTables[i].bDeviceClass) &&
+                                                          (desc->bDeviceSubClass == e->matchTables[i].bDeviceSubClass) &&
+                                                          ((devnum == -1) || (strtol(dev->filename, NULL, 10) == devnum)) ) {
+                                                                  int ac;
+                                                                  for (ac = 0; ac < desc->bNumConfigurations; ac++) {
+                                                                          struct usb_interface *interface = dev->config[ac].interface;
+                                                                          int ai;
+
+                                                                          for (ai = 0; ai < interface->num_altsetting; ai++) {
+
+                                                                                  DPRINTF("intclass: %x, intsubclass: %x, intproto: %x\n",
+                                                                                  interface->altsetting[i].bInterfaceClass,
+                                                                                  interface->altsetting[i].bInterfaceSubClass,
+                                                                                  interface->altsetting[i].bInterfaceProtocol);
+
+                                                                                  if ((interface->altsetting[ai].bInterfaceSubClass == e->matchTables[i].bInterfaceSubClass) &&
+                                                                                                  (interface->altsetting[ai].bInterfaceProtocol == e->matchTables[i].bInterfaceProtocol)){
+                                                                                          /* TODO: check interfaceClass! */
+                                                                                          DPRINTF("found device with libusb\n");
+                                                                                          usbdevice = dev;
+                                                                                          card_type = e->dwCardType;
+                                                                                  }
+                                                                          }
+                                                                  }
+                                                       }
+                                               }
+                                       }
+                               }
+
+#ifndef NO_WINDRVR
+                               ret = (*ioctl_func) (fd, request, wdioctl);
+#else
+                               e->handle++;
+#endif
+
+#ifdef DEBUG
+                               DPRINTF("handle: %lu, action: %lu, status: %lu, eventid: %lu, cardtype: %lu, kplug: %lu, options: %lu, dev: %lx:%lx, unique: %lu, ver: %lu, nummatch: %lu\n",
+                               e->handle, e->dwAction,
+                               e->dwStatus, e->dwEventId, e->dwCardType,
+                               e->hKernelPlugIn, e->dwOptions,
+                               e->u.Usb.deviceId.dwVendorId,
+                               e->u.Usb.deviceId.dwProductId,
+                               e->u.Usb.dwUniqueID, e->dwEventVer,
+                               e->dwNumMatchTables);
+
+                               for (i = 0; i < e->dwNumMatchTables; i++)
+                                       DPRINTF("match: dev: %04x:%04x, class: %x, subclass: %x, intclass: %x, intsubclass: %x, intproto: %x\n",
+                                       e->matchTables[i].VendorId,
+                                       e->matchTables[i].ProductId,
+                                       e->matchTables[i].bDeviceClass,
+                                       e->matchTables[i].bDeviceSubClass,
+                                       e->matchTables[i].bInterfaceClass,
+                                       e->matchTables[i].bInterfaceSubClass,
+                                       e->matchTables[i].bInterfaceProtocol);
+#endif
+                       }
+                       break;
+
+               case TRANSFER_OLD:
+               case TRANSFER:
+                       DPRINTF("TRANSFER\n");
+                       {
+                               WD_TRANSFER *tr = (WD_TRANSFER*)(wdheader->data);
+
+#ifndef NO_WINDRVR
+                               ret = (*ioctl_func) (fd, request, wdioctl);
+#else
+                               ret = pport->transfer(tr, fd, request, ppbase, ecpbase, 1);
+#endif
+                       }
+                       break;
+
+               case MULTI_TRANSFER_OLD:
+               case MULTI_TRANSFER:
+                       DPRINTF("MULTI_TRANSFER\n");
+                       {
+                               WD_TRANSFER *tr = (WD_TRANSFER*)(wdheader->data);
+                               unsigned long num = wdheader->size/sizeof(WD_TRANSFER);
+#ifndef NO_WINDRVR
+                               ret = (*ioctl_func) (fd, request, wdioctl);
+#else
+                               ret = pport->transfer(tr, fd, request, ppbase, ecpbase, num);
+#endif
+                       }
+                       break;
+
+               case EVENT_UNREGISTER:
+                       DPRINTF("EVENT_UNREGISTER\n");
+#ifndef NO_WINDRVR
+                       ret = (*ioctl_func) (fd, request, wdioctl);
+#endif
+                       break;
+
+               case INT_WAIT:
+                       DPRINTF("INT_WAIT\n");
+                       {
+                               struct interrupt *it = (struct interrupt*)(wdheader->data);
+
+                               DPRINTF("Handle: %lu, Options: %lx, ncmds: %lu, enableok: %lu, count: %lu, lost: %lu, stopped: %lu\n",
+                               it->hInterrupt, it->dwOptions,
+                               it->dwCmds, it->fEnableOk, it->dwCounter,
+                               it->dwLost, it->fStopped);
+
+#ifndef NO_WINDRVR
+                               ret = (*ioctl_func) (fd, request, wdioctl);
+#else
+                               if (usbdevice) {
+                                       if (it->dwCounter == 0) {
+                                               it->dwCounter = 1;
+                                       } else {
+                                               pthread_mutex_lock(&int_wait);
+                                               pthread_mutex_unlock(&int_wait);
+                                       }
+                               } else {
+                                       pthread_mutex_lock(&int_wait);
+                                       pthread_mutex_unlock(&int_wait);
+                               }
+#endif
+
+                               DPRINTF("INT_WAIT_RETURN: Handle: %lu, Options: %lx, ncmds: %lu, enableok: %lu, count: %lu, lost: %lu, stopped: %lu\n",
+                               it->hInterrupt, it->dwOptions, it->dwCmds,
+                               it->fEnableOk, it->dwCounter, it->dwLost,
+                               it->fStopped);
+                       }
+                       break;
+
+               case CARD_UNREGISTER:
+                       DPRINTF("CARD_UNREGISTER\n");
+                       {
+                               struct card_register* cr = (struct card_register*)(wdheader->data);
+
+                               DPRINTF("Addr: 0x%lx, bytes: %lu, bar: %lu\n",
+                               (unsigned long)cr->Card.Item[0].I.IO.dwAddr,
+                               cr->Card.Item[0].I.IO.dwBytes,
+                               cr->Card.Item[0].I.IO.dwBar);
+
+                               DPRINTF("hCard: %lu\n", cr->hCard);
+
+#ifndef NO_WINDRVR
+                               ret = (*ioctl_func) (fd, request, wdioctl);
+#else
+                               if (pport)
+                                       pport->close(cr->hCard);
+
+                               pport = NULL;
+#endif
+                       }
+                       break;
+
+               case EVENT_PULL:
+                       DPRINTF("EVENT_PULL\n");
+                       {
+                               struct event *e = (struct event*)(wdheader->data);
+#ifdef DEBUG
+                               int i;
+
+                               DPRINTF("handle: %lu, action: %lu, status: %lu, eventid: %lu, cardtype: %lx, kplug: %lu, options: %lu, dev: %lx:%lx, unique: %lu, ver: %lu, nummatch: %lu\n",
+                               e->handle, e->dwAction, e->dwStatus,
+                               e->dwEventId, e->dwCardType, e->hKernelPlugIn,
+                               e->dwOptions, e->u.Usb.deviceId.dwVendorId,
+                               e->u.Usb.deviceId.dwProductId,
+                               e->u.Usb.dwUniqueID, e->dwEventVer,
+                               e->dwNumMatchTables);
+
+                               for (i = 0; i < e->dwNumMatchTables; i++)
+                                       DPRINTF("match: dev: %04x:%04x, class: %x, subclass: %x, intclass: %x, intsubclass: %x, intproto: %x\n",
+                                       e->matchTables[i].VendorId,
+                                       e->matchTables[i].ProductId,
+                                       e->matchTables[i].bDeviceClass,
+                                       e->matchTables[i].bDeviceSubClass,
+                                       e->matchTables[i].bInterfaceClass,
+                                       e->matchTables[i].bInterfaceSubClass,
+                                       e->matchTables[i].bInterfaceProtocol);
+#endif
+
+#ifndef NO_WINDRVR
+                               ret = (*ioctl_func) (fd, request, wdioctl);
+#else
+                               if (usbdevice) {
+                                       struct usb_interface *interface = usbdevice->config->interface;
+
+                                       e->dwCardType = card_type;
+                                       e->dwAction = 1;
+                                       e->dwEventId = 109;
+                                       e->u.Usb.dwUniqueID = 110;
+                                       e->matchTables[0].VendorId = usbdevice->descriptor.idVendor;
+                                       e->matchTables[0].ProductId = usbdevice->descriptor.idProduct;
+                                       e->matchTables[0].bDeviceClass = usbdevice->descriptor.bDeviceClass;
+                                       e->matchTables[0].bDeviceSubClass = usbdevice->descriptor.bDeviceSubClass;
+                                       e->matchTables[0].bInterfaceClass = interface->altsetting[0].bInterfaceClass;
+                                       e->matchTables[0].bInterfaceSubClass = interface->altsetting[0].bInterfaceSubClass;
+                                       e->matchTables[0].bInterfaceProtocol = interface->altsetting[0].bInterfaceProtocol;
+                               }
+#endif
+
+#ifdef DEBUG
+                               DPRINTF("handle: %lu, action: %lu, status: %lu, eventid: %lu, cardtype: %lx, kplug: %lu, options: %lu, dev: %lx:%lx, unique: %lu, ver: %lu, nummatch: %lu\n",
+                               e->handle, e->dwAction, e->dwStatus,
+                               e->dwEventId, e->dwCardType, e->hKernelPlugIn,
+                               e->dwOptions, e->u.Usb.deviceId.dwVendorId,
+                               e->u.Usb.deviceId.dwProductId,
+                               e->u.Usb.dwUniqueID, e->dwEventVer,
+                               e->dwNumMatchTables);
+
+                               for (i = 0; i < e->dwNumMatchTables; i++)
+                                       DPRINTF("match: dev: %04x:%04x, class: %x, subclass: %x, intclass: %x, intsubclass: %x, intproto: %x\n",
+                                       e->matchTables[i].VendorId,
+                                       e->matchTables[i].ProductId,
+                                       e->matchTables[i].bDeviceClass,
+                                       e->matchTables[i].bDeviceSubClass,
+                                       e->matchTables[i].bInterfaceClass,
+                                       e->matchTables[i].bInterfaceSubClass,
+                                       e->matchTables[i].bInterfaceProtocol);
+#endif
+
+                       }
+                       break;
+
+               default:
+                       fprintf(stderr,"!!!Unsupported IOCTL: %x!!!\n", request);
+#ifndef NO_WINDRVR
+                       ret = (*ioctl_func) (fd, request, wdioctl);
+#endif
+                       break;
+       }
+
+       return ret;
+}
+
+int ioctl(int fd, unsigned long int request, ...) {
+       va_list args;
+       void *argp;
+       int ret;
+
+       if (!ioctl_func)                                                                    
+               ioctl_func = (int (*) (int, int, void *)) dlsym (RTLD_NEXT, "ioctl");             
+
+       va_start (args, request);
+       argp = va_arg (args, void *);
+       va_end (args);
+
+       if (fd == windrvrfd)
+               ret = do_wdioctl(fd, request, argp);
+       else
+               ret = (*ioctl_func) (fd, request, argp);
+
+       return ret;
+}
+
+int open (const char *pathname, int flags, ...) {
+       static int (*func) (const char *, int, mode_t) = NULL;
+       mode_t mode = 0;
+       va_list args;
+       int fd;
+
+       if (!func)
+               func = (int (*) (const char *, int, mode_t)) dlsym (RTLD_NEXT, "open");
+
+       if (flags & O_CREAT) {
+               va_start(args, flags);
+               mode = va_arg(args, mode_t);
+               va_end(args);
+       }
+
+       if (!strcmp (pathname, "/dev/windrvr6")) {
+               DPRINTF("opening windrvr6\n");
+#ifdef NO_WINDRVR
+               windrvrfd = fd = (*func) ("/dev/null", flags, mode);
+#else
+               windrvrfd = fd = (*func) (pathname, flags, mode);
+#endif
+               if (!busses) {
+                       usb_init();
+                       usb_find_busses();
+                       usb_find_devices();
+
+                       busses = usb_get_busses();
+               }
+
+               return fd;
+       }
+
+       return (*func) (pathname, flags, mode);
+}
+
+int close(int fd) {
+       static int (*func) (int) = NULL;
+
+       if (!func)
+               func = (int (*) (int)) dlsym(RTLD_NEXT, "close");
+       
+       if (fd == windrvrfd && windrvrfd >= 0) {
+               DPRINTF("close windrvrfd\n");
+               if (usbinterface >= 0)
+                       usb_release_interface(usb_devhandle, usbinterface);
+
+               if (usb_devhandle)
+                       usb_close(usb_devhandle);
+
+               usb_devhandle = NULL;
+               usbinterface = -1;
+               windrvrfd = -1;
+       }
+
+       return (*func) (fd);
+}
+
+FILE *fopen(const char *path, const char *mode) {
+       FILE *ret;
+       static FILE* (*func) (const char*, const char*) = NULL;
+       char buf[256];
+       int i;
+
+       if (!func)
+               func = (FILE* (*) (const char*, const char*)) dlsym(RTLD_NEXT, "fopen");
+
+       for (i = 0; i < 4; i++) {
+               snprintf(buf, sizeof(buf), "/proc/sys/dev/parport/parport%d/base-addr", i);
+               if (!strcmp(path, buf)) {
+                       DPRINTF("open base-addr of parport%d\n", i);
+                       if (config_is_real_pport(i)) {
+                               ret = (*func) (path, mode);
+                       } else {
+                               ret = (*func) ("/dev/null", mode);
+                       }
+
+                       if (ret) {
+                               baseaddrfp = ret;
+                               baseaddrnum = i;
+                       }
+
+                       return ret;
+               }
+       }
+
+       ret = (*func) (path, mode);
+
+       if (!strcmp(path, "/proc/modules")) {
+               DPRINTF("opening /proc/modules\n");
+#ifdef NO_WINDRVR
+               modulesfp = ret;
+               modules_read = 0;
+#endif
+       }
+
+       return ret;
+}
+
+char *fgets(char *s, int size, FILE *stream) {
+        static char* (*func) (char*, int, FILE*) = NULL;
+       const char modules[][256] = {"windrvr6 1 0 - Live 0xdeadbeef\n", "parport_pc 1 0 - Live 0xdeadbeef\n"};
+       char buf[256];
+       char *ret = NULL;
+
+
+       if (!func)
+               func = (char* (*) (char*, int, FILE*)) dlsym(RTLD_NEXT, "fgets");
+       
+       if (modulesfp == stream) {
+               if (modules_read < sizeof(modules) / sizeof(modules[0])) {
+                       strcpy(s, modules[modules_read]);
+                       ret = s;
+                       modules_read++;
+               }
+       } else if (baseaddrfp == stream) {
+               snprintf(s, sizeof(buf), "%d\t%d\n",
+                       (baseaddrnum) * 0x10,
+                       ((baseaddrnum) * 0x10) + 0x400);
+               ret = s;
+       } else {
+               ret = (*func)(s,size,stream);
+       }
+
+       return ret;
+}
+
+int fclose(FILE *fp) {
+       static int (*func) (FILE*) = NULL;
+
+       if (!func)
+               func = (int (*) (FILE*)) dlsym(RTLD_NEXT, "fclose");
+
+       if (fp == modulesfp) {
+               modulesfp = NULL;
+       }
+
+       if (fp == baseaddrfp) {
+               baseaddrfp = NULL;
+       }
+       
+       return (*func)(fp);
+}
+
+int access(const char *pathname, int mode) {
+       static int (*func) (const char*, int);
+
+       if (!func)
+               func = (int (*) (const char*, int)) dlsym(RTLD_NEXT, "access");
+
+       if (pathname && !strcmp(pathname, "/dev/windrvr6")) {
+               return 0;
+       } else {
+               return (*func)(pathname, mode);
+       }
+}
diff --git a/misc/usb-driver.h b/misc/usb-driver.h
new file mode 100644 (file)
index 0000000..baddf4a
--- /dev/null
@@ -0,0 +1,398 @@
+#define VERSION                        0x910
+#define LICENSE                        0x952
+#define TRANSFER               0x98c
+#define MULTI_TRANSFER         0x98d
+#define USB_TRANSFER           0x983
+#define EVENT_UNREGISTER       0x987
+#define INT_DISABLE            0x91f
+#define INT_WAIT               0x94b
+#define CARD_REGISTER          0x9a4
+#define EVENT_REGISTER         0x9a5
+#define CARD_UNREGISTER                0x92b
+#define USB_GET_DEVICE_DATA    0x9a7
+#define INT_ENABLE             0x98e
+#define EVENT_PULL             0x988
+#define USB_SET_INTERFACE      0x981
+#define CARD_REGISTER_OLD      0x97d
+#define INT_ENABLE_OLD         0x91e
+#define USB_GET_DEVICE_DATA_OLD        0x980
+#define EVENT_REGISTER_OLD     0x986
+#define TRANSFER_OLD           0x903
+#define MULTI_TRANSFER_OLD     0x904
+
+#define MAGIC 0xa410b413UL
+
+#define PP_DATA                        0
+#define PP_STATUS              1
+#define PP_CONTROL             2
+#define PP_ECP_CFGA            0
+#define PP_ECP_CFGB            1
+#define PP_ECP_ECR             2
+#define PP_READ                        10
+#define PP_WRITE               13
+
+#define PP_TDI                 0x01
+#define PP_TDO                 0x10
+#define PP_PROG                        0x10
+#define PP_TCK                 0x02
+#define PP_TMS                 0x04
+#define PP_CTRL                        0x08
+
+#ifdef DEBUG
+#define DPRINTF(format, args...) fprintf(stderr, format, ##args)
+#else
+#define DPRINTF(format, args...)
+#endif
+
+void hexdump(unsigned char *buf, int len);
+
+#define WDU_GET_MAX_PACKET_SIZE(x)                ((unsigned short) (((x) & 0x7ff) * (1 + (((x) & 0x1800) >> 11))))
+
+/* http://www.jungo.com/support/documentation/windriver/811/wdusb_man_mhtml/node78.html#SECTION001734000000000000000 */
+
+struct header_struct {
+       unsigned long magic;
+       void* data;
+       unsigned long size;
+};
+
+struct version_struct {
+       unsigned long versionul;
+       char version[128];
+};
+
+struct license_struct {
+       char cLicense[128]; // Buffer with license string to put.
+       // If empty string then get current license setting
+       // into dwLicense.
+       unsigned long dwLicense;  // Returns license settings: LICENSE_DEMO, LICENSE_WD
+       // etc..., or 0 for invalid license.
+       unsigned long dwLicense2; // Returns additional license settings, if dwLicense
+       // could not hold all the information.
+       // Then dwLicense will return 0.
+};
+
+typedef struct
+{
+       unsigned long dwVendorId;
+       unsigned long dwDeviceId;
+} WD_PCI_ID;
+
+typedef struct
+{
+       unsigned long dwBus;
+       unsigned long dwSlot;
+       unsigned long dwFunction;
+} WD_PCI_SLOT;
+
+typedef struct
+{
+       unsigned long dwVendorId;
+       unsigned long dwProductId;
+} WD_USB_ID;
+
+typedef struct
+{
+       unsigned short VendorId;
+       unsigned short ProductId;
+       unsigned char bDeviceClass;
+       unsigned char bDeviceSubClass;
+       unsigned char bInterfaceClass;
+       unsigned char bInterfaceSubClass;
+       unsigned char bInterfaceProtocol;
+} WDU_MATCH_TABLE;
+
+typedef struct
+{
+       unsigned long dwNumber;        // Pipe 0 is the default pipe
+       unsigned long dwMaximumPacketSize;
+       unsigned long type;            // USB_PIPE_TYPE
+       unsigned long direction;       // WDU_DIR
+       // Isochronous, Bulk, Interrupt are either USB_DIR_IN or USB_DIR_OUT
+       // Control are USB_DIR_IN_OUT
+       unsigned long dwInterval;      // interval in ms relevant to Interrupt pipes
+} WD_USB_PIPE_INFO, WD_USB_PIPE_INFO_V43, WDU_PIPE_INFO;
+
+#define WD_USB_MAX_PIPE_NUMBER 32
+
+typedef struct
+{
+       unsigned long dwPipes;
+       WD_USB_PIPE_INFO Pipe[WD_USB_MAX_PIPE_NUMBER];
+} WD_USB_DEVICE_INFO, WD_USB_DEVICE_INFO_V43;
+
+struct usb_transfer
+{
+       unsigned long dwUniqueID;
+       unsigned long dwPipeNum;    // Pipe number on device.
+       unsigned long fRead;        // TRUE for read (IN) transfers; FALSE for write (OUT) transfers.
+       unsigned long dwOptions;    // USB_TRANSFER options:
+       // USB_ISOCH_FULL_PACKETS_ONLY - For isochronous
+       // transfers only. If set, only full packets will be
+       // transmitted and the transfer function will return
+       // when the amount of bytes left to transfer is less
+       // than the maximum packet size for the pipe (the
+       // function will return without transmitting the
+       // remaining bytes).
+       void* pBuffer;    // Pointer to buffer to read/write.
+       unsigned long dwBufferSize; // Amount of bytes to transfer.
+       unsigned long dwBytesTransferred; // Returns the number of bytes actually read/written
+       unsigned char SetupPacket[8];          // Setup packet for control pipe transfer.
+       unsigned long dwTimeout;    // Timeout for the transfer in milliseconds. Set to 0 for infinite wait.
+};
+
+
+
+
+struct event {
+       unsigned long handle;
+       unsigned long dwAction; // WD_EVENT_ACTION
+       unsigned long dwStatus; // EVENT_STATUS
+       unsigned long dwEventId;
+       unsigned long dwCardType; //WD_BUS_PCI, WD_BUS_USB, WD_BUS_PCMCIA
+       unsigned long hKernelPlugIn;
+       unsigned long dwOptions; // WD_EVENT_OPTION
+       union
+       {
+               struct
+               {
+                       WD_PCI_ID cardId;
+                       WD_PCI_SLOT pciSlot;
+               } Pci;
+               struct
+               {
+                       WD_USB_ID deviceId;
+                       unsigned long dwUniqueID;
+               } Usb;
+       } u;
+       unsigned long dwEventVer;
+       unsigned long dwNumMatchTables;
+       WDU_MATCH_TABLE matchTables[1];
+};
+
+typedef struct
+{
+       unsigned long dwBusType;        // Bus Type: ISA, EISA, PCI, PCMCIA.
+       unsigned long dwBusNum;         // Bus number.
+       unsigned long dwSlotFunc;       // Slot number on Bus.
+} WD_BUS, WD_BUS_V30;
+
+typedef struct
+{
+       unsigned long item; // ITEM_TYPE
+       unsigned long fNotSharable;
+       unsigned long dwReserved; // Reserved for internal use
+       unsigned long dwOptions; // WD_ITEM_OPTIONS
+       union
+       {
+               struct
+               { // ITEM_MEMORY
+                       unsigned long dwPhysicalAddr;     // Physical address on card.
+                       unsigned long dwBytes;            // Address range.
+                       void* dwTransAddr;         // Returns the address to pass on to transfer commands.
+                       void* dwUserDirectAddr;   // Returns the address for direct user read/write.
+                       unsigned long dwCpuPhysicalAddr;  // Returns the CPU physical address
+                       unsigned long dwBar;              // Base Address Register number of PCI card.
+               } Mem;
+               struct
+               { // ITEM_IO
+                       void* dwAddr;          // Beginning of io address.
+                       unsigned long dwBytes;        // IO range.
+                       unsigned long dwBar;          // Base Address Register number of PCI card.
+               } IO;
+               struct
+               { // ITEM_INTERRUPT
+                       unsigned long dwInterrupt; // Number of interrupt to install.
+                       unsigned long dwOptions;   // Interrupt options. For level sensitive
+                       // interrupts - set to: INTERRUPT_LEVEL_SENSITIVE.
+                       unsigned long hInterrupt;  // Returns the handle of the interrupt installed.
+               } Int;
+               WD_BUS Bus; // ITEM_BUS
+               struct
+               {
+                       unsigned long dw1, dw2, dw3, dw4; // Reserved for internal use
+                       void* dw5; // Reserved for internal use
+               } Val;
+       } I;
+} WD_ITEMS, WD_ITEMS_V30;
+
+#define WD_CARD_ITEMS  20
+
+typedef struct
+{
+       unsigned long dwItems;
+       WD_ITEMS Item[WD_CARD_ITEMS];
+} WD_CARD, WD_CARD_V30;
+
+enum { CARD_VX_NO_MMU_INIT = 0x4000000 };
+
+struct card_register
+{
+       WD_CARD Card;           // Card to register.
+       unsigned long fCheckLockOnly;   // Only check if card is lockable, return hCard=1 if OK.
+       unsigned long hCard;            // Handle of card.
+       unsigned long dwOptions;        // Should be zero.
+       char cName[32];         // Name of card.
+       char cDescription[100]; // Description.
+};
+
+typedef struct
+{
+       void* dwPort;       // IO port for transfer or kernel memory address.
+       unsigned long cmdTrans;    // Transfer command WD_TRANSFER_CMD.
+
+       // Parameters used for string transfers:
+       unsigned long dwBytes;     // For string transfer.
+       unsigned long fAutoinc;    // Transfer from one port/address
+       // or use incremental range of addresses.
+       unsigned long dwOptions;   // Must be 0.
+       union
+       {
+               unsigned char Byte;     // Use for 8 bit transfer.
+               unsigned short Word;     // Use for 16 bit transfer.
+               uint32_t Dword;   // Use for 32 bit transfer.
+               uint64_t Qword;  // Use for 64 bit transfer.
+               void* pBuffer; // Use for string transfer.
+       } Data;
+} WD_TRANSFER, WD_TRANSFER_V61;
+
+typedef struct
+{
+       unsigned long hKernelPlugIn;
+       unsigned long dwMessage;
+       void* pData;
+       unsigned long dwResult;
+} WD_KERNEL_PLUGIN_CALL, WD_KERNEL_PLUGIN_CALL_V40;
+
+
+struct interrupt
+{
+       unsigned long hInterrupt;    // Handle of interrupt.
+       unsigned long dwOptions;     // Interrupt options: can be INTERRUPT_CMD_COPY
+
+       WD_TRANSFER *Cmd;    // Commands to do on interrupt.
+       unsigned long dwCmds;        // Number of commands.
+
+       // For WD_IntEnable():
+       WD_KERNEL_PLUGIN_CALL kpCall; // Kernel PlugIn call.
+       unsigned long fEnableOk;     // TRUE if interrupt was enabled (WD_IntEnable() succeed).
+
+       // For WD_IntWait() and WD_IntCount():
+       unsigned long dwCounter;     // Number of interrupts received.
+       unsigned long dwLost;        // Number of interrupts not yet dealt with.
+       unsigned long fStopped;      // Was interrupt disabled during wait.
+};
+
+struct usb_set_interface
+{
+       unsigned long dwUniqueID;
+       unsigned long dwInterfaceNum;
+       unsigned long dwAlternateSetting;
+       unsigned long dwOptions;
+};
+
+struct usb_get_device_data
+{
+       unsigned long dwUniqueID;
+       void* pBuf;
+       unsigned long dwBytes;
+       unsigned long dwOptions;
+};
+
+#define WD_USB_MAX_INTERFACES 30
+
+typedef struct
+{
+       unsigned char bLength;
+       unsigned char bDescriptorType;
+       unsigned char bInterfaceNumber;
+       unsigned char bAlternateSetting;
+       unsigned char bNumEndpoints;
+       unsigned char bInterfaceClass;
+       unsigned char bInterfaceSubClass;
+       unsigned char bInterfaceProtocol;
+       unsigned char iInterface;
+} WDU_INTERFACE_DESCRIPTOR;
+
+typedef struct
+{
+       unsigned char bLength;
+       unsigned char bDescriptorType;
+       unsigned char bEndpointAddress;
+       unsigned char bmAttributes;
+       unsigned short wMaxPacketSize;
+       unsigned char bInterval;
+} WDU_ENDPOINT_DESCRIPTOR;
+
+typedef struct
+{
+       unsigned char bLength;
+       unsigned char bDescriptorType;
+       unsigned short wTotalLength;
+       unsigned char bNumInterfaces;
+       unsigned char bConfigurationValue;
+       unsigned char iConfiguration;
+       unsigned char bmAttributes;
+       unsigned char MaxPower;
+} WDU_CONFIGURATION_DESCRIPTOR;
+
+typedef struct
+{
+       unsigned char bLength;
+       unsigned char bDescriptorType;
+       unsigned short bcdUSB;
+       unsigned char bDeviceClass;
+       unsigned char bDeviceSubClass;
+       unsigned char bDeviceProtocol;
+       unsigned char bMaxPacketSize0;
+
+       unsigned short idVendor;
+       unsigned short idProduct;
+       unsigned short bcdDevice;
+       unsigned char iManufacturer;
+       unsigned char iProduct;
+       unsigned char iSerialNumber;
+       unsigned char bNumConfigurations;
+} WDU_DEVICE_DESCRIPTOR;
+
+typedef struct
+{
+       WDU_INTERFACE_DESCRIPTOR Descriptor;
+       WDU_ENDPOINT_DESCRIPTOR *pEndpointDescriptors;
+       WDU_PIPE_INFO *pPipes;
+} WDU_ALTERNATE_SETTING;
+
+typedef struct
+{
+       WDU_ALTERNATE_SETTING *pAlternateSettings;
+       unsigned long dwNumAltSettings;
+       WDU_ALTERNATE_SETTING *pActiveAltSetting;
+} WDU_INTERFACE;
+
+typedef struct
+{
+       WDU_CONFIGURATION_DESCRIPTOR Descriptor;
+       unsigned long dwNumInterfaces;
+       WDU_INTERFACE *pInterfaces;
+} WDU_CONFIGURATION;
+
+struct usb_device_info {
+       WDU_DEVICE_DESCRIPTOR Descriptor;
+       WDU_PIPE_INFO Pipe0;
+       WDU_CONFIGURATION *pConfigs;
+       WDU_CONFIGURATION *pActiveConfig;
+       WDU_INTERFACE *pActiveInterface[WD_USB_MAX_INTERFACES];
+};
+
+typedef enum {
+       WDU_DIR_IN     = 1,
+       WDU_DIR_OUT    = 2,
+       WDU_DIR_IN_OUT = 3
+} WDU_DIR;
+
+typedef enum {
+       PIPE_TYPE_CONTROL     = 0,
+       PIPE_TYPE_ISOCHRONOUS = 1,
+       PIPE_TYPE_BULK        = 2,
+       PIPE_TYPE_INTERRUPT   = 3
+} USB_PIPE_TYPE;