Forum Discussion
Altera_Forum
Honored Contributor
15 years ago uint32_t st_flags;
void * reserved01;
fn_find_devs p_find_devs;
fn_find_descriptions p_find_descriptions;
fn_init_dev p_init_dev;
fn_close p_close;
void * reserved02;
fn_pkt_wr_pattern p_pkt_wr_pattern;
fn_pkt_wr_bits p_pkt_wr_bits;
void * reserved03;
fn_do_flush p_do_flush;
void * reserved04;
};
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; /* 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, r_nbits;
};
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, sizeof(d.r_buf_2)/sizeof(d.r_buf_2) - 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 = 0x80;
d.w_buf = 0x10;
d.w_buf = 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;
*(wp++) = 0x80; *(wp++) = 0x10; *(wp++) = 0x9b; *(wp++) = 0x87;
do_ftdi_write(&d.w_buf, 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;
for (q = 0; q < d.r_nbits; q++) {
if (!bit) d.r_buf_2 = 0; /* prepare next byte to receive bits */
if (bv & (0x80 >> (d.r_nbits - q - 1))) d.r_buf_2 |= 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 = 0x80; d.w_buf = 0x10 | (tms ? 0x08 : 0); d.w_buf = 0x9b;
d.last_tms = !!tms;
d.chain_3d = 0;
} else if (d.w_buf_use > 3 && d.w_buf == 0x3e) {
if (d.w_buf < 6) {
d.w_buf |= (v ? 1 : 0) << (++d.w_buf);
d.r_nbits++;
} else {
if (!d.chain_3d) {
d.w_buf = 0x3d;
d.w_buf = d.w_buf | (v ? 0x80 : 0); d.w_buf = 0x00; d.w_buf = 0x00;
d.w_buf_use++;
d.r_nbits++;
d.chain_3d = d.last_cmd;
} else {
unsigned chain = (d.w_buf | (d.w_buf << 8)) + 1;
d.w_buf = chain & 0xff; d.w_buf = (chain >> 8) & 0xff; d.w_buf = d.w_buf | (v ? 0x80 : 0);
d.w_buf_use = d.chain_3d + chain + 4;
d.last_cmd = d.chain_3d;
d.r_nbits++;
}
}
return;
}
d.last_cmd = d.w_buf_use;
d.w_buf = 0x3e; d.w_buf = 0x00; d.w_buf = (v ? 1 : 0);
d.r_nbits = 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 & 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;
}