/*
* Clone of usb blaster driver
*
* Copyright (C) 2009 Setec Astronomy Project - who are not aware of the donation of this code
* to their cause, but can be notified by sending this file to them.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version, with the exception of
* any individual providing services to a corporation, or the corporation itself,
* if the name of the corporation starts with:
*
* "ARR" or "ALTER"
*
* These corporations and their employees, assigns, contractors, shareholders,
* rightsholders, attorneys and associates are specifically excluded by this
* license. This is not discriminatory; they can obtain software to perform
* interoperability and necessary functionality by pursuing internal licensing
* within their corporations or with all relevant rightsholders.
*
* Copyright infringement by the above corporations and their employees, assigns,
* contractors, shareholders, rightsholders, attorneys and associates will be
* prosecuted to the fullest extent of the law. This license shall be governed
* by the laws of the State of California. If any part of this license
* is deemed to be invalid under applicable law, the remainder of the license
* shall be deemed severable and remain in force.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
*
* Please read to the bottom of the file for instructions on how to use this.
*/
#include <string.h>
#include <dlfcn.h>
/*
* The following section is pasted verbatim from libftdi.h, part of the package
* libftdi-0.18
*
* If you prefer, you can use the file installed on your system using:
* #include "libftdi-0.18.h"
*
* libftdi.so must also be installed from the same package. It is dynamically loaded
* below.
*
* The following is Copyright (C) 2003 by Intra2net AG, and is licensed under
* the GNU Lesser General Public License.
*
* The derived work, namely, the whole of this file, is governed by the copyright above,
* under the compatible but more restrictive GNU Affero General Public License.
*/
/***************************************************************************
ftdi.h - description
-------------------
begin : Fri Apr 4 2003
copyright : (C) 2003 by Intra2net AG
email : opensource@intra2net.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License *
* version 2.1 as published by the Free Software Foundation; *
* *
***************************************************************************/
#ifndef __libftdi_h__
#define __libftdi_h__
#include <usb.h>
#define FTDI_DEFAULT_EEPROM_SIZE 128
/** FTDI chip type */
enum ftdi_chip_type { TYPE_AM=0, TYPE_BM=1, TYPE_2232C=2, TYPE_R=3, TYPE_2232H=4, TYPE_4232H=5 };
/** Parity mode for ftdi_set_line_property() */
enum ftdi_parity_type { NONE=0, ODD=1, EVEN=2, MARK=3, SPACE=4 };
/** Number of stop bits for ftdi_set_line_property() */
enum ftdi_stopbits_type { STOP_BIT_1=0, STOP_BIT_15=1, STOP_BIT_2=2 };
/** Number of bits for ftdi_set_line_property() */
enum ftdi_bits_type { BITS_7=7, BITS_8=8 };
/** Break type for ftdi_set_line_property2() */
enum ftdi_break_type { BREAK_OFF=0, BREAK_ON=1 };
/** MPSSE bitbang modes */
enum ftdi_mpsse_mode
{
BITMODE_RESET = 0x00, /**< switch off bitbang mode, back to regular serial/FIFO */
BITMODE_BITBANG= 0x01, /**< classical asynchronous bitbang mode, introduced with B-type chips */
BITMODE_MPSSE = 0x02, /**< MPSSE mode, available on 2232x chips */
BITMODE_SYNCBB = 0x04, /**< synchronous bitbang mode, available on 2232x and R-type chips */
BITMODE_MCU = 0x08, /**< MCU Host Bus Emulation mode, available on 2232x chips */
/* CPU-style fifo mode gets set via EEPROM */
BITMODE_OPTO = 0x10, /**< Fast Opto-Isolated Serial Interface Mode, available on 2232x chips */
BITMODE_CBUS = 0x20, /**< Bitbang on CBUS pins of R-type chips, configure in EEPROM before */
BITMODE_SYNCFF = 0x40, /**< Single Channel Synchronous FIFO mode, available on 2232H chips */
};
/** Port interface for chips with multiple interfaces */
enum ftdi_interface
{
INTERFACE_ANY = 0,
INTERFACE_A = 1,
INTERFACE_B = 2,
INTERFACE_C = 3,
INTERFACE_D = 4
};
/* Shifting commands IN MPSSE Mode*/
#define MPSSE_WRITE_NEG 0x01 /* Write TDI/DO on negative TCK/SK edge*/
#define MPSSE_BITMODE 0x02 /* Write bits, not bytes */
#define MPSSE_READ_NEG 0x04 /* Sample TDO/DI on negative TCK/SK edge */
#define MPSSE_LSB 0x08 /* LSB first */
#define MPSSE_DO_WRITE 0x10 /* Write TDI/DO */
#define MPSSE_DO_READ 0x20 /* Read TDO/DI */
#define MPSSE_WRITE_TMS 0x40 /* Write TMS/CS */
/* FTDI MPSSE commands */
#define SET_BITS_LOW 0x80
/*BYTE DATA*/
/*BYTE Direction*/
#define SET_BITS_HIGH 0x82
/*BYTE DATA*/
/*BYTE Direction*/
#define GET_BITS_LOW 0x81
#define GET_BITS_HIGH 0x83
#define LOOPBACK_START 0x84
#define LOOPBACK_END 0x85
#define TCK_DIVISOR 0x86
/* Value Low */
/* Value HIGH */ /*rate is 12000000/((1+value)*2) */
#define DIV_VALUE(rate) (rate > 6000000)?0:((6000000/rate -1) > 0xffff)? 0xffff: (6000000/rate -1)
/* Commands in MPSSE and Host Emulation Mode */
#define SEND_IMMEDIATE 0x87
#define WAIT_ON_HIGH 0x88
#define WAIT_ON_LOW 0x89
/* Commands in Host Emulation Mode */
#define READ_SHORT 0x90
/* Address_Low */
#define READ_EXTENDED 0x91
/* Address High */
/* Address Low */
#define WRITE_SHORT 0x92
/* Address_Low */
#define WRITE_EXTENDED 0x93
/* Address High */
/* Address Low */
/* Definitions for flow control */
#define SIO_RESET 0 /* Reset the port */
#define SIO_MODEM_CTRL 1 /* Set the modem control register */
#define SIO_SET_FLOW_CTRL 2 /* Set flow control register */
#define SIO_SET_BAUD_RATE 3 /* Set baud rate */
#define SIO_SET_DATA 4 /* Set the data characteristics of the port */
#define FTDI_DEVICE_OUT_REQTYPE (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT)
#define FTDI_DEVICE_IN_REQTYPE (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN)
/* Requests */
#define SIO_RESET_REQUEST SIO_RESET
#define SIO_SET_BAUDRATE_REQUEST SIO_SET_BAUD_RATE
#define SIO_SET_DATA_REQUEST SIO_SET_DATA
#define SIO_SET_FLOW_CTRL_REQUEST SIO_SET_FLOW_CTRL
#define SIO_SET_MODEM_CTRL_REQUEST SIO_MODEM_CTRL
#define SIO_POLL_MODEM_STATUS_REQUEST 0x05
#define SIO_SET_EVENT_CHAR_REQUEST 0x06
#define SIO_SET_ERROR_CHAR_REQUEST 0x07
#define SIO_SET_LATENCY_TIMER_REQUEST 0x09
#define SIO_GET_LATENCY_TIMER_REQUEST 0x0A
#define SIO_SET_BITMODE_REQUEST 0x0B
#define SIO_READ_PINS_REQUEST 0x0C
#define SIO_READ_EEPROM_REQUEST 0x90
#define SIO_WRITE_EEPROM_REQUEST 0x91
#define SIO_ERASE_EEPROM_REQUEST 0x92
#define SIO_RESET_SIO 0
#define SIO_RESET_PURGE_RX 1
#define SIO_RESET_PURGE_TX 2
#define SIO_DISABLE_FLOW_CTRL 0x0
#define SIO_RTS_CTS_HS (0x1 << 8)
#define SIO_DTR_DSR_HS (0x2 << 8)
#define SIO_XON_XOFF_HS (0x4 << 8)
#define SIO_SET_DTR_MASK 0x1
#define SIO_SET_DTR_HIGH ( 1 | ( SIO_SET_DTR_MASK << 8))
#define SIO_SET_DTR_LOW ( 0 | ( SIO_SET_DTR_MASK << 8))
#define SIO_SET_RTS_MASK 0x2
#define SIO_SET_RTS_HIGH ( 2 | ( SIO_SET_RTS_MASK << 8 ))
#define SIO_SET_RTS_LOW ( 0 | ( SIO_SET_RTS_MASK << 8 ))
#define SIO_RTS_CTS_HS (0x1 << 8)
/* marker for unused usb urb structures
(taken from libusb) */
#define FTDI_URB_USERCONTEXT_COOKIE ((void *)0x1)
#ifdef __GNUC__
#define DEPRECATED(func) func __attribute__ ((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED(func) __declspec(deprecated) func
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED(func) func
#endif
/**
\brief Main context structure for all libftdi functions.
Do not access directly if possible.
*/
struct ftdi_context
{
/* USB specific */
/** libusb's usb_dev_handle */
struct usb_dev_handle *usb_dev;
/** usb read timeout */
int usb_read_timeout;
/** usb write timeout */
int usb_write_timeout;
/* FTDI specific */
/** FTDI chip type */
enum ftdi_chip_type type;
/** baudrate */
int baudrate;
/** bitbang mode state */
unsigned char bitbang_enabled;
/** pointer to read buffer for ftdi_read_data */
unsigned char *readbuffer;
/** read buffer offset */
unsigned int readbuffer_offset;
/** number of remaining data in internal read buffer */
unsigned int readbuffer_remaining;
/** read buffer chunk size */
unsigned int readbuffer_chunksize;
/** write buffer chunk size */
unsigned int writebuffer_chunksize;
/** maximum packet size. Needed for filtering modem status bytes every n packets. */
unsigned int max_packet_size;
/* FTDI FT2232C requirecments */
/** FT2232C interface number: 0 or 1 */
int interface; /* 0 or 1 */
/** FT2232C index number: 1 or 2 */
int index; /* 1 or 2 */
/* Endpoints */
/** FT2232C end points: 1 or 2 */
int in_ep;
int out_ep; /* 1 or 2 */
/** Bitbang mode. 1: (default) Normal bitbang mode, 2: FT2232C SPI bitbang mode */
unsigned char bitbang_mode;
/** EEPROM size. Default is 128 bytes for 232BM and 245BM chips */
int eeprom_size;
/** String representation of last error */
char *error_str;
/** Buffer needed for async communication */
char *async_usb_buffer;
/** Number of URB-structures we can buffer */
unsigned int async_usb_buffer_size;
};
/**
\brief list of usb devices created by ftdi_usb_find_all()
*/
struct ftdi_device_list
{
/** pointer to next entry */
struct ftdi_device_list *next;
/** pointer to libusb's usb_device */
struct usb_device *dev;
};
/**
\brief FTDI eeprom structure
*/
struct ftdi_eeprom
{
/** vendor id */
int vendor_id;
/** product id */
int product_id;
/** self powered */
int self_powered;
/** remote wakeup */
int remote_wakeup;
/** chip type */
int BM_type_chip;
/** input in isochronous transfer mode */
int in_is_isochronous;
/** output in isochronous transfer mode */
int out_is_isochronous;
/** suspend pull downs */
int suspend_pull_downs;
/** use serial */
int use_serial;
/** fake usb version */
int change_usb_version;
/** usb version */
int usb_version;
/** maximum power */
int max_power;
/** manufacturer name */
char *manufacturer;
/** product name */
char *product;
/** serial number */
char *serial;
/** eeprom size in bytes. This doesn't get stored in the eeprom
but is the only way to pass it to ftdi_eeprom_build. */
int size;
};
#ifdef __cplusplus
extern "C"
{
#endif
int ftdi_init(struct ftdi_context *ftdi);
struct ftdi_context *ftdi_new(void);
int ftdi_set_interface(struct ftdi_context *ftdi, enum ftdi_interface interface);
void ftdi_deinit(struct ftdi_context *ftdi);
void ftdi_free(struct ftdi_context *ftdi);
void ftdi_set_usbdev (struct ftdi_context *ftdi, usb_dev_handle *usbdev);
int ftdi_usb_find_all(struct ftdi_context *ftdi, struct ftdi_device_list **devlist,
int vendor, int product);
void ftdi_list_free(struct ftdi_device_list **devlist);
void ftdi_list_free2(struct ftdi_device_list *devlist);
int ftdi_usb_get_strings(struct ftdi_context *ftdi, struct usb_device *dev,
char * manufacturer, int mnf_len,
char * description, int desc_len,
char * serial, int serial_len);
int ftdi_usb_open(struct ftdi_context *ftdi, int vendor, int product);
int ftdi_usb_open_desc(struct ftdi_context *ftdi, int vendor, int product,
const char* description, const char* serial);
int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product,
const char* description, const char* serial, unsigned int index);
int ftdi_usb_open_dev(struct ftdi_context *ftdi, struct usb_device *dev);
int ftdi_usb_open_string(struct ftdi_context *ftdi, const char* description);
int ftdi_usb_close(struct ftdi_context *ftdi);
int ftdi_usb_reset(struct ftdi_context *ftdi);
int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi);
int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi);
int ftdi_usb_purge_buffers(struct ftdi_context *ftdi);
int ftdi_set_baudrate(struct ftdi_context *ftdi, int baudrate);
int ftdi_set_line_property(struct ftdi_context *ftdi, enum ftdi_bits_type bits,
enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity);
int ftdi_set_line_property2(struct ftdi_context *ftdi, enum ftdi_bits_type bits,
enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity,
enum ftdi_break_type break_type);
int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size);
int ftdi_read_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize);
int ftdi_read_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize);
int ftdi_write_data(struct ftdi_context *ftdi, unsigned char *buf, int size);
int ftdi_write_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize);
int ftdi_write_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize);
int ftdi_write_data_async(struct ftdi_context *ftdi, unsigned char *buf, int size);
void ftdi_async_complete(struct ftdi_context *ftdi, int wait_for_more);
int DEPRECATED(ftdi_enable_bitbang(struct ftdi_context *ftdi, unsigned char bitmask));
int ftdi_disable_bitbang(struct ftdi_context *ftdi);
int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode);
int ftdi_read_pins(struct ftdi_context *ftdi, unsigned char *pins);
int ftdi_set_latency_timer(struct ftdi_context *ftdi, unsigned char latency);
int ftdi_get_latency_timer(struct ftdi_context *ftdi, unsigned char *latency);
int ftdi_poll_modem_status(struct ftdi_context *ftdi, unsigned short *status);
/* flow control */
int ftdi_setflowctrl(struct ftdi_context *ftdi, int flowctrl);
int ftdi_setdtr_rts(struct ftdi_context *ftdi, int dtr, int rts);
int ftdi_setdtr(struct ftdi_context *ftdi, int state);
int ftdi_setrts(struct ftdi_context *ftdi, int state);
int ftdi_set_event_char(struct ftdi_context *ftdi, unsigned char eventch, unsigned char enable);
int ftdi_set_error_char(struct ftdi_context *ftdi, unsigned char errorch, unsigned char enable);
/* set eeprom size */
void ftdi_eeprom_setsize(struct ftdi_context *ftdi, struct ftdi_eeprom *eeprom, int size);
/* init and build eeprom from ftdi_eeprom structure */
void ftdi_eeprom_initdefaults(struct ftdi_eeprom *eeprom);
void ftdi_eeprom_free(struct ftdi_eeprom *eeprom);
int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output);
int ftdi_eeprom_decode(struct ftdi_eeprom *eeprom, unsigned char *output, int size);
/* "eeprom" needs to be valid 128 byte eeprom (generated by the eeprom generator)
the checksum of the eeprom is valided */
int ftdi_read_eeprom(struct ftdi_context *ftdi, unsigned char *eeprom);
int ftdi_read_chipid(struct ftdi_context *ftdi, unsigned int *chipid);
int ftdi_read_eeprom_getsize(struct ftdi_context *ftdi, unsigned char *eeprom, int maxsize);
int ftdi_write_eeprom(struct ftdi_context *ftdi, unsigned char *eeprom);
int ftdi_erase_eeprom(struct ftdi_context *ftdi);
int ftdi_read_eeprom_location (struct ftdi_context *ftdi, int eeprom_addr, unsigned short *eeprom_val);
int ftdi_write_eeprom_location(struct ftdi_context *ftdi, int eeprom_addr, unsigned short eeprom_val);
char *ftdi_get_error_string(struct ftdi_context *ftdi);
#ifdef __cplusplus
}
#endif
#endif /* __libftdi_h__ */
/* end of libftdi.h */
#include <stdint.h>
#include <stdio.h>
#define ATTR_CDECL __attribute__((cdecl))
struct ftdi_so_st { /* pointers to libftdi.so */
ATTR_CDECL int (* p_ftdi_init)(struct ftdi_context *ftdi);
ATTR_CDECL uint32_t (* p_ftdi_interface_write)(void * unused_void, unsigned long const * buf, unsigned long count);
ATTR_CDECL int (* p_ftdi_set_interface)(struct ftdi_context *ftdi, enum ftdi_interface interface);
ATTR_CDECL void (* p_ftdi_deinit)(struct ftdi_context *ftdi);
ATTR_CDECL int (* p_ftdi_usb_open)(struct ftdi_context *ftdi, int vendor, int product);
ATTR_CDECL char (* p_ftdi_interface_close)(void * unused_void);
ATTR_CDECL int (* p_ftdi_usb_close)(struct ftdi_context *ftdi);
ATTR_CDECL int (* p_ftdi_usb_reset)(struct ftdi_context *ftdi);
ATTR_CDECL int (* p_ftdi_usb_purge_buffers)(struct ftdi_context *ftdi);
ATTR_CDECL int (* p_ftdi_read_data)(struct ftdi_context *ftdi, unsigned char *buf, int size);
ATTR_CDECL int (* p_ftdi_read_data_set_chunksize)(struct ftdi_context *ftdi, unsigned int chunksize);
ATTR_CDECL int (* p_ftdi_write_data)(struct ftdi_context *ftdi, unsigned char *buf, int size);
ATTR_CDECL int (* p_ftdi_write_data_set_chunksize)(struct ftdi_context *ftdi, unsigned int chunksize);
ATTR_CDECL int (* p_ftdi_write_data_get_chunksize)(struct ftdi_context *ftdi, unsigned int *chunksize);
ATTR_CDECL int (* p_ftdi_set_bitmode)(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode);
ATTR_CDECL char * (* p_ftdi_get_error_string)(struct ftdi_context *ftdi);
void * handle; /* handle to libftdi DSO returned from dlopen() */
unsigned chunksize; /* cached from ftdi_write_data_get_chunksize */
};
typedef ATTR_CDECL char (* fn_find_devs)(uint32_t dev_index, char * out_desc, uint32_t api_ver);
typedef ATTR_CDECL char (* fn_find_descriptions)(const char * description);
typedef ATTR_CDECL int (* fn_init_dev)(uint32_t * p_exit_status, const char * desc, struct ftdi_so_st * s_server_ops, void * parent);
typedef ATTR_CDECL void (* fn_close)(void * unused_void);
typedef ATTR_CDECL void (* fn_pkt_wr_pattern)(void * unused_void, uint32_t jtag_tms, uint32_t v, unsigned long len);
typedef ATTR_CDECL void (* fn_pkt_wr_bits)(void * unused_void, unsigned jtag_tms, unsigned long * p_bits, unsigned long len, unsigned long field_144_minus_len);
typedef ATTR_CDECL char (* fn_do_flush)(void * unused_void, int bool_val, uint32_t index_val);
struct virtual_fns_st { /* ABI to pass data in and out of driver */
uint32_t st_size; /* to check ABI compatibility */
char dev_description[32];
uint32_t st_flags;
void * reserved01[2];
fn_find_devs p_find_devs;
fn_find_descriptions p_find_descriptions;
fn_init_dev p_init_dev;
fn_close p_close;
void * reserved02[3];
fn_pkt_wr_pattern p_pkt_wr_pattern;
fn_pkt_wr_bits p_pkt_wr_bits;
void * reserved03[1];
fn_do_flush p_do_flush;
void * reserved04[5];
};
struct driver_st
{
uint32_t num_devs;
struct virtual_fns_st vfns;
struct ftdi_so_st ffns, str_fns;
struct ftdi_context dev_info;
void * parent;
uint8_t w_buf[0x10000]; /* FT2232D can receive up to 64KB in one USB transfer */
uint32_t w_buf_use, want_read, last_tms, last_cmd, chain_3d;
uint8_t r_buf_2[0x10000], r_nbits[0x10000];
};
extern struct driver_st d;
int do_ftdi_write(uint8_t * c, size_t s)
{
if (!d.ffns.chunksize) return 1;
int r;
if (d.ffns.chunksize < ((s + 0xff) & ~0xff)) {
if ((r = d.ffns.p_ftdi_write_data_set_chunksize(&d.dev_info, (s + 0xff) & ~0xff)) < 0) return 1;
}
size_t i;
if ((r = d.ffns.p_ftdi_write_data(&d.dev_info, c, s)) < 0) return 1;
if (!d.want_read) return 0;
unsigned got_read;
for (got_read = 0, i = 0; got_read < d.want_read; got_read += r, i++) {
if ((r = d.ffns.p_ftdi_read_data(&d.dev_info, &d.r_buf_2[got_read], sizeof(d.r_buf_2)/sizeof(d.r_buf_2[0]) - got_read)) < 0) return 1;
if (i >= 10) return 1;
}
return 0;
}
ATTR_CDECL char find_devs(uint32_t dev_index, char * out_desc, uint32_t api_ver)
{
if (api_ver < 4) return 0;
if (dev_index >= d.num_devs) return 0;
strcpy(out_desc, "bus-instance");
return 1;
}
ATTR_CDECL char find_descriptions(const char * description)
{
return !strcmp(description, "bus-instance");
}
inline void init_w_buf_red_on()
{
d.w_buf[0] = 0x80;
d.w_buf[1] = 0x10;
d.w_buf[2] = 0x9b;
d.w_buf_use = 3;
d.last_tms = 0;
d.last_cmd = 0;
d.chain_3d = 0;
d.want_read = 0;
}
ATTR_CDECL int init_dev(uint32_t * p_exit_status, const char * desc, struct ftdi_so_st * s_server_ops, void * parent)
{
if (!parent) return 1;
if (strcmp(desc, "bus-instance") != 0) return 1;
init_w_buf_red_on();
if (d.ffns.chunksize) return 1;
memset(&d.str_fns, 0, sizeof(d.str_fns));
d.str_fns.p_ftdi_interface_write = s_server_ops->p_ftdi_interface_write;
d.str_fns.p_ftdi_interface_close = s_server_ops->p_ftdi_interface_close;
d.parent = parent;
if (d.ffns.chunksize) return 1;
if (d.ffns.p_ftdi_write_data_get_chunksize(&d.dev_info, &d.ffns.chunksize) < 0 || d.ffns.p_ftdi_set_bitmode(&d.dev_info, 0x0b, 2) < 0) return 1;
d.want_read = 0;
uint8_t cmd[] = { 0x80, 0x90, 0x9b, 0x82, 0x07, 0x07, 0x86, 0, 0, 0x85, };
if (do_ftdi_write(cmd, sizeof(cmd)) || d.ffns.p_ftdi_usb_purge_buffers(&d.dev_info) < 0) return 1;
*p_exit_status = 1;
return 0;
}
ATTR_CDECL void do_close(void * unused_void)
{
}
ATTR_CDECL char do_flush(void * unused_void, int bool_val, uint32_t index_val)
{
if (!d.num_devs) return 1;
uint8_t * wp = &d.w_buf[d.w_buf_use];
*(wp++) = 0x80; *(wp++) = 0x10; *(wp++) = 0x9b; *(wp++) = 0x87;
do_ftdi_write(&d.w_buf[0], d.w_buf_use + 3);
unsigned ulout_use = 0, bit = 0, i, q;
for (i = 0; i < d.want_read; i++) {
uint8_t bv = d.r_buf_2[i];
for (q = 0; q < d.r_nbits[i]; q++) {
if (!bit) d.r_buf_2[ulout_use] = 0; /* prepare next byte to receive bits */
if (bv & (0x80 >> (d.r_nbits[i] - q - 1))) d.r_buf_2[ulout_use] |= 1 << bit;
bit++;
if (bit & 8) {
bit = 0;
ulout_use++;
}
}
}
if (d.str_fns.p_ftdi_interface_write) d.str_fns.p_ftdi_interface_write(d.parent, (unsigned long *) d.r_buf_2, ulout_use * 8 + bit);
if (d.str_fns.p_ftdi_interface_close) d.str_fns.p_ftdi_interface_close(d.parent);
init_w_buf_red_on();
return 1;
}
void send_bit(unsigned tms, unsigned v)
{
if (d.last_tms != tms) {
if (d.last_cmd == 0 && d.w_buf_use == 3) d.w_buf_use = 0;
/* datasheet: TMS should be asserted before rising edge of first clock */
d.w_buf[d.w_buf_use++] = 0x80; d.w_buf[d.w_buf_use++] = 0x10 | (tms ? 0x08 : 0); d.w_buf[d.w_buf_use++] = 0x9b;
d.last_tms = !!tms;
d.chain_3d = 0;
} else if (d.w_buf_use > 3 && d.w_buf[d.last_cmd] == 0x3e) {
if (d.w_buf[d.last_cmd + 1] < 6) {
d.w_buf[d.last_cmd + 2] |= (v ? 1 : 0) << (++d.w_buf[d.last_cmd + 1]);
d.r_nbits[d.want_read - 1]++;
} else {
if (!d.chain_3d) {
d.w_buf[d.last_cmd] = 0x3d;
d.w_buf[d.w_buf_use] = d.w_buf[d.w_buf_use - 1] | (v ? 0x80 : 0); d.w_buf[d.w_buf_use - 1] = 0x00; d.w_buf[d.w_buf_use - 2] = 0x00;
d.w_buf_use++;
d.r_nbits[d.want_read - 1]++;
d.chain_3d = d.last_cmd;
} else {
unsigned chain = (d.w_buf[d.chain_3d + 1] | (d.w_buf[d.chain_3d + 2] << 8)) + 1;
d.w_buf[d.chain_3d + 1] = chain & 0xff; d.w_buf[d.chain_3d + 2] = (chain >> 8) & 0xff; d.w_buf[d.chain_3d + 3 + chain] = d.w_buf[d.last_cmd + 2] | (v ? 0x80 : 0);
d.w_buf_use = d.chain_3d + chain + 4;
d.last_cmd = d.chain_3d;
d.r_nbits[d.want_read - 1]++;
}
}
return;
}
d.last_cmd = d.w_buf_use;
d.w_buf[d.w_buf_use++] = 0x3e; d.w_buf[d.w_buf_use++] = 0x00; d.w_buf[d.w_buf_use++] = (v ? 1 : 0);
d.r_nbits[d.want_read++] = 1;
if (d.want_read > 128) do_flush(0, 0, 0);
}
ATTR_CDECL void pkt_wr_pattern(void * unused_void, uint32_t jtag_tms, uint32_t v, unsigned long len)
{
if (!d.num_devs || len < 1) return;
unsigned long i;
for (i = 0; i < len; i++) send_bit(jtag_tms, v);
}
ATTR_CDECL void pkt_wr_bits(void * unused_void, unsigned jtag_tms, unsigned long * p_bits, unsigned long len, unsigned long field_144_minus_len)
{
if (!d.num_devs || len < 1) return;
unsigned long i;
for (i = 0; i < len; i++) send_bit(jtag_tms, (p_bits[i / 32] >> (i & 31)) & 1);
}
int do_set_interface()
{
if (d.ffns.p_ftdi_set_interface(&d.dev_info, INTERFACE_A) < 0 || d.ffns.p_ftdi_usb_open(&d.dev_info, Vendor, ProdID) < 0)
{
d.ffns.p_ftdi_deinit(&d.dev_info);
return 1;
}
if (d.ffns.p_ftdi_usb_reset(&d.dev_info) < 0 || d.ffns.p_ftdi_read_data_set_chunksize(&d.dev_info, 65536) < 0)
{
d.ffns.p_ftdi_usb_close(&d.dev_info);
d.ffns.p_ftdi_deinit(&d.dev_info);
return 1;
}
return 0;
}
struct driver_st d = {
.vfns = {
.st_size = sizeof(struct virtual_fns_st),
.dev_description = "usb-blaster-clone",
.st_flags = 0x800,
.p_find_devs = find_devs,
.p_find_descriptions = find_descriptions,
.p_init_dev = init_dev,
.p_close = do_close,
.p_pkt_wr_pattern = pkt_wr_pattern,
.p_pkt_wr_bits = pkt_wr_bits,
.p_do_flush = do_flush,
},
};
#define STRINGIFIER_DSO_METHOD_NAME(x) #x
#define STRINGIFY_DSO_METHOD_NAME(y) STRINGIFIER_DSO_METHOD_NAME(y)
#define STRING_DSO_METHOD_NAME STRINGIFY_DSO_METHOD_NAME(DSO_METHOD_NAME)
#define VISIBILITY_DEFAULT_EXTERN __attribute__((visibility("default"))) extern
VISIBILITY_DEFAULT_EXTERN struct virtual_fns_st * DSO_METHOD_NAME(uint32_t hw_type)
{
if (hw_type != 0) return 0;
if (d.ffns.handle) return &d.vfns;
d.ffns.handle = dlopen("libftdi.so", RTLD_NOW);
if (!d.ffns.handle) {
#if 0
If you have libftdi.so installed and you get this error, try a test:
Create a file test.c:
int main() { return 0; }
Next, compile it with: gcc -o test -lftdi test.c
Use google to fix any problems, then make sure libftdi.so is in /usr/lib
As a last resort, change the call to dlopen() above so it has the full file path
#endif
return 0;
}
#define load_ffn(f) (!(d.ffns.p_##f = dlsym(d.ffns.handle, #f)))
/* these can fail when the version is wrong. it must be libftdi-0.18 */
if (load_ffn(ftdi_init) || load_ffn(ftdi_set_interface) || load_ffn(ftdi_deinit) ||
load_ffn(ftdi_usb_open) || load_ffn(ftdi_usb_close) || load_ffn(ftdi_usb_reset) ||
load_ffn(ftdi_usb_purge_buffers) || load_ffn(ftdi_read_data) ||
load_ffn(ftdi_read_data_set_chunksize) || load_ffn(ftdi_write_data) ||
load_ffn(ftdi_write_data_set_chunksize) || load_ffn(ftdi_write_data_get_chunksize) ||
load_ffn(ftdi_set_bitmode) || load_ffn(ftdi_get_error_string) ||
d.ffns.p_ftdi_init(&d.dev_info) < 0 || do_set_interface())
{
dlclose(d.ffns.handle);
d.ffns.handle = 0;
return 0;
}
d.num_devs = 1;
return &d.vfns;
}
/*
TODO
multiple device support
use bulk usb transfer, programming speed can be a lot faster
mac os support
INSTRUCTIONS
------------
save this file as libjtag_hw_your_name_here.c
(yes, you can use any name after libjtag_hw_)
you must then plug in your hardware to detect the USB ID and compile it into the .so file
then compile it with this command:
(this is a very long line, and it must all be typed on the same line)
gcc -fPIC -fvisibility=hidden -DDSO_METHOD_NAME=`wget -qO - http://ubuntuforums.org/archive/index.php/t-142166.html | sed -e '/ial pro/p;d' | cut -d " " --output-delimiter=_ -sf 37-39 | sed -e 's/.$//'` `awk '/clone/{print gensub("=","=0x","g",gensub(".*(V[^ ]*) *(P[^ ]*).*","-D\\\\1 -D\\\\2","",Q))}{Q=P;P=$0}' /proc/bus/usb/devices` -shared -Wl,-soname,libjtag_hw_your_name_here.so -o libjtag_hw_your_name_here.so -ldl libjtag_hw_your_name_here.c
then check that compilation went ok by typing this command:
nm -CD *.so|md5sum|awk '{if ($1 == "9c9ae1be799a6ebda49a84a7a3b09104") print "ok"; else print "problem"}'
then copy the .so file to the directory that has other files named libjtag_hw_*,
note that there are two directories, you can copy the .so file into both for normal situations
*/