aboutsummaryrefslogtreecommitdiff
path: root/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c
blob: eb312ef4eeab548049f4aa15029969448a08fa42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// SPDX-License-Identifier: GPL-2.0-or-later

/*
 *   Driver for USB-JTAG, Altera USB-Blaster and compatibles
 *
 *   Inspired from original code from Kolja Waschk's USB-JTAG project
 *   (http://www.ixo.de/info/usb_jtag/), and from openocd project.
 *
 *   Copyright (C) 2012 Robert Jarzmik robert.jarzmik@free.fr
 *   Copyright (C) 2011 Ali Lown ali@lown.me.uk
 *   Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca
 *   Copyright (C) 2006 Kolja Waschk usbjtag@ixo.de
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <jtag/interface.h>
#include <jtag/commands.h>

#include "ublast_access.h"
#include <ftdi.h>

static struct ftdi_context *ublast_getftdic(struct ublast_lowlevel *low)
{
	return low->priv;
}

static int ublast_ftdi_read(struct ublast_lowlevel *low, uint8_t *buf,
			    unsigned size, uint32_t *bytes_read)
{
	int retval;
	int timeout = 100;
	struct ftdi_context *ftdic = ublast_getftdic(low);

	*bytes_read = 0;
	while ((*bytes_read < size) && timeout--) {
		retval = ftdi_read_data(ftdic, buf + *bytes_read,
				size - *bytes_read);
		if (retval < 0)	{
			*bytes_read = 0;
			LOG_ERROR("ftdi_read_data: %s",
					ftdi_get_error_string(ftdic));
			return ERROR_JTAG_DEVICE_ERROR;
		}
		*bytes_read += retval;
	}
	return ERROR_OK;
}

static int ublast_ftdi_write(struct ublast_lowlevel *low, uint8_t *buf, int size,
			     uint32_t *bytes_written)
{
	int retval;
	struct ftdi_context *ftdic = ublast_getftdic(low);

	retval = ftdi_write_data(ftdic, buf, size);
	if (retval < 0)	{
		*bytes_written = 0;
		LOG_ERROR("ftdi_write_data: %s",
			  ftdi_get_error_string(ftdic));
		return ERROR_JTAG_DEVICE_ERROR;
	}
	*bytes_written = retval;
	return ERROR_OK;
}

static int ublast_ftdi_init(struct ublast_lowlevel *low)
{
	uint8_t latency_timer;
	struct ftdi_context *ftdic = ublast_getftdic(low);

	LOG_INFO("usb blaster interface using libftdi");
	if (ftdi_init(ftdic) < 0)
		return ERROR_JTAG_INIT_FAILED;

	/* context, vendor id, product id */
	if (ftdi_usb_open(ftdic, low->ublast_vid, low->ublast_pid) < 0)	{
		LOG_ERROR("unable to open ftdi device: %s", ftdic->error_str);
		return ERROR_JTAG_INIT_FAILED;
	}

	if (ftdi_usb_reset(ftdic) < 0) {
		LOG_ERROR("unable to reset ftdi device");
		return ERROR_JTAG_INIT_FAILED;
	}

	if (ftdi_set_latency_timer(ftdic, 2) < 0) {
		LOG_ERROR("unable to set latency timer");
		return ERROR_JTAG_INIT_FAILED;
	}

	if (ftdi_get_latency_timer(ftdic, &latency_timer) < 0)
		LOG_ERROR("unable to get latency timer");
	else
		LOG_DEBUG("current latency timer: %u", latency_timer);

	ftdi_disable_bitbang(ftdic);
	return ERROR_OK;
}

static int ublast_ftdi_quit(struct ublast_lowlevel *low)
{
	struct ftdi_context *ftdic = ublast_getftdic(low);

	ftdi_usb_close(ftdic);
	ftdi_deinit(ftdic);
	return ERROR_OK;
};

static struct ublast_lowlevel_priv {
	struct ftdi_context ftdic;
} info;

static struct ublast_lowlevel low = {
	.open = ublast_ftdi_init,
	.close = ublast_ftdi_quit,
	.read = ublast_ftdi_read,
	.write = ublast_ftdi_write,
	.priv = &info,
};

struct ublast_lowlevel *ublast_register_ftdi(void)
{
	return &low;
}