aboutsummaryrefslogtreecommitdiff
path: root/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c
blob: 2527fe9a6315f41dd856ac80622b6a9867b635f6 (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
128
129
130
131
132
133
134
135
/*
 *   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
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   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 General Public License for more details.
 *
 */

#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;
}