stlink: Decode more errors.
[fw/openocd] / src / jtag / drivers / remote_bitbang.c
1 /***************************************************************************
2  *   Copyright (C) 2011 by Richard Uhler                                   *
3  *   ruhler@mit.edu                                                        *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
19  ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #ifndef _WIN32
26 #include <sys/un.h>
27 #include <netdb.h>
28 #endif
29 #include <jtag/interface.h>
30 #include "bitbang.h"
31
32 /* arbitrary limit on host name length: */
33 #define REMOTE_BITBANG_HOST_MAX 255
34
35 #define REMOTE_BITBANG_RAISE_ERROR(expr ...) \
36         do { \
37                 LOG_ERROR(expr); \
38                 LOG_ERROR("Terminating openocd."); \
39                 exit(-1); \
40         } while (0)
41
42 static char *remote_bitbang_host;
43 static char *remote_bitbang_port;
44
45 FILE *remote_bitbang_in;
46 FILE *remote_bitbang_out;
47
48 static void remote_bitbang_putc(int c)
49 {
50         if (EOF == fputc(c, remote_bitbang_out))
51                 REMOTE_BITBANG_RAISE_ERROR("remote_bitbang_putc: %s", strerror(errno));
52 }
53
54 static int remote_bitbang_quit(void)
55 {
56         if (EOF == fputc('Q', remote_bitbang_out)) {
57                 LOG_ERROR("fputs: %s", strerror(errno));
58                 return ERROR_FAIL;
59         }
60
61         if (EOF == fflush(remote_bitbang_out)) {
62                 LOG_ERROR("fflush: %s", strerror(errno));
63                 return ERROR_FAIL;
64         }
65
66         /* We only need to close one of the FILE*s, because they both use the same */
67         /* underlying file descriptor. */
68         if (EOF == fclose(remote_bitbang_out)) {
69                 LOG_ERROR("fclose: %s", strerror(errno));
70                 return ERROR_FAIL;
71         }
72
73         free(remote_bitbang_host);
74         free(remote_bitbang_port);
75
76         LOG_INFO("remote_bitbang interface quit");
77         return ERROR_OK;
78 }
79
80 /* Get the next read response. */
81 static int remote_bitbang_rread(void)
82 {
83         if (EOF == fflush(remote_bitbang_out)) {
84                 remote_bitbang_quit();
85                 REMOTE_BITBANG_RAISE_ERROR("fflush: %s", strerror(errno));
86         }
87
88         int c = fgetc(remote_bitbang_in);
89         switch (c) {
90                 case '0':
91                         return 0;
92                 case '1':
93                         return 1;
94                 default:
95                         remote_bitbang_quit();
96                         REMOTE_BITBANG_RAISE_ERROR(
97                                         "remote_bitbang: invalid read response: %c(%i)", c, c);
98         }
99 }
100
101 static int remote_bitbang_read(void)
102 {
103         remote_bitbang_putc('R');
104         return remote_bitbang_rread();
105 }
106
107 static void remote_bitbang_write(int tck, int tms, int tdi)
108 {
109         char c = '0' + ((tck ? 0x4 : 0x0) | (tms ? 0x2 : 0x0) | (tdi ? 0x1 : 0x0));
110         remote_bitbang_putc(c);
111 }
112
113 static void remote_bitbang_reset(int trst, int srst)
114 {
115         char c = 'r' + ((trst ? 0x2 : 0x0) | (srst ? 0x1 : 0x0));
116         remote_bitbang_putc(c);
117 }
118
119 static void remote_bitbang_blink(int on)
120 {
121         char c = on ? 'B' : 'b';
122         remote_bitbang_putc(c);
123 }
124
125 static struct bitbang_interface remote_bitbang_bitbang = {
126         .read = &remote_bitbang_read,
127         .write = &remote_bitbang_write,
128         .reset = &remote_bitbang_reset,
129         .blink = &remote_bitbang_blink,
130 };
131
132 static int remote_bitbang_init_tcp(void)
133 {
134         struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM };
135         struct addrinfo *result, *rp;
136         int fd;
137
138         LOG_INFO("Connecting to %s:%s",
139                         remote_bitbang_host ? remote_bitbang_host : "localhost",
140                         remote_bitbang_port);
141
142         /* Obtain address(es) matching host/port */
143         int s = getaddrinfo(remote_bitbang_host, remote_bitbang_port, &hints, &result);
144         if (s != 0) {
145                 LOG_ERROR("getaddrinfo: %s\n", gai_strerror(s));
146                 return ERROR_FAIL;
147         }
148
149         /* getaddrinfo() returns a list of address structures.
150          Try each address until we successfully connect(2).
151          If socket(2) (or connect(2)) fails, we (close the socket
152          and) try the next address. */
153
154         for (rp = result; rp != NULL ; rp = rp->ai_next) {
155                 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
156                 if (fd == -1)
157                         continue;
158
159                 if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1)
160                         break; /* Success */
161
162                 close(fd);
163         }
164
165         freeaddrinfo(result); /* No longer needed */
166
167         if (rp == NULL) { /* No address succeeded */
168                 LOG_ERROR("Failed to connect: %s", strerror(errno));
169                 return ERROR_FAIL;
170         }
171
172         return fd;
173 }
174
175 static int remote_bitbang_init_unix(void)
176 {
177         if (remote_bitbang_host == NULL) {
178                 LOG_ERROR("host/socket not specified");
179                 return ERROR_FAIL;
180         }
181
182         LOG_INFO("Connecting to unix socket %s", remote_bitbang_host);
183         int fd = socket(PF_UNIX, SOCK_STREAM, 0);
184         if (fd < 0) {
185                 LOG_ERROR("socket: %s", strerror(errno));
186                 return ERROR_FAIL;
187         }
188
189         struct sockaddr_un addr;
190         addr.sun_family = AF_UNIX;
191         strncpy(addr.sun_path, remote_bitbang_host, sizeof(addr.sun_path));
192         addr.sun_path[sizeof(addr.sun_path)-1] = '\0';
193
194         if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
195                 LOG_ERROR("connect: %s", strerror(errno));
196                 return ERROR_FAIL;
197         }
198
199         return fd;
200 }
201
202 static int remote_bitbang_init(void)
203 {
204         int fd;
205         bitbang_interface = &remote_bitbang_bitbang;
206
207         LOG_INFO("Initializing remote_bitbang driver");
208         if (remote_bitbang_port == NULL)
209                 fd = remote_bitbang_init_unix();
210         else
211                 fd = remote_bitbang_init_tcp();
212
213         if (fd < 0)
214                 return fd;
215
216         remote_bitbang_in = fdopen(fd, "r");
217         if (remote_bitbang_in == NULL) {
218                 LOG_ERROR("fdopen: failed to open read stream");
219                 close(fd);
220                 return ERROR_FAIL;
221         }
222
223         remote_bitbang_out = fdopen(fd, "w");
224         if (remote_bitbang_out == NULL) {
225                 LOG_ERROR("fdopen: failed to open write stream");
226                 fclose(remote_bitbang_in);
227                 return ERROR_FAIL;
228         }
229
230         LOG_INFO("remote_bitbang driver initialized");
231         return ERROR_OK;
232 }
233
234 COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_port_command)
235 {
236         if (CMD_ARGC == 1) {
237                 uint16_t port;
238                 COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port);
239                 free(remote_bitbang_port);
240                 remote_bitbang_port = port == 0 ? NULL : strdup(CMD_ARGV[0]);
241                 return ERROR_OK;
242         }
243         return ERROR_COMMAND_SYNTAX_ERROR;
244 }
245
246 COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_host_command)
247 {
248         if (CMD_ARGC == 1) {
249                 free(remote_bitbang_host);
250                 remote_bitbang_host = strdup(CMD_ARGV[0]);
251                 return ERROR_OK;
252         }
253         return ERROR_COMMAND_SYNTAX_ERROR;
254 }
255
256 static const struct command_registration remote_bitbang_command_handlers[] = {
257         {
258                 .name = "remote_bitbang_port",
259                 .handler = remote_bitbang_handle_remote_bitbang_port_command,
260                 .mode = COMMAND_CONFIG,
261                 .help = "Set the port to use to connect to the remote jtag.\n"
262                         "  if 0 or unset, use unix sockets to connect to the remote jtag.",
263                 .usage = "port_number",
264         },
265         {
266                 .name = "remote_bitbang_host",
267                 .handler = remote_bitbang_handle_remote_bitbang_host_command,
268                 .mode = COMMAND_CONFIG,
269                 .help = "Set the host to use to connect to the remote jtag.\n"
270                         "  if port is 0 or unset, this is the name of the unix socket to use.",
271                 .usage = "host_name",
272         },
273         COMMAND_REGISTRATION_DONE,
274 };
275
276 struct jtag_interface remote_bitbang_interface = {
277         .name = "remote_bitbang",
278         .execute_queue = &bitbang_execute_queue,
279         .commands = remote_bitbang_command_handlers,
280         .init = &remote_bitbang_init,
281         .quit = &remote_bitbang_quit,
282 };