From: adam Date: Wed, 30 Jan 2008 07:33:47 +0000 (+0100) Subject: add misc directory X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=06167b8360ee840a0e5c42d67492ef1410f624d6;p=fleet.git add misc directory --- diff --git a/misc/Makefile b/misc/Makefile new file mode 100644 index 0000000..8a21424 --- /dev/null +++ b/misc/Makefile @@ -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 index 0000000..f69cadd --- /dev/null +++ b/misc/README @@ -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 index 0000000..a39902e --- /dev/null +++ b/misc/config.c @@ -0,0 +1,245 @@ +#include +#include +#include +#include +#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 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 + + + XILINX USB/Parallel JTAG cables on Linux without windrvr + + +

XILINX JTAG tools on Linux without proprietary kernel modules

+

About

+

+ When using XILINX JTAG software like Impact, Chipscope and XMD + on Linux, the proprietary kernel module windrvr from Jungo + 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. +

+

+ The library uses libusb to access USB devices and the + ppdev 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. +

+

+ 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. +

+

+ The library is called libusb-driver as it was developed to support the USB cable, but later + extended to also support parallel cables. +

+

Supported Cables

+ The following cables are reported to work with this driver: + + These cables should work but have not yet been tested: +
    +
  • Integrated Platform Cable USB on other development boards
  • +
  • other Parallel Cable III clones
  • +
  • other FTDI2232 based devices which use the chips standard JTAG pinout (experimental)
  • +
+

Supported Software

+ The following software is reported to work with this driver: + +

Download

+
    +
  • Download usb-driver-HEAD.tar.gz (to build it, you need to have the libusb development package installed. It is called libusb-dev on Debian.)
  • +
  • Read the README
  • +
  • Browse the Git repository (Summary)
  • +
  • Precompiled libusb-driver.so for Debian Etch, but better build your own
  • +
  • Clone the Git repository with: git clone git://git.zerfleddert.de/usb-driver
  • +
+

Links

+ +
+ Michael Gernoth + + diff --git a/misc/jtagkey.c b/misc/jtagkey.c new file mode 100644 index 0000000..fc9587c --- /dev/null +++ b/misc/jtagkey.c @@ -0,0 +1,376 @@ +#include +#include +#include +#include +#include +#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 index 0000000..2c13260 --- /dev/null +++ b/misc/jtagkey.h @@ -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 index 0000000..1a71ce0 --- /dev/null +++ b/misc/jtagmon.c @@ -0,0 +1,214 @@ +#include +#include +#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 index 0000000..030db23 --- /dev/null +++ b/misc/jtagmon.h @@ -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 index 0000000..98d0e31 --- /dev/null +++ b/misc/libusb-driverrc @@ -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 index 0000000..57ab083 --- /dev/null +++ b/misc/parport.c @@ -0,0 +1,168 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 0000000..ee46098 --- /dev/null +++ b/misc/parport.h @@ -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 index 0000000..bb9357d --- /dev/null +++ b/misc/program.sh @@ -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' < + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; iDescriptor.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; idescriptor.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; jbNumInterfaces; 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; jbNumInterfaces; 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; knum_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 index 0000000..baddf4a --- /dev/null +++ b/misc/usb-driver.h @@ -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;