11b0e65d752aae3c49dcf6a4fb9c72ea8074c407
[fw/openocd] / src / jtag / drivers / usb_blaster / ublast_access_ftdi.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /*
4  *   Driver for USB-JTAG, Altera USB-Blaster and compatibles
5  *
6  *   Inspired from original code from Kolja Waschk's USB-JTAG project
7  *   (http://www.ixo.de/info/usb_jtag/), and from openocd project.
8  *
9  *   Copyright (C) 2012 Robert Jarzmik robert.jarzmik@free.fr
10  *   Copyright (C) 2011 Ali Lown ali@lown.me.uk
11  *   Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca
12  *   Copyright (C) 2006 Kolja Waschk usbjtag@ixo.de
13  *
14  */
15
16 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19 #include <jtag/interface.h>
20 #include <jtag/commands.h>
21
22 #include "ublast_access.h"
23 #include <ftdi.h>
24
25 static struct ftdi_context *ublast_getftdic(struct ublast_lowlevel *low)
26 {
27         return low->priv;
28 }
29
30 static int ublast_ftdi_read(struct ublast_lowlevel *low, uint8_t *buf,
31                             unsigned size, uint32_t *bytes_read)
32 {
33         int retval;
34         int timeout = 100;
35         struct ftdi_context *ftdic = ublast_getftdic(low);
36
37         *bytes_read = 0;
38         while ((*bytes_read < size) && timeout--) {
39                 retval = ftdi_read_data(ftdic, buf + *bytes_read,
40                                 size - *bytes_read);
41                 if (retval < 0) {
42                         *bytes_read = 0;
43                         LOG_ERROR("ftdi_read_data: %s",
44                                         ftdi_get_error_string(ftdic));
45                         return ERROR_JTAG_DEVICE_ERROR;
46                 }
47                 *bytes_read += retval;
48         }
49         return ERROR_OK;
50 }
51
52 static int ublast_ftdi_write(struct ublast_lowlevel *low, uint8_t *buf, int size,
53                              uint32_t *bytes_written)
54 {
55         int retval;
56         struct ftdi_context *ftdic = ublast_getftdic(low);
57
58         retval = ftdi_write_data(ftdic, buf, size);
59         if (retval < 0) {
60                 *bytes_written = 0;
61                 LOG_ERROR("ftdi_write_data: %s",
62                           ftdi_get_error_string(ftdic));
63                 return ERROR_JTAG_DEVICE_ERROR;
64         }
65         *bytes_written = retval;
66         return ERROR_OK;
67 }
68
69 static int ublast_ftdi_init(struct ublast_lowlevel *low)
70 {
71         uint8_t latency_timer;
72         struct ftdi_context *ftdic = ublast_getftdic(low);
73
74         LOG_INFO("usb blaster interface using libftdi");
75         if (ftdi_init(ftdic) < 0)
76                 return ERROR_JTAG_INIT_FAILED;
77
78         /* context, vendor id, product id */
79         if (ftdi_usb_open(ftdic, low->ublast_vid, low->ublast_pid) < 0) {
80                 LOG_ERROR("unable to open ftdi device: %s", ftdic->error_str);
81                 return ERROR_JTAG_INIT_FAILED;
82         }
83
84         if (ftdi_usb_reset(ftdic) < 0) {
85                 LOG_ERROR("unable to reset ftdi device");
86                 return ERROR_JTAG_INIT_FAILED;
87         }
88
89         if (ftdi_set_latency_timer(ftdic, 2) < 0) {
90                 LOG_ERROR("unable to set latency timer");
91                 return ERROR_JTAG_INIT_FAILED;
92         }
93
94         if (ftdi_get_latency_timer(ftdic, &latency_timer) < 0)
95                 LOG_ERROR("unable to get latency timer");
96         else
97                 LOG_DEBUG("current latency timer: %u", latency_timer);
98
99         ftdi_disable_bitbang(ftdic);
100         return ERROR_OK;
101 }
102
103 static int ublast_ftdi_quit(struct ublast_lowlevel *low)
104 {
105         struct ftdi_context *ftdic = ublast_getftdic(low);
106
107         ftdi_usb_close(ftdic);
108         ftdi_deinit(ftdic);
109         return ERROR_OK;
110 };
111
112 static struct ublast_lowlevel_priv {
113         struct ftdi_context ftdic;
114 } info;
115
116 static struct ublast_lowlevel low = {
117         .open = ublast_ftdi_init,
118         .close = ublast_ftdi_quit,
119         .read = ublast_ftdi_read,
120         .write = ublast_ftdi_write,
121         .priv = &info,
122 };
123
124 struct ublast_lowlevel *ublast_register_ftdi(void)
125 {
126         return &low;
127 }