--- /dev/null
+#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
--- /dev/null
+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
--- /dev/null
+#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;
+}
--- /dev/null
+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);
--- /dev/null
+<!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 (> 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&Nav2=Cables&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>
--- /dev/null
+#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;
+}
--- /dev/null
+#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);
--- /dev/null
+#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;
+}
--- /dev/null
+void jtagmon(unsigned char tck, unsigned char tms, unsigned char tdi);
--- /dev/null
+# 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
--- /dev/null
+#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;
+ }
+}
--- /dev/null
+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);
--- /dev/null
+#!/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
--- /dev/null
+/* 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);
+ }
+}
--- /dev/null
+#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;